Index: /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.h
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.h (revision 3323)
+++ /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.h (revision 3323)
@@ -0,0 +1,191 @@
+/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2004 Robert Osfield 
+ *
+ * This library is open source and may be redistributed and/or modified under  
+ * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
+ * (at your option) any later version.  The full license is in LICENSE file
+ * included with this distribution, and on the openscenegraph.org website.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * OpenSceneGraph Public License for more details.
+*/
+
+#ifndef OBJ_H
+#define OBJ_H
+
+#include <string>
+#include <vector>
+#include <map>
+#include <istream>
+
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+#include <osg/Vec2>
+#include <osg/Vec3>
+#include <osg/Vec4>
+
+
+namespace obj
+{
+
+class Material
+{
+public:
+    Material():
+        ambient(0.2f,0.2f,0.2f,1.0f),
+        diffuse(0.8f,0.8f,0.8f,1.0f),
+        specular(0.0f,0.0f,0.0f,1.0f),
+        emissive(0.0f,0.0f,0.0f,1.0f),
+        shininess(0.0f),
+        sharpness(0.0f),
+        illum(0),
+        Tf(0.0f,0.0f,0.0f,1.0f),
+        textureReflection(false),
+        alpha(1.0f),
+        uScale(1.0f),
+        vScale(1.0f),
+        uOffset(1.0f),
+        vOffset(1.0f) {}
+    
+    std::string name;
+    
+    osg::Vec4   ambient;
+    osg::Vec4   diffuse;
+    osg::Vec4   specular;
+    osg::Vec4   emissive;
+    float       shininess;
+    float       sharpness;
+    int         illum;
+    
+    osg::Vec4   Tf;
+    int         Ni;
+    int         Ns;
+
+    std::string map_Ka;
+    std::string map_Kd;
+    std::string map_Ks;
+    bool        textureReflection;
+    float       alpha;
+    float       uScale;
+    float       vScale;
+    float       uOffset;
+    float       vOffset;
+    
+protected:
+
+};
+
+class Element : public osg::Referenced
+{
+public:
+
+    typedef std::vector<int> IndexList;
+
+    enum DataType
+    {
+        POINTS,
+        POLYLINE,
+        POLYGON
+    };
+    
+    Element(DataType type):
+        dataType(type) {}
+        
+    enum CoordinateCombination
+    {
+        VERTICES,
+        VERTICES_NORMALS,
+        VERTICES_TEXCOORDS,
+        VERTICES_NORMALS_TEXCOORDS
+    };
+    
+    CoordinateCombination getCoordinateCombination() const
+    {
+        if (vertexIndices.size()==normalIndices.size())
+            return (vertexIndices.size()==texCoordIndices.size()) ? VERTICES_NORMALS_TEXCOORDS : VERTICES_NORMALS;
+        else 
+            return (vertexIndices.size()==texCoordIndices.size()) ?  VERTICES_TEXCOORDS : VERTICES;
+    }
+    
+    DataType  dataType;  
+    IndexList vertexIndices;
+    IndexList normalIndices;
+    IndexList texCoordIndices;
+};
+
+class ElementState
+{
+public:
+
+    ElementState():
+        coordinateCombination(Element::VERTICES),
+        smoothingGroup(0) {}
+        
+    bool operator < (const ElementState& rhs) const
+    {
+        if (materialName<rhs.materialName) return true;
+        else if (rhs.materialName<materialName) return false;
+
+        if (objectName<rhs.objectName) return true;
+        else if (rhs.objectName<objectName) return false;
+
+        if (groupName<rhs.groupName) return true;
+        else if (rhs.groupName<groupName) return false;
+
+        if (coordinateCombination<rhs.coordinateCombination) return true;
+        else if (rhs.coordinateCombination<coordinateCombination) return false;
+
+        return (smoothingGroup<rhs.smoothingGroup);
+    }
+
+
+    std::string                     objectName;
+    std::string                     groupName;
+    std::string                     materialName;
+    Element::CoordinateCombination  coordinateCombination;
+    int                             smoothingGroup;
+};
+
+class Model
+{
+public:
+    Model():
+        currentElementList(0) {}
+    
+    bool readMTL(std::istream& fin);
+    bool readOBJ(std::istream& fin);
+    
+    bool readline(std::istream& fin, char* line, const int LINE_SIZE);
+    void addElement(Element* element);
+    
+    int remapVertexIndex(int vi) { return (vi<0) ? vertices.size()+vi : vi-1; }
+    int remapNormalIndex(int vi) { return (vi<0) ? normals.size()+vi : vi-1; }
+    int remapTexCoordIndex(int vi) { return (vi<0) ? texcoords.size()+vi : vi-1; }
+    
+    typedef std::map<std::string,Material>          MaterialMap;
+    typedef std::vector< osg::Vec2 >                Vec2Array;
+    typedef std::vector< osg::Vec3 >                Vec3Array;
+    typedef std::vector< osg::ref_ptr<Element> >    ElementList;
+    typedef std::map< ElementState,ElementList >    ElementStateMap;
+    
+    MaterialMap     materialMap;
+       
+    Vec3Array       vertices;
+    Vec3Array       normals;
+    Vec2Array       texcoords;
+    
+    ElementState    currentElementState;
+    
+    ElementStateMap elementStateMap;
+    ElementList*    currentElementList;
+
+};
+
+}
+
+
+
+
+
+#endif
Index: /OpenSceneGraph/trunk/src/osgPlugins/obj/GNUmakefile
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/GNUmakefile (revision 1681)
+++ /OpenSceneGraph/trunk/src/osgPlugins/obj/GNUmakefile (revision 3323)
@@ -3,5 +3,5 @@
 
 CXXFILES =\
-	glm.cpp\
+        obj.cpp\
 	ReaderWriterOBJ.cpp\
 
Index: /OpenSceneGraph/trunk/src/osgPlugins/obj/ReaderWriterOBJ.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/ReaderWriterOBJ.cpp (revision 3282)
+++ /OpenSceneGraph/trunk/src/osgPlugins/obj/ReaderWriterOBJ.cpp (revision 3323)
@@ -39,16 +39,10 @@
 #include <osgUtil/TriStripVisitor>
 #include <osgUtil/SmoothingVisitor>
-
-#include "glm.h"
+#include <osgUtil/Tesselator>
+
+#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
@@ -64,85 +58,19 @@
     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::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;
-    
-    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;
-            
-    };
-
-
+    typedef std::map< std::string, osg::ref_ptr<osg::StateSet> > MaterialToStateSetMap;
+    
+    void buildMaterialToStateSetMap(obj::Model& model, MaterialToStateSetMap& materialToSetSetMap);
+    
+    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()); }
+    
 };
 
@@ -150,4 +78,328 @@
 // 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;
+}
 
 
@@ -160,468 +412,17 @@
     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++)
-    {
-        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);
-            }
-        }
+    
+    
+    std::ifstream fin(fileName.c_str());
+    if (fin)
+    {
+        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;
-        }        
-    }
-
-    // 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;
+        osg::Node* node = convertModelToSceneGraph(model);
+        return node;
+    }
+    
+    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;
-}
Index: /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.cpp (revision 3323)
+++ /OpenSceneGraph/trunk/src/osgPlugins/obj/obj.cpp (revision 3323)
@@ -0,0 +1,458 @@
+/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2004 Robert Osfield 
+ *
+ * This library is open source and may be redistributed and/or modified under  
+ * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
+ * (at your option) any later version.  The full license is in LICENSE file
+ * included with this distribution, and on the openscenegraph.org website.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
+ * OpenSceneGraph Public License for more details.
+*/
+
+#include <fstream>
+
+#include "obj.h"
+
+#include <osg/Notify>
+
+using namespace obj;
+
+bool Model::readline(std::istream& fin, char* line, const int LINE_SIZE)
+{
+    if (LINE_SIZE<1) return false;
+
+    bool eatWhiteSpaceAtStart = true;
+
+    char* ptr = line;
+    char* end = line+LINE_SIZE-1;
+    bool skipNewline = false;
+    while (fin && ptr<end)
+    {
+
+        int c=fin.get();
+        int p=fin.peek();
+        if (c=='\r')
+        {
+            if (p=='\n')
+            {
+                // we have a windows line endings.
+                fin.get();
+                // osg::notify(osg::NOTICE)<<"We have dos line ending"<<std::endl;
+                if (skipNewline)
+                {
+                    skipNewline = false; 
+                    continue;
+                }
+                else break;
+            }
+            // we have Mac line ending
+            // osg::notify(osg::NOTICE)<<"We have mac line ending"<<std::endl;
+            if (skipNewline)
+            {
+                skipNewline = false; 
+                continue;
+            }
+            else break;
+        }
+        else if (c=='\n')
+        {
+            // we have unix line ending.
+            // osg::notify(osg::NOTICE)<<"We have unix line ending"<<std::endl;
+            if (skipNewline)
+            {
+                skipNewline = false; 
+                continue;
+            }
+            else break;
+        }
+        else if (c=='\\' && (p=='\r' || p=='\n'))
+        {
+            // need to keep return;
+            skipNewline = true;   
+        }
+        else if (c!=std::ifstream::traits_type::eof()) // don't copy eof.
+        {
+            skipNewline = false;
+
+            if (!eatWhiteSpaceAtStart || (c!=' ' && c!='\t'))
+            {
+                eatWhiteSpaceAtStart = false;
+                *ptr++ = c;
+            }
+        }
+        
+        
+    }
+    *ptr = 0;
+    
+    return true;
+}
+
+
+bool Model::readMTL(std::istream& fin)
+{
+    osg::notify(osg::NOTICE)<<"Reading MTL file"<<std::endl;
+
+    const int LINE_SIZE = 4096;
+    char line[LINE_SIZE];
+    float r = 1.0f, g = 1.0f, b = 1.0f, a = 1.0f;
+
+    Material* material = &(materialMap[""]);
+
+    while (fin)
+    {
+        readline(fin,line,LINE_SIZE);
+        if (line[0]=='#')
+        {
+            // comment line
+            // osg::notify(osg::NOTICE) <<"Comment: "<<line<<std::endl;
+        }
+        else if (strlen(line)>0)
+        {
+            if (strncmp(line,"Ka ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
+
+                if (fieldsRead==1)      material->ambient.set(r,0.0f,0.0f,1.0f);
+                else if (fieldsRead==2) material->ambient.set(r,g,0.0f,1.0f);
+                else if (fieldsRead==3) material->ambient.set(r,g,b,1.0f);
+                else if (fieldsRead==4) material->ambient.set(r,g,b,a);
+            }
+            else if (strncmp(line,"Kd ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
+
+                if (fieldsRead==1)      material->diffuse.set(r,0.0f,0.0f,1.0f);
+                else if (fieldsRead==2) material->diffuse.set(r,g,0.0f,1.0f);
+                else if (fieldsRead==3) material->diffuse.set(r,g,b,1.0f);
+                else if (fieldsRead==4) material->diffuse.set(r,g,b,a);
+            }
+            else if (strncmp(line,"Ks ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
+
+                if (fieldsRead==1)      material->specular.set(r,0.0f,0.0f,1.0f);
+                else if (fieldsRead==2) material->specular.set(r,g,0.0f,1.0f);
+                else if (fieldsRead==3) material->specular.set(r,g,b,1.0f);
+                else if (fieldsRead==4) material->specular.set(r,g,b,a);
+            }
+            else if (strncmp(line,"Ke ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
+
+                if (fieldsRead==1)      material->emissive.set(r,0.0f,0.0f,1.0f);
+                else if (fieldsRead==2) material->emissive.set(r,g,0.0f,1.0f);
+                else if (fieldsRead==3) material->emissive.set(r,g,b,1.0f);
+                else if (fieldsRead==4) material->emissive.set(r,g,b,a);
+            }
+            else if (strncmp(line,"Tf ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f %f", &r, &g, &b, &a);
+
+                if (fieldsRead==1)      material->Tf.set(r,0.0f,0.0f,1.0f);
+                else if (fieldsRead==2) material->Tf.set(r,g,0.0f,1.0f);
+                else if (fieldsRead==3) material->Tf.set(r,g,b,1.0f);
+                else if (fieldsRead==4) material->Tf.set(r,g,b,a);
+            }
+            else if (strncmp(line,"newmtl ",7)==0)
+            {
+                std::string materialName(line+7);
+                if (material->name != materialName)
+                {
+                    material = & materialMap[materialName];
+                    material->name = materialName;
+                }
+            }
+            else if (strncmp(line,"sharpness ",10)==0)
+            {
+                float sharpness = 0.0f;
+                unsigned int fieldsRead = sscanf(line+10,"%f", &sharpness);
+
+                if (fieldsRead==1) material->sharpness = sharpness;
+            }
+            else if (strncmp(line,"illum ",6)==0)
+            {
+                int illum = 0;
+                unsigned int fieldsRead = sscanf(line+6,"%d", &illum);
+
+                if (fieldsRead==1) material->illum = illum;
+            }
+            else if (strncmp(line,"Ns ",3)==0)
+            {
+                int Ns = 0;
+                unsigned int fieldsRead = sscanf(line+3,"%d", &Ns);
+
+                if (fieldsRead==1) material->Ns = Ns;
+            }
+            else if (strncmp(line,"Ni ",3)==0)
+            {
+                int Ni = 0;
+                unsigned int fieldsRead = sscanf(line+3,"%d", &Ni);
+
+                if (fieldsRead==1) material->Ni = Ni;
+            }
+            else if (strncmp(line,"illum ",6)==0)
+            {
+                int illum = 0;
+                unsigned int fieldsRead = sscanf(line+6,"%d", &illum);
+
+                if (fieldsRead==1) material->illum = illum;
+            }
+            else if (strncmp(line,"Tr ",3)==0)
+            {
+                float alpha=1.0f;
+                unsigned int fieldsRead = sscanf(line+3,"%f", &alpha);
+
+                if (fieldsRead==1)
+                {
+                    material->ambient[3] = alpha;
+                    material->diffuse[3] = alpha;
+                    material->specular[3] = alpha;
+                    material->emissive[3] = alpha;
+                }
+            }
+            else if (strncmp(line,"d ",2)==0)
+            {
+                float alpha=1.0f;
+                unsigned int fieldsRead = sscanf(line+2,"%f", &alpha);
+
+                if (fieldsRead==1)
+                {
+                    material->ambient[3] = alpha;
+                    material->diffuse[3] = alpha;
+                    material->specular[3] = alpha;
+                    material->emissive[3] = alpha;
+                }
+            }
+            else if (strncmp(line,"map_Ka ",7)==0)
+            {
+                std::string filename(line+7);
+                material->map_Ka = filename;
+            }
+            else if (strncmp(line,"map_Kd ",7)==0)
+            {
+                std::string filename(line+7);
+                material->map_Kd = filename;
+            }
+            else if (strncmp(line,"map_Ks ",7)==0)
+            {
+                std::string filename(line+7);
+                material->map_Ks = filename;
+            }
+            else
+            {
+                osg::notify(osg::NOTICE) <<"*** line not handled *** :"<<line<<std::endl;
+            }
+        
+        }
+
+    }
+
+    return true;
+}
+
+bool Model::readOBJ(std::istream& fin)
+{
+    osg::notify(osg::NOTICE)<<"Reading OBJ file"<<std::endl;
+
+    const int LINE_SIZE = 4096;
+    char line[LINE_SIZE];
+    float x = 0.0f, y = 0.0f, z = 0.0f, w = 0.0f;
+
+    while (fin)
+    {
+        readline(fin,line,LINE_SIZE);
+        if (line[0]=='#')
+        {
+            // comment line
+            // osg::notify(osg::NOTICE) <<"Comment: "<<line<<std::endl;
+        }
+        else if (strlen(line)>0)
+        {
+            if (strncmp(line,"v ",2)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+2,"%f %f %f %f", &x, &y, &z, &w);
+
+                if (fieldsRead==1) vertices.push_back(osg::Vec3(x,0.0f,0.0f));
+                else if (fieldsRead==2) vertices.push_back(osg::Vec3(x,y,0.0f));
+                else if (fieldsRead==3) vertices.push_back(osg::Vec3(x,y,z));
+                else if (fieldsRead>=4) vertices.push_back(osg::Vec3(x/w,y/w,z/w));
+            }
+            else if (strncmp(line,"vn ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f", &x, &y, &z);
+
+                if (fieldsRead==1) normals.push_back(osg::Vec3(x,0.0f,0.0f));
+                else if (fieldsRead==2) normals.push_back(osg::Vec3(x,y,0.0f));
+                else if (fieldsRead==3) normals.push_back(osg::Vec3(x,y,z));
+            }
+            else if (strncmp(line,"vt ",3)==0)
+            {
+                unsigned int fieldsRead = sscanf(line+3,"%f %f %f", &x, &y, &z);
+
+                if (fieldsRead==1) texcoords.push_back(osg::Vec2(x,0.0f));
+                else if (fieldsRead==2) texcoords.push_back(osg::Vec2(x,y));
+                else if (fieldsRead==3) texcoords.push_back(osg::Vec2(x,y));
+            }
+            else if (strncmp(line,"l ",2)==0 ||
+                     strncmp(line,"p ",2)==0 ||
+                     strncmp(line,"f ",2)==0)
+            {
+                char* ptr = line+2;
+                
+                Element* element = new Element( (line[0]=='p') ? Element::POINTS :
+                                                (line[0]=='l') ? Element::POLYLINE :
+                                                Element::POLYGON );
+
+                int vi=0, ti=0, ni=0;
+                while(*ptr!=0)
+                {
+                    // skip white space
+                    while(*ptr==' ') ++ptr;
+                    
+                    if (sscanf(ptr, "%d/%d/%d", &vi, &ti, &ni) == 3)
+                    {
+                        element->vertexIndices.push_back(remapVertexIndex(vi));
+                        element->normalIndices.push_back(remapNormalIndex(ni));
+                        element->texCoordIndices.push_back(remapTexCoordIndex(ti));
+                    }
+                    else if (sscanf(ptr, "%d//%d", &vi, &ni) == 2)
+                    {
+                        element->vertexIndices.push_back(remapVertexIndex(vi));
+                        element->normalIndices.push_back(remapNormalIndex(ni));
+                    }
+                    else if (sscanf(ptr, "%d/%d", &vi, &ti) == 2)
+                    {
+                        element->vertexIndices.push_back(remapVertexIndex(vi));
+                        element->texCoordIndices.push_back(remapTexCoordIndex(ti));
+                    }
+                    else if (sscanf(ptr, "%d", &vi) == 1)
+                    {
+                        element->vertexIndices.push_back(remapVertexIndex(vi));
+                    }
+
+                    // skip to white space or end of line
+                    while(*ptr!=' ' && *ptr!=0) ++ptr;
+                
+                }
+                
+                if (!element->normalIndices.empty() && element->normalIndices.size() != element->vertexIndices.size())
+                {
+                    element->normalIndices.clear();
+                }
+                
+                if (!element->texCoordIndices.empty() && element->texCoordIndices.size() != element->vertexIndices.size())
+                {
+                    element->texCoordIndices.clear();
+                }
+                
+                if (!element->vertexIndices.empty())
+                {
+                    Element::CoordinateCombination coordateCombination = element->getCoordinateCombination();
+                    if (coordateCombination!=currentElementState.coordinateCombination)
+                    {
+                        currentElementState.coordinateCombination = coordateCombination;
+                        currentElementList = 0; // reset the element list to force a recompute of which ElementList to use
+                    }
+                    addElement(element);
+                }
+                else
+                {
+                    // empty element, don't both adding, just unref to delete it.
+                    element->unref();
+                }
+
+            }
+            else if (strncmp(line,"usemtl ",7)==0)
+            {
+                std::string materialName(line+7);
+                if (currentElementState.materialName != materialName)
+                {
+                    currentElementState.materialName = materialName;
+                    currentElementList = 0; // reset the element list to force a recompute of which ElementList to use
+                }
+            }
+            else if (strncmp(line,"mtllib ",7)==0)
+            {
+                std::ifstream mfin(line+7);
+                if (mfin)
+                {
+                    readMTL(mfin);
+                }
+            }
+            else if (strncmp(line,"o ",2)==0)
+            {
+                std::string objectName(line+2);
+                if (currentElementState.objectName != objectName)
+                {
+                    currentElementState.objectName = objectName;
+                    currentElementList = 0; // reset the element list to force a recompute of which ElementList to use
+                }
+            }
+            else if (strncmp(line,"g ",2)==0)
+            {
+                std::string groupName(line+2);
+                if (currentElementState.groupName != groupName)
+                {
+                    currentElementState.groupName = groupName;
+                    currentElementList = 0; // reset the element list to force a recompute of which ElementList to use
+                }
+            }
+            else if (strncmp(line,"s ",2)==0)
+            {
+                int smoothingGroup=0;
+                if (strncmp(line+2,"off",3)==0) smoothingGroup = 0;
+                else sscanf(line+2,"%d",&smoothingGroup);
+                
+                if (currentElementState.smoothingGroup != smoothingGroup)
+                {
+                    currentElementState.smoothingGroup = smoothingGroup;
+                    currentElementList = 0; // reset the element list to force a recompute of which ElementList to use
+                }
+            }
+            else
+            {
+                osg::notify(osg::NOTICE) <<"*** line not handled *** :"<<line<<std::endl;
+            }
+        
+        }
+
+    }
+
+    osg::notify(osg::NOTICE) <<"vertices :"<<vertices.size()<<std::endl;
+    osg::notify(osg::NOTICE) <<"normals :"<<normals.size()<<std::endl;
+    osg::notify(osg::NOTICE) <<"texcoords :"<<texcoords.size()<<std::endl;
+    osg::notify(osg::NOTICE) <<"materials :"<<materialMap.size()<<std::endl;
+    osg::notify(osg::NOTICE) <<"elementStates :"<<elementStateMap.size()<<std::endl;
+/*    
+    unsigned int pos=0;
+    for(ElementStateMap::iterator itr=elementStateMap.begin();
+        itr!=elementStateMap.end();
+        ++itr,++pos)
+    {
+        const ElementState& es = itr->first;
+        ElementList& el = itr->second;
+        osg::notify(osg::NOTICE)<<"ElementState "<<pos<<std::endl;
+        osg::notify(osg::NOTICE)<<"    es.objectName="<<es.objectName<<std::endl;
+        osg::notify(osg::NOTICE)<<"    es.groupName="<<es.groupName<<std::endl;
+        osg::notify(osg::NOTICE)<<"    es.materialName="<<es.materialName<<std::endl;
+        osg::notify(osg::NOTICE)<<"    es.smoothGroup="<<es.smoothingGroup<<std::endl;
+        osg::notify(osg::NOTICE)<<"    ElementList ="<<el.size()<<std::endl;
+        
+    }
+*/
+    return true;
+}
+
+
+void Model::addElement(Element* element)
+{
+    if (!currentElementList)
+    {
+        currentElementList = & (elementStateMap[currentElementState]);
+    }
+    currentElementList->push_back(element);
+    
+}
Index: /enSceneGraph/trunk/src/osgPlugins/obj/glm.cpp
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/glm.cpp (revision 3314)
+++  (revision )
@@ -1,1932 +1,0 @@
-/*    
- *  Wavefront .obj file format reader.
- *
- *  author: Nate Robins
- *  email: ndr@pobox.com
- *  www: http://www.pobox.com/~ndr
- */
-
-
-/* includes */
-#include "glm.h"
-#include <math.h>
-#include <stdio.h>
-#include <string.h>
-#include <assert.h>
-#include <osg/Math>
-#include <stdlib.h>
-
-#include <osg/Math>
-
-#include <iostream>
-
-/* defines */
-#define T(x) model->triangles[(x)]
-
-
-/* enums */
-enum { X, Y, Z, W };            /* elements of a vertex */
-
-
-/* typedefs */
-
-/* _GLMnode: general purpose node
- */
-typedef struct _GLMnode {
-  unsigned int           index;
-  GLboolean        averaged;
-  struct _GLMnode* next;
-} GLMnode;
-
-
-/* private functions */
-
-/* _glmMax: returns the maximum of two floats */
-static GLfloat
-_glmMax(GLfloat a, GLfloat b) 
-{
-  if (a > b)
-    return a;
-  return b;
-}
-
-/* _glmAbs: returns the absolute value of a float */
-static GLfloat
-_glmAbs(GLfloat f)
-{
-  if (f < 0)
-    return -f;
-  return f;
-}
-
-/* _glmDot: compute the dot product of two vectors
- *
- * u - array of 3 GLfloats (GLfloat u[3])
- * v - array of 3 GLfloats (GLfloat v[3])
- */
-static GLfloat
-_glmDot(GLfloat* u, GLfloat* v)
-{
-  assert(u);
-  assert(v);
-
-  /* compute the dot product */
-  return u[X] * v[X] + u[Y] * v[Y] + u[Z] * v[Z];
-}
-
-/* _glmCross: compute the cross product of two vectors
- *
- * u - array of 3 GLfloats (GLfloat u[3])
- * v - array of 3 GLfloats (GLfloat v[3])
- * n - array of 3 GLfloats (GLfloat n[3]) to return the cross product in
- */
-static GLvoid
-_glmCross(GLfloat* u, GLfloat* v, GLfloat* n)
-{
-  assert(u);
-  assert(v);
-  assert(n);
-
-  /* compute the cross product (u x v for right-handed [ccw]) */
-  n[X] = u[Y] * v[Z] - u[Z] * v[Y];
-  n[Y] = u[Z] * v[X] - u[X] * v[Z];
-  n[Z] = u[X] * v[Y] - u[Y] * v[X];
-}
-
-/* _glmNormalize: normalize a vector
- *
- * n - array of 3 GLfloats (GLfloat n[3]) to be normalized
- */
-static GLvoid
-_glmNormalize(GLfloat* n)
-{
-  GLfloat l;
-
-  assert(n);
-
-  /* normalize */
-  l = (GLfloat)sqrt(n[X] * n[X] + n[Y] * n[Y] + n[Z] * n[Z]);
-  n[0] /= l;
-  n[1] /= l;
-  n[2] /= l;
-}
-
-/* _glmEqual: compares two vectors and returns GL_TRUE if they are
- * equal (within a certain threshold) or GL_FALSE if not. An epsilon
- * that works fairly well is 0.000001.
- *
- * u - array of 3 GLfloats (GLfloat u[3])
- * v - array of 3 GLfloats (GLfloat v[3]) 
- */
-static GLboolean
-_glmEqual(GLfloat* u, GLfloat* v, GLfloat epsilon)
-{
-  if (_glmAbs(u[0] - v[0]) < epsilon &&
-      _glmAbs(u[1] - v[1]) < epsilon &&
-      _glmAbs(u[2] - v[2]) < epsilon) 
-  {
-    return GL_TRUE;
-  }
-  return GL_FALSE;
-}
-
-/* _glmWeldVectors: eliminate (weld) vectors that are within an
- * epsilon of each other.
- *
- * vectors    - array of GLfloat[3]'s to be welded
- * numvectors - number of GLfloat[3]'s in vectors
- * epsilon    - maximum difference between vectors 
- *
- */
-GLfloat*
-_glmWeldVectors(GLfloat* vectors, unsigned int* numvectors, GLfloat epsilon)
-{
-  GLfloat* copies;
-  unsigned int   copied;
-  unsigned int   i, j;
-
-  copies = (GLfloat*)malloc(sizeof(GLfloat) * 3 * (*numvectors + 1));
-  memcpy(copies, vectors, (sizeof(GLfloat) * 3 * (*numvectors + 1)));
-
-  copied = 1;
-  for (i = 1; i <= *numvectors; i++) {
-    for (j = 1; j <= copied; j++) {
-      if (_glmEqual(&vectors[3 * i], &copies[3 * j], epsilon)) {
-    goto duplicate;
-      }
-    }
-
-    /* must not be any duplicates -- add to the copies array */
-    copies[3 * copied + 0] = vectors[3 * i + 0];
-    copies[3 * copied + 1] = vectors[3 * i + 1];
-    copies[3 * copied + 2] = vectors[3 * i + 2];
-    j = copied;                /* pass this along for below */
-    copied++;
-
-  duplicate:
-    /* set the first component of this vector to point at the correct
-       index into the new copies array */
-    vectors[3 * i + 0] = (GLfloat)j;
-  }
-
-  *numvectors = copied-1;
-  return copies;
-}
-
-/* _glmFindGroup: Find a group in the model
- */
-GLMgroup*
-_glmFindGroup(GLMmodel* model, char* name)
-{
-  GLMgroup* group;
-
-  assert(model);
-
-  group = model->groups;
-  while(group) {
-    if (!strcmp(name, group->name))
-      break;
-    group = group->next;
-  }
-
-  return group;
-}
-
-/* _glmAddGroup: Add a group to the model
- */
-GLMgroup*
-_glmAddGroup(GLMmodel* model, char* name)
-{
-  GLMgroup* group;
-
-  group = _glmFindGroup(model, name);
-  if (!group) {
-    group = (GLMgroup*)malloc(sizeof(GLMgroup));
-    group->init();
-    group->name = strdup(name);
-    group->material = 0;
-    group->numtriangles = 0;
-    group->triangles = NULL;
-    group->hastexcoords = false;
-    group->next = model->groups;
-    model->groups = group;
-    model->numgroups++;
-
-    std::cout<<"_glmAddGroup="<<name<<std::endl;
-  }
-
-  return group;
-}
-
-/* _glmFindGroup: Find a material in the model
- */
-unsigned int
-_glmFindMaterial(GLMmodel* model, char* name)
-{
-  unsigned int i;
-
-  for (i = 0; i < model->nummaterials; i++) {
-    if (!strcmp(model->materials[i].name, name))
-      goto found;
-  }
-
-  /* didn't find the name, so set it as the default material */
-  fprintf(stderr,"_glmFindMaterial():  can't find material \"%s\".\n", name);
-  i = 0;
-
-found:
-  return i;
-}
-
-
-/* _glmDirName: return the directory given a path
- *
- * path - filesystem path
- *
- * The return value should be free'd.
- */
-static char*
-_glmDirName(char* path)
-{
-  char* dir;
-  char* s;
-  char* s2;
-
-  dir = strdup(path);
-
-  s = strrchr(dir, '/');
-  s2 = strrchr(dir, '\\');    // also look for backslashes
-  if (s2 > s)                // take whichever is later
-      s = s2;
-
-  if (s)
-    s[1] = '\0';
-  else
-    dir[0] = '\0';
-
-  return dir;
-}
-
-
-/* _glmReadMTLTextureOptions: parses the given line for texture options
- * and applies the options to the given model/material
- *
- * model         - properly initialized GLMmodel structure
- * materialIndex - the material affected in the given model
- * line          - white-space separated options
- */
-GLvoid
-_glmReadMTLTextureOptions(GLMmodel* model, unsigned int materialIndex, char* line)
-{
-  char *token;
-  char seps[] = " \t\n\r\f\v";
-  token = ::strtok(line, seps);
-  while(NULL != token) 
-  {
-    switch(token[0])
-    {
-      case '-':
-        switch(token[1])
-        {
-          // Scaling:  -s <uScale> <vScale>
-          case 's':
-            float uScale, vScale;
-            token = ::strtok(NULL, seps);
-            uScale = token ? (float)::atof(token) : 1.0f;
-
-            token = ::strtok(NULL, seps);
-            vScale = token ? (float)::atof(token) : 1.0f;
-
-            if ((0.0f != uScale) && (0.0f != vScale))
-            {
-              uScale = 1.0f / uScale;
-              vScale = 1.0f / vScale;
-              model->materials[materialIndex].textureUScale = uScale;
-              model->materials[materialIndex].textureVScale = vScale;
-            }
-            break;
-
-          // Offset:  -o <uOffset> <vOffset>
-          case 'o':
-            float uOffset, vOffset;
-            token = ::strtok(NULL, seps);
-            uOffset = token ? (float)::atof(token) : 0.0f;
-
-            token = ::strtok(NULL, seps);
-            vOffset = token ? (float)::atof(token) : 0.0f;
-
-            model->materials[materialIndex].textureUOffset = uOffset;
-            model->materials[materialIndex].textureVOffset = vOffset;
-            break;
-
-          // These options are not handled - so just advance to the next 
-          // valid token
-          // ==================================================================
-          //
-
-          // Clamping:  -clamp <on|off>
-          case 'c':
-            token = ::strtok(NULL, seps);
-            break;
-
-          // Bias and gain:  -mm <bias> <gain>
-          case 'm':
-          // Turbulence/Noise:  -t <uNoise> <vNoise>
-          case 't':
-            token = ::strtok(NULL, seps);
-            token = ::strtok(NULL, seps);
-            break;
-
-          default:
-            break;
-        }
-        break;
-
-      // Image filename
-      default:
-        if (0 != strlen(token))
-        {
-          model->materials[materialIndex].textureName = strdup(token);
-        }
-    }
-
-    // Advance to the next token
-    token = ::strtok(NULL, seps);
-  }
-}
-
-
-/* _glmReadMTL: read a wavefront material library file
- *
- * model - properly initialized GLMmodel structure
- * name  - name of the material library
- */
-static GLvoid
-_glmReadMTL(GLMmodel* model, char* name)
-{
-  FILE* file;
-  char* dir;
-  char* filename;
-  char  buf[128];
-  unsigned int nummaterials, i;
-
-  dir = _glmDirName(model->pathname);
-  filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(name) + 1));
-  strcpy(filename, dir);
-  strcat(filename, name);
-  free(dir);
-
-  /* open the file */
-  file = fopen(filename, "r");
-  if (!file) {
-    fprintf(stderr, "_glmReadMTL() failed: can't open material file \"%s\".\n",
-        filename);
-    return;
-  }
-  free(filename);
-
-  /* count the number of materials in the file */
-  nummaterials = 1;
-  while(fscanf(file, "%s", buf) != EOF) {
-    switch(buf[0]) {
-    case '#':                /* comment */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'n':                /* newmtl */
-      fgets(buf, sizeof(buf), file);
-      nummaterials++;
-      sscanf(buf, "%s %s", buf, buf);
-      break;
-    default:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-  }
-
-  rewind(file);
-
-  /* allocate memory for the materials */
-  model->materials = (GLMmaterial*)malloc(sizeof(GLMmaterial) * nummaterials);
-  model->nummaterials = nummaterials;
-
-  /* set the default material */
-  for (i = 0; i < nummaterials; i++) {
-    model->materials[i].init();
-    model->materials[i].name = NULL;
-    model->materials[i].shininess = 0.0f;
-    model->materials[i].diffuse[0] = 0.8f;
-    model->materials[i].diffuse[1] = 0.8f;
-    model->materials[i].diffuse[2] = 0.8f;
-    model->materials[i].diffuse[3] = 1.0f;
-    model->materials[i].ambient[0] = 0.2f;
-    model->materials[i].ambient[1] = 0.2f;
-    model->materials[i].ambient[2] = 0.2f;
-    model->materials[i].ambient[3] = 1.0f;
-    model->materials[i].specular[0] = 0.0f;
-    model->materials[i].specular[1] = 0.0f;
-    model->materials[i].specular[2] = 0.0f;
-    model->materials[i].textureName = NULL;
-    model->materials[i].textureReflection = false;
-    model->materials[i].textureUScale = 1.0f;
-    model->materials[i].textureVScale = 1.0f;
-    model->materials[i].textureUOffset = 0.0f;
-    model->materials[i].textureVOffset = 0.0f;
-    model->materials[i].alpha = 1.0f;
-  }
-  model->materials[0].name = strdup("default");
-
-  /* now, read in the data */
-  nummaterials = 0;
-  while(fscanf(file, "%s", buf) != EOF) {
-    switch(buf[0]) {
-    case '#':                /* comment */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'n':                /* newmtl */
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s %s", buf, buf);
-      nummaterials++;
-      model->materials[nummaterials].name = strdup(buf);
-      break;
-    case 'N':
-      fscanf(file, "%f", &model->materials[nummaterials].shininess);
-      /* wavefront shininess is from [0, 1000], so scale for OpenGL */
-      model->materials[nummaterials].shininess /= 1000.0;
-      model->materials[nummaterials].shininess *= 128.0;
-      break;
-    case 'd':
-      fscanf(file, "%f", &model->materials[nummaterials].alpha);
-      break;
-    case 'K':
-      switch(buf[1]) {
-      case 'd':
-    fscanf(file, "%f %f %f",
-           &model->materials[nummaterials].diffuse[0],
-           &model->materials[nummaterials].diffuse[1],
-           &model->materials[nummaterials].diffuse[2]);
-    break;
-      case 's':
-    fscanf(file, "%f %f %f",
-           &model->materials[nummaterials].specular[0],
-           &model->materials[nummaterials].specular[1],
-           &model->materials[nummaterials].specular[2]);
-    break;
-      case 'a':
-    fscanf(file, "%f %f %f",
-           &model->materials[nummaterials].ambient[0],
-           &model->materials[nummaterials].ambient[1],
-           &model->materials[nummaterials].ambient[2]);
-    break;
-      default:
-    /* eat up rest of line */
-    fgets(buf, sizeof(buf), file);
-    break;
-      }
-      break;
-      
-    default:
-    
-      /* added by RO */
-      if (strcmp(buf,"map_Kd")==0)
-      {
-        fgets(buf, sizeof(buf), file);
-        _glmReadMTLTextureOptions(model, nummaterials, buf);
-      }
-      else if (strcmp(buf,"refl")==0)
-      {
-        model->materials[nummaterials].textureReflection = true;
-      }
-      else
-      {
-        /* eat up rest of line */
-        fgets(buf, sizeof(buf), file);
-      }
-      break;
-    }
-  }
-  fclose(file);
-}
-
-/* _glmWriteMTL: write a wavefront material library file
- *
- * model      - properly initialized GLMmodel structure
- * modelpath  - pathname of the model being written
- * mtllibname - name of the material library to be written
- */
-static GLvoid
-_glmWriteMTL(GLMmodel* model, char* modelpath, char* mtllibname)
-{
-  FILE* file;
-  char* dir;
-  char* filename;
-  GLMmaterial* material;
-  unsigned int i;
-
-  dir = _glmDirName(modelpath);
-  filename = (char*)malloc(sizeof(char) * (strlen(dir) + strlen(mtllibname)));
-  strcpy(filename, dir);
-  strcat(filename, mtllibname);
-  free(dir);
-
-  /* open the file */
-  file = fopen(filename, "w");
-  if (!file) {
-    fprintf(stderr, "_glmWriteMTL() failed: can't open file \"%s\".\n",
-        filename);
-    return;
-  }
-  free(filename);
-
-  /* spit out a header */
-  fprintf(file, "#  \n");
-  fprintf(file, "#  Wavefront MTL generated by GLM library\n");
-  fprintf(file, "#  \n");
-  fprintf(file, "#  GLM library copyright (C) 1997 by Nate Robins\n");
-  fprintf(file, "#  email: ndr@pobox.com\n");
-  fprintf(file, "#  www:   http://www.pobox.com/~ndr\n");
-  fprintf(file, "#  \n\n");
-
-  for (i = 0; i < model->nummaterials; i++) {
-    material = &model->materials[i];
-    fprintf(file, "newmtl %s\n", material->name);
-    fprintf(file, "Ka %f %f %f\n", 
-        material->ambient[0], material->ambient[1], material->ambient[2]);
-    fprintf(file, "Kd %f %f %f\n", 
-        material->diffuse[0], material->diffuse[1], material->diffuse[2]);
-    fprintf(file, "Ks %f %f %f\n", 
-        material->specular[0],material->specular[1],material->specular[2]);
-    fprintf(file, "Ns %f\n", material->shininess);
-    fprintf(file, "\n");
-  }
-}
-/* Create by RO to help handle g %s %s groups */
-static void createCompositeName(char* buf,char* compositeName)
-{
-    char *ptr_b = buf;
-    char *ptr_c = compositeName;
-
-    /* first skip over leading spaces */
-    while(*ptr_b!=0 && *ptr_b==' ') ++ptr_b;
-
-    /* copy over rest, changing spaces for underscores, 
-     * to handle faces which are contained in several groups */
-    while(*ptr_b>=' ')
-    {
-      if (*ptr_b==' ') *ptr_c = '_';
-      else *ptr_c = *ptr_b;
-      ++ptr_c;
-      ++ptr_b;
-    }
-    *ptr_c = 0;
-}
-/* _glmFirstPass: first pass at a Wavefront OBJ file that gets all the
- * statistics of the model (such as #vertices, #normals, etc)
- *
- * model - properly initialized GLMmodel structure
- * file  - (fopen'd) file descriptor 
- */
-static GLvoid
-_glmFirstPass(GLMmodel* model, FILE* file) 
-{
-  unsigned int    numvertices;        /* number of vertices in model */
-  unsigned int    numnormals;            /* number of normals in model */
-  unsigned int    numtexcoords;        /* number of texcoords in model */
-  unsigned int    numtriangles;        /* number of triangles in model */
-  GLMgroup* group;            /* current group */
-  unsigned  v, n, t;
-  char      buf[128];
-
-  /* make a default group */
-  group = _glmAddGroup(model, "default");
-
-  float x,y,z;
-  int r,g,b;
-
-  numvertices = numnormals = numtexcoords = numtriangles = 0;
-  
-  unsigned int numcolors = 0;
-  
-  while(fscanf(file, "%s", buf) != EOF) {
-  
-  
-    switch(buf[0]) {
-    case '#':                /* comment */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'v':                /* v, vn, vt */
-      switch(buf[1]) {
-      case '\0':            /* vertex */
-        {
-            /* eat up rest of line */
-            fgets(buf, sizeof(buf), file);
-
-            int noRead = sscanf(buf, "%f %f %f %d %d %d", 
-                                &x, &y, &z, &r,&g,&b);
-
-            numvertices++;
-            if (noRead==6) numcolors++;
-
-
-            break;
-        }
-      case 'n':                /* normal */
-        /* eat up rest of line */
-        fgets(buf, sizeof(buf), file);
-        numnormals++;
-        break;
-      case 't':                /* texcoord */
-        /* eat up rest of line */
-        fgets(buf, sizeof(buf), file);
-        numtexcoords++;
-        break;
-      default:
-        printf("_glmFirstPass(): Unknown token \"%s\".\n", buf);
-        //exit(1);
-        return;
-      }
-      break;
-    case 'm':
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s %s", buf, buf);
-      model->mtllibname = strdup(buf);
-      _glmReadMTL(model, buf);
-      break;
-    case 'u':
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'o':                /* group */
-    case 's':                /* group */
-    case 'g':                /* group */
-      {
-        /* eat up rest of line */
-        fgets(buf, sizeof(buf), file);
-
-        char compositeName[128];
-        createCompositeName(buf,compositeName);
-
-        group = _glmAddGroup(model, compositeName);
-      }
-      break;
-    case 'f':                /* face */
-      v = n = t = 0;
-      fscanf(file, "%s", buf);
-      /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
-      if (strstr(buf, "//")) {
-    /* v//n */
-    sscanf(buf, "%d//%d", &v, &n);
-    fscanf(file, "%d//%d", &v, &n);
-    fscanf(file, "%d//%d", &v, &n);
-    numtriangles++;
-    group->numtriangles++;
-    while(fscanf(file, "%d//%d", &v, &n) > 0) {
-      numtriangles++;
-      group->numtriangles++;
-    }
-      } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
-    /* v/t/n */
-    fscanf(file, "%d/%d/%d", &v, &t, &n);
-    fscanf(file, "%d/%d/%d", &v, &t, &n);
-    numtriangles++;
-    group->numtriangles++;
-    while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
-      numtriangles++;
-      group->numtriangles++;
-    }
-      } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
-    /* v/t */
-    fscanf(file, "%d/%d", &v, &t);
-    fscanf(file, "%d/%d", &v, &t);
-    numtriangles++;
-    group->numtriangles++;
-    while(fscanf(file, "%d/%d", &v, &t) > 0) {
-      numtriangles++;
-      group->numtriangles++;
-    }
-      } else {
-    /* v */
-    fscanf(file, "%d", &v);
-    fscanf(file, "%d", &v);
-    numtriangles++;
-    group->numtriangles++;
-    while(fscanf(file, "%d", &v) > 0) {
-      numtriangles++;
-      group->numtriangles++;
-    }
-      }
-      break;
-
-    default:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-
-    std::cout<<"line="<<buf<<std::endl;
-
-  }
-
-#if 0
-  /* announce the model statistics */
-  printf(" Vertices: %d\n", numvertices);
-  printf(" Normals: %d\n", numnormals);
-  printf(" Texcoords: %d\n", numtexcoords);
-  printf(" Triangles: %d\n", numtriangles);
-  printf(" Groups: %d\n", model->numgroups);
-#endif
-
-  /* set the stats in the model structure */
-  model->numvertices  = numvertices;
-  model->numnormals   = numnormals;
-  model->numtexcoords = numtexcoords;
-  model->numtriangles = numtriangles;
-
-  /* allocate memory for the triangles in each group */
-  group = model->groups;
-  while(group) {
-    group->triangles = (unsigned int*)malloc(sizeof(unsigned int) * group->numtriangles);
-    group->numtriangles = 0;
-    group = group->next;
-  }
-
-
-  // if all vertices have colours enables per vertex colors
-  if (numvertices==numcolors) model->useColors = true;
-
-}
-
-/* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
- * the data.
- *
- * model - properly initialized GLMmodel structure
- * file  - (fopen'd) file descriptor 
- */
-static GLvoid
-_glmSecondPass(GLMmodel* model, FILE* file) 
-{
-  unsigned int    numvertices;        /* number of vertices in model */
-  unsigned int    numnormals;            /* number of normals in model */
-  unsigned int    numtexcoords;        /* number of texcoords in model */
-  unsigned int    numtriangles;        /* number of triangles in model */
-  GLfloat*  vertices;            /* array of vertices  */
-  GLfloat*  normals;            /* array of normals */
-  GLfloat*  texcoords;            /* array of texture coordinates */
-  GLMgroup* group;            /* current group pointer */
-  unsigned int    material;            /* current material */
-  unsigned int    v, n, t;
-  char      buf[128];
-
-  /* set the pointer shortcuts */
-  vertices     = model->vertices;
-  normals      = model->normals;
-  texcoords    = model->texcoords;
-  group        = model->groups;
-
-  /* on the second pass through the file, read all the data into the
-     allocated arrays */
-  numvertices = numnormals = numtexcoords = 1;
-  numtriangles = 0;
-  material = 0;
-  
-  bool firstGroup = true;
-  bool previousLineWas_g = false;
-
-  int r,g,b;
-  while(fscanf(file, "%s", buf) != EOF) {
-    char c = buf[0];
-    switch(c) {
-    case '#':                /* comment */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'v':                /* v, vn, vt */
-      switch(buf[1]) {
-      case '\0':            /* vertex */
-        {
-            if (model->useColors)
-            {
-                fscanf(file, "%f %f %f %d %d %d", 
-                             &vertices[3 * numvertices + X], 
-                             &vertices[3 * numvertices + Y], 
-                             &vertices[3 * numvertices + Z],
-                             &r,&g,&b);
-                model->colors[numvertices].set(r,g,b,255);
-
-                numvertices++;               
-            } else
-            {
-                fscanf(file, "%f %f %f", 
-                             &vertices[3 * numvertices + X], 
-                             &vertices[3 * numvertices + Y], 
-                             &vertices[3 * numvertices + Z]);
-                numvertices++;               
-            }
-        }
-        break;
-      case 'n':                /* normal */
-        fscanf(file, "%f %f %f", 
-               &normals[3 * numnormals + X],
-               &normals[3 * numnormals + Y], 
-               &normals[3 * numnormals + Z]);
-        numnormals++;
-        break;
-      case 't':                /* texcoord */
-        fscanf(file, "%f %f", 
-               &texcoords[2 * numtexcoords + X],
-               &texcoords[2 * numtexcoords + Y]);
-        numtexcoords++;
-        break;
-      }
-      break;
-    case 'u':
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s %s", buf, buf);
-      
-      material = _glmFindMaterial(model, buf);
-      
-      group->material = material;
-
-      break;
-    case 'o':                /* group */
-    case 's':                /* group */
-    case 'g':                /* group */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      char compositeName[128];
-      createCompositeName(buf,compositeName);
-      group = _glmFindGroup(model, compositeName);
-      std::cout<<"compositeName="<<compositeName<<"  group="<<group<<std::endl;
-      group->material = material;
-      firstGroup = false;
-      break;
-    case 'f':                /* face */
-      v = n = t = 0;
-      fscanf(file, "%s", buf);
-      /* can be one of %d, %d//%d, %d/%d, %d/%d/%d %d//%d */
-      if (strstr(buf, "//")) {
-        /* v//n */
-        sscanf(buf, "%d//%d", &v, &n);
-        T(numtriangles).vindices[0] = v;
-        T(numtriangles).nindices[0] = n;
-        fscanf(file, "%d//%d", &v, &n);
-        T(numtriangles).vindices[1] = v;
-        T(numtriangles).nindices[1] = n;
-        fscanf(file, "%d//%d", &v, &n);
-        T(numtriangles).vindices[2] = v;
-        T(numtriangles).nindices[2] = n;
-        group->triangles[group->numtriangles++] = numtriangles;
-        numtriangles++;
-        while(fscanf(file, "%d//%d", &v, &n) > 0) {
-          T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
-          T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
-          T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
-          T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
-          T(numtriangles).vindices[2] = v;
-          T(numtriangles).nindices[2] = n;
-          group->triangles[group->numtriangles++] = numtriangles;
-          numtriangles++;
-        }
-      } else if (sscanf(buf, "%d/%d/%d", &v, &t, &n) == 3) {
-        /* v/t/n */
-        T(numtriangles).vindices[0] = v;
-        T(numtriangles).tindices[0] = t;
-        T(numtriangles).nindices[0] = n;
-        fscanf(file, "%d/%d/%d", &v, &t, &n);
-        T(numtriangles).vindices[1] = v;
-        T(numtriangles).tindices[1] = t;
-        T(numtriangles).nindices[1] = n;
-        fscanf(file, "%d/%d/%d", &v, &t, &n);
-        T(numtriangles).vindices[2] = v;
-        T(numtriangles).tindices[2] = t;
-        T(numtriangles).nindices[2] = n;
-        group->triangles[group->numtriangles++] = numtriangles;
-        group->hastexcoords = true;
-        numtriangles++;
-        while(fscanf(file, "%d/%d/%d", &v, &t, &n) > 0) {
-          T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
-          T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
-          T(numtriangles).nindices[0] = T(numtriangles-1).nindices[0];
-          T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
-          T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
-          T(numtriangles).nindices[1] = T(numtriangles-1).nindices[2];
-          T(numtriangles).vindices[2] = v;
-          T(numtriangles).tindices[2] = t;
-          T(numtriangles).nindices[2] = n;
-          group->triangles[group->numtriangles++] = numtriangles;
-          numtriangles++;
-        }
-      } else if (sscanf(buf, "%d/%d", &v, &t) == 2) {
-        /* v/t */
-        T(numtriangles).vindices[0] = v;
-        T(numtriangles).tindices[0] = t;
-        fscanf(file, "%d/%d", &v, &t);
-        T(numtriangles).vindices[1] = v;
-        T(numtriangles).tindices[1] = t;
-        fscanf(file, "%d/%d", &v, &t);
-        T(numtriangles).vindices[2] = v;
-        T(numtriangles).tindices[2] = t;
-        group->triangles[group->numtriangles++] = numtriangles;
-        group->hastexcoords = true;
-        numtriangles++;
-        while(fscanf(file, "%d/%d", &v, &t) > 0) {
-          T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
-          T(numtriangles).tindices[0] = T(numtriangles-1).tindices[0];
-          T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
-          T(numtriangles).tindices[1] = T(numtriangles-1).tindices[2];
-          T(numtriangles).vindices[2] = v;
-          T(numtriangles).tindices[2] = t;
-          group->triangles[group->numtriangles++] = numtriangles;
-          numtriangles++;
-        }
-      } else {
-        /* v */
-        sscanf(buf, "%d", &v);
-        T(numtriangles).vindices[0] = v;
-        fscanf(file, "%d", &v);
-        T(numtriangles).vindices[1] = v;
-        fscanf(file, "%d", &v);
-        T(numtriangles).vindices[2] = v;
-        group->triangles[group->numtriangles++] = numtriangles;
-        numtriangles++;
-        while(fscanf(file, "%d", &v) > 0) {
-          T(numtriangles).vindices[0] = T(numtriangles-1).vindices[0];
-          T(numtriangles).vindices[1] = T(numtriangles-1).vindices[2];
-          T(numtriangles).vindices[2] = v;
-          group->triangles[group->numtriangles++] = numtriangles;
-          numtriangles++;
-        }
-      }
-      break;
-
-    default:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-    
-    // a hack by Robert Osfield to account for usemtl being infront
-    // or the group, or after - but only one line after.
-    previousLineWas_g = (c=='g');
-  }
-
-#if 0
-  /* announce the memory requirements */
-  printf(" Memory: %d bytes\n",
-     numvertices  * 3*sizeof(GLfloat) +
-     numnormals   * 3*sizeof(GLfloat) * (numnormals ? 1 : 0) +
-     numtexcoords * 3*sizeof(GLfloat) * (numtexcoords ? 1 : 0) +
-     numtriangles * sizeof(GLMtriangle));
-#endif
-}
-
-
-
-
-/* public functions */
-
-/* glmUnitize: "unitize" a model by translating it to the origin and
- * scaling it to fit in a unit cube around the origin.  Returns the
- * scalefactor used.
- *
- * model - properly initialized GLMmodel structure 
- */
-GLfloat
-glmUnitize(GLMmodel* model)
-{
-  unsigned int  i;
-  GLfloat maxx, minx, maxy, miny, maxz, minz;
-  GLfloat cx, cy, cz, w, h, d;
-  GLfloat scale;
-
-  assert(model);
-  assert(model->vertices);
-
-  /* get the max/mins */
-  maxx = minx = model->vertices[3 + X];
-  maxy = miny = model->vertices[3 + Y];
-  maxz = minz = model->vertices[3 + Z];
-  for (i = 1; i <= model->numvertices; i++) {
-    if (maxx < model->vertices[3 * i + X])
-      maxx = model->vertices[3 * i + X];
-    if (minx > model->vertices[3 * i + X])
-      minx = model->vertices[3 * i + X];
-
-    if (maxy < model->vertices[3 * i + Y])
-      maxy = model->vertices[3 * i + Y];
-    if (miny > model->vertices[3 * i + Y])
-      miny = model->vertices[3 * i + Y];
-
-    if (maxz < model->vertices[3 * i + Z])
-      maxz = model->vertices[3 * i + Z];
-    if (minz > model->vertices[3 * i + Z])
-      minz = model->vertices[3 * i + Z];
-  }
-
-  /* calculate model width, height, and depth */
-  w = _glmAbs(maxx) + _glmAbs(minx);
-  h = _glmAbs(maxy) + _glmAbs(miny);
-  d = _glmAbs(maxz) + _glmAbs(minz);
-
-  /* calculate center of the model */
-  cx = (maxx + minx) / 2.0f;
-  cy = (maxy + miny) / 2.0f;
-  cz = (maxz + minz) / 2.0f;
-
-  /* calculate unitizing scale factor */
-  scale = 2.0f / _glmMax(_glmMax(w, h), d);
-
-  /* translate around center then scale */
-  for (i = 1; i <= model->numvertices; i++) {
-    model->vertices[3 * i + X] -= cx;
-    model->vertices[3 * i + Y] -= cy;
-    model->vertices[3 * i + Z] -= cz;
-    model->vertices[3 * i + X] *= scale;
-    model->vertices[3 * i + Y] *= scale;
-    model->vertices[3 * i + Z] *= scale;
-  }
-
-  return scale;
-}
-
-/* glmDimensions: Calculates the dimensions (width, height, depth) of
- * a model.
- *
- * model      - initialized GLMmodel structure
- * dimensions - array of 3 GLfloats (GLfloat dimensions[3])
- */
-GLvoid
-glmDimensions(GLMmodel* model, GLfloat* dimensions)
-{
-  unsigned int i;
-  GLfloat maxx, minx, maxy, miny, maxz, minz;
-
-  assert(model);
-  assert(model->vertices);
-  assert(dimensions);
-
-  /* get the max/mins */
-  maxx = minx = model->vertices[3 + X];
-  maxy = miny = model->vertices[3 + Y];
-  maxz = minz = model->vertices[3 + Z];
-  for (i = 1; i <= model->numvertices; i++) {
-    if (maxx < model->vertices[3 * i + X])
-      maxx = model->vertices[3 * i + X];
-    if (minx > model->vertices[3 * i + X])
-      minx = model->vertices[3 * i + X];
-
-    if (maxy < model->vertices[3 * i + Y])
-      maxy = model->vertices[3 * i + Y];
-    if (miny > model->vertices[3 * i + Y])
-      miny = model->vertices[3 * i + Y];
-
-    if (maxz < model->vertices[3 * i + Z])
-      maxz = model->vertices[3 * i + Z];
-    if (minz > model->vertices[3 * i + Z])
-      minz = model->vertices[3 * i + Z];
-  }
-
-  /* calculate model width, height, and depth */
-  dimensions[X] = _glmAbs(maxx) + _glmAbs(minx);
-  dimensions[Y] = _glmAbs(maxy) + _glmAbs(miny);
-  dimensions[Z] = _glmAbs(maxz) + _glmAbs(minz);
-}
-
-/* glmScale: Scales a model by a given amount.
- * 
- * model - properly initialized GLMmodel structure
- * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
- */
-GLvoid
-glmScale(GLMmodel* model, GLfloat scale)
-{
-  unsigned int i;
-
-  for (i = 1; i <= model->numvertices; i++) {
-    model->vertices[3 * i + X] *= scale;
-    model->vertices[3 * i + Y] *= scale;
-    model->vertices[3 * i + Z] *= scale;
-  }
-}
-
-/* glmReverseWinding: Reverse the polygon winding for all polygons in
- * this model.  Default winding is counter-clockwise.  Also changes
- * the direction of the normals.
- * 
- * model - properly initialized GLMmodel structure 
- */
-GLvoid
-glmReverseWinding(GLMmodel* model)
-{
-  unsigned int i, swap;
-
-  assert(model);
-
-  for (i = 0; i < model->numtriangles; i++) {
-    swap = T(i).vindices[0];
-    T(i).vindices[0] = T(i).vindices[2];
-    T(i).vindices[2] = swap;
-
-    if (model->numnormals) {
-      swap = T(i).nindices[0];
-      T(i).nindices[0] = T(i).nindices[2];
-      T(i).nindices[2] = swap;
-    }
-
-    if (model->numtexcoords) {
-      swap = T(i).tindices[0];
-      T(i).tindices[0] = T(i).tindices[2];
-      T(i).tindices[2] = swap;
-    }
-  }
-
-  /* reverse facet normals */
-  for (i = 1; i <= model->numfacetnorms; i++) {
-    model->facetnorms[3 * i + X] = -model->facetnorms[3 * i + X];
-    model->facetnorms[3 * i + Y] = -model->facetnorms[3 * i + Y];
-    model->facetnorms[3 * i + Z] = -model->facetnorms[3 * i + Z];
-  }
-
-  /* reverse vertex normals */
-  for (i = 1; i <= model->numnormals; i++) {
-    model->normals[3 * i + X] = -model->normals[3 * i + X];
-    model->normals[3 * i + Y] = -model->normals[3 * i + Y];
-    model->normals[3 * i + Z] = -model->normals[3 * i + Z];
-  }
-}
-
-/* glmFacetNormals: Generates facet normals for a model (by taking the
- * cross product of the two vectors derived from the sides of each
- * triangle).  Assumes a counter-clockwise winding.
- *
- * model - initialized GLMmodel structure
- */
-GLvoid
-glmFacetNormals(GLMmodel* model)
-{
-  unsigned int  i;
-  GLfloat u[3];
-  GLfloat v[3];
-  
-  assert(model);
-  assert(model->vertices);
-
-  /* clobber any old facetnormals */
-  if (model->facetnorms)
-    free(model->facetnorms);
-
-  /* allocate memory for the new facet normals */
-  model->numfacetnorms = model->numtriangles;
-  model->facetnorms = (GLfloat*)malloc(sizeof(GLfloat) *
-                       3 * (model->numfacetnorms + 1));
-
-  for (i = 0; i < model->numtriangles; i++) {
-    model->triangles[i].findex = i+1;
-
-    u[X] = model->vertices[3 * T(i).vindices[1] + X] -
-           model->vertices[3 * T(i).vindices[0] + X];
-    u[Y] = model->vertices[3 * T(i).vindices[1] + Y] -
-           model->vertices[3 * T(i).vindices[0] + Y];
-    u[Z] = model->vertices[3 * T(i).vindices[1] + Z] -
-           model->vertices[3 * T(i).vindices[0] + Z];
-
-    v[X] = model->vertices[3 * T(i).vindices[2] + X] -
-           model->vertices[3 * T(i).vindices[0] + X];
-    v[Y] = model->vertices[3 * T(i).vindices[2] + Y] -
-           model->vertices[3 * T(i).vindices[0] + Y];
-    v[Z] = model->vertices[3 * T(i).vindices[2] + Z] -
-           model->vertices[3 * T(i).vindices[0] + Z];
-
-    _glmCross(u, v, &model->facetnorms[3 * (i+1)]);
-    _glmNormalize(&model->facetnorms[3 * (i+1)]);
-  }
-}
-
-/* glmVertexNormals: Generates smooth vertex normals for a model.
- * First builds a list of all the triangles each vertex is in.  Then
- * loops through each vertex in the the list averaging all the facet
- * normals of the triangles each vertex is in.  Finally, sets the
- * normal index in the triangle for the vertex to the generated smooth
- * normal.  If the dot product of a facet normal and the facet normal
- * associated with the first triangle in the list of triangles the
- * current vertex is in is greater than the cosine of the angle
- * parameter to the function, that facet normal is not added into the
- * average normal calculation and the corresponding vertex is given
- * the facet normal.  This tends to preserve hard edges.  The angle to
- * use depends on the model, but 90 degrees is usually a good start.
- *
- * model - initialized GLMmodel structure
- * angle - maximum angle (in degrees) to smooth across
- */
-GLvoid
-glmVertexNormals(GLMmodel* model, GLfloat angle)
-{
-  GLMnode*  node;
-  GLMnode*  tail;
-  GLMnode** members;
-  GLfloat*  normals;
-  unsigned int    numnormals;
-  GLfloat   average[3];
-  GLfloat   dot, cos_angle;
-  unsigned int    i, avg;
-
-  assert(model);
-  assert(model->facetnorms);
-
-  /* calculate the cosine of the angle (in degrees) */
-  cos_angle = (float)cos(osg::DegreesToRadians(angle));
-
-  /* nuke any previous normals */
-  if (model->normals)
-    free(model->normals);
-
-  /* allocate space for new normals */
-  model->numnormals = model->numtriangles * 3; /* 3 normals per triangle */
-  model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1));
-
-  /* allocate a structure that will hold a linked list of triangle
-     indices for each vertex */
-  members = (GLMnode**)malloc(sizeof(GLMnode*) * (model->numvertices + 1));
-  for (i = 1; i <= model->numvertices; i++)
-    members[i] = NULL;
-  
-  /* for every triangle, create a node for each vertex in it */
-  for (i = 0; i < model->numtriangles; i++) {
-    node = (GLMnode*)malloc(sizeof(GLMnode));
-    node->index = i;
-    node->next  = members[T(i).vindices[0]];
-    members[T(i).vindices[0]] = node;
-
-    node = (GLMnode*)malloc(sizeof(GLMnode));
-    node->index = i;
-    node->next  = members[T(i).vindices[1]];
-    members[T(i).vindices[1]] = node;
-
-    node = (GLMnode*)malloc(sizeof(GLMnode));
-    node->index = i;
-    node->next  = members[T(i).vindices[2]];
-    members[T(i).vindices[2]] = node;
-  }
-
-  /* calculate the average normal for each vertex */
-  numnormals = 1;
-  for (i = 1; i <= model->numvertices; i++) {
-    /* calculate an average normal for this vertex by averaging the
-       facet normal of every triangle this vertex is in */
-    node = members[i];
-    if (!node)
-      fprintf(stderr, "glmVertexNormals(): vertex w/o a triangle\n");
-    average[0] = 0.0; average[1] = 0.0; average[2] = 0.0;
-    avg = 0;
-    while (node) {
-      /* only average if the dot product of the angle between the two
-         facet normals is greater than the cosine of the threshold
-         angle -- or, said another way, the angle between the two
-         facet normals is less than (or equal to) the threshold angle */
-      dot = _glmDot(&model->facetnorms[3 * T(node->index).findex],
-             &model->facetnorms[3 * T(members[i]->index).findex]);
-      if (dot > cos_angle) {
-    node->averaged = GL_TRUE;
-    average[0] += model->facetnorms[3 * T(node->index).findex + 0];
-    average[1] += model->facetnorms[3 * T(node->index).findex + 1];
-    average[2] += model->facetnorms[3 * T(node->index).findex + 2];
-    avg = 1;            /* we averaged at least one normal! */
-      } else {
-    node->averaged = GL_FALSE;
-      }
-      node = node->next;
-    }
-
-    if (avg) {
-      /* normalize the averaged normal */
-      _glmNormalize(average);
-
-      /* add the normal to the vertex normals list */
-      model->normals[3 * numnormals + 0] = average[0];
-      model->normals[3 * numnormals + 1] = average[1];
-      model->normals[3 * numnormals + 2] = average[2];
-      avg = numnormals;
-      numnormals++;
-    }
-
-    /* set the normal of this vertex in each triangle it is in */
-    node = members[i];
-    while (node) {
-      if (node->averaged) {
-    /* if this node was averaged, use the average normal */
-    if (T(node->index).vindices[0] == i)
-      T(node->index).nindices[0] = avg;
-    else if (T(node->index).vindices[1] == i)
-      T(node->index).nindices[1] = avg;
-    else if (T(node->index).vindices[2] == i)
-      T(node->index).nindices[2] = avg;
-      } else {
-    /* if this node wasn't averaged, use the facet normal */
-    model->normals[3 * numnormals + 0] = 
-      model->facetnorms[3 * T(node->index).findex + 0];
-    model->normals[3 * numnormals + 1] = 
-      model->facetnorms[3 * T(node->index).findex + 1];
-    model->normals[3 * numnormals + 2] = 
-      model->facetnorms[3 * T(node->index).findex + 2];
-    if (T(node->index).vindices[0] == i)
-      T(node->index).nindices[0] = numnormals;
-    else if (T(node->index).vindices[1] == i)
-      T(node->index).nindices[1] = numnormals;
-    else if (T(node->index).vindices[2] == i)
-      T(node->index).nindices[2] = numnormals;
-    numnormals++;
-      }
-      node = node->next;
-    }
-  }
-  
-  model->numnormals = numnormals - 1;
-
-  /* free the member information */
-  for (i = 1; i <= model->numvertices; i++) {
-    node = members[i];
-    while (node) {
-      tail = node;
-      node = node->next;
-      free(tail);
-    }
-  }
-  free(members);
-
-  /* pack the normals array (we previously allocated the maximum
-     number of normals that could possibly be created (numtriangles *
-     3), so get rid of some of them (usually alot unless none of the
-     facet normals were averaged)) */
-  normals = model->normals;
-  model->normals = (GLfloat*)malloc(sizeof(GLfloat)* 3* (model->numnormals+1));
-  for (i = 1; i <= model->numnormals; i++) {
-    model->normals[3 * i + 0] = normals[3 * i + 0];
-    model->normals[3 * i + 1] = normals[3 * i + 1];
-    model->normals[3 * i + 2] = normals[3 * i + 2];
-  }
-  free(normals);
-
-  printf("glmVertexNormals(): %d normals generated\n", model->numnormals);
-}
-
-
-/* glmLinearTexture: Generates texture coordinates according to a
- * linear projection of the texture map.  It generates these by
- * linearly mapping the vertices onto a square.
- *
- * model - pointer to initialized GLMmodel structure
- */
-GLvoid
-glmLinearTexture(GLMmodel* model)
-{
-  GLMgroup *group;
-  GLfloat dimensions[3];
-  GLfloat x, y, scalefactor;
-  unsigned int i;
-  
-  assert(model);
-
-  if (model->texcoords)
-    free(model->texcoords);
-  model->numtexcoords = model->numvertices;
-  model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1));
-  
-  glmDimensions(model, dimensions);
-  scalefactor = 2.0f / 
-    _glmAbs(_glmMax(_glmMax(dimensions[0], dimensions[1]), dimensions[2]));
-
-  /* do the calculations */
-  for(i = 1; i <= model->numvertices; i++) {
-    x = model->vertices[3 * i + 0] * scalefactor;
-    y = model->vertices[3 * i + 2] * scalefactor;
-    model->texcoords[2 * i + 0] = (x + 1.0f) / 2.0f;
-    model->texcoords[2 * i + 1] = (y + 1.0f) / 2.0f;
-  }
-  
-  /* go through and put texture coordinate indices in all the triangles */
-  group = model->groups;
-  while(group) {
-    for(i = 0; i < group->numtriangles; i++) {
-      T(group->triangles[i]).tindices[0] = T(group->triangles[i]).vindices[0];
-      T(group->triangles[i]).tindices[1] = T(group->triangles[i]).vindices[1];
-      T(group->triangles[i]).tindices[2] = T(group->triangles[i]).vindices[2];
-    }    
-    group = group->next;
-  }
-
-#if 0
-  printf("glmLinearTexture(): generated %d linear texture coordinates\n",
-      model->numtexcoords);
-#endif
-}
-
-/* glmSpheremapTexture: Generates texture coordinates according to a
- * spherical projection of the texture map.  Sometimes referred to as
- * spheremap, or reflection map texture coordinates.  It generates
- * these by using the normal to calculate where that vertex would map
- * onto a sphere.  Since it is impossible to map something flat
- * perfectly onto something spherical, there is distortion at the
- * poles.  This particular implementation causes the poles along the X
- * axis to be distorted.
- *
- * model - pointer to initialized GLMmodel structure
- */
-GLvoid
-glmSpheremapTexture(GLMmodel* model)
-{
-  GLMgroup* group;
-  GLfloat theta, phi, rho, x, y, z, r;
-  unsigned int i;
-  
-  assert(model);
-  assert(model->normals);
-
-  if (model->texcoords)
-    free(model->texcoords);
-  model->numtexcoords = model->numnormals;
-  model->texcoords=(GLfloat*)malloc(sizeof(GLfloat)*2*(model->numtexcoords+1));
-     
-  /* do the calculations */
-  for (i = 1; i <= model->numnormals; i++) {
-    z = model->normals[3 * i + 0];    /* re-arrange for pole distortion */
-    y = model->normals[3 * i + 1];
-    x = model->normals[3 * i + 2];
-    r = sqrtf((x * x) + (y * y));
-    rho = sqrtf((r * r) + (z * z));
-      
-    if(r == 0.0f) {
-    theta = 0.0f;
-    phi = 0.0f;
-    } else {
-      if(z == 0.0)
-    phi = 3.14159265f / 2.0f;
-      else
-    phi = acosf(z / rho);
-      
-#if WE_DONT_NEED_THIS_CODE
-      if(x == 0.0)
-    theta = 3.14159265f / 2.0f;    /* asin(y / r); */
-      else
-    theta = acos(x / r);
-#endif
-      
-      if(y == 0.0)
-    theta = 3.141592365f / 2.0f;    /* acos(x / r); */
-      else
-    theta = asinf(y / r) + 3.14159265f / 2.0f;
-    }
-    
-    model->texcoords[2 * i + 0] = theta / 3.14159265f;
-    model->texcoords[2 * i + 1] = phi / 3.14159265f;
-  }
-  
-  /* go through and put texcoord indices in all the triangles */
-  group = model->groups;
-  while(group) {
-    for (i = 0; i < group->numtriangles; i++) {
-      T(group->triangles[i]).tindices[0] = T(group->triangles[i]).nindices[0];
-      T(group->triangles[i]).tindices[1] = T(group->triangles[i]).nindices[1];
-      T(group->triangles[i]).tindices[2] = T(group->triangles[i]).nindices[2];
-    }
-    group = group->next;
-  }
-
-#if 0  
-  printf("glmSpheremapTexture(): generated %d spheremap texture coordinates\n",
-     model->numtexcoords);
-#endif
-}
-
-/* glmDelete: Deletes a GLMmodel structure.
- *
- * model - initialized GLMmodel structure
- */
-GLvoid
-glmDelete(GLMmodel* model)
-{
-  GLMgroup* group;
-  unsigned int i;
-
-  assert(model);
-
-  if (model->pathname)   free(model->pathname);
-  if (model->mtllibname) free(model->mtllibname);
-  if (model->vertices)   free(model->vertices);
-  if (model->colors)     free(model->colors);
-  if (model->normals)    free(model->normals);
-  if (model->texcoords)  free(model->texcoords);
-  if (model->facetnorms) free(model->facetnorms);
-  if (model->triangles)  free(model->triangles);
-  if (model->materials) {
-    for (i = 0; i < model->nummaterials; i++)
-    {
-      free(model->materials[i].name);
-      free(model->materials[i].textureName);
-    }
-  }
-  free(model->materials);
-  while(model->groups) {
-    group = model->groups;
-    model->groups = model->groups->next;
-    free(group->name);
-    free(group->triangles);
-    free(group);
-  }
-
-  free(model);
-}
-
-/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
- * Returns a pointer to the created object which should be free'd with
- * glmDelete().
- *
- * filename - name of the file containing the Wavefront .OBJ format data.  
- */
-GLMmodel* 
-glmReadOBJ(char* filename)
-{
-  GLMmodel* model;
-  FILE*     file;
-
-  /* open the file */
-  file = fopen(filename, "r");
-  if (!file) {
-    fprintf(stderr, "glmReadOBJ() failed: can't open data file \"%s\".\n",
-        filename);
-    //exit(1);
-    return NULL;
-  }
-
-#if 0
-  /* announce the model name */
-  printf("Model: %s\n", filename);
-#endif
-
-  /* allocate a new model */
-  model = (GLMmodel*)malloc(sizeof(GLMmodel));
-  model->pathname      = strdup(filename);
-  model->mtllibname    = NULL;
-  model->numvertices   = 0;
-  model->vertices      = NULL;
-  model->useColors     = false;
-  model->colors        = NULL;
-  model->numnormals    = 0;
-  model->normals       = NULL;
-  model->numtexcoords  = 0;
-  model->texcoords     = NULL;
-  model->numfacetnorms = 0;
-  model->facetnorms    = NULL;
-  model->numtriangles  = 0;
-  model->triangles     = NULL;
-  model->nummaterials  = 0;
-  model->materials     = NULL;
-  model->numgroups     = 0;
-  model->groups        = NULL;
-  model->position[0]   = 0.0;
-  model->position[1]   = 0.0;
-  model->position[2]   = 0.0;
-
-  /* make a first pass through the file to get a count of the number
-     of vertices, normals, texcoords & triangles */
-  _glmFirstPass(model, file);
-
-  /* allocate memory */
-  model->vertices = (GLfloat*)malloc(sizeof(GLfloat) *
-                     3 * (model->numvertices + 1));
-
-  if (model->useColors)                     
-      model->colors = (osg::UByte4*)malloc(sizeof(osg::UByte4)*(model->numvertices + 1));
-  
-  model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
-                      model->numtriangles);
-  if (model->numnormals) {
-    model->normals = (GLfloat*)malloc(sizeof(GLfloat) *
-                      3 * (model->numnormals + 1));
-  }
-  if (model->numtexcoords) {
-    model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) *
-                    2 * (model->numtexcoords + 1));
-  }
-
-  /* rewind to beginning of file and read in the data this pass */
-  rewind(file);
-
-  _glmSecondPass(model, file);
-
-  /* close the file */
-  fclose(file);
-
-  return model;
-}
-
-/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
- * a file.
- *
- * model    - initialized GLMmodel structure
- * filename - name of the file to write the Wavefront .OBJ format data to
- * mode     - a bitwise or of values describing what is written to the file
- *            GLM_NONE     -  render with only vertices
- *            GLM_FLAT     -  render with facet normals
- *            GLM_SMOOTH   -  render with vertex normals
- *            GLM_TEXTURE  -  render with texture coords
- *            GLM_COLOR    -  render with colors (color material)
- *            GLM_MATERIAL -  render with materials
- *            GLM_COLOR and GLM_MATERIAL should not both be specified.  
- *            GLM_FLAT and GLM_SMOOTH should not both be specified.  
- */
-GLvoid
-glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode)
-{
-  unsigned int    i;
-  FILE*     file;
-  GLMgroup* group;
-
-  assert(model);
-
-  /* do a bit of warning */
-  if (mode & GLM_FLAT && !model->facetnorms) {
-    printf("glmWriteOBJ() warning: flat normal output requested "
-       "with no facet normals defined.\n");
-    mode &= ~GLM_FLAT;
-  }
-  if (mode & GLM_SMOOTH && !model->normals) {
-    printf("glmWriteOBJ() warning: smooth normal output requested "
-       "with no normals defined.\n");
-    mode &= ~GLM_SMOOTH;
-  }
-  if (mode & GLM_TEXTURE && !model->texcoords) {
-    printf("glmWriteOBJ() warning: texture coordinate output requested "
-       "with no texture coordinates defined.\n");
-    mode &= ~GLM_TEXTURE;
-  }
-  if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
-    printf("glmWriteOBJ() warning: flat normal output requested "
-       "and smooth normal output requested (using smooth).\n");
-    mode &= ~GLM_FLAT;
-  }
-
-  /* open the file */
-  file = fopen(filename, "w");
-  if (!file) {
-    fprintf(stderr, "glmWriteOBJ() failed: can't open file \"%s\" to write.\n",
-        filename);
-    //exit(1);
-    return;
-  }
-
-  /* spit out a header */
-  fprintf(file, "#  \n");
-  fprintf(file, "#  Wavefront OBJ generated by GLM library\n");
-  fprintf(file, "#  \n");
-  fprintf(file, "#  GLM library copyright (C) 1997 by Nate Robins\n");
-  fprintf(file, "#  email: ndr@pobox.com\n");
-  fprintf(file, "#  www:   http://www.pobox.com/~ndr\n");
-  fprintf(file, "#  \n");
-
-  if (mode & GLM_MATERIAL && model->mtllibname) {
-    fprintf(file, "\nmtllib %s\n\n", model->mtllibname);
-    _glmWriteMTL(model, filename, model->mtllibname);
-  }
-
-  /* spit out the vertices */
-  fprintf(file, "\n");
-  fprintf(file, "# %d vertices\n", model->numvertices);
-  for (i = 1; i <= model->numvertices; i++) {
-    fprintf(file, "v %f %f %f\n", 
-        model->vertices[3 * i + 0],
-        model->vertices[3 * i + 1],
-        model->vertices[3 * i + 2]);
-  }
-
-  /* spit out the smooth/flat normals */
-  if (mode & GLM_SMOOTH) {
-    fprintf(file, "\n");
-    fprintf(file, "# %d normals\n", model->numnormals);
-    for (i = 1; i <= model->numnormals; i++) {
-      fprintf(file, "vn %f %f %f\n", 
-          model->normals[3 * i + 0],
-          model->normals[3 * i + 1],
-          model->normals[3 * i + 2]);
-    }
-  } else if (mode & GLM_FLAT) {
-    fprintf(file, "\n");
-    fprintf(file, "# %d normals\n", model->numfacetnorms);
-    for (i = 1; i <= model->numnormals; i++) {
-      fprintf(file, "vn %f %f %f\n", 
-          model->facetnorms[3 * i + 0],
-          model->facetnorms[3 * i + 1],
-          model->facetnorms[3 * i + 2]);
-    }
-  }
-
-  /* spit out the texture coordinates */
-  if (mode & GLM_TEXTURE) {
-    fprintf(file, "\n");
-    fprintf(file, "# %d texcoords\n", model->numtexcoords);
-    for (i = 1; i <= model->numtexcoords; i++) {
-      fprintf(file, "vt %f %f\n", 
-          model->texcoords[2 * i + 0],
-          model->texcoords[2 * i + 1]);
-    }
-  }
-
-  fprintf(file, "\n");
-  fprintf(file, "# %d groups\n", model->numgroups);
-  fprintf(file, "# %d faces (triangles)\n", model->numtriangles);
-  fprintf(file, "\n");
-
-  group = model->groups;
-  while(group) {
-    fprintf(file, "g %s\n", group->name);
-    if (mode & GLM_MATERIAL)
-      fprintf(file, "usemtl %s\n", model->materials[group->material].name);
-    for (i = 0; i < group->numtriangles; i++) {
-      if (mode & GLM_SMOOTH && mode & GLM_TEXTURE) {
-    fprintf(file, "f %d/%d/%d %d/%d/%d %d/%d/%d\n",
-        T(group->triangles[i]).vindices[0], 
-        T(group->triangles[i]).nindices[0], 
-        T(group->triangles[i]).tindices[0],
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).nindices[1],
-        T(group->triangles[i]).tindices[1],
-        T(group->triangles[i]).vindices[2],
-        T(group->triangles[i]).nindices[2],
-        T(group->triangles[i]).tindices[2]);
-      } else if (mode & GLM_FLAT && mode & GLM_TEXTURE) {
-    fprintf(file, "f %d/%d %d/%d %d/%d\n",
-        T(group->triangles[i]).vindices[0],
-        T(group->triangles[i]).findex,
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).findex,
-        T(group->triangles[i]).vindices[2],
-        T(group->triangles[i]).findex);
-      } else if (mode & GLM_TEXTURE) {
-    fprintf(file, "f %d/%d %d/%d %d/%d\n",
-        T(group->triangles[i]).vindices[0],
-        T(group->triangles[i]).tindices[0],
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).tindices[1],
-        T(group->triangles[i]).vindices[2],
-        T(group->triangles[i]).tindices[2]);
-      } else if (mode & GLM_SMOOTH) {
-    fprintf(file, "f %d//%d %d//%d %d//%d\n",
-        T(group->triangles[i]).vindices[0],
-        T(group->triangles[i]).nindices[0],
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).nindices[1],
-        T(group->triangles[i]).vindices[2], 
-        T(group->triangles[i]).nindices[2]);
-      } else if (mode & GLM_FLAT) {
-    fprintf(file, "f %d//%d %d//%d %d//%d\n",
-        T(group->triangles[i]).vindices[0], 
-        T(group->triangles[i]).findex,
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).findex,
-        T(group->triangles[i]).vindices[2],
-        T(group->triangles[i]).findex);
-      } else {
-    fprintf(file, "f %d %d %d\n",
-        T(group->triangles[i]).vindices[0],
-        T(group->triangles[i]).vindices[1],
-        T(group->triangles[i]).vindices[2]);
-      }
-    }
-    fprintf(file, "\n");
-    group = group->next;
-  }
-
-  fclose(file);
-}
-
-/* glmWeld: eliminate (weld) vectors that are within an epsilon of
- * each other.
- *
- * model      - initialized GLMmodel structure
- * epsilon    - maximum difference between vertices
- *              ( 0.00001 is a good start for a unitized model)
- *
- */
-GLvoid
-glmWeld(GLMmodel* model, GLfloat epsilon)
-{
-  GLfloat* vectors;
-  GLfloat* copies;
-  unsigned int   numvectors;
-  unsigned int   i;
-
-  /* vertices */
-  numvectors = model->numvertices;
-  vectors    = model->vertices;
-  copies = _glmWeldVectors(vectors, &numvectors, epsilon);
-
-  printf("glmWeld(): %d redundant vertices.\n", 
-     model->numvertices - numvectors - 1);
-
-  for (i = 0; i < model->numtriangles; i++) {
-    T(i).vindices[0] = (unsigned int)vectors[3 * T(i).vindices[0] + 0];
-    T(i).vindices[1] = (unsigned int)vectors[3 * T(i).vindices[1] + 0];
-    T(i).vindices[2] = (unsigned int)vectors[3 * T(i).vindices[2] + 0];
-  }
-
-  /* free space for old vertices */
-  free(vectors);
-
-  /* allocate space for the new vertices */
-  model->numvertices = numvectors;
-  model->vertices = (GLfloat*)malloc(sizeof(GLfloat) * 
-                     3 * (model->numvertices + 1));
-
-  /* copy the optimized vertices into the actual vertex list */
-  for (i = 1; i <= model->numvertices; i++) {
-    model->vertices[3 * i + 0] = copies[3 * i + 0];
-    model->vertices[3 * i + 1] = copies[3 * i + 1];
-    model->vertices[3 * i + 2] = copies[3 * i + 2];
-  }
-
-  free(copies);
-}
-
-
-#if 0
-  /* normals */
-  if (model->numnormals) {
-  numvectors = model->numnormals;
-  vectors    = model->normals;
-  copies = _glmOptimizeVectors(vectors, &numvectors);
-
-  printf("glmOptimize(): %d redundant normals.\n", 
-     model->numnormals - numvectors);
-
-  for (i = 0; i < model->numtriangles; i++) {
-    T(i).nindices[0] = (unsigned int)vectors[3 * T(i).nindices[0] + 0];
-    T(i).nindices[1] = (unsigned int)vectors[3 * T(i).nindices[1] + 0];
-    T(i).nindices[2] = (unsigned int)vectors[3 * T(i).nindices[2] + 0];
-  }
-
-  /* free space for old normals */
-  free(vectors);
-
-  /* allocate space for the new normals */
-  model->numnormals = numvectors;
-  model->normals = (GLfloat*)malloc(sizeof(GLfloat) * 
-                    3 * (model->numnormals + 1));
-
-  /* copy the optimized vertices into the actual vertex list */
-  for (i = 1; i <= model->numnormals; i++) {
-    model->normals[3 * i + 0] = copies[3 * i + 0];
-    model->normals[3 * i + 1] = copies[3 * i + 1];
-    model->normals[3 * i + 2] = copies[3 * i + 2];
-  }
-
-  free(copies);
-  }
-
-  /* texcoords */
-  if (model->numtexcoords) {
-  numvectors = model->numtexcoords;
-  vectors    = model->texcoords;
-  copies = _glmOptimizeVectors(vectors, &numvectors);
-
-  printf("glmOptimize(): %d redundant texcoords.\n", 
-     model->numtexcoords - numvectors);
-
-  for (i = 0; i < model->numtriangles; i++) {
-    for (j = 0; j < 3; j++) {
-      T(i).tindices[j] = (unsigned int)vectors[3 * T(i).tindices[j] + 0];
-    }
-  }
-
-  /* free space for old texcoords */
-  free(vectors);
-
-  /* allocate space for the new texcoords */
-  model->numtexcoords = numvectors;
-  model->texcoords = (GLfloat*)malloc(sizeof(GLfloat) * 
-                      2 * (model->numtexcoords + 1));
-
-  /* copy the optimized vertices into the actual vertex list */
-  for (i = 1; i <= model->numtexcoords; i++) {
-    model->texcoords[2 * i + 0] = copies[2 * i + 0];
-    model->texcoords[2 * i + 1] = copies[2 * i + 1];
-  }
-
-  free(copies);
-  }
-#endif
-
-#if 0
-  /* look for unused vertices */
-  /* look for unused normals */
-  /* look for unused texcoords */
-  for (i = 1; i <= model->numvertices; i++) {
-    for (j = 0; j < model->numtriangles; i++) {
-      if (T(j).vindices[0] == i || 
-      T(j).vindices[1] == i || 
-      T(j).vindices[1] == i)
-    break;
-    }
-  }
-#endif
Index: /enSceneGraph/trunk/src/osgPlugins/obj/glm.h
===================================================================
--- /OpenSceneGraph/trunk/src/osgPlugins/obj/glm.h (revision 2441)
+++  (revision )
@@ -1,306 +1,0 @@
-/*    
- *  Wavefront .obj file format reader.
- *
- *  author: Nate Robins
- *  email: ndr@pobox.com
- *  www: http://www.pobox.com/~ndr
- */
-
-
-/* includes */
-/* #include "glut.h" */
-//#include <GL/glu.h>
-//#include<GL/glut.h>
-
-// Replace about glu/glut calls with the more x-platform friendly osg version,
-// also neither glu or glut were requied?!  Only gl.h... even this I think
-// should be removed since all the GLfloat etc could just as easily be floats.
-// Will leave for now as it works... Robert Osfield, June 5th 2001. 
-#include <osg/GL>
-#include <osg/UByte4>
-
-#ifndef M_PI
-#define M_PI 3.14159265
-#endif
-
-
-/* defines */
-#define GLM_NONE     (0)        /* render with only vertices */
-#define GLM_FLAT     (1 << 0)        /* render with facet normals */
-#define GLM_SMOOTH   (1 << 1)        /* render with vertex normals */
-#define GLM_TEXTURE  (1 << 2)        /* render with texture coords */
-#define GLM_COLOR    (1 << 3)        /* render with colors */
-#define GLM_MATERIAL (1 << 4)        /* render with materials */
-
-
-/* structs */
-
-/* GLMmaterial: Structure that defines a material in a model. 
- */
-struct GLMmaterial
-{
-  char*   name;                /* name of material */
-  GLfloat diffuse[4];            /* diffuse component */
-  GLfloat ambient[4];            /* ambient component */
-  GLfloat specular[4];            /* specular component */
-  GLfloat emmissive[4];            /* emmissive component */
-  GLfloat shininess;            /* specular exponent */
-  char*   textureName;                  /* name of any attached texture, add by RO */
-  bool    textureReflection;            /* true if texture is a reflection map */    
-  float   alpha;                /* alpha */
-  float   textureUScale;            /* Scaling along U */
-  float	  textureVScale;            /* Scaling along V */
-  float   textureUOffset;            /* Offset along U */
-  float	  textureVOffset;            /* Offset along V */
-
-  void init()
-  {
-    name = NULL;
-    diffuse[0] = diffuse[1] = diffuse[2] = 0.8f; diffuse[3] = 1.0f;
-    ambient[0] = ambient[1] = ambient[2] = 0.2f; ambient[3] = 1.0f;
-    specular[0] = specular[1] = specular[2] = 0.0f; specular[3] = 1.0f;
-    emmissive[0] = emmissive[1] = emmissive[2] = 0.0f; emmissive[3] = 1.0f;
-    shininess = 0.0f;
-    textureName = NULL;
-    textureReflection = false;
-    alpha = 1.0f;
-  }
-
-};
-
-/* GLMtriangle: Structure that defines a triangle in a model.
- */
-struct GLMtriangle {
-  unsigned int vindices[3];            /* array of triangle vertex indices */
-  unsigned int nindices[3];            /* array of triangle normal indices */
-  unsigned int tindices[3];            /* array of triangle texcoord indices*/
-  unsigned int findex;                /* index of triangle facet normal */
-  void init()
-  {
-    vindices[0] = vindices[2] = vindices[2] = 0 ;
-    nindices[0] = nindices[2] = nindices[2] = 0 ;
-    tindices[0] = tindices[2] = tindices[2] = 0 ;
-    findex=0;
-  }
-};
-
-/* GLMgroup: Structure that defines a group in a model.
- */
-struct GLMgroup {
-  char*             name;        /* name of this group */
-  unsigned int            numtriangles;    /* number of triangles in this group */
-  unsigned int*           triangles;        /* array of triangle indices */
-  unsigned int            material;           /* index to material for group */
-  bool              hastexcoords;       /* set to true if triangles have texture coords */
-  struct GLMgroup*  next;        /* pointer to next group in model */
-
-  void init()
-  {
-    name = NULL;        
-    numtriangles = 0;    
-    triangles = NULL;    
-    material = 0;       
-        hastexcoords = false;
-    next = NULL;        
-  }
-};
-
-/* GLMmodel: Structure that defines a model.
- */
-struct  GLMmodel {
-  char*    pathname;            /* path to this model */
-  char*    mtllibname;            /* name of the material library */
-
-  unsigned int   numvertices;            /* number of vertices in model */
-  GLfloat* vertices;            /* array of vertices  */
-
-  bool useColors;               /* true if per vertex colors are present.*/
-  osg::UByte4* colors;            /* array of per vertex colors  */
-
-  unsigned int   numnormals;            /* number of normals in model */
-  GLfloat* normals;            /* array of normals */
-
-  unsigned int   numtexcoords;        /* number of texcoords in model */
-  GLfloat* texcoords;            /* array of texture coordinates */
-
-  unsigned int   numfacetnorms;        /* number of facetnorms in model */
-  GLfloat* facetnorms;            /* array of facetnorms */
-
-  unsigned int       numtriangles;        /* number of triangles in model */
-  GLMtriangle* triangles;        /* array of triangles */
-
-  unsigned int       nummaterials;        /* number of materials in model */
-  GLMmaterial* materials;        /* array of materials */
-
-  unsigned int       numgroups;        /* number of groups in model */
-  GLMgroup*    groups;            /* linked list of groups */
-
-  GLfloat position[3];            /* position of the model */
-
-
-  void init()
-  {
-    pathname = NULL;    
-    mtllibname = NULL;    
-
-    numvertices = 0;    
-    vertices = NULL;
-    
-    useColors = false;
-    colors = NULL;
-
-    numnormals = 0;        
-    normals = NULL;    
-
-    numtexcoords = 0;    
-    texcoords = NULL;
-
-    numfacetnorms = 0;    
-    facetnorms = NULL;
-
-    numtriangles = 0;    
-    triangles = NULL;        
-
-    nummaterials = 0;    
-    materials = NULL;
-
-    numgroups = 0;
-    groups = NULL;
-
-    position[0] = position[1] = position[2] = 0.0f;
-
-  }
-
-};
-
-
-/* public functions */
-
-/* glmUnitize: "unitize" a model by translating it to the origin and
- * scaling it to fit in a unit cube around the origin.  Returns the
- * scalefactor used.
- *
- * model - properly initialized GLMmodel structure 
- */
-GLfloat
-glmUnitize(GLMmodel* model);
-
-/* glmDimensions: Calculates the dimensions (width, height, depth) of
- * a model.
- *
- * model      - initialized GLMmodel structure
- * dimensions - array of 3 GLfloats (GLfloat dimensions[3])
- */
-GLvoid
-glmDimensions(GLMmodel* model, GLfloat* dimensions);
-
-/* glmScale: Scales a model by a given amount.
- * 
- * model - properly initialized GLMmodel structure
- * scale - scalefactor (0.5 = half as large, 2.0 = twice as large)
- */
-GLvoid
-glmScale(GLMmodel* model, GLfloat scale);
-
-/* glmReverseWinding: Reverse the polygon winding for all polygons in
- * this model.  Default winding is counter-clockwise.  Also changes
- * the direction of the normals.
- * 
- * model - properly initialized GLMmodel structure 
- */
-GLvoid
-glmReverseWinding(GLMmodel* model);
-
-/* glmFacetNormals: Generates facet normals for a model (by taking the
- * cross product of the two vectors derived from the sides of each
- * triangle).  Assumes a counter-clockwise winding.
- *
- * model - initialized GLMmodel structure
- */
-GLvoid
-glmFacetNormals(GLMmodel* model);
-
-/* glmVertexNormals: Generates smooth vertex normals for a model.
- * First builds a list of all the triangles each vertex is in.  Then
- * loops through each vertex in the the list averaging all the facet
- * normals of the triangles each vertex is in.  Finally, sets the
- * normal index in the triangle for the vertex to the generated smooth
- * normal.  If the dot product of a facet normal and the facet normal
- * associated with the first triangle in the list of triangles the
- * current vertex is in is greater than the cosine of the angle
- * parameter to the function, that facet normal is not added into the
- * average normal calculation and the corresponding vertex is given
- * the facet normal.  This tends to preserve hard edges.  The angle to
- * use depends on the model, but 90 degrees is usually a good start.
- *
- * model - initialized GLMmodel structure
- * angle - maximum angle (in degrees) to smooth across
- */
-GLvoid
-glmVertexNormals(GLMmodel* model, GLfloat angle);
-
-/* glmLinearTexture: Generates texture coordinates according to a
- * linear projection of the texture map.  It generates these by
- * linearly mapping the vertices onto a square.
- *
- * model - pointer to initialized GLMmodel structure
- */
-GLvoid
-glmLinearTexture(GLMmodel* model);
-
-/* glmSpheremapTexture: Generates texture coordinates according to a
- * spherical projection of the texture map.  Sometimes referred to as
- * spheremap, or reflection map texture coordinates.  It generates
- * these by using the normal to calculate where that vertex would map
- * onto a sphere.  Since it is impossible to map something flat
- * perfectly onto something spherical, there is distortion at the
- * poles.  This particular implementation causes the poles along the X
- * axis to be distorted.
- *
- * model - pointer to initialized GLMmodel structure
- */
-GLvoid
-glmSpheremapTexture(GLMmodel* model);
-
-/* glmDelete: Deletes a GLMmodel structure.
- *
- * model - initialized GLMmodel structure
- */
-GLvoid
-glmDelete(GLMmodel* model);
-
-/* glmReadOBJ: Reads a model description from a Wavefront .OBJ file.
- * Returns a pointer to the created object which should be free'd with
- * glmDelete().
- *
- * filename - name of the file containing the Wavefront .OBJ format data.  
- */
-GLMmodel* 
-glmReadOBJ(char* filename);
-
-/* glmWriteOBJ: Writes a model description in Wavefront .OBJ format to
- * a file.
- *
- * model    - initialized GLMmodel structure
- * filename - name of the file to write the Wavefront .OBJ format data to
- * mode     - a bitwise or of values describing what is written to the file
- *            GLM_NONE    -  write only vertices
- *            GLM_FLAT    -  write facet normals
- *            GLM_SMOOTH  -  write vertex normals
- *            GLM_TEXTURE -  write texture coords
- *            GLM_FLAT and GLM_SMOOTH should not both be specified.
- */
-GLvoid
-glmWriteOBJ(GLMmodel* model, char* filename, unsigned int mode);
-
-
-/* glmWeld: eliminate (weld) vectors that are within an epsilon of
- * each other.
- *
- * model      - initialized GLMmodel structure
- * epsilon    - maximum difference between vertices
- *              ( 0.00001 is a good start for a unitized model)
- *
- */
-GLvoid
-glmWeld(GLMmodel* model, GLfloat epsilon);
Index: /OpenSceneGraph/trunk/VisualStudio/osgPlugins/obj/obj.dsp
===================================================================
--- /OpenSceneGraph/trunk/VisualStudio/osgPlugins/obj/obj.dsp (revision 3181)
+++ /OpenSceneGraph/trunk/VisualStudio/osgPlugins/obj/obj.dsp (revision 3323)
@@ -97,5 +97,5 @@
 # Begin Source File
 
-SOURCE=..\..\..\src\osgPlugins\obj\glm.cpp
+SOURCE=..\..\..\src\osgPlugins\obj\obj.cpp
 # End Source File
 # Begin Source File
@@ -109,5 +109,5 @@
 # Begin Source File
 
-SOURCE=..\..\..\Src\osgPlugins\obj\glm.h
+SOURCE=..\..\..\Src\osgPlugins\obj\obj.h
 # End Source File
 # End Group
