Rewrite of OBJ parser + converter to OSG

This commit is contained in:
Robert Osfield
2004-08-26 14:33:38 +00:00
parent 075c2f94d0
commit 889704964b
7 changed files with 996 additions and 2784 deletions

View File

@@ -38,19 +38,13 @@
#include <osgUtil/TriStripVisitor>
#include <osgUtil/SmoothingVisitor>
#include <osgUtil/Tesselator>
#include "glm.h"
#include "obj.h"
#include <map>
#include <set>
template <class T>
struct DerefLess
{
bool operator ()(T lhs,T rhs) const { return *lhs < *rhs; }
};
class ReaderWriterOBJ : public osgDB::ReaderWriter
{
public:
@@ -63,93 +57,351 @@ public:
virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*);
protected:
enum DrawableMode
{
DUPLICATE_COORDS,
USE_SEPERATE_INDICES,
};
osg::Drawable* makeDrawable(DrawableMode drawableMode, GLMmodel* obj, GLMgroup* grp);
osg::Drawable* makeDrawable_duplicateCoords(GLMmodel* obj, GLMgroup* grp);
osg::Drawable* makeDrawable_useSeperateIndices(GLMmodel* obj, GLMgroup* grp);
typedef std::map< std::string, osg::ref_ptr<osg::StateSet> > MaterialToStateSetMap;
typedef std::map< std::string, osg::ref_ptr<osg::Texture2D> > TextureMap;
typedef std::set< osg::ref_ptr<osg::Material>, DerefLess< osg::ref_ptr<osg::Material> > > MaterialSet;
typedef std::set< osg::ref_ptr<osg::StateSet>, DerefLess< osg::ref_ptr<osg::StateSet> > > StateSetSet;
typedef std::vector< osg::ref_ptr<osg::StateSet> > ObjMatierialOsgStateSetArray;
void buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToSetSetMap);
class IndexMap
{
public:
IndexMap():
_maximumIn(-1),
_maximumOut(-1) {}
inline void updateMaximum(int index)
{
if (index>_maximumIn) _maximumIn=index;
}
inline void initialize()
{
_indices.assign(_maximumIn+1,-1);
}
inline void insertIndex(int index)
{
if (_indices[index]<0) _indices[index]=++_maximumOut;
}
inline int index(int i) const { return _indices[i]; }
osg::Vec3Array* createVec3Array(const float* array)
{
osg::Vec3Array* vec3array = new osg::Vec3Array(_maximumOut+1);
for(unsigned int i=0;i<_indices.size();++i)
{
if (_indices[i]>=0) (*vec3array)[_indices[i]].set(array[i*3],-array[i*3+2],array[i*3+1]);
}
return vec3array;
}
osg::Vec2Array* createVec2Array(const float* array)
{
osg::Vec2Array* vec2array = new osg::Vec2Array(_maximumOut+1);
for(unsigned int i=0;i<_indices.size();++i)
{
if (_indices[i]>=0) (*vec2array)[_indices[i]].set(array[i*2],array[i*2+1]);
}
return vec2array;
}
osg::UByte4Array* createUByte4Array(const osg::UByte4* array)
{
osg::UByte4Array* ubyte4array = new osg::UByte4Array(_maximumOut+1);
for(unsigned int i=0;i<_indices.size();++i)
{
if (_indices[i]>=0) (*ubyte4array)[_indices[i]] = array[i];
}
return ubyte4array;
}
typedef std::vector<int> Indices;
int _maximumIn;
int _maximumOut;
Indices _indices;
};
osg::Geometry* convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList);
osg::Node* convertModelToSceneGraph(obj::Model& model);
inline osg::Vec3 transformVertex(const osg::Vec3& vec) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); }
inline osg::Vec3 transformNormal(const osg::Vec3& vec) { return osg::Vec3(vec.x(),-vec.z(),vec.y()); }
};
// register with Registry to instantiate the above reader/writer.
osgDB::RegisterReaderWriterProxy<ReaderWriterOBJ> g_objReaderWriterProxy;
void ReaderWriterOBJ::buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToStateSetMap)
{
for(obj::Model::MaterialMap::iterator itr = model.materialMap.begin();
itr != model.materialMap.end();
++itr)
{
obj::Material& material = itr->second;
osg::StateSet* stateset = new osg::StateSet;
// handle material colors
{
osg::Material* osg_material = new osg::Material;
stateset->setAttribute(osg_material);
osg_material->setAmbient(osg::Material::FRONT_AND_BACK,material.ambient);
osg_material->setDiffuse(osg::Material::FRONT_AND_BACK,material.diffuse);
osg_material->setSpecular(osg::Material::FRONT_AND_BACK,material.specular);
osg_material->setShininess(osg::Material::FRONT_AND_BACK,(material.shininess/1000.0f)*128.0f ); // note OBJ shiniess is 0..1000.
}
// handle textures
if (!material.map_Kd.empty())
{
std::string filename = material.map_Kd;
osg::Image* image = osgDB::readImageFile(filename);
if (image)
{
osg::Texture2D* texture = new osg::Texture2D(image);
stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
}
}
materialToStateSetMap[material.name] = stateset;
}
}
osg::Geometry* ReaderWriterOBJ::convertElementListToGeometry(obj::Model& model, obj::Model::ElementList& elementList)
{
unsigned int numVertexIndices = 0;
unsigned int numNormalIndices = 0;
unsigned int numTexCoordIndices = 0;
unsigned int numPointElements = 0;
unsigned int numPolylineElements = 0;
unsigned int numPolygonElements = 0;
obj::Model::ElementList::iterator itr;
for(itr=elementList.begin();
itr!=elementList.end();
++itr)
{
obj::Element& element = *(*itr);
numVertexIndices += element.vertexIndices.size();
numNormalIndices += element.normalIndices.size();
numTexCoordIndices += element.texCoordIndices.size();
numPointElements += (element.dataType==obj::Element::POINTS) ? 1 : 0;
numPolylineElements += (element.dataType==obj::Element::POLYLINE) ? 1 : 0;
numPolygonElements += (element.dataType==obj::Element::POLYGON) ? 1 : 0;
}
if (numVertexIndices==0) return 0;
if (numNormalIndices!=0 && numNormalIndices!=numVertexIndices)
{
osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl;
numNormalIndices = 0;
}
if (numTexCoordIndices!=0 && numTexCoordIndices!=numVertexIndices)
{
osg::notify(osg::NOTICE)<<"Incorrect number of normals, ignore them"<<std::endl;
numTexCoordIndices = 0;
}
osg::Vec3Array* vertices = numVertexIndices ? new osg::Vec3Array : 0;
osg::Vec3Array* normals = numNormalIndices ? new osg::Vec3Array : 0;
osg::Vec2Array* texcoords = numTexCoordIndices ? new osg::Vec2Array : 0;
if (vertices) vertices->reserve(numVertexIndices);
if (normals) normals->reserve(numNormalIndices);
if (texcoords) texcoords->reserve(numTexCoordIndices);
osg::Geometry* geometry = new osg::Geometry;
if (vertices) geometry->setVertexArray(vertices);
if (normals)
{
geometry->setNormalArray(normals);
geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (texcoords)
{
geometry->setTexCoordArray(0,texcoords);
}
if (numPointElements>0)
{
unsigned int startPos = vertices->size();
unsigned int numPoints = 0;
for(itr=elementList.begin();
itr!=elementList.end();
++itr)
{
obj::Element& element = *(*itr);
if (element.dataType==obj::Element::POINTS)
{
for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
index_itr != element.vertexIndices.end();
++index_itr)
{
vertices->push_back(transformVertex(model.vertices[*index_itr]));
++numPoints;
}
if (numNormalIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
index_itr != element.normalIndices.end();
++index_itr)
{
normals->push_back(transformNormal(model.normals[*index_itr]));
}
}
if (numTexCoordIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
index_itr != element.texCoordIndices.end();
++index_itr)
{
texcoords->push_back(model.texcoords[*index_itr]);
}
}
}
}
osg::DrawArrays* drawArrays = new osg::DrawArrays(GL_POINTS,startPos,numPoints);
geometry->addPrimitiveSet(drawArrays);
}
if (numPolylineElements>0)
{
unsigned int startPos = vertices->size();
osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(GL_LINES,startPos);
for(itr=elementList.begin();
itr!=elementList.end();
++itr)
{
obj::Element& element = *(*itr);
if (element.dataType==obj::Element::POLYLINE)
{
drawArrayLengths->push_back(element.vertexIndices.size());
for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
index_itr != element.vertexIndices.end();
++index_itr)
{
vertices->push_back(transformVertex(model.vertices[*index_itr]));
}
if (numNormalIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
index_itr != element.normalIndices.end();
++index_itr)
{
normals->push_back(transformNormal(model.normals[*index_itr]));
}
}
if (numTexCoordIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
index_itr != element.texCoordIndices.end();
++index_itr)
{
texcoords->push_back(model.texcoords[*index_itr]);
}
}
}
}
geometry->addPrimitiveSet(drawArrayLengths);
}
bool reverseWinding = true;
if (numPolygonElements>0)
{
unsigned int startPos = vertices->size();
osg::DrawArrayLengths* drawArrayLengths = new osg::DrawArrayLengths(GL_POLYGON,startPos);
for(itr=elementList.begin();
itr!=elementList.end();
++itr)
{
obj::Element& element = *(*itr);
if (element.dataType==obj::Element::POLYGON)
{
drawArrayLengths->push_back(element.vertexIndices.size());
if (reverseWinding)
{
// need to reverse so add to OSG arrays in same order as in OBJ, as OSG assume anticlockwise ordering.
for(obj::Element::IndexList::reverse_iterator index_itr = element.vertexIndices.rbegin();
index_itr != element.vertexIndices.rend();
++index_itr)
{
vertices->push_back(transformVertex(model.vertices[*index_itr]));
}
if (numNormalIndices)
{
for(obj::Element::IndexList::reverse_iterator index_itr = element.normalIndices.rbegin();
index_itr != element.normalIndices.rend();
++index_itr)
{
normals->push_back(transformNormal(model.normals[*index_itr]));
}
}
if (numTexCoordIndices)
{
for(obj::Element::IndexList::reverse_iterator index_itr = element.texCoordIndices.rbegin();
index_itr != element.texCoordIndices.rend();
++index_itr)
{
texcoords->push_back(model.texcoords[*index_itr]);
}
}
}
else
{
// no need to reverse so add to OSG arrays in same order as in OBJ.
for(obj::Element::IndexList::iterator index_itr = element.vertexIndices.begin();
index_itr != element.vertexIndices.end();
++index_itr)
{
vertices->push_back(model.vertices[*index_itr]);
}
if (numNormalIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.normalIndices.begin();
index_itr != element.normalIndices.end();
++index_itr)
{
normals->push_back(model.normals[*index_itr]);
}
}
if (numTexCoordIndices)
{
for(obj::Element::IndexList::iterator index_itr = element.texCoordIndices.begin();
index_itr != element.texCoordIndices.end();
++index_itr)
{
texcoords->push_back(model.texcoords[*index_itr]);
}
}
}
}
}
geometry->addPrimitiveSet(drawArrayLengths);
}
return geometry;
}
osg::Node* ReaderWriterOBJ::convertModelToSceneGraph(obj::Model& model)
{
if (model.elementStateMap.empty()) return 0;
osg::Group* group = new osg::Group;
// set up the materials
MaterialToStateSetMap materialToSetSetMap;
buildMaterialToStateSetMap(model, materialToSetSetMap);
// go through the groups of related elements and build geometry from them.
for(obj::Model::ElementStateMap::iterator itr=model.elementStateMap.begin();
itr!=model.elementStateMap.end();
++itr)
{
const obj::ElementState& es = itr->first;
obj::Model::ElementList& el = itr->second;
osg::Geometry* geometry = convertElementListToGeometry(model,el);
if (geometry)
{
osg::StateSet* stateset = materialToSetSetMap[es.materialName].get();
geometry->setStateSet(stateset);
// osgUtil::Tesselator tesselator;
// tesselator.retesselatePolygons(*geometry);
osgUtil::TriStripVisitor tsv;
tsv.stripify(*geometry);
if (!geometry->getNormalArray() || geometry->getNormalArray()->getNumElements()==0)
{
osgUtil::SmoothingVisitor tsv;
tsv.smooth(*geometry);
}
osg::Geode* geode = new osg::Geode;
geode->addDrawable(geometry);
geode->setName(es.objectName);
group->addChild(geode);
}
}
return group;
}
// read file and convert to OSG.
osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& file, const osgDB::ReaderWriter::Options*)
@@ -159,469 +411,18 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil
std::string fileName = osgDB::findDataFile( file );
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
GLMmodel* obj = glmReadOBJ((char*) fileName.c_str());
if (!obj)
return ReadResult::FILE_NOT_HANDLED;
std::string directory = osgDB::getFilePath(fileName);
osg::notify(osg::INFO) << "vertices " << obj->numvertices << std::endl;
osg::notify(osg::INFO) << "normals " << obj->numnormals << std::endl;
osg::notify(osg::INFO) << "texcoords " << obj->numtexcoords << std::endl;
osg::notify(osg::INFO) << "face normals " << obj->numfacetnorms << std::endl;
osg::notify(osg::INFO) << "tris " << obj->numtriangles << std::endl;
osg::notify(osg::INFO) << "materials " << obj->nummaterials << std::endl;
osg::notify(osg::INFO) << "groups " << obj->numgroups << std::endl;
// if (obj->numnormals==0)
// {
// osg::notify(osg::NOTICE) << "No normals in .obj file, automatically calculating normals..."<< std::endl;
// glmFacetNormals(obj);
// glmVertexNormals(obj,90.0f);
// }
unsigned int i;
TextureMap textureMap;
MaterialSet materialSet;
StateSetSet statesetSet;
// create a sphere mapped texgen just in case we need it.
osg::ref_ptr<osg::TexGen> osg_texgen = new osg::TexGen;
osg_texgen->setMode(osg::TexGen::SPHERE_MAP);
ObjMatierialOsgStateSetArray osg_mtl(obj->nummaterials);
for (i = 0; i < obj->nummaterials; i++)
std::ifstream fin(fileName.c_str());
if (fin)
{
GLMmaterial* omtl = &(obj->materials[i]);
osg::notify(osg::DEBUG_INFO) << "mtl: " << omtl->name << std::endl;
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
osg::ref_ptr<osg::Material> mtl = new osg::Material;
mtl->setAmbient(osg::Material::FRONT_AND_BACK,
osg::Vec4(omtl->ambient[0], omtl->ambient[1],
omtl->ambient[2], omtl->ambient[3]));
mtl->setDiffuse(osg::Material::FRONT_AND_BACK,
osg::Vec4(omtl->diffuse[0], omtl->diffuse[1],
omtl->diffuse[2], omtl->diffuse[3]));
mtl->setSpecular(osg::Material::FRONT_AND_BACK,
osg::Vec4(omtl->specular[0], omtl->specular[1],
omtl->specular[2], omtl->specular[3]));
mtl->setEmission(osg::Material::FRONT_AND_BACK,
osg::Vec4(omtl->emmissive[0], omtl->emmissive[1],
omtl->emmissive[2], omtl->emmissive[3]));
// note, osg shininess scales between 0.0 and 1.0.
mtl->setShininess(osg::Material::FRONT_AND_BACK, omtl->shininess);
mtl->setAlpha(osg::Material::FRONT_AND_BACK, omtl->alpha);
MaterialSet::iterator mitr = materialSet.find(mtl);
if (mitr==materialSet.end())
{
materialSet.insert(mtl);
}
else
{
mtl = *mitr;
}
stateset->setAttribute(mtl.get());
if (omtl->alpha<1.0f) {
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
if (omtl->textureName)
{
TextureMap::iterator titr = textureMap.find(omtl->textureName);
osg::notify(osg::DEBUG_INFO) << "textureName: " << omtl->textureName << std::endl;
if (titr==textureMap.end())
{
std::string fileName = osgDB::findFileInDirectory(omtl->textureName,directory,osgDB::CASE_INSENSITIVE);
if (fileName.empty()) fileName = osgDB::findDataFile(omtl->textureName,osgDB::CASE_INSENSITIVE);
if (!fileName.empty())
{
osg::notify(osg::DEBUG_INFO) << "filename: " << fileName << std::endl;
osg::Image* osg_image = osgDB::readImageFile(fileName.c_str());
if (osg_image)
{
osg::notify(osg::DEBUG_INFO) << "imageRead: " << omtl->textureName << std::endl;
osg::Texture2D* osg_texture = new osg::Texture2D;
osg_texture->setImage(osg_image);
stateset->setTextureAttributeAndModes(0,osg_texture,osg::StateAttribute::ON);
textureMap[omtl->textureName] = osg_texture;
// Adjust the texture matrix if necessary
bool needsUVScaling = (1.0 != omtl->textureUScale) || (1.0 != omtl->textureVScale);
bool needsUVOffsetting = (0.0 != omtl->textureUOffset) || (0.0 != omtl->textureVOffset);
if (needsUVScaling || needsUVOffsetting)
{
osg::TexMat* osg_texmat = new osg::TexMat;
osg::Matrix scale;
osg::Matrix translate;
scale.makeIdentity();
translate.makeIdentity();
if (needsUVScaling)
{
scale.makeScale(omtl->textureUScale, omtl->textureVScale, 1.0f);
}
if (needsUVOffsetting)
{
translate.makeTranslate(omtl->textureUOffset, omtl->textureVOffset, 0.0f);
}
osg_texmat->setMatrix(scale * translate);
stateset->setTextureAttributeAndModes(0,osg_texmat,osg::StateAttribute::ON);
}
}
else
{
osg::notify(osg::NOTICE) << "Warning: Cannot create texture "<<omtl->textureName<< std::endl;
}
}
else
{
osg::notify(osg::WARN) << "texture '"<<omtl->textureName<<"' not found"<< std::endl;
}
}
else
{
stateset->setTextureAttributeAndModes(0,titr->second.get(),osg::StateAttribute::ON);
}
}
obj::Model model;
model.readOBJ(fin);
if (omtl->textureReflection)
{
stateset->setTextureAttributeAndModes(0,osg_texgen.get(),osg::StateAttribute::ON);
}
StateSetSet::iterator sitr = statesetSet.find(stateset);
if (sitr==statesetSet.end())
{
osg_mtl[i] = stateset;
statesetSet.insert(stateset);
}
else
{
osg_mtl[i] = *sitr;
}
osg::Node* node = convertModelToSceneGraph(model);
return node;
}
// toplevel group or transform
osg::Group* osg_top = NULL;
if (obj->position[0] != 0.0f || obj->position[1] != 0.0f || obj->position[2] != 0.0f) {
osg::MatrixTransform* xform = new osg::MatrixTransform;
// note obj_x -> osg_x,
// obj_y -> osg_z,
// obj_z -> osg_y,
xform->setMatrix(osg::Matrix::translate(obj->position[0], -obj->position[2], obj->position[1]));
osg_top = xform;
}
else
osg_top = new osg::Group;
osg_top->setName(obj->pathname);
DrawableMode drawableMode = USE_SEPERATE_INDICES;
// DrawableMode drawableMode = DUPLICATE_COORDS;
// subgroups
// XXX one Geode per group is probably not necessary...
GLMgroup* ogrp = obj->groups;
while (ogrp) {
if (ogrp->numtriangles > 0) {
osg::Geode* osg_geo = new osg::Geode;
osg_geo->setName(ogrp->name);
osg::Drawable* drawable = makeDrawable(drawableMode,obj,ogrp);
// state and material (if any)
if (!osg_mtl.empty()) {
osg::notify(osg::NOTICE)<<"ogrp->material="<<ogrp->material<<std::endl;
drawable->setStateSet(osg_mtl[ogrp->material].get());
}
osg_geo->addDrawable(drawable);
osg_top->addChild(osg_geo);
}
ogrp = ogrp->next;
}
// free
glmDelete(obj);
return osg_top;
return ReadResult::FILE_NOT_HANDLED;
}
osg::Drawable* ReaderWriterOBJ::makeDrawable(DrawableMode drawableMode, GLMmodel* obj, GLMgroup* grp)
{
switch(drawableMode)
{
case(DUPLICATE_COORDS): return makeDrawable_duplicateCoords(obj,grp);
case(USE_SEPERATE_INDICES): return makeDrawable_useSeperateIndices(obj,grp);
}
return 0;
}
// make drawable from OBJ group
osg::Drawable* ReaderWriterOBJ::makeDrawable_duplicateCoords(GLMmodel* obj, GLMgroup* grp)
{
GLMtriangle* tris = obj->triangles;
unsigned int ntris = grp->numtriangles;
unsigned int i = 0;
// geometry
osg::Geometry* geom = new osg::Geometry;
geom->setUseDisplayList(false);
// geom->setUseVertexBufferObjects(true);
// primitives are only triangles
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,ntris*3));
// the following code for mapping the coords, normals and texcoords
// is complicated greatly by the need to create separate out the
// sets of coords etc for each drawable.
bool needColors = obj->useColors && obj->colors;
bool needNormals = obj->normals && obj->normals;
bool needTexcoords = obj->texcoords && obj->numtexcoords>0 && grp->hastexcoords;
osg::Vec3Array* coordArray = new osg::Vec3Array(3*ntris);
osg::Vec3Array::iterator coords = coordArray->begin();
geom->setVertexArray(coordArray);
osg::UByte4Array::iterator colors = osg::UByte4Array::iterator();// dummy assignment to get round stupid compiler warnings.
if (needColors)
{
osg::UByte4Array* colorArray = new osg::UByte4Array(3*ntris);
geom->setColorArray(colorArray);
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
colors = colorArray->begin();
}
osg::Vec3Array::iterator normals = osg::Vec3Array::iterator();// dummy assignment to get round stupid compiler warnings.
if (needNormals)
{
osg::Vec3Array* normalArray = new osg::Vec3Array(3*ntris);
geom->setNormalArray(normalArray);
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
normals = normalArray->begin();
}
osg::Vec2Array::iterator texcoords = osg::Vec2Array::iterator(); // dummy assignment to get round stupid compiler warnings.
if (needTexcoords)
{
osg::Vec2Array* texCoordArray = new osg::Vec2Array(3*ntris);
geom->setTexCoordArray(0,texCoordArray);
texcoords = texCoordArray->begin();
}
// first count the number of vertices used in this group.
for (i = 0; i < ntris; i++)
{
GLMtriangle* tri = &(tris[grp->triangles[i]]);
for(int corner=0;corner<3;++corner)
{
int ci = tri->vindices[corner]*3;
// note rotate about the x axis to place the OBJ y up to OSG z up.
coords->set(obj->vertices[ci],-obj->vertices[ci+2],obj->vertices[ci+1]);
++coords;
if (needColors)
{
(*colors) = obj->colors[tri->vindices[corner]];
++colors;
}
if (needNormals)
{
int ni = tri->nindices[corner]*3;
// note rotate about the x axis to place the OBJ y up to OSG z up.
normals->set(obj->normals[ni],-obj->normals[ni+2],obj->normals[ni+1]);
++normals;
}
if (needTexcoords)
{
int ti = tri->tindices[corner]*2;
texcoords->set(obj->texcoords[ti+0], obj->texcoords[ti+1]);
++texcoords;
}
}
}
return geom;
}
osg::Drawable* ReaderWriterOBJ::makeDrawable_useSeperateIndices(GLMmodel* obj, GLMgroup* grp)
{
GLMtriangle* tris = obj->triangles;
unsigned int ntris = grp->numtriangles;
unsigned int i = 0;
// geometry
osg::Geometry* geom = new osg::Geometry;
// geom->setUseDisplayList(false);
// geom->setUseVertexBufferObjects(true);
// the following code for mapping the coords, normals and texcoords
// is complicated greatly by the need to create separate out the
// sets of coords etc for each drawable.
bool needColors = obj->useColors && obj->colors;
bool needNormals = obj->normals && obj->normals;
bool needTexcoords = obj->texcoords && obj->numtexcoords>0 && grp->hastexcoords;
// needNormals = false;
IndexMap vertexIndexMap;
IndexMap normalIndexMap;
IndexMap texcoordIndexMap;
// find maxium value.
for (i = 0; i < ntris; i++)
{
GLMtriangle& tri = tris[grp->triangles[i]];
for(int corner=0;corner<3;++corner)
{
vertexIndexMap.updateMaximum(tri.vindices[corner]);
if (needNormals) normalIndexMap.updateMaximum(tri.nindices[corner]);
if (needTexcoords) texcoordIndexMap.updateMaximum(tri.tindices[corner]);
}
}
// intialialize map.
vertexIndexMap.initialize();
if (needNormals) normalIndexMap.initialize();
if (needTexcoords) texcoordIndexMap.initialize();
// populate map.
for (i = 0; i < ntris; i++)
{
GLMtriangle& tri = tris[grp->triangles[i]];
for(int corner=0;corner<3;++corner)
{
vertexIndexMap.insertIndex(tri.vindices[corner]);
if (needNormals) normalIndexMap.insertIndex(tri.nindices[corner]);
if (needTexcoords) texcoordIndexMap.insertIndex(tri.tindices[corner]);
}
}
// copy data across to geometry.
geom->setVertexArray(vertexIndexMap.createVec3Array(obj->vertices));
if (needColors)
{
geom->setColorArray(vertexIndexMap.createUByte4Array(obj->colors));
geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (needNormals)
{
geom->setNormalArray(normalIndexMap.createVec3Array(obj->normals));
geom->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
}
if (needTexcoords)
{
geom->setTexCoordArray(0,texcoordIndexMap.createVec2Array(obj->texcoords));
}
osg::ref_ptr<osg::UIntArray> vertexIndices = new osg::UIntArray(ntris*3);
osg::ref_ptr<osg::UIntArray> normalIndices = needNormals ? new osg::UIntArray(ntris*3) : 0;
osg::ref_ptr<osg::UIntArray> texcoordIndices = needTexcoords ? new osg::UIntArray(ntris*3) : 0;
int vi=0;
for (i = 0; i < ntris; i++)
{
GLMtriangle& tri = (tris[grp->triangles[i]]);
for(int corner=0;corner<3;++corner,++vi)
{
(*vertexIndices)[vi] = vertexIndexMap.index(tri.vindices[corner]);
if (needNormals)
{
(*normalIndices)[vi] = normalIndexMap.index(tri.nindices[corner]);
}
if (needTexcoords)
{
(*texcoordIndices)[vi] = texcoordIndexMap.index(tri.tindices[corner]);
}
}
}
bool indexArraysEqual=true;
if (needNormals) indexArraysEqual=(*vertexIndices==*normalIndices);
if (indexArraysEqual && needTexcoords) indexArraysEqual=(*vertexIndices==*texcoordIndices);
if (indexArraysEqual)
{
geom->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::TRIANGLES,vertexIndices->begin(),vertexIndices->end()));
}
else
{
geom->setVertexIndices(vertexIndices.get());
if (needColors) geom->setColorIndices(vertexIndices.get());
if (needNormals) geom->setNormalIndices(normalIndices.get());
if (needTexcoords) geom->setTexCoordIndices(0,texcoordIndices.get());
// primitives are only triangles
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,ntris*3));
}
#if 0
osgUtil::TriStripVisitor tsv;
tsv.stripify(*geom);
#endif
if (obj->numnormals==0)
{
osgUtil::SmoothingVisitor tsv;
tsv.smooth(*geom);
}
return geom;
}