diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index 44ebc8e14..a462c23a1 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -37,6 +37,15 @@ #include "glm.h" +#include +#include + +template +struct DerefLess +{ + bool operator ()(T lhs,T rhs) const { return *lhs < *rhs; } +}; + class ReaderWriterOBJ : public osgDB::ReaderWriter { @@ -51,7 +60,13 @@ public: virtual ReadResult readNode(const std::string& fileName, const osgDB::ReaderWriter::Options*); protected: - osg::Drawable* makeDrawable(GLMmodel* obj, GLMgroup* grp, osg::StateSet**); + osg::Drawable* makeDrawable(GLMmodel* obj, GLMgroup* grp); + + typedef std::map< std::string, osg::ref_ptr > TextureMap; + typedef std::set< osg::ref_ptr, DerefLess< osg::ref_ptr > > MaterialSet; + typedef std::set< osg::ref_ptr, DerefLess< osg::ref_ptr > > StateSetSet; + typedef std::vector< osg::ref_ptr > ObjMatierialOsgStateSetArray; + }; @@ -92,43 +107,64 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil unsigned int i; - // materials - osg::StateSet** osg_mtl = NULL; - if (obj->nummaterials > 0) { - osg_mtl = new osg::StateSet*[obj->nummaterials]; - for (i = 0; i < obj->nummaterials; i++) { - GLMmaterial* omtl = &(obj->materials[i]); - osg::notify(osg::DEBUG_INFO) << "mtl: " << omtl->name << std::endl; + TextureMap textureMap; + MaterialSet materialSet; + StateSetSet statesetSet; + + // create a sphere mapped texgen just in case we need it. + osg::ref_ptr osg_texgen = new osg::TexGen; + osg_texgen->setMode(osg::TexGen::SPHERE_MAP); - osg::StateSet* stateset = new osg::StateSet; - osg_mtl[i] = stateset; + ObjMatierialOsgStateSetArray osg_mtl(obj->nummaterials); - 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); - - stateset->setAttribute(mtl); + for (i = 0; i < obj->nummaterials; i++) + { + GLMmaterial* omtl = &(obj->materials[i]); + osg::notify(osg::DEBUG_INFO) << "mtl: " << omtl->name << std::endl; - if (omtl->alpha<1.0f) { - stateset->setMode(GL_BLEND,osg::StateAttribute::ON); - stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); - } - - if (omtl->textureName) + osg::ref_ptr stateset = new osg::StateSet; + + osg::ref_ptr 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); + if (titr==textureMap.end()) { + std::string fileName = osgDB::findFileInDirectory(omtl->textureName,directory,true); if (!fileName.empty()) { @@ -140,12 +176,8 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil osg_texture->setImage(osg_image); stateset->setTextureAttributeAndModes(0,osg_texture,osg::StateAttribute::ON); - if (omtl->textureReflection) - { - osg::TexGen* osg_texgen = new osg::TexGen; - osg_texgen->setMode(osg::TexGen::SPHERE_MAP); - stateset->setTextureAttributeAndModes(0,osg_texgen,osg::StateAttribute::ON); - } + textureMap[omtl->textureName] = osg_texture; + } else { @@ -156,8 +188,29 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil { osg::notify(osg::WARN) << "texture '"<textureName<<"' not found"<< std::endl; } + + } + else + { + stateset->setTextureAttributeAndModes(0,titr->second.get(),osg::StateAttribute::ON); } } + + 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; + } } // toplevel group or transform @@ -183,7 +236,14 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil osg::Geode* osg_geo = new osg::Geode; osg_geo->setName(ogrp->name); - osg_geo->addDrawable(makeDrawable(obj,ogrp, osg_mtl)); + osg::Drawable* drawable = makeDrawable(obj,ogrp); + + // state and material (if any) + if (!osg_mtl.empty()) { + drawable->setStateSet(osg_mtl[ogrp->material].get()); + } + + osg_geo->addDrawable(drawable); osg_top->addChild(osg_geo); } ogrp = ogrp->next; @@ -191,8 +251,6 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil // free glmDelete(obj); - if (osg_mtl) - delete[] osg_mtl; return osg_top; } @@ -200,8 +258,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriterOBJ::readNode(const std::string& fil // make drawable from OBJ group osg::Drawable* ReaderWriterOBJ::makeDrawable(GLMmodel* obj, - GLMgroup* grp, - osg::StateSet** mtl) + GLMgroup* grp) { GLMtriangle* tris = obj->triangles; @@ -211,6 +268,8 @@ osg::Drawable* ReaderWriterOBJ::makeDrawable(GLMmodel* obj, // geometry osg::Geometry* geom = new osg::Geometry; + + // geom->setUseVertexBufferObjects(true); // primitives are only triangles geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,ntris*3)); @@ -282,14 +341,6 @@ osg::Drawable* ReaderWriterOBJ::makeDrawable(GLMmodel* obj, } } - // state and material (if any) - if (mtl) { - - geom->setStateSet(mtl[grp->material]); - } - else - osg::notify(osg::INFO) << "Group " << grp->name << " has no material" << std::endl; - return geom; }