Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[MANTA] r771 - in trunk: . Core Core/Exceptions Image Interface Model/Groups Model/Materials Model/Primitives Model/Readers Model/Readers/glm Model/Textures fox scenes


Chronological Thread 
  • From: abe@sci.utah.edu
  • To: manta@sci.utah.edu
  • Subject: [MANTA] r771 - in trunk: . Core Core/Exceptions Image Interface Model/Groups Model/Materials Model/Primitives Model/Readers Model/Readers/glm Model/Textures fox scenes
  • Date: Mon, 12 Dec 2005 17:07:51 -0700 (MST)

Author: abe
Date: Mon Dec 12 17:07:44 2005
New Revision: 771

Added:
   trunk/Core/Exceptions/InputError.cc
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/InputError.cc
   trunk/Core/Exceptions/InputError.h
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/InputError.h
   trunk/Core/Exceptions/OutputError.cc
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/OutputError.cc
   trunk/Core/Exceptions/OutputError.h
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/OutputError.h
   trunk/Core/Exceptions/UnknownPixel.cc
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/UnknownPixel.cc
   trunk/Core/Exceptions/UnknownPixel.h
      - copied unchanged from r768, 
branches/itanium2/Core/Exceptions/UnknownPixel.h
   trunk/Image/NRRDFile.cc
      - copied unchanged from r767, branches/itanium2/Image/NRRDFile.cc
   trunk/Image/NRRDFile.h
      - copied unchanged from r767, branches/itanium2/Image/NRRDFile.h
   trunk/Model/Textures/TexCoordTexture.cc
      - copied unchanged from r768, 
branches/itanium2/Model/Textures/TexCoordTexture.cc
   trunk/Model/Textures/TexCoordTexture.h
      - copied unchanged from r768, 
branches/itanium2/Model/Textures/TexCoordTexture.h
Modified:
   trunk/CMakeLists.txt
   trunk/Core/CMakeLists.txt
   trunk/Image/CMakeLists.txt
   trunk/Image/Pixel.h
   trunk/Image/SimpleImage.h
   trunk/Image/TGAFile.cc
   trunk/Image/TGAFile.h
   trunk/Interface/TexCoordMapper.h
   trunk/MantaTypes.h
   trunk/Model/Groups/KDTree.cc
   trunk/Model/Groups/TransparentKDTree.cc
   trunk/Model/Materials/NormalMaterial.cc
   trunk/Model/Materials/Phong.h
   trunk/Model/Primitives/BvhTriangleMesh.cc
   trunk/Model/Primitives/BvhTriangleMesh.h
   trunk/Model/Primitives/Cone.cc
   trunk/Model/Primitives/Cube.cc
   trunk/Model/Primitives/Cylinder.cc
   trunk/Model/Primitives/Disk.cc
   trunk/Model/Primitives/HeavyTriangle.cc
   trunk/Model/Primitives/HeavyTriangle.h
   trunk/Model/Primitives/Heightfield.cc
   trunk/Model/Primitives/Hemisphere.cc
   trunk/Model/Primitives/Parallelogram.cc
   trunk/Model/Primitives/ParticleBVH.cc
   trunk/Model/Primitives/Plane.cc
   trunk/Model/Primitives/PrimitiveCommon.h
   trunk/Model/Primitives/Ring.cc
   trunk/Model/Primitives/Sphere.cc
   trunk/Model/Primitives/SuperEllipsoid.cc
   trunk/Model/Primitives/TexTriangle.cc
   trunk/Model/Primitives/TexTriangle.h
   trunk/Model/Primitives/Triangle.cc
   trunk/Model/Readers/CMakeLists.txt
   trunk/Model/Readers/PlyReader.cc
   trunk/Model/Readers/PlyReader.h
   trunk/Model/Readers/glm/glm.cc
   trunk/Model/Readers/glm/glm.h
   trunk/Model/Textures/CMakeLists.txt
   trunk/Model/Textures/CheckerTexture.cc
   trunk/Model/Textures/CheckerTexture.h
   trunk/Model/Textures/Constant.cc
   trunk/Model/Textures/Constant.h
   trunk/Model/Textures/ImageTexture.cc
   trunk/Model/Textures/ImageTexture.h
   trunk/Model/Textures/MarbleTexture.cc
   trunk/Model/Textures/MarbleTexture.h
   trunk/Model/Textures/OakTexture.cc
   trunk/Model/Textures/OakTexture.h
   trunk/Model/Textures/TriVerTexture.cc
   trunk/Model/Textures/TriVerTexture.h
   trunk/Model/Textures/WoodTexture.cc
   trunk/Model/Textures/WoodTexture.h
   trunk/fox/FMantaWindow.cc
   trunk/fox/dm_demo.cc
   trunk/scenes/objviewer.cc
Log:

Last changes merged over from itanium2.


Modified objviewer to read standard obj files and create a scene with 
reflection, dielectrics, textures etc.
Currently there is a problem reading/copying texture coordinates... although 
they work fine if the scene graph is constructed manually.
M    scenes/objviewer.cc

Added support for reading nrrd, ppm, png, etc image files using teem.
M    Image/TGAFile.cc
M    Image/TGAFile.h
M    Image/SimpleImage.h
M    Image/Pixel.h
A    Image/NRRDFile.cc
A    Image/NRRDFile.h
M    Image/CMakeLists.txt

Added exception types more specific than "InternalError"
A    Core/Exceptions/InputError.h
A    Core/Exceptions/OutputError.h
A    Core/Exceptions/UnknownPixel.cc
A    Core/Exceptions/UnknownPixel.h
A    Core/Exceptions/InputError.cc
A    Core/Exceptions/OutputError.cc
M    Core/CMakeLists.txt

M    fox/FMantaWindow.cc
M    fox/dm_demo.cc
M    Model/Groups/TransparentKDTree.cc
M    Model/Groups/KDTree.cc
M    Model/Materials/NormalMaterial.cc
M    Model/Materials/Phong.h

Removed inclusion of .cc files in .h files.
M    Model/Textures/WoodTexture.h
M    Model/Textures/OakTexture.cc
M    Model/Textures/Constant.h
M    Model/Textures/TriVerTexture.cc
M    Model/Textures/OakTexture.h
M    Model/Textures/TriVerTexture.h
M    Model/Textures/ImageTexture.cc
M    Model/Textures/ImageTexture.h
A    Model/Textures/TexCoordTexture.cc
A    Model/Textures/TexCoordTexture.h
M    Model/Textures/MarbleTexture.cc
M    Model/Textures/MarbleTexture.h
M    Model/Textures/CheckerTexture.cc
M    Model/Textures/CheckerTexture.h
M    Model/Textures/CMakeLists.txt
M    Model/Textures/WoodTexture.cc
M    Model/Textures/Constant.cc

Added support for more obj directives to glm.
M    Model/Readers/glm/glm.cc
M    Model/Readers/glm/glm.h

Fixed link error introduced earlier in ply reader.
M    Model/Readers/PlyReader.cc
M    Model/Readers/CMakeLists.txt
M    Model/Readers/PlyReader.h

Made PrimitiveCommon tex and material private, added accessor.
M    Model/Primitives/Plane.cc
M    Model/Primitives/SuperEllipsoid.cc
M    Model/Primitives/ParticleBVH.cc
M    Model/Primitives/HeavyTriangle.h
M    Model/Primitives/Cylinder.cc
M    Model/Primitives/Cube.cc
M    Model/Primitives/Cone.cc
M    Model/Primitives/BvhTriangleMesh.h
M    Model/Primitives/TexTriangle.cc
M    Model/Primitives/Hemisphere.cc
M    Model/Primitives/Disk.cc
M    Model/Primitives/Ring.cc
M    Model/Primitives/HeavyTriangle.cc
M    Model/Primitives/Triangle.cc
M    Model/Primitives/Heightfield.cc
M    Model/Primitives/Parallelogram.cc
M    Model/Primitives/BvhTriangleMesh.cc
M    Model/Primitives/PrimitiveCommon.h
M    Model/Primitives/Sphere.cc
M    Model/Primitives/TexTriangle.h
M    Interface/TexCoordMapper.h

Added license to MantaTypes.h. If you create a new file, copy the license 
from here.
M    MantaTypes.h
M    CMakeLists.txt


Modified: trunk/CMakeLists.txt
==============================================================================
--- trunk/CMakeLists.txt        (original)
+++ trunk/CMakeLists.txt        Mon Dec 12 17:07:44 2005
@@ -195,6 +195,20 @@
   SUBDIRS(fox)
 ENDIF(BUILD_FOX)
 
+# Look for Teem http://teem.sourceforge.net/
+FIND_LIBRARY( FOUND_TEEM_LIB     NAMES teem        
+                                 PATHS /usr/local/lib /usr/lib 
+                                 DOC "Teem library (This is a path.)" )
+FIND_PATH   ( FOUND_TEEM_INCLUDE NAMES teem/nrrd.h /usr/local/include 
/usr/include
+                                 DOC "Teem Include (This is a path.)" )
+
+# Check for teem dependencies
+IF(FOUND_TEEM_LIB) 
+  LINK_DIRECTORIES(${FOUND_TEEM_LIB})
+ENDIF(FOUND_TEEM_LIB)
+
+
+
 # Now that everything is done indicate that we have finished
 # configuring at least once.
 

Modified: trunk/Core/CMakeLists.txt
==============================================================================
--- trunk/Core/CMakeLists.txt   (original)
+++ trunk/Core/CMakeLists.txt   Mon Dec 12 17:07:44 2005
@@ -20,6 +20,12 @@
      Exceptions/IllegalArgument.cc
      Exceptions/UnknownColor.h
      Exceptions/UnknownColor.cc
+     Exceptions/UnknownPixel.h
+     Exceptions/UnknownPixel.cc
+     Exceptions/InputError.h
+     Exceptions/InputError.cc
+     Exceptions/OutputError.h
+     Exceptions/OutputError.cc
      )
 SET (CORE_SOURCES ${CORE_SOURCES}
      Math/MT_RNG.h

Modified: trunk/Image/CMakeLists.txt
==============================================================================
--- trunk/Image/CMakeLists.txt  (original)
+++ trunk/Image/CMakeLists.txt  Mon Dec 12 17:07:44 2005
@@ -1,4 +1,22 @@
 
+###############################################################################
+# Check to see if nrrd dependent files should be included.
+IF (FOUND_TEEM_INCLUDE) 
+
+  # Add the Nrrd read/write files to the build
+  SET (NRRD_IMAGE_SRC NRRDFile.h NRRDFile.cc)  
+
+  # Add the include directory to the build
+  INCLUDE_DIRECTORIES(${FOUND_TEEM_INCLUDE})
+
+ENDIF (FOUND_TEEM_INCLUDE)
+
+IF (FOUND_TEEM_LIB)
+  # Add the library dependency
+  SET (NRRD_IMAGE_LIB teem png)
+ENDIF(FOUND_TEEM_LIB)
+
+
 ADD_LIBRARY (Manta_Image 
              NullImage.cc
              NullImage.h
@@ -7,6 +25,8 @@
              SimpleImage_templates.cc
              TGAFile.h
              TGAFile.cc
+             ${NRRD_IMAGE_SRC}
              )
 
-TARGET_LINK_LIBRARIES(Manta_Image Manta_Interface SCIRun_Core)
+TARGET_LINK_LIBRARIES(Manta_Image Manta_Interface SCIRun_Core 
+                      ${NRRD_IMAGE_LIB})

Modified: trunk/Image/Pixel.h
==============================================================================
--- trunk/Image/Pixel.h (original)
+++ trunk/Image/Pixel.h Mon Dec 12 17:07:44 2005
@@ -2,6 +2,7 @@
 #ifndef Manta_Image_Pixel_h
 #define Manta_Image_Pixel_h
 
+#include <MantaTypes.h>
 #include <Core/Color/RGBColor.h>
 
 namespace Manta {

Modified: trunk/Image/SimpleImage.h
==============================================================================
--- trunk/Image/SimpleImage.h   (original)
+++ trunk/Image/SimpleImage.h   Mon Dec 12 17:07:44 2005
@@ -1,3 +1,30 @@
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institue, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
 
 #ifndef Manta_SimpleImage_h
 #define Manta_SimpleImage_h
@@ -26,6 +53,7 @@
                         int xres, int yres);
 
     Pixel* getRaw(int which_eye) const;
+
   private:
     SimpleImage(const Image&);
     SimpleImage& operator=(const SimpleImage&);

Modified: trunk/Image/TGAFile.cc
==============================================================================
--- trunk/Image/TGAFile.cc      (original)
+++ trunk/Image/TGAFile.cc      Mon Dec 12 17:07:44 2005
@@ -1,4 +1,31 @@
 
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institue, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
 #include <Core/Exceptions/IllegalArgument.h>
 #include <Core/Exceptions/InternalError.h>
 #include <Core/Util/NotFinished.h>

Modified: trunk/Image/TGAFile.h
==============================================================================
--- trunk/Image/TGAFile.h       (original)
+++ trunk/Image/TGAFile.h       Mon Dec 12 17:07:44 2005
@@ -1,4 +1,32 @@
 
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institue, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
 #ifndef Manta_Engine_TGAFile_h
 #define Manta_Engine_TGAFile_h
 

Modified: trunk/Interface/TexCoordMapper.h
==============================================================================
--- trunk/Interface/TexCoordMapper.h    (original)
+++ trunk/Interface/TexCoordMapper.h    Mon Dec 12 17:07:44 2005
@@ -16,8 +16,8 @@
     virtual void computeTexCoords3(const RenderContext& context,
                                   RayPacket& rays) const = 0;
   private:
-    TexCoordMapper(const TexCoordMapper&);
-    TexCoordMapper& operator=(const TexCoordMapper&);
+    // TexCoordMapper(const TexCoordMapper&);
+    // TexCoordMapper& operator=(const TexCoordMapper&);
   };
 }
 

Modified: trunk/MantaTypes.h
==============================================================================
--- trunk/MantaTypes.h  (original)
+++ trunk/MantaTypes.h  Mon Dec 12 17:07:44 2005
@@ -1,4 +1,32 @@
 
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institute, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
 #ifndef Manta_MantaTypes_h
 #define Manta_MantaTypes_h
 

Modified: trunk/Model/Groups/KDTree.cc
==============================================================================
--- trunk/Model/Groups/KDTree.cc        (original)
+++ trunk/Model/Groups/KDTree.cc        Mon Dec 12 17:07:44 2005
@@ -237,7 +237,7 @@
   
   // Keep a stack of entry and exit positions into the traversal nodes.
 #ifdef __ia64__
-  __declspec(align(128))
+  // __declspec(align(128))
 #endif
     TravStackEntry travStack[128];
 
@@ -347,7 +347,7 @@
                                
                                
        // Check against the hit record, Note that tex coord mapper is null.
-        if (e.hitInfo.hit(isectData.rayHit.t, material, this, 0 )) {
+        if (e.hitInfo.hit(isectData.rayHit.t, getMaterial(), this, 0 )) {
 
           // if (isectData.rayHit.t > t_epsilon) {
           // e.hitInfo.set_hit(isectData.rayHit.t, material, this, 0 );

Modified: trunk/Model/Groups/TransparentKDTree.cc
==============================================================================
--- trunk/Model/Groups/TransparentKDTree.cc     (original)
+++ trunk/Model/Groups/TransparentKDTree.cc     Mon Dec 12 17:07:44 2005
@@ -319,7 +319,7 @@
   
   // Keep a stack of entry and exit positions into the traversal nodes.
 #ifdef __ia64__
-       __declspec(align(128))
+       // __declspec(align(128))
 #endif
     TravStackEntry travStack[128];
        
@@ -421,7 +421,7 @@
                                        }
 
                                        // Process the hit.
-                                       e.hitInfo.hit(isectData.rayHit.t, 
material, this, 0 );
+                                       e.hitInfo.hit(isectData.rayHit.t, 
getMaterial(), this, 0 );
                                        
                                        // Copy the normal into the scratch 
pad.
                                        // Used for shootOneRay type queries.
@@ -455,7 +455,7 @@
 
 /********************************************************/
 /* AABB-triangle overlap test code                      */
-/* by Tomas Akenine-Mˆller                              */
+/* by Tomas Akenine-Moller                              */
 /* Function: int triBoxOverlap(float boxcenter[3],      */
 /*          float boxhalfsize[3],float triverts[3][3]); */
 /* History:                                             */

Modified: trunk/Model/Materials/NormalMaterial.cc
==============================================================================
--- trunk/Model/Materials/NormalMaterial.cc     (original)
+++ trunk/Model/Materials/NormalMaterial.cc     Mon Dec 12 17:07:44 2005
@@ -2,6 +2,8 @@
 #include <Model/Materials/NormalMaterial.h>
 #include <Interface/RayPacket.h>
 
+#include <Model/Primitives/HeavyTriangle.h>
+
 using namespace Manta;
 
 void NormalMaterial::shade( const RenderContext &context, RayPacket &rays) 
const {
@@ -11,14 +13,49 @@
        
        // Iterate over the packet and set the colors.
        for (int i=0;i<rays.getSize();++i) {
+
+    // Copy the normal out.
+    Vector normal = rays.get(i).normal;
+    rays.setResult( i, Color( RGB( normal[0],normal[1], normal[2] )) );
                
-               Vector normal = rays.get(i).normal;
-               
-               RGBColor rgb( normal[0]*0.5 + 0.5,
-                                                                       
normal[1]*0.5 + 0.5,
-                                                                       
normal[2]*0.5 + 0.5 );
-               
-               rays.setResult( i, Color(rgb) );
+#if 0
+    // Add a wireframe.
+    HeavyTriangle::TriangleHit &th =
+      rays.get(i).hitInfo.scratchpad<HeavyTriangle::TriangleHit>();
+
+    Real a = th.a;
+    Real b = th.b;
+    Real c = (1.0 - th.a - th.b);
+    
+    if ((a > 0.9) && (b < 0.1) && (c < 0.1)) {
+      // rays.setResult( i, Color(RGB(1.0,0.0,0.0)) );
+
+      Vector normal = th.n1;
+      Color rgb( RGB( normal[0],normal[1], normal[2] ));
+      rays.setResult( i, rgb );
+    }
+    else if ((b > 0.9) && (c < 0.1) && (a < 0.1)) {
+      // rays.setResult( i, Color(RGB(0.0,1.0,0.0)) );
+
+      Vector normal = th.n2;
+      Color rgb( RGB( normal[0],normal[1], normal[2] ));
+      rays.setResult( i, rgb );
+    }
+    else if ((c > 0.9) && (a < 0.1) && (b < 0.1)) {
+      // rays.setResult( i, Color(RGB(0.0,0.0,1.0)) );
+      Vector normal = th.n0;
+      Color rgb( RGB( normal[0],normal[1], normal[2] ));
+      rays.setResult( i, rgb );
+    }
+    else if ((a < 0.05) || (b < 0.05) || (c < 0.05)) {
+      rays.setResult( i, Color(RGB(0.0,0.0,0.0)) );
+    }
+    else {
+      rays.setResult( i, Color(RGB(1.0,1.0,1.0)) );
+    }
+#endif
+
+
        }
 }
 

Modified: trunk/Model/Materials/Phong.h
==============================================================================
--- trunk/Model/Materials/Phong.h       (original)
+++ trunk/Model/Materials/Phong.h       Mon Dec 12 17:07:44 2005
@@ -1,4 +1,6 @@
 
+
+
 #ifndef Manta_Model_Phong_h
 #define Manta_Model_Phong_h
 

Modified: trunk/Model/Primitives/BvhTriangleMesh.cc
==============================================================================
--- trunk/Model/Primitives/BvhTriangleMesh.cc   (original)
+++ trunk/Model/Primitives/BvhTriangleMesh.cc   Mon Dec 12 17:07:44 2005
@@ -72,7 +72,7 @@
                                                                              
                                                                              
                     vertex_array[tri.v0] ))
                {
                        // Check to see if the hit is closest so far.
-                       if (e.hitInfo.hit(hit_t, material, this, tex)) {
+                       if (e.hitInfo.hit(hit_t, getMaterial(), this, 
getTexCoordMapper())) {
                        
                                // Copy over the hit record.
                                Hit &info = e.hitInfo.scratchpad<Hit>();

Modified: trunk/Model/Primitives/BvhTriangleMesh.h
==============================================================================
--- trunk/Model/Primitives/BvhTriangleMesh.h    (original)
+++ trunk/Model/Primitives/BvhTriangleMesh.h    Mon Dec 12 17:07:44 2005
@@ -145,4 +145,6 @@
 };
 
 #endif 
-       
\ No newline at end of file
+
+
+

Modified: trunk/Model/Primitives/Cone.cc
==============================================================================
--- trunk/Model/Primitives/Cone.cc      (original)
+++ trunk/Model/Primitives/Cone.cc      Mon Dec 12 17:07:44 2005
@@ -73,10 +73,10 @@
         Real z1 = P.z()+t1*V.z();
         Real z2 = P.z()+t2*V.z();
         if(t1>0 && z1 > 0 && z1 < 1) {
-          e.hitInfo.hit(t1/dist_scale, material, this, tex);
+          e.hitInfo.hit(t1/dist_scale, getMaterial(), this, 
getTexCoordMapper());
         }
         if(t2>0 && z2 > 0 && z2 < 1) {
-          e.hitInfo.hit(t2/dist_scale, material, this, tex);
+          e.hitInfo.hit(t2/dist_scale, getMaterial(), this, 
getTexCoordMapper());
         }
       }
     }
@@ -125,10 +125,10 @@
         Real z1 = P.z()+t1*V.z();
         Real z2 = P.z()+t2*V.z();
         if(t1>0 && z1 > 0 && z1 < 1) {
-          e.hitInfo.hit(t1/dist_scale, material, this, tex);
+          e.hitInfo.hit(t1/dist_scale, getMaterial(), this, 
getTexCoordMapper());
         }
         if(t2>0 && z2 > 0 && z2 < 1) {
-          e.hitInfo.hit(t2/dist_scale, material, this, tex);
+          e.hitInfo.hit(t2/dist_scale, getMaterial(), this, 
getTexCoordMapper());
         }
       }
     }

Modified: trunk/Model/Primitives/Cube.cc
==============================================================================
--- trunk/Model/Primitives/Cube.cc      (original)
+++ trunk/Model/Primitives/Cube.cc      Mon Dec 12 17:07:44 2005
@@ -60,12 +60,12 @@
 
       // Check to see if we are inside the box.
       if (tmin > 0.0) {
-        e.hitInfo.hit( tmin, material, this, tex );
+        e.hitInfo.hit( tmin, getMaterial(), this, getTexCoordMapper() );
       }
 
       // And use the max intersection if we are.
       else
-        e.hitInfo.hit( tmax, material, this, tex );
+        e.hitInfo.hit( tmax, getMaterial(), this, getTexCoordMapper() );
     }
                                  
   }

Modified: trunk/Model/Primitives/Cylinder.cc
==============================================================================
--- trunk/Model/Primitives/Cylinder.cc  (original)
+++ trunk/Model/Primitives/Cylinder.cc  Mon Dec 12 17:07:44 2005
@@ -56,9 +56,9 @@
        double z1=oz+t1*dz;
        double z2=oz+t2*dz;
        if(t1 > 1.e-6 && z1 > 0.0 && z1 < 1.0){
-         e.hitInfo.hit(t1/dist_scale, material, this, tex);
+         e.hitInfo.hit(t1/dist_scale, getMaterial(), this, 
getTexCoordMapper());
        } else if(t2 > 1.e-6 && z2 > 0.0 && z2 < 1.0){
-         e.hitInfo.hit(t2/dist_scale, material, this, tex);
+         e.hitInfo.hit(t2/dist_scale, getMaterial(), this, 
getTexCoordMapper());
        }
       }
     }

Modified: trunk/Model/Primitives/Disk.cc
==============================================================================
--- trunk/Model/Primitives/Disk.cc      (original)
+++ trunk/Model/Primitives/Disk.cc      Mon Dec 12 17:07:44 2005
@@ -45,7 +45,7 @@
       if ((denom < -EPSILON) || (denom > EPSILON)) {
         t = -(_d + nDotO) / denom;
         if (checkBounds(rayO + t * rayD)) {
-          e.hitInfo.hit(t, material, this, tex);
+          e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
         }
       }
     }
@@ -59,7 +59,7 @@
       if ((denom < -EPSILON) || (denom > EPSILON)) {
         t = -(_d + Dot(_n, rayO)) / denom;
         if (checkBounds(rayO + t * rayD)) {
-          e.hitInfo.hit(t, material, this, tex);
+          e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
         }
       }
     }

Modified: trunk/Model/Primitives/HeavyTriangle.cc
==============================================================================
--- trunk/Model/Primitives/HeavyTriangle.cc     (original)
+++ trunk/Model/Primitives/HeavyTriangle.cc     Mon Dec 12 17:07:44 2005
@@ -1,52 +1,64 @@
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institute, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
+
 #include <Model/Primitives/HeavyTriangle.h>
 #include <Interface/RayPacket.h>
 #include <Core/Geometry/BBox.h>
 #include <sgi_stl_warnings_off.h>
 #include <iostream>
 #include <sgi_stl_warnings_on.h>
+#include <Model/Intersections/TriangleEdge.h>
 
 using namespace Manta;
 using namespace std;
 
-HeavyTriangle::HeavyTriangle(Material* mat, const Point& _p1, const Point& 
_p2, const Point& _p3)
-  : Triangle(mat, _p1, _p2, _p3)
-{
-  e1 = p2-p1;
-  e2 = p3-p1;
-  n = Cross(e1, e2);
-  n.normalize();
-}
 
 HeavyTriangle::~HeavyTriangle()
 {
 }
 
+
 void HeavyTriangle::intersect(const RenderContext&, RayPacket& rays) const
 {
   rays.normalizeDirections();
-
+  
   for(int i=0; i<rays.getSize(); i++) {
     RayPacket::Element& e = rays.get(i);
-    const Vector& dir(e.ray.direction());
-    Vector o(p1 - e.ray.origin());
+    Real t, u, v;
+    
+    if (Intersection::intersectTriangleEdge( t, u, v, e.ray, edge[0], 
edge[1], point ) &&
+        e.hitInfo.hit( t, getMaterial(), this, getTexCoordMapper() )) {
+      
+      TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
+      th.a = u;
+      th.b = v;
 
-    Real det=Dot(n,dir);
-    if(det > (Real)1.e-9 || det < (Real)-1.e-9) {
-      Real idet = 1/det;
-
-      Vector DX(Cross(dir, o));
-      Real A=-Dot(DX, e2)*idet;
-      if( A>0 && A<1 ) {
-        Real B=Dot(DX, e1)*idet;
-        if( B>0 && A+B<1 ) {
-          Real t=Dot(n, o)*idet;
-          if (e.hitInfo.hit(t, material, this, tex)){
-             TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
-             th.a = A;
-             th.b = B;
-          }
-        }
-      }
     }
   }
 }
@@ -56,23 +68,34 @@
 {
   rays.computeHitPositions();
 
-  if (rays.getFlag(RayPacket::HaveNormals)){
+  if (rays.getFlag(RayPacket::HaveNormals)) {
     if (rays.getFlag(RayPacket::HaveUnitNormals))
        return;
-
-    int nrays = rays.getSize();
-    for(int i=0; i<nrays; i++){
-       rays.get(i).normal = n;
-    }
-    rays.setFlag(RayPacket::HaveUnitNormals);
   }
-  else{
-    int nrays = rays.getSize();
-    for(int i=0; i<nrays; i++) {
-      rays.get(i).normal = n;
+  else {
+
+    for(int i=0; i<rays.getSize(); i++) {
+      
+      RayPacket::Element &e = rays.get(i);
+      
+      TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
+      
+      Real a = th.a;
+      Real b = th.b;
+      Real c = (1.0 - th.a - th.b);
+    
+      e.normal = (n[1]*a) + (n[2]*b) + (n[0]*c);
+      e.normal.normalize();
     }
+
     rays.setFlag(RayPacket::HaveUnitNormals);
   }
-
+  
 }
 
+void HeavyTriangle::computeBounds(const PreprocessContext& context, BBox& 
bbox) const {
+
+  bbox.extendByPoint( point );
+  bbox.extendByPoint( point+edge[0] );
+  bbox.extendByPoint( point+edge[1] );
+}

Modified: trunk/Model/Primitives/HeavyTriangle.h
==============================================================================
--- trunk/Model/Primitives/HeavyTriangle.h      (original)
+++ trunk/Model/Primitives/HeavyTriangle.h      Mon Dec 12 17:07:44 2005
@@ -2,20 +2,88 @@
 #ifndef Manta_Model_HeavyTriangle_h
 #define Manta_Model_HeavyTriangle_h
 
-#include <Model/Primitives/Triangle.h>
 
-namespace Manta
-{
-  class HeavyTriangle : public Triangle {
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institute, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include <Model/Primitives/PrimitiveCommon.h>
+#include <Core/Geometry/PointVector.h>
+#include <Core/Geometry/Ray.h>
+
+// Major revision: Abe Stephens, December 2005
+
+namespace Manta {
+  
+  
/////////////////////////////////////////////////////////////////////////////
+  // Heavy triangle contains an edge triangle representation in addition to a
+  // normal for each vertex.
+  class HeavyTriangle : public PrimitiveCommon {
+  private:
+    Point  point;
+    Vector edge[2];
+    Vector n[3];
+    
   public:
-    HeavyTriangle(Material* mat, const Point& _a, const Point& _b, const 
Point& _c);
-    virtual ~HeavyTriangle();
+    struct TriangleHit {
+      Real a, b;
+    };
+
+    HeavyTriangle() : PrimitiveCommon( 0 ) { };
+    HeavyTriangle(Material *material_, const Point &p0_, const Point &p1_, 
const Point &p2_ ) :
+      PrimitiveCommon( material_ )
+    {
+      point = p0_;
+
+      edge[0] = (p1_-p0_);
+      edge[1] = (p2_-p0_);
+
+      n[0] = Cross( edge[0], edge[1] );
+      n[0].normalize();
+      n[1] = n[2] = n[0];
+    }
     
-    virtual void intersect(const RenderContext& context, RayPacket& rays) 
const ;
-    virtual void computeNormal(const RenderContext& context, RayPacket 
&rays) const;    
+    HeavyTriangle(Material *material_, const Point &point_, const Vector 
&edge0_, const Vector &edge1_,
+                  const Vector &n0_, const Vector &n1_, const Vector &n2_ ) :
+      PrimitiveCommon( material_ )
+    {
+      point = point_;
+      edge[0] = edge0_;
+      edge[1] = edge1_;
+      n[0] = n0_;
+      n[1] = n1_;
+      n[2] = n2_;
+    }
+    virtual ~HeavyTriangle();
     
-  protected:
-    Vector e1,e2,n;
+    virtual void intersect    (const RenderContext& context, RayPacket& 
rays) const;
+    virtual void computeNormal(const RenderContext& context, RayPacket 
&rays) const;
+    virtual void computeBounds(const PreprocessContext& context, BBox& bbox) 
const;
   };
 }
 

Modified: trunk/Model/Primitives/Heightfield.cc
==============================================================================
--- trunk/Model/Primitives/Heightfield.cc       (original)
+++ trunk/Model/Primitives/Heightfield.cc       Mon Dec 12 17:07:44 2005
@@ -189,7 +189,7 @@
 
           if (tcell > T_EPSILON && tcell < texit && u > 0.0 && u < 1.0 && v 
> 0.0 && v < 1.0)
           {
-            if (e.hitInfo.hit(tnear + tcell, material, this, tex))
+            if (e.hitInfo.hit(tnear + tcell, getMaterial(), this, 
getTexCoordMapper()))
               e.hitInfo.scratchpad<Vector>() = Vector(- (z[1] + v*z[3]) / 
cellSize[0], - (z[2] + u*z[3]) / cellSize[1], 1.0);
             break;
           }
@@ -221,7 +221,7 @@
               v = sy + tcell * dy;
               if (u > 0.0 && u < 1.0 && v > 0.0 && v < 1.0)
               {
-                if (e.hitInfo.hit(tnear + tcell, material, this, tex))
+                if (e.hitInfo.hit(tnear + tcell, getMaterial(), this, 
getTexCoordMapper()))
                   e.hitInfo.scratchpad<Vector>() = Vector( - (z[1] + v*z[3]) 
/ cellSize[0], - (z[2] + u*z[3]) / cellSize[1], 1.0);
                 break;
               }

Modified: trunk/Model/Primitives/Hemisphere.cc
==============================================================================
--- trunk/Model/Primitives/Hemisphere.cc        (original)
+++ trunk/Model/Primitives/Hemisphere.cc        Mon Dec 12 17:07:44 2005
@@ -46,11 +46,11 @@
        r = sqrt(disc);
        t = -(b + r);
        if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-         e.hitInfo.hit(t, material, this, tex);
+         e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
        } else {
          t = r - b;
          if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-           e.hitInfo.hit(t, material, this, tex);
+           e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
          }
        }
       }
@@ -74,11 +74,11 @@
        r = sqrt(disc);
        t = -(b + r) / a;
        if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-         e.hitInfo.hit(t, material, this, tex);
+         e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
        } else {
          t = (r - b) / a;
          if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-           e.hitInfo.hit(t, material, this, tex);
+           e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
          }
        }
       }
@@ -100,11 +100,11 @@
        r = sqrt(disc);
        t = -(b + r);
        if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-         e.hitInfo.hit(t, material, this, tex);
+         e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
        } else {
          t = r - b;
          if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-           e.hitInfo.hit(t, material, this, tex);
+           e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
          }
        }
       }
@@ -127,11 +127,11 @@
        r = sqrt(disc);
        t = -(b + r) / a;
        if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-         e.hitInfo.hit(t, material, this, tex);
+         e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
        } else {
          t = (r - b) / a;
          if ((t > 0.0) && checkBounds(rayO + t * rayD)) {
-           e.hitInfo.hit(t, material, this, tex);
+           e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
          }
        }
       }

Modified: trunk/Model/Primitives/Parallelogram.cc
==============================================================================
--- trunk/Model/Primitives/Parallelogram.cc     (original)
+++ trunk/Model/Primitives/Parallelogram.cc     Mon Dec 12 17:07:44 2005
@@ -69,7 +69,7 @@
       if (a2 < 0 || a2 > 1)
         continue;
 
-      if(e.hitInfo.hit(t, material, this, tex))
+      if(e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper()))
         e.hitInfo.scratchpad<Point>() = Point(a1, a2, 0);
     }
   } else {
@@ -90,7 +90,7 @@
       if (a2 < 0 || a2 > 1)
         continue;
 
-      if(e.hitInfo.hit(t, material, this, tex))
+      if(e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper()))
         e.hitInfo.scratchpad<Point>() = Point(a1, a2, 0);
     }
   }

Modified: trunk/Model/Primitives/ParticleBVH.cc
==============================================================================
--- trunk/Model/Primitives/ParticleBVH.cc       (original)
+++ trunk/Model/Primitives/ParticleBVH.cc       Mon Dec 12 17:07:44 2005
@@ -163,11 +163,11 @@
         double r = sqrt( discriminant );
         double t0 = -r - B;
         if( t0 > 0.0 )
-          if ( element.hitInfo.hit( t0, material, this, tex ) )
+          if ( element.hitInfo.hit( t0, getMaterial(), this, 
getTexCoordMapper() ) )
             element.hitInfo.scratchpad< int >() = current;
         else {
           double t1 = r - B;
-          if ( element.hitInfo.hit( t1, material, this, tex ) )
+          if ( element.hitInfo.hit( t1, getMaterial(), this, 
getTexCoordMapper() ) )
             element.hitInfo.scratchpad< int >() = current;
         }
       }

Modified: trunk/Model/Primitives/Plane.cc
==============================================================================
--- trunk/Model/Primitives/Plane.cc     (original)
+++ trunk/Model/Primitives/Plane.cc     Mon Dec 12 17:07:44 2005
@@ -69,7 +69,7 @@
       // Ray isn't parallel to the plane.
       Real ao = Dot( (center-e.ray.origin()), normal );
       Real t = ao/dn;
-      e.hitInfo.hit(t, material, this, tex);
+      e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
     }
   }
 }

Modified: trunk/Model/Primitives/PrimitiveCommon.h
==============================================================================
--- trunk/Model/Primitives/PrimitiveCommon.h    (original)
+++ trunk/Model/Primitives/PrimitiveCommon.h    Mon Dec 12 17:07:44 2005
@@ -15,8 +15,16 @@
                // Note that this preprocess method sets up the activeLights 
for the associated
                // material (not sure what happens for shared materials)
     virtual void preprocess(const PreprocessContext&);
-    virtual void setTexCoordMapper(const TexCoordMapper* new_tex);
-  protected:
+
+    // Accessors.
+    void setTexCoordMapper(const TexCoordMapper* new_tex);
+    const TexCoordMapper *getTexCoordMapper() const { return tex; }
+
+    void setMaterial( Material *material_ ) { material = material; }
+    Material *getMaterial() const { return material; }
+    
+
+  private:
     Material* material;
     const TexCoordMapper* tex;
   };

Modified: trunk/Model/Primitives/Ring.cc
==============================================================================
--- trunk/Model/Primitives/Ring.cc      (original)
+++ trunk/Model/Primitives/Ring.cc      Mon Dec 12 17:07:44 2005
@@ -76,7 +76,7 @@
     Point hitPosition(orig+dir*t);
     Real l = (hitPosition-center).length2();
     if(l > radius2 && l < outer_radius2)
-      e.hitInfo.hit(t, material, this, tex);
+      e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
   }
 }
 

Modified: trunk/Model/Primitives/Sphere.cc
==============================================================================
--- trunk/Model/Primitives/Sphere.cc    (original)
+++ trunk/Model/Primitives/Sphere.cc    Mon Dec 12 17:07:44 2005
@@ -39,19 +39,19 @@
       Real t2hc=rad2-l2oc+tca*tca;
       Real thc=Sqrt(t2hc);
       Real t=tca+thc;
-      e.hitInfo.hit(t, material, this, tex);
+      e.hitInfo.hit(t, getMaterial(), this, getTexCoordMapper());
     } else {
       if(tca < 0){
         // Behind ray, no intersections...
       } else {
-        Real t2hc=rad2-l2oc+tca*tca;
-        if(t2hc <= 0){
-          // Ray misses, no intersections
-        } else {
-          Real thc=Sqrt(t2hc);
-          e.hitInfo.hit(tca-thc, material, this, tex);
-          e.hitInfo.hit(tca+thc, material, this, tex);
-        }
+                         Real t2hc=rad2-l2oc+tca*tca;
+                               if(t2hc <= 0){
+                                       // Ray misses, no intersections
+                               } else {
+                                       Real thc=Sqrt(t2hc);
+                                       e.hitInfo.hit(tca-thc, getMaterial(), 
this, getTexCoordMapper());
+                                       e.hitInfo.hit(tca+thc, getMaterial(), 
this, getTexCoordMapper());
+                               }
       }
     }
   }
@@ -72,10 +72,10 @@
           Real r = Sqrt(disc);
           Real t0 = -(r+B);
           if(t0 > 0){
-            e.hitInfo.hit(t0, material, this, tex);
+            e.hitInfo.hit(t0, getMaterial(), this, getTexCoordMapper());
           } else {
             Real t1 = r-B;
-            e.hitInfo.hit(t1, material, this, tex);
+            e.hitInfo.hit(t1, getMaterial(), this, getTexCoordMapper());
           }
         }
       }
@@ -97,10 +97,10 @@
           Real r = Sqrt(disc);
           Real t0 = -(r+B)/A;
           if(t0 > 0){
-            e.hitInfo.hit(t0, material, this, tex);
+            e.hitInfo.hit(t0, getMaterial(), this, getTexCoordMapper());
           } else {
             Real t1 = (r-B)/A;
-            e.hitInfo.hit(t1, material, this, tex);
+            e.hitInfo.hit(t1, getMaterial(), this, getTexCoordMapper());
           }
         }
       }
@@ -120,10 +120,10 @@
           Real r = Sqrt(disc);
           Real t0 = -(r+B);
           if(t0 > 0){
-            e.hitInfo.hit(t0, material, this, tex);
+            e.hitInfo.hit(t0, getMaterial(), this, getTexCoordMapper());
           } else {
             Real t1 = r-B;
-            e.hitInfo.hit(t1, material, this, tex);
+            e.hitInfo.hit(t1, getMaterial(), this, getTexCoordMapper());
           }
         }
       }
@@ -144,10 +144,10 @@
           Real r = Sqrt(disc);
           Real t0 = -(r+B)/A;
           if(t0 > 0){
-            e.hitInfo.hit(t0, material, this, tex);
+            e.hitInfo.hit(t0, getMaterial(), this, getTexCoordMapper());
           } else {
             Real t1 = (r-B)/A;
-            e.hitInfo.hit(t1, material, this, tex);
+            e.hitInfo.hit(t1, getMaterial(), this, getTexCoordMapper());
           }
         }
       }

Modified: trunk/Model/Primitives/SuperEllipsoid.cc
==============================================================================
--- trunk/Model/Primitives/SuperEllipsoid.cc    (original)
+++ trunk/Model/Primitives/SuperEllipsoid.cc    Mon Dec 12 17:07:44 2005
@@ -217,7 +217,7 @@
     }
 
     // Finally, set the hit location
-    e.hitInfo.hit( troot, material, this, tex );
+    e.hitInfo.hit( troot, getMaterial(), this, getTexCoordMapper() );
 
   }
 

Modified: trunk/Model/Primitives/TexTriangle.cc
==============================================================================
--- trunk/Model/Primitives/TexTriangle.cc       (original)
+++ trunk/Model/Primitives/TexTriangle.cc       Mon Dec 12 17:07:44 2005
@@ -1,79 +1,35 @@
+
 #include <Model/Primitives/TexTriangle.h>
 #include <Interface/RayPacket.h>
 #include <Core/Geometry/BBox.h>
-#include <sgi_stl_warnings_off.h>
-#include <iostream>
-#include <sgi_stl_warnings_on.h>
+
+#include <Model/Intersections/TriangleEdge.h>
 
 using namespace Manta;
 using namespace std;
 
-TexTriangle::TexTriangle(Material* mat, 
-                         const Point& _p1, const Point& _p2, const Point& 
_p3, 
-                         const Vector& _n1, const Vector& _n2, const Vector& 
_n3, 
-                         const Point& _tc1, const Point& _tc2, const Point& 
_tc3)
-  : HeavyTriangle(mat, _p1, _p2, _p3)
-{
-  n1 = _n1;
-  n2 = _n2;
-  n3 = _n3;
-  n1.normalize();
-  n2.normalize();
-  n3.normalize();
-  tc1 = _tc1;
-  tc2 = _tc2;
-  tc3 = _tc3;
-}
-
-TexTriangle::~TexTriangle()
-{
-}
+//Performs the exact same operation as computeTexCoords3
+void TexTriangle::computeTexCoords2(const RenderContext& /*context*/, 
RayPacket& rays) const {
 
-void TexTriangle::computeNormal(const RenderContext&, RayPacket& rays) const
-{
-  int nrays = rays.getSize();
-  for(int i=0; i<nrays; i++) {
+  int size = rays.getSize();
+  for(int i=0; i<size; i++) {
     RayPacket::Element& e = rays.get(i);
+    
     TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
-    double A = th.a;
-    double B = th.b;
-    e.normal = (n1 * A) + (n2 * B) + (n3 * (1.0 - A - B));
-    e.normal.normalize();
+    Real a = th.a;
+    Real b = th.b;
+    Real c = (1.0 - a - b);
+
+    e.texCoords = Point((tex[1] * a) + (tex[2] * b) +(tex[0] * c));
+    // e.texCoords = Point((t2 * a) + (t0 * b) +(t1 * c));
+    // e.texCoords = Point( tex[0] );
+        
+    // e.texCoords = Point( c, a, b );
   }
-  rays.setFlag(RayPacket::HaveUnitNormals);
+  rays.setFlag( RayPacket::HaveTexture2|RayPacket::HaveTexture3 );
 }
 
-//Performs the exact same operation as computeTexCoords3
-void TexTriangle::computeTexCoords2(const RenderContext& /*context*/,
-                                    RayPacket& rays) const
-{
-  int nrays = rays.getSize();
-  for(int i=0; i<nrays; i++) {
-    RayPacket::Element& e = rays.get(i);
-    TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
-    double A = th.a;
-    double B = th.b;
-    e.texCoords = tc1.multipliedBy(A);
-    e.texCoords.addTo(tc2.multipliedBy(B));
-    e.texCoords.addTo(tc3.multipliedBy(1.0 - A - B));
-  }
-  rays.setFlag(RayPacket::HaveTexture2|RayPacket::HaveTexture3);
-}
 
 
-void TexTriangle::computeTexCoords3(const RenderContext& /*context*/,
-                                    RayPacket& rays) const
-{
-  int nrays = rays.getSize();
-  for(int i=0; i<nrays; i++) {
-    RayPacket::Element& e = rays.get(i);
-    TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
-    double A = th.a;
-    double B = th.b;
-    e.texCoords = tc1.multipliedBy(A);
-    e.texCoords.addTo(tc2.multipliedBy(B));
-    e.texCoords.addTo(tc3.multipliedBy(1.0 - A - B));
-  }
-  rays.setFlag(RayPacket::HaveTexture2|RayPacket::HaveTexture3);
-}
+
 

Modified: trunk/Model/Primitives/TexTriangle.h
==============================================================================
--- trunk/Model/Primitives/TexTriangle.h        (original)
+++ trunk/Model/Primitives/TexTriangle.h        Mon Dec 12 17:07:44 2005
@@ -2,27 +2,81 @@
 #ifndef Manta_Model_TexTriangle_h
 #define Manta_Model_TexTriangle_h
 
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institute, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
 #include <Model/Primitives/HeavyTriangle.h>
+#include <Interface/TexCoordMapper.h>
+
+// Major revision: Abe Stephens, December 2005
 
 namespace Manta
 {
-  class TexTriangle : public HeavyTriangle {
+  class TexTriangle : public HeavyTriangle, public TexCoordMapper  {
   public:
-    TexTriangle(Material* mat, 
-                const Point& _p1, const Point& _p2, const Point& _p3, 
-                const Vector& _n1, const Vector& _n2, const Vector& _n3, 
-                const Point& _tc1, const Point& _tc2, const Point& _tc3);
-    virtual ~TexTriangle();
+    TexTriangle() { setTexCoordMapper( this ); };
+    TexTriangle( Material *material_,
+                 const Point &p0_, const Point &p1_, const Point &p2_,
+                 const Vector &tex0_, const Vector &tex1_, const Vector 
&tex2_ ) :
+
+      HeavyTriangle( material_, p0_, p1_, p2_ )
+    {
+      tex[0] = tex0_;
+      tex[1] = tex1_;
+      tex[2] = tex2_;
+
+      setTexCoordMapper( this );
+    }
     
-    virtual void computeNormal(const RenderContext& context, RayPacket 
&rays) const;    
+    TexTriangle( Material *material_,
+                 const Point &point_, const Vector &edge0_, const Vector 
&edge1_,
+                 const Vector &n0_,   const Vector &n1_,    const Vector 
&n2_,
+                 const Vector &tex0_,  const Vector &tex1_,   const Vector 
&tex2_ ) :
+
+      HeavyTriangle( material_, point_, edge0_, edge1_, n0_, n1_, n2_ )
+    {
+      tex[0] = tex0_;
+      tex[1] = tex1_;
+      tex[2] = tex2_;
 
+      setTexCoordMapper( this );
+    }
+    virtual ~TexTriangle() { };
+    
     virtual void computeTexCoords2(const RenderContext& context, RayPacket& 
rays) const;
-    virtual void computeTexCoords3(const RenderContext& context, RayPacket& 
rays) const;
+    virtual void computeTexCoords3(const RenderContext& context, RayPacket& 
rays) const {
+
+      computeTexCoords2( context, rays );
+    }
+
     
   protected:
-    Vector n1,n2,n3;
-    Point tc1,tc2,tc3;
-    Vector e1,e2;
+    Vector tex[3];
   };
 }
 

Modified: trunk/Model/Primitives/Triangle.cc
==============================================================================
--- trunk/Model/Primitives/Triangle.cc  (original)
+++ trunk/Model/Primitives/Triangle.cc  Mon Dec 12 17:07:44 2005
@@ -59,7 +59,7 @@
 
           bool h = Intersection::intersectTriangleEdge( t, A, B, e.ray, _e1, 
_e2, p1 );
 
-          if (h && e.hitInfo.hit(t, material, this, tex)){
+          if (h && e.hitInfo.hit(t, getMaterial(), this, 
getTexCoordMapper())){
             TriangleHit& th = e.hitInfo.scratchpad<TriangleHit>();
             th.a = A;
             th.b = B;

Modified: trunk/Model/Readers/CMakeLists.txt
==============================================================================
--- trunk/Model/Readers/CMakeLists.txt  (original)
+++ trunk/Model/Readers/CMakeLists.txt  Mon Dec 12 17:07:44 2005
@@ -1,13 +1,16 @@
 
 SET (Manta_Readers_SRCS
+     Readers/glm/glm.h
+     Readers/glm/glm.cc
+     Readers/rply/rply.c
      Readers/BART/kbsplpos.c
      Readers/BART/kbsplrot.c
      Readers/BART/parse.cc
      Readers/BART/quat.c
      Readers/PlyReader.cc
-     Readers/rply/rply.c
-     Readers/glm/glm.h
-     Readers/glm/glm.cc)
+
+)
+
 
 # Apple places malloc.h in /usr/include/malloc/malloc.h
 IF (APPLE)

Modified: trunk/Model/Readers/PlyReader.cc
==============================================================================
--- trunk/Model/Readers/PlyReader.cc    (original)
+++ trunk/Model/Readers/PlyReader.cc    Mon Dec 12 17:07:44 2005
@@ -1,8 +1,9 @@
 
+#include <Model/Readers/PlyReader.h>
+
 #include <Model/Primitives/Triangle.h>
 #include <Model/Primitives/VertexColoredTriangle.h>
 #include <Model/Textures/TriVerTexture.h>
-#include <Model/Readers/PlyReader.h>
 #include <Model/Materials/Lambertian.h>
 #include <Core/Color/Color.h>
 #include <Core/Color/RGBColor.h>

Modified: trunk/Model/Readers/PlyReader.h
==============================================================================
--- trunk/Model/Readers/PlyReader.h     (original)
+++ trunk/Model/Readers/PlyReader.h     Mon Dec 12 17:07:44 2005
@@ -6,10 +6,17 @@
 #include <Core/Geometry/AffineTransform.h>
 #include <Model/Groups/Group.h>
 
+#include <string>
+
 namespace Manta {
-  bool
-    readPlyFile(const string fileName, AffineTransform &t, 
-                Group *g, int gridsize=0, Material *m=0);
+
+  using std::string;
+  
+  class Material;
+  class Group;
+  
+  extern "C" bool readPlyFile(const string fileName, AffineTransform &t, 
+                   Group *g, int gridsize=0, Material *m=0);
 }
 
 #endif

Modified: trunk/Model/Readers/glm/glm.cc
==============================================================================
--- trunk/Model/Readers/glm/glm.cc      (original)
+++ trunk/Model/Readers/glm/glm.cc      Mon Dec 12 17:07:44 2005
@@ -17,6 +17,8 @@
 #include <malloc.h>
 #include <stdlib.h>
 
+#include <iostream>
+
 #include <limits.h>
 
 /* defines */
@@ -24,1850 +26,1888 @@
 
 namespace Glm {
 
-/* enums */
-enum { X, Y, Z, W };                   /* elements of a vertex */
+  /* enums */
+  enum { X, Y, Z, W };                 /* elements of a vertex */
 
 
-/* typedefs */
+  /* typedefs */
 
-/* _GLMnode: general purpose node
- */
-typedef struct _GLMnode {
-  unsigned int     index;
-  bool        averaged;
-  struct _GLMnode* next;
-} GLMnode;
-
-
-/* private functions */
-
-/* _glmMax: returns the maximum of two floats */
-
-static float
-_glmMax(float a, float b) 
-{
-  if (a > b)
-    return a;
-  return b;
-}
-
-/* _glmAbs: returns the absolute value of a float */
-static float
-_glmAbs(float f)
-{
-  if (f < 0)
-    return -f;
-  return f;
-}
-
-/* _glmDot: compute the dot product of two vectors
- *
- * u - array of 3 floats (float u[3])
- * v - array of 3 floats (float v[3])
- */
-static float
-_glmDot(float* u, float* 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 floats (float u[3])
- * v - array of 3 floats (float v[3])
- * n - array of 3 floats (float n[3]) to return the cross product in
- */
-static void
-_glmCross(float* u, float* v, float* 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 floats (float n[3]) to be normalized
- */
-static void
-_glmNormalize(float* n)
-{
-  float l;
-
-  assert(n);
-
-  /* normalize */
-  l = 1.0f/sqrtf(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 true if they are
- * equal (within a certain threshold) or false if not. An epsilon
- * that works fairly well is 0.000001.
- *
- * u - array of 3 floats (float u[3])
- * v - array of 3 floats (float v[3]) 
- */
-static bool
-_glmEqual(float* u, float* v, float epsilon)
-{
-  if (_glmAbs(u[0] - v[0]) < epsilon &&
-      _glmAbs(u[1] - v[1]) < epsilon &&
-      _glmAbs(u[2] - v[2]) < epsilon) 
-    {
-      return true;
-    }
-  return false;
-}
-
-/* _glmWeldVectors: eliminate (weld) vectors that are within an
- * epsilon of each other.
- *
- * vectors    - array of float[3]'s to be welded
- * numvectors - number of float[3]'s in vectors
- * epsilon    - maximum difference between vectors 
- *
- */
-static float*
-_glmWeldVectors(float* vectors, unsigned int* numvectors, float epsilon)
-{
-  float* copies;
-  unsigned int   copied;
-  unsigned int   i, j;
-
-  copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1));
-  memcpy(copies, vectors, (sizeof(float) * 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] = (float)j;
-  }
-
-  *numvectors = copied-1;
-  return copies;
-}
-
-/* _glmFindGroup: Find a group in the model
- */
-static 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
- */
-static GLMgroup*
-_glmAddGroup(GLMmodel* model, char* name)
-{
-  GLMgroup* group;
-
-  group = _glmFindGroup(model, name);
-  if (!group) {
-    group = (GLMgroup*)malloc(sizeof(GLMgroup));
-    group->name = strdup(name);
-    group->material = 0;
-    group->numtriangles = 0;
-    group->triangles = NULL;
-    group->next = model->groups;
-    model->groups = group;
-    model->numgroups++;
-  }
-
-  return group;
-}
-
-/* _glmFindGroup: Find a material in the model
- */
-static 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 */
-  printf("_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;
-
-  dir = strdup(path);
-
-  s = strrchr(dir, '/');
-  if (s)
-    s[1] = '\0';
-  else
-    dir[0] = '\0';
-
-  return dir;
-}
-
-
-/* _glmReadMTL: read a wavefront material library file
- *
- * model - properly initialized GLMmodel structure
- * name  - name of the material library
- */
-static int
-_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);
-    free(filename);
-    return 1;
+  /* _GLMnode: general purpose node
+   */
+  typedef struct _GLMnode {
+    unsigned int     index;
+    bool        averaged;
+    struct _GLMnode* next;
+  } GLMnode;
+
+
+  /* private functions */
+
+  /* _glmMax: returns the maximum of two floats */
+
+  static float
+  _glmMax(float a, float b) 
+  {
+    if (a > b)
+      return a;
+    return b;
+  }
+
+  /* _glmAbs: returns the absolute value of a float */
+  static float
+  _glmAbs(float f)
+  {
+    if (f < 0)
+      return -f;
+    return f;
+  }
+
+  /* _glmDot: compute the dot product of two vectors
+   *
+   * u - array of 3 floats (float u[3])
+   * v - array of 3 floats (float v[3])
+   */
+  static float
+  _glmDot(float* u, float* 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 floats (float u[3])
+   * v - array of 3 floats (float v[3])
+   * n - array of 3 floats (float n[3]) to return the cross product in
+   */
+  static void
+  _glmCross(float* u, float* v, float* 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 floats (float n[3]) to be normalized
+   */
+  static void
+  _glmNormalize(float* n)
+  {
+    float l;
+
+    assert(n);
+
+    /* normalize */
+    l = 1.0f/sqrtf(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 true if they are
+   * equal (within a certain threshold) or false if not. An epsilon
+   * that works fairly well is 0.000001.
+   *
+   * u - array of 3 floats (float u[3])
+   * v - array of 3 floats (float v[3]) 
+   */
+  static bool
+  _glmEqual(float* u, float* v, float epsilon)
+  {
+    if (_glmAbs(u[0] - v[0]) < epsilon &&
+        _glmAbs(u[1] - v[1]) < epsilon &&
+        _glmAbs(u[2] - v[2]) < epsilon) 
+      {
+        return true;
+      }
+    return false;
   }
-  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].name = NULL;
-    model->materials[i].shininess = 0;
-    model->materials[i].diffuse[0] = 0.8;
-    model->materials[i].diffuse[1] = 0.8;
-    model->materials[i].diffuse[2] = 0.8;
-    model->materials[i].diffuse[3] = 1.0;
-    model->materials[i].ambient[0] = 0.2;
-    model->materials[i].ambient[1] = 0.2;
-    model->materials[i].ambient[2] = 0.2;
-    model->materials[i].ambient[3] = 1.0;
-    model->materials[i].specular[0] = 0.0;
-    model->materials[i].specular[1] = 0.0;
-    model->materials[i].specular[2] = 0.0;
-    model->materials[i].specular[3] = 1.0;
-  }
-  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 '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:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-  }
-  return 0;
-}
-
-/* _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 int
-_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);
-    free(filename);
-    return 1;
-  }
-  free(filename);
+  /* _glmWeldVectors: eliminate (weld) vectors that are within an
+   * epsilon of each other.
+   *
+   * vectors    - array of float[3]'s to be welded
+   * numvectors - number of float[3]'s in vectors
+   * epsilon    - maximum difference between vectors 
+   *
+   */
+  static float*
+  _glmWeldVectors(float* vectors, unsigned int* numvectors, float epsilon)
+  {
+    float* copies;
+    unsigned int   copied;
+    unsigned int   i, j;
+
+    copies = (float*)malloc(sizeof(float) * 3 * (*numvectors + 1));
+    memcpy(copies, vectors, (sizeof(float) * 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;
+        }
+      }
 
-  /* 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");
+      /* 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] = (float)j;
+    }
+
+    *numvectors = copied-1;
+    return copies;
+  }
+
+  /* _glmFindGroup: Find a group in the model
+   */
+  static 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;
   }
-  return 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 int
-_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 */
+  /* _glmAddGroup: Add a group to the model
+   */
+  static GLMgroup*
+  _glmAddGroup(GLMmodel* model, char* name)
+  {
+    GLMgroup* group;
+
+    group = _glmFindGroup(model, name);
+    if (!group) {
+      group = (GLMgroup*)malloc(sizeof(GLMgroup));
+      group->name = strdup(name);
+      group->material = 0;
+      group->numtriangles = 0;
+      group->triangles = NULL;
+      group->next = model->groups;
+      model->groups = group;
+      model->numgroups++;
+    }
+
+    return group;
+  }
+
+  /* _glmFindGroup: Find a material in the model
+   */
+  static unsigned int
+  _glmFindMaterial(GLMmodel* model, char* name)
+  {
+    unsigned int i;
+
+    for (i = 0; i < model->nummaterials; i++) {
+      if (model->materials[i].name && !strcmp(model->materials[i].name, 
name))
+        goto found;
+    }
+
+    /* didn't find the name, so set it as the default material */
+    printf("_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;
+
+    dir = strdup(path);
+
+    s = strrchr(dir, '/');
+    if (s)
+      s[1] = '\0';
+    else
+      dir[0] = '\0';
+
+    return dir;
+  }
+
+
+  /* _glmReadMTL: read a wavefront material library file
+   *
+   * model - properly initialized GLMmodel structure
+   * name  - name of the material library
+   */
+  static int
+  _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);
+      free(filename);
+      return 1;
+    }
+    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);
 
-  GLMgroup* group;                     /* current group */
-  int       v, n, t;
-  char      buf[128];
-
-  /* make a default group */
-  group = _glmAddGroup(model, "default");
-
-  numvertices = numnormals = numtexcoords = numtriangles = 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 */
+    /* 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].name = NULL;
+      model->materials[i].shininess = 0;
+      model->materials[i].refraction = 0;
+      model->materials[i].alpha      = 1;
+      model->materials[i].shader     = GLM_FLAT_SHADE;
+    
+      model->materials[i].diffuse[0] = 0.8;
+      model->materials[i].diffuse[1] = 0.8;
+      model->materials[i].diffuse[2] = 0.8;
+      model->materials[i].diffuse[3] = 1.0;
+      model->materials[i].ambient[0] = 0.2;
+      model->materials[i].ambient[1] = 0.2;
+      model->materials[i].ambient[2] = 0.2;
+      model->materials[i].ambient[3] = 1.0;
+      model->materials[i].specular[0] = 0.0;
+      model->materials[i].specular[1] = 0.0;
+      model->materials[i].specular[2] = 0.0;
+      model->materials[i].specular[3] = 1.0;
+
+      model->materials[i].ambient_map[0] = '\0';
+      model->materials[i].diffuse_map[0] = '\0';
+      model->materials[i].specular_map[0] = '\0';
+    }
+    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 */
 
-        // TODO: Check if colors for this vertex
-        float vx,vy,vz;
-        int   val = -1;
-        sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val);
-        if (val >= 0) {
-          model->usePerVertexColors = true;
-        }
+        // Make sure the previous material has a name.
+        assert( model->materials[nummaterials].name );
+
+        // Read in the new material name.
+        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);
+        break;
+      case 'T': // Tr
+        fscanf(file, "%f", &model->materials[nummaterials].refraction);
+        break;
+      case 'd': // d
+        fscanf(file, "%f", &model->materials[nummaterials].alpha);
+        break;
+      case 'i': // illum
+        fscanf(file, "%d", &model->materials[nummaterials].shader);
+        break;
+      case 'm':
+
+        // Determine which type of map.
+        if (strcmp(buf,"map_Ka")==0)
+          fscanf(file, "%s", model->materials[nummaterials].ambient_map );
+
+        else if (strcmp(buf,"map_Kd")==0)
+          fscanf(file, "%s", model->materials[nummaterials].diffuse_map );   
     
+
+        else if (strcmp(buf,"map_Ks")==0)
+          fscanf(file, "%s", model->materials[nummaterials].specular_map );
 
-        numvertices++;
+        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:
+        /* eat up rest of line */
+        fgets(buf, sizeof(buf), file);
         break;
       }
-      case 'n':                                /* normal */
+    }
+
+    // Make sure we found the same number of materials the second time 
around.
+    // Note that glm adds a default material to the beginning of the array
+    assert((nummaterials+1) == model->nummaterials);
+    
+    return 0;
+  }
+
+  /* _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 int
+  _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);
+      free(filename);
+      return 1;
+    }
+    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");
+    }
+    return 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 int
+  _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 */
+    int       v, n, t;
+    char      buf[128];
+
+    /* make a default group */
+    group = _glmAddGroup(model, "default");
+
+    numvertices = numnormals = numtexcoords = numtriangles = 0;
+
+    while(fscanf(file, "%s", buf) != EOF) {
+      switch(buf[0]) {
+      case '#':                                /* comment */
         /* eat up rest of line */
         fgets(buf, sizeof(buf), file);
-        numnormals++;
         break;
-      case 't':                                /* texcoord */
+      case 'v':                                /* v, vn, vt */
+        switch(buf[1]) {
+        case '\0':     {               /* vertex */
+          /* eat up rest of line */
+          fgets(buf, sizeof(buf), file);
+
+          // TODO: Check if colors for this vertex
+          float vx,vy,vz;
+          int   val = -1;
+          sscanf(buf,"%f %f %f %d",&vx, &vy, &vz, &val);
+          if (val >= 0) {
+            model->usePerVertexColors = true;
+          }
+
+          numvertices++;
+          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);
+          /* Could error out here, but we'll just skip it for now.*/
+          /* return 1; */
+          break;
+        }
+        break;
+      case 'm':
+        fgets(buf, sizeof(buf), file);
+        sscanf(buf, "%s %s", buf, buf);
+        model->mtllibname = strdup(buf);
+        if (_glmReadMTL(model, buf)) {
+          /* Uh oh.  Trouble reading in the material file. */
+          return 1;
+        }
+        break;
+      case 'u':
         /* eat up rest of line */
         fgets(buf, sizeof(buf), file);
-        numtexcoords++;
         break;
-      default:
-        printf("_glmFirstPass(): Unknown token \"%s\".\n", buf);
-        /* Could error out here, but we'll just skip it for now.*/
-        /* return 1; */
+      case 'o':
+      case 'g':                                /* group */
+        /* eat up rest of line */
+        fgets(buf, sizeof(buf), file);
+        sscanf(buf, "%s", buf);
+        group = _glmAddGroup(model, buf);
         break;
-      }
-      break;
-    case 'm':
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s %s", buf, buf);
-      model->mtllibname = strdup(buf);
-      if (_glmReadMTL(model, buf)) {
-        /* Uh oh.  Trouble reading in the material file. */
-        return 1;
-      }
-      break;
-    case 'u':
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    case 'o':
-    case 'g':                          /* group */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s", buf);
-      group = _glmAddGroup(model, buf);
-      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) {
+      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++;
-        }
-      } 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) {
+          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++;
-        }
-      } 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) {
+          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++;
-        }
-      } else {
-        /* v */
-        fscanf(file, "%d", &v);
-        fscanf(file, "%d", &v);
-        numtriangles++;
-        group->numtriangles++;
-        while(fscanf(file, "%d", &v) > 0) {
+          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;
       }
-      break;
+    }
 
-    default:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-  }
-
-  // #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;
-  }
-  return 0;
-}
-
-/* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
- * the data.
- *
- * model - properly initialized GLMmodel structure
- * file  - (fopen'd) file descriptor 
- */
-static void
-_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 */
-  float*  vertices;                    /* array of vertices  */
-  unsigned char*  vertexColors;       /* array of vertex colors */
-  float*  normals;                     /* array of normals */
-  float*  texcoords;                   /* array of texture coordinates */
-  GLMgroup* group;                     /* current group pointer */
-  unsigned int    material;                    /* current material */
-  int     v, n, t;
-  char      buf[128];
-
-  /* set the pointer shortcuts */
-  vertices     = model->vertices;
-  vertexColors = model->vertexColors;
-  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;
-  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 */
-        if (!model->usePerVertexColors) {
+    // #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;
+    }
+    return 0;
+  }
+
+  /* _glmSecondPass: second pass at a Wavefront OBJ file that gets all
+   * the data.
+   *
+   * model - properly initialized GLMmodel structure
+   * file  - (fopen'd) file descriptor 
+   */
+  static void
+  _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 */
+    float*  vertices;                  /* array of vertices  */
+    unsigned char*  vertexColors;       /* array of vertex colors */
+    float*  normals;                   /* array of normals */
+    float*  texcoords;                 /* array of texture coordinates */
+    GLMgroup* group;                   /* current group pointer */
+    unsigned int    material;                  /* current material */
+    int     v, n, t;
+    char      buf[128];
+
+    /* set the pointer shortcuts */
+    vertices     = model->vertices;
+    vertexColors = model->vertexColors;
+    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;
+    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 */
+          if (!model->usePerVertexColors) {
+            fscanf(file, "%f %f %f", 
+                   &vertices[3 * numvertices + X], 
+                   &vertices[3 * numvertices + Y], 
+                   &vertices[3 * numvertices + Z]);
+          }
+          else {
+            int r,g,b;
+            fscanf(file, "%f %f %f %d %d %d", 
+                   &vertices[3 * numvertices + X], 
+                   &vertices[3 * numvertices + Y], 
+                   &vertices[3 * numvertices + Z], &r, &g, &b);
+            vertexColors[3 * numvertices + X] = (unsigned char)r; 
+            vertexColors[3 * numvertices + Y] = (unsigned char)g; 
+            vertexColors[3 * numvertices + Z] = (unsigned char)b;
+          }
+          numvertices++;
+          break;
+        case 'n':                              /* normal */
           fscanf(file, "%f %f %f", 
-                 &vertices[3 * numvertices + X], 
-                 &vertices[3 * numvertices + Y], 
-                 &vertices[3 * numvertices + Z]);
+                 &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;
         }
-        else {
-          int r,g,b;
-          fscanf(file, "%f %f %f %d %d %d", 
-                 &vertices[3 * numvertices + X], 
-                 &vertices[3 * numvertices + Y], 
-                 &vertices[3 * numvertices + Z], &r, &g, &b);
-          vertexColors[3 * numvertices + X] = (unsigned char)r; 
-          vertexColors[3 * numvertices + Y] = (unsigned char)g; 
-          vertexColors[3 * numvertices + Z] = (unsigned char)b;
-        }
-        numvertices++;
         break;
-      case 'n':                                /* normal */
-        fscanf(file, "%f %f %f", 
-               &normals[3 * numnormals + X],
-               &normals[3 * numnormals + Y], 
-               &normals[3 * numnormals + Z]);
-        numnormals++;
+      case 'u':
+        fgets(buf, sizeof(buf), file);
+        sscanf(buf, "%s %s", buf, buf);
+        group->material = material = _glmFindMaterial(model, buf);
         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);
-      group->material = material = _glmFindMaterial(model, buf);
-      break;
-    case 'o':
-    case 'g':                          /* group */
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      sscanf(buf, "%s", buf);
-      group = _glmFindGroup(model, buf);
-      group->material = material;
-      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 >= 0) ? v : (numvertices + v);
-        T(numtriangles).nindices[0] = n;
-        fscanf(file, "%d//%d", &v, &n);
-        T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
-        T(numtriangles).nindices[1] = n;
-        fscanf(file, "%d//%d", &v, &n);
-        T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + 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];
+      case 'o':
+      case 'g':                                /* group */
+        /* eat up rest of line */
+        fgets(buf, sizeof(buf), file);
+        sscanf(buf, "%s", buf);
+        group = _glmFindGroup(model, buf);
+        group->material = material;
+        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 >= 0) ? v : (numvertices + v);
+          T(numtriangles).nindices[0] = n;
+          fscanf(file, "%d//%d", &v, &n);
+          T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+          T(numtriangles).nindices[1] = n;
+          fscanf(file, "%d//%d", &v, &n);
           T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + 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 >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[0] = t;
-        T(numtriangles).nindices[0] = n;
-        fscanf(file, "%d/%d/%d", &v, &t, &n);
-        T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[1] = t;
-        T(numtriangles).nindices[1] = n;
-        fscanf(file, "%d/%d/%d", &v, &t, &n);
-        T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[2] = t;
-        T(numtriangles).nindices[2] = n;
-        group->triangles[group->numtriangles++] = numtriangles;
-        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];
+          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 >= 0) ? v : (numvertices + 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 >= 0) ? v : (numvertices + v);
+          T(numtriangles).tindices[0] = t;
+          T(numtriangles).nindices[0] = n;
+          fscanf(file, "%d/%d/%d", &v, &t, &n);
+          T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+          T(numtriangles).tindices[1] = t;
+          T(numtriangles).nindices[1] = n;
+          fscanf(file, "%d/%d/%d", &v, &t, &n);
           T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + 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 >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[0] = t;
-        fscanf(file, "%d/%d", &v, &t);
-        T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[1] = t;
-        fscanf(file, "%d/%d", &v, &t);
-        T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
-        T(numtriangles).tindices[2] = t;
-        group->triangles[group->numtriangles++] = numtriangles;
-        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];
+          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 >= 0) ? v : (numvertices + 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 >= 0) ? v : (numvertices + v);
+          T(numtriangles).tindices[0] = t;
+          fscanf(file, "%d/%d", &v, &t);
+          T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+          T(numtriangles).tindices[1] = t;
+          fscanf(file, "%d/%d", &v, &t);
           T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + v);
           T(numtriangles).tindices[2] = t;
           group->triangles[group->numtriangles++] = numtriangles;
           numtriangles++;
-        }
-      } else {
-        /* v */
-        sscanf(buf, "%d", &v);
-        T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
-        fscanf(file, "%d", &v);
-        T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
-        fscanf(file, "%d", &v);
-        T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + 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];
+          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 >= 0) ? v : (numvertices + v);
+            T(numtriangles).tindices[2] = t;
+            group->triangles[group->numtriangles++] = numtriangles;
+            numtriangles++;
+          }
+        } else {
+          /* v */
+          sscanf(buf, "%d", &v);
+          T(numtriangles).vindices[0] = (v >= 0) ? v : (numvertices + v);
+          fscanf(file, "%d", &v);
+          T(numtriangles).vindices[1] = (v >= 0) ? v : (numvertices + v);
+          fscanf(file, "%d", &v);
           T(numtriangles).vindices[2] = (v >= 0) ? v : (numvertices + 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 >= 0) ? v : (numvertices + v);
+            group->triangles[group->numtriangles++] = numtriangles;
+            numtriangles++;
+          }
         }
-      }
-      break;
+        break;
 
-    default:
-      /* eat up rest of line */
-      fgets(buf, sizeof(buf), file);
-      break;
-    }
-  } 
+      default:
+        /* eat up rest of line */
+        fgets(buf, sizeof(buf), file);
+        break;
+      }
+    } 
 
 #if 0
-  /* announce the memory requirements */
-  printf(" Memory: %d bytes\n",
-        numvertices  * 3*sizeof(float) +
-        numnormals   * 3*sizeof(float) * (numnormals ? 1 : 0) +
-        numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
-        numtriangles * sizeof(GLMtriangle));
+    /* announce the memory requirements */
+    printf(" Memory: %d bytes\n",
+           numvertices  * 3*sizeof(float) +
+           numnormals   * 3*sizeof(float) * (numnormals ? 1 : 0) +
+           numtexcoords * 3*sizeof(float) * (numtexcoords ? 1 : 0) +
+           numtriangles * sizeof(GLMtriangle));
 #endif
-}
+  }
 
 
 
 
-/* public functions */
+  /* 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 
- */
-float
-glmUnitize(GLMmodel* model)
-{
-  unsigned int  i;
-  float maxx, minx, maxy, miny, maxz, minz;
-  float cx, cy, cz, w, h, d;
-  float 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 floats (float dimensions[3])
- */
-void
-glmDimensions(GLMmodel* model, float* dimensions)
-{
-  unsigned int i;
-  float 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);
-}
-
-/*
- * glmBoundingBox: Calculates the min/max positions of the model
- */
-void
-glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos)
-{
-  unsigned int i;
-  float maxx, minx, maxy, miny, maxz, minz;
-
-  assert(model);
-  assert(model->vertices);
-  assert(minpos);
-  assert(maxpos);
-
-  /* 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];
-  }
-
-  minpos[0] = minx;
-  minpos[1] = miny;
-  minpos[2] = minz;
-  maxpos[0] = maxx;
-  maxpos[1] = maxy;
-  maxpos[2] = maxz;
-
-}
-
-/* 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)
- */
-void
-glmScale(GLMmodel* model, float 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 
- */
-void
-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;
+  /* 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 
+   */
+  float
+  glmUnitize(GLMmodel* model)
+  {
+    unsigned int  i;
+    float maxx, minx, maxy, miny, maxz, minz;
+    float cx, cy, cz, w, h, d;
+    float 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 floats (float dimensions[3])
+   */
+  void
+  glmDimensions(GLMmodel* model, float* dimensions)
+  {
+    unsigned int i;
+    float 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);
+  }
+
+  /*
+   * glmBoundingBox: Calculates the min/max positions of the model
+   */
+  void
+  glmBoundingBox(GLMmodel *model, float *minpos, float *maxpos)
+  {
+    unsigned int i;
+    float maxx, minx, maxy, miny, maxz, minz;
+
+    assert(model);
+    assert(model->vertices);
+    assert(minpos);
+    assert(maxpos);
+
+    /* 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];
+    }
+
+    minpos[0] = minx;
+    minpos[1] = miny;
+    minpos[2] = minz;
+    maxpos[0] = maxx;
+    maxpos[1] = maxy;
+    maxpos[2] = maxz;
+
+  }
+
+  /* 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)
+   */
+  void
+  glmScale(GLMmodel* model, float 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 
+   */
+  void
+  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->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;
+      }
     }
 
-    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];
     }
   }
 
-  /* 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
- */
-void
-glmFacetNormals(GLMmodel* model)
-{
-  unsigned int  i;
-  float u[3];
-  float v[3];
+  /* 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
+   */
+  void
+  glmFacetNormals(GLMmodel* model)
+  {
+    unsigned int  i;
+    float u[3];
+    float v[3];
   
-  assert(model);
-  assert(model->vertices);
+    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 = (float*)malloc(sizeof(float) *
-                                     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
- */
-void
-glmVertexNormals(GLMmodel* model, float angle)
-{
-  GLMnode*  node;
-  GLMnode*  tail;
-  GLMnode** members;
-  float*  normals;
-  unsigned int    numnormals;
-  float   average[3];
-  float   dot, cos_angle;
-  unsigned int    i, avg;
-
-  assert(model);
-  assert(model->facetnorms);
-
-  /* calculate the cosine of the angle (in degrees) */
-  cos_angle = cosf(angle * (float)M_PI / 180.0f);
-
-  /* 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 = (float*)malloc(sizeof(float)* 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;
+    /* clobber any old facetnormals */
+    if (model->facetnorms)
+      free(model->facetnorms);
+
+    /* allocate memory for the new facet normals */
+    model->numfacetnorms = model->numtriangles;
+    model->facetnorms = (float*)malloc(sizeof(float) *
+                                       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
+   */
+  void
+  glmVertexNormals(GLMmodel* model, float angle)
+  {
+    GLMnode*  node;
+    GLMnode*  tail;
+    GLMnode** members;
+    float*  normals;
+    unsigned int    numnormals;
+    float   average[3];
+    float   dot, cos_angle;
+    unsigned int    i, avg;
+
+    assert(model);
+    assert(model->facetnorms);
+
+    /* calculate the cosine of the angle (in degrees) */
+    cos_angle = cosf(angle * (float)M_PI / 180.0f);
+
+    /* 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 = (float*)malloc(sizeof(float)* 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 = 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 = false;
+    /* 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 = 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 = 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;
       }
-      node = node->next;
     }
+  
+    model->numnormals = numnormals - 1;
 
-    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++;
+    /* free the member information */
+    for (i = 1; i <= model->numvertices; i++) {
+      node = members[i];
+      while (node) {
+        tail = node;
+        node = node->next;
+        free(tail);
       }
-      node = node->next;
     }
+    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 = (float*)malloc(sizeof(float)* 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(): %u normals generated\n", model->numnormals);
   }
-  
-  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 = (float*)malloc(sizeof(float)* 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(): %u 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
- */
-void
-glmLinearTexture(GLMmodel* model)
-{
-  GLMgroup *group;
-  float dimensions[3];
-  float x, y, scalefactor;
-  unsigned int i;
+
+  /* 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
+   */
+  void
+  glmLinearTexture(GLMmodel* model)
+  {
+    GLMgroup *group;
+    float dimensions[3];
+    float x, y, scalefactor;
+    unsigned int i;
   
-  assert(model);
+    assert(model);
 
-  if (model->texcoords)
-    free(model->texcoords);
-  model->numtexcoords = model->numvertices;
-  model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
+    if (model->texcoords)
+      free(model->texcoords);
+    model->numtexcoords = model->numvertices;
+    model->texcoords=(float*)malloc(sizeof(float)*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;
-  }
+    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;
-  }
+    /* 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);
+    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
- */
-void
-glmSpheremapTexture(GLMmodel* model)
-{
-  GLMgroup* group;
-  float theta, phi, rho, x, y, z, r;
-  unsigned int i;
+  /* 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
+   */
+  void
+  glmSpheremapTexture(GLMmodel* model)
+  {
+    GLMgroup* group;
+    float theta, phi, rho, x, y, z, r;
+    unsigned int i;
   
-  assert(model);
-  assert(model->normals);
+    assert(model);
+    assert(model->normals);
 
-  if (model->texcoords)
-    free(model->texcoords);
-  model->numtexcoords = model->numnormals;
-  model->texcoords=(float*)malloc(sizeof(float)*2*(model->numtexcoords+1));
+    if (model->texcoords)
+      free(model->texcoords);
+    model->numtexcoords = model->numnormals;
+    model->texcoords=(float*)malloc(sizeof(float)*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));
+    /* 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(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.0f)
-        theta = 3.14159265f / 2.0f;    /* asin(y / r); */
-      else
-        theta = acosf(x / r);
+        if(x == 0.0f)
+          theta = 3.14159265f / 2.0f;  /* asin(y / r); */
+        else
+          theta = acosf(x / r);
 #endif
       
-      if(y == 0.0f)
-        theta = 3.141592365f / 2.0f;   /* acos(x / r); */
-      else
-        theta = asinf(y / r) + (3.14159265f / 2.0f);
-    }
+        if(y == 0.0f)
+          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;
-  }
+      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];
+    /* 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;
     }
-    group = group->next;
-  }
 
 #if 0  
-  printf("glmSpheremapTexture(): generated %d spheremap texture 
coordinates\n",
-        model->numtexcoords);
+    printf("glmSpheremapTexture(): generated %d spheremap texture 
coordinates\n",
+           model->numtexcoords);
 #endif
-}
-
-/* glmDelete: Deletes a GLMmodel structure.
- *
- * model - initialized GLMmodel structure
- */
-void
-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->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++)
-      if (model->materials[i].name) free(model->materials[i].name);
-    free(model->materials);
-  }
-  while(model->groups) {
-    group = model->groups;
-    /* Take the group off the linked list. */
-    model->groups = model->groups->next;
-    if (group->name) free(group->name);
-    if (group->triangles) 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(const char* filename)
-{
-  GLMmodel* model;
-  FILE*     file;
-
-  /* open the file */
-  file = fopen(filename, "r");
-  if (!file) {
-    perror("glmReadOBJ() failed: can't open data file");
-    return 0;
   }
 
+  /* glmDelete: Deletes a GLMmodel structure.
+   *
+   * model - initialized GLMmodel structure
+   */
+  void
+  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->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++)
+        if (model->materials[i].name) free(model->materials[i].name);
+      free(model->materials);
+    }
+    while(model->groups) {
+      group = model->groups;
+      /* Take the group off the linked list. */
+      model->groups = model->groups->next;
+      if (group->name) free(group->name);
+      if (group->triangles) 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(const char* filename)
+  {
+    GLMmodel* model;
+    FILE*     file;
+
+    /* open the file */
+    file = fopen(filename, "r");
+    if (!file) {
+      perror("glmReadOBJ() failed: can't open data file");
+      return 0;
+    }
+
 #if 0
-  /* announce the model name */
-  printf("Model: %s\n", filename);
+    /* 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->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 */
-  if (_glmFirstPass(model, file)) {
-    /* There was a problem here, so cleanup and exit. */
-    glmDelete(model);
+    /* allocate a new model */
+    model = (GLMmodel*)malloc(sizeof(GLMmodel));
+    model->pathname      = strdup(filename);
+    model->mtllibname    = NULL;
+    model->numvertices   = 0;
+    model->vertices      = 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 */
+    if (_glmFirstPass(model, file)) {
+      /* There was a problem here, so cleanup and exit. */
+      glmDelete(model);
+      fclose(file);
+      return 0;
+    }
+
+    /* allocate memory */
+    model->vertices = (float*)malloc(sizeof(float) *
+                                     3 * (model->numvertices + 1));
+    model->vertexColors = (unsigned char*)malloc(sizeof(unsigned char) *
+                                                 3 * (model->numvertices + 
1));
+    model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
+                                            model->numtriangles);
+    if (model->numnormals) {
+      model->normals = (float*)malloc(sizeof(float) *
+                                      3 * (model->numnormals + 1));
+    }
+    if (model->numtexcoords) {
+      model->texcoords = (float*)malloc(sizeof(float) *
+                                        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 0;
+
+    return model;
   }
 
-  /* allocate memory */
-  model->vertices = (float*)malloc(sizeof(float) *
-                                   3 * (model->numvertices + 1));
-  model->vertexColors = (unsigned char*)malloc(sizeof(unsigned char) *
-                                               3 * (model->numvertices + 1));
-  model->triangles = (GLMtriangle*)malloc(sizeof(GLMtriangle) *
-                                         model->numtriangles);
-  if (model->numnormals) {
-    model->normals = (float*)malloc(sizeof(float) *
-                                    3 * (model->numnormals + 1));
-  }
-  if (model->numtexcoords) {
-    model->texcoords = (float*)malloc(sizeof(float) *
-                                      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.  
- */
-int
-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);
-    return 1;
-  }
-
-  /* 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);
-    if (_glmWriteMTL(model, filename, model->mtllibname)) {
-      /* Problem opening up the material file for output. */
-      fclose(file);
+  /* 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.  
+   */
+  int
+  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);
       return 1;
     }
-  }
 
-  /* spit out the vertices */
-  fprintf(file, "\n");
-  fprintf(file, "# %u 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 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);
+      if (_glmWriteMTL(model, filename, model->mtllibname)) {
+        /* Problem opening up the material file for output. */
+        fclose(file);
+        return 1;
+      }
+    }
 
-  /* spit out the smooth/flat normals */
-  if (mode & GLM_SMOOTH) {
+    /* spit out the vertices */
     fprintf(file, "\n");
-    fprintf(file, "# %u 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]);
+    fprintf(file, "# %u 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, "# %u 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, "# %u 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]);
+      }
     }
-  } else if (mode & GLM_FLAT) {
-    fprintf(file, "\n");
-    fprintf(file, "# %u 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, "# %u 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]);
+      }
     }
-  }
 
-  /* spit out the texture coordinates */
-  if (mode & GLM_TEXTURE) {
     fprintf(file, "\n");
-    fprintf(file, "# %u 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, "# %u groups\n", model->numgroups);
+    fprintf(file, "# %u faces (triangles)\n", model->numtriangles);
+    fprintf(file, "\n");
 
-  fprintf(file, "\n");
-  fprintf(file, "# %u groups\n", model->numgroups);
-  fprintf(file, "# %u 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 %u/%u/%u %u/%u/%u %u/%u/%u\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 %u/%u %u/%u %u/%u\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 %u/%u %u/%u %u/%u\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 %u//%u %u//%u %u//%u\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 %u//%u %u//%u %u//%u\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 %u %u %u\n",
-               T(group->triangles[i]).vindices[0],
-               T(group->triangles[i]).vindices[1],
-               T(group->triangles[i]).vindices[2]);
+    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 %u/%u/%u %u/%u/%u %u/%u/%u\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 %u/%u %u/%u %u/%u\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 %u/%u %u/%u %u/%u\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 %u//%u %u//%u %u//%u\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 %u//%u %u//%u %u//%u\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 %u %u %u\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;
     }
-    fprintf(file, "\n");
-    group = group->next;
-  }
 
-  fclose(file);
-  return 0;
-}
-
-/* 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)
- *
- */
-void
-glmWeld(GLMmodel* model, float epsilon)
-{
-  float* vectors;
-  float* copies;
-  unsigned int   numvectors;
-  unsigned int   i;
-
-  /* vertices */
-  numvectors = model->numvertices;
-  vectors    = model->vertices;
-  copies = _glmWeldVectors(vectors, &numvectors, epsilon);
-
-  printf("glmWeld(): %u 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 = (float*)malloc(sizeof(float) * 
-                                   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];
+    fclose(file);
+    return 0;
   }
 
-  free(copies);
-}
+  /* 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)
+   *
+   */
+  void
+  glmWeld(GLMmodel* model, float epsilon)
+  {
+    float* vectors;
+    float* copies;
+    unsigned int   numvectors;
+    unsigned int   i;
+
+    /* vertices */
+    numvectors = model->numvertices;
+    vectors    = model->vertices;
+    copies = _glmWeldVectors(vectors, &numvectors, epsilon);
+
+    printf("glmWeld(): %u 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 = (float*)malloc(sizeof(float) * 
+                                     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   /** This is left in only as a reference to how to get to the data. */
-/* glmDraw: Renders the model to the current OpenGL context using the
- * mode specified.
- *
- * model    - initialized GLMmodel structure
- * mode     - a bitwise OR of values describing what is to be rendered.
- *            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
-glmDraw(GLMmodel* model, unsigned int mode)
-{
-  unsigned int i;
-  GLMgroup* group;
-
-  assert(model);
-  assert(model->vertices);
-
-  /* do a bit of warning */
-  if (mode & GLM_FLAT && !model->facetnorms) {
-    printf("glmDraw() warning: flat render mode requested "
-          "with no facet normals defined.\n");
-    mode &= ~GLM_FLAT;
-  }
-  if (mode & GLM_SMOOTH && !model->normals) {
-    printf("glmDraw() warning: smooth render mode requested "
-          "with no normals defined.\n");
-    mode &= ~GLM_SMOOTH;
-  }
-  if (mode & GLM_TEXTURE && !model->texcoords) {
-    printf("glmDraw() warning: texture render mode requested "
-          "with no texture coordinates defined.\n");
-    mode &= ~GLM_TEXTURE;
-  }
-  if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
-    printf("glmDraw() warning: flat render mode requested "
-          "and smooth render mode requested (using smooth).\n");
-    mode &= ~GLM_FLAT;
-  }
-  if (mode & GLM_COLOR && !model->materials) {
-    printf("glmDraw() warning: color render mode requested "
-          "with no materials defined.\n");
-    mode &= ~GLM_COLOR;
-  }
-  if (mode & GLM_MATERIAL && !model->materials) {
-    printf("glmDraw() warning: material render mode requested "
-          "with no materials defined.\n");
-    mode &= ~GLM_MATERIAL;
-  }
-  if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
-    printf("glmDraw() warning: color and material render mode requested "
-          "using only material mode\n");
-    mode &= ~GLM_COLOR;
-  }
-  if (mode & GLM_COLOR)
-    glEnable(GL_COLOR_MATERIAL);
-  if (mode & GLM_MATERIAL)
-    glDisable(GL_COLOR_MATERIAL);
-
-  glPushMatrix();
-  glTranslatef(model->position[0], model->position[1], model->position[2]);
-
-  glBegin(GL_TRIANGLES);
-  group = model->groups;
-  while (group) {
-    if (mode & GLM_MATERIAL) {
-      glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 
-                  model->materials[group->material].ambient);
-      glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
-                  model->materials[group->material].diffuse);
-      glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 
-                  model->materials[group->material].specular);
-      glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
-                 model->materials[group->material].shininess);
-    }
-
-    if (mode & GLM_COLOR) {
-      glColor3fv(model->materials[group->material].diffuse);
-    }
-
-    for (i = 0; i < group->numtriangles; i++) {
-      if (mode & GLM_FLAT)
-        glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]);
-      
-      if (mode & GLM_SMOOTH)
-        glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[0]]);
-      if (mode & GLM_TEXTURE)
-        
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]);
+  /* glmDraw: Renders the model to the current OpenGL context using the
+   * mode specified.
+   *
+   * model    - initialized GLMmodel structure
+   * mode     - a bitwise OR of values describing what is to be rendered.
+   *            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
+  glmDraw(GLMmodel* model, unsigned int mode)
+  {
+    unsigned int i;
+    GLMgroup* group;
+
+    assert(model);
+    assert(model->vertices);
+
+    /* do a bit of warning */
+    if (mode & GLM_FLAT && !model->facetnorms) {
+      printf("glmDraw() warning: flat render mode requested "
+             "with no facet normals defined.\n");
+      mode &= ~GLM_FLAT;
+    }
+    if (mode & GLM_SMOOTH && !model->normals) {
+      printf("glmDraw() warning: smooth render mode requested "
+             "with no normals defined.\n");
+      mode &= ~GLM_SMOOTH;
+    }
+    if (mode & GLM_TEXTURE && !model->texcoords) {
+      printf("glmDraw() warning: texture render mode requested "
+             "with no texture coordinates defined.\n");
+      mode &= ~GLM_TEXTURE;
+    }
+    if (mode & GLM_FLAT && mode & GLM_SMOOTH) {
+      printf("glmDraw() warning: flat render mode requested "
+             "and smooth render mode requested (using smooth).\n");
+      mode &= ~GLM_FLAT;
+    }
+    if (mode & GLM_COLOR && !model->materials) {
+      printf("glmDraw() warning: color render mode requested "
+             "with no materials defined.\n");
+      mode &= ~GLM_COLOR;
+    }
+    if (mode & GLM_MATERIAL && !model->materials) {
+      printf("glmDraw() warning: material render mode requested "
+             "with no materials defined.\n");
+      mode &= ~GLM_MATERIAL;
+    }
+    if (mode & GLM_COLOR && mode & GLM_MATERIAL) {
+      printf("glmDraw() warning: color and material render mode requested "
+             "using only material mode\n");
+      mode &= ~GLM_COLOR;
+    }
+    if (mode & GLM_COLOR)
+      glEnable(GL_COLOR_MATERIAL);
+    if (mode & GLM_MATERIAL)
+      glDisable(GL_COLOR_MATERIAL);
+
+    glPushMatrix();
+    glTranslatef(model->position[0], model->position[1], model->position[2]);
+
+    glBegin(GL_TRIANGLES);
+    group = model->groups;
+    while (group) {
+      if (mode & GLM_MATERIAL) {
+        glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, 
+                     model->materials[group->material].ambient);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, 
+                     model->materials[group->material].diffuse);
+        glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, 
+                     model->materials[group->material].specular);
+        glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 
+                    model->materials[group->material].shininess);
+      }
 
-      if (model->usePerVertexColors) {
-        glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[0]] );
+      if (mode & GLM_COLOR) {
+        glColor3fv(model->materials[group->material].diffuse);
       }
 
-      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[0]]);
+      for (i = 0; i < group->numtriangles; i++) {
+        if (mode & GLM_FLAT)
+          glNormal3fv(&model->facetnorms[3 * T(group->triangles[i]).findex]);
+      
+        if (mode & GLM_SMOOTH)
+          glNormal3fv(&model->normals[3 * 
T(group->triangles[i]).nindices[0]]);
+        if (mode & GLM_TEXTURE)
+          
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[0]]);
+
+        if (model->usePerVertexColors) {
+          glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[0]] );
+        }
+
+        glVertex3fv(&model->vertices[3 * 
T(group->triangles[i]).vindices[0]]);
 #if 0
-      printf("%f %f %f\n", 
-            model->vertices[3 * T(group->triangles[i]).vindices[0] + X],
-            model->vertices[3 * T(group->triangles[i]).vindices[0] + Y],
-            model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]);
+        printf("%f %f %f\n", 
+               model->vertices[3 * T(group->triangles[i]).vindices[0] + X],
+               model->vertices[3 * T(group->triangles[i]).vindices[0] + Y],
+               model->vertices[3 * T(group->triangles[i]).vindices[0] + Z]);
 #endif
       
-      if (mode & GLM_SMOOTH)
-        glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[1]]);
-      if (mode & GLM_TEXTURE)
-        
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]);
-      if (model->usePerVertexColors) {
-        glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[1]] );
-      }
-      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[1]]);
+        if (mode & GLM_SMOOTH)
+          glNormal3fv(&model->normals[3 * 
T(group->triangles[i]).nindices[1]]);
+        if (mode & GLM_TEXTURE)
+          
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[1]]);
+        if (model->usePerVertexColors) {
+          glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[1]] );
+        }
+        glVertex3fv(&model->vertices[3 * 
T(group->triangles[i]).vindices[1]]);
 #if 0
-      printf("%f %f %f\n", 
-            model->vertices[3 * T(group->triangles[i]).vindices[1] + X],
-            model->vertices[3 * T(group->triangles[i]).vindices[1] + Y],
-            model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]);
+        printf("%f %f %f\n", 
+               model->vertices[3 * T(group->triangles[i]).vindices[1] + X],
+               model->vertices[3 * T(group->triangles[i]).vindices[1] + Y],
+               model->vertices[3 * T(group->triangles[i]).vindices[1] + Z]);
 #endif
       
-      if (mode & GLM_SMOOTH)
-       glNormal3fv(&model->normals[3 * T(group->triangles[i]).nindices[2]]);
-      if (mode & GLM_TEXTURE)
-       
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]);
-      if (model->usePerVertexColors) {
-        glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[2]] );
-      }
-      glVertex3fv(&model->vertices[3 * T(group->triangles[i]).vindices[2]]);
+        if (mode & GLM_SMOOTH)
+          glNormal3fv(&model->normals[3 * 
T(group->triangles[i]).nindices[2]]);
+        if (mode & GLM_TEXTURE)
+          
glTexCoord2fv(&model->texcoords[2*T(group->triangles[i]).tindices[2]]);
+        if (model->usePerVertexColors) {
+          glColor3ubv( &model->vertexColors[3 * 
T(group->triangles[i]).vindices[2]] );
+        }
+        glVertex3fv(&model->vertices[3 * 
T(group->triangles[i]).vindices[2]]);
 #if 0
-      printf("%f %f %f\n", 
-            model->vertices[3 * T(group->triangles[i]).vindices[2] + X],
-            model->vertices[3 * T(group->triangles[i]).vindices[2] + Y],
-            model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]);
+        printf("%f %f %f\n", 
+               model->vertices[3 * T(group->triangles[i]).vindices[2] + X],
+               model->vertices[3 * T(group->triangles[i]).vindices[2] + Y],
+               model->vertices[3 * T(group->triangles[i]).vindices[2] + Z]);
 #endif
       
-    }
+      }
     
-    group = group->next;
-  }
-  glEnd();
+      group = group->next;
+    }
+    glEnd();
 
-  glPopMatrix();
-}
+    glPopMatrix();
+  }
 #endif
 
 }

Modified: trunk/Model/Readers/glm/glm.h
==============================================================================
--- trunk/Model/Readers/glm/glm.h       (original)
+++ trunk/Model/Readers/glm/glm.h       Mon Dec 12 17:07:44 2005
@@ -24,12 +24,14 @@
 #endif
 
        enum {
-               GLM_NONE     = (0),
-               GLM_FLAT     = (1 << 0),
-               GLM_SMOOTH   = (1 << 1),
-               GLM_TEXTURE  = (1 << 2),
-               GLM_COLOR    = (1 << 3),
-               GLM_MATERIAL = (1 << 4)
+               GLM_NONE           = (0),
+               GLM_FLAT           = (1 << 0),
+               GLM_SMOOTH         = (1 << 1),
+               GLM_TEXTURE        = (1 << 2),
+               GLM_COLOR          = (1 << 3),
+               GLM_MATERIAL       = (1 << 4),
+    GLM_FLAT_SHADE     = (1 << 5),
+    GLM_SPECULAR_SHADE = (1 << 6)
        };
 
        /* structs */
@@ -39,11 +41,20 @@
        typedef struct _GLMmaterial
        {
                char* name;                             /* name of material */
-               float diffuse[4];                       /* diffuse component 
*/
-               float ambient[4];                       /* ambient component 
*/
-               float specular[4];                      /* specular component 
*/
-               float emmissive[4];                     /* emmissive 
component */
-               float shininess;                        /* specular exponent 
*/
+               float diffuse[4];                         // Kd diffuse 
component
+               float ambient[4];                         // Ka ambient 
component
+               float specular[4];                // Ks specular component
+               float emmissive[4];               // emmissive component
+               float shininess;                          // Ns specular 
exponent
+    float refraction;       // Tr
+    float alpha;            // d
+    int   shader;           // illum
+
+    // Texture maps, zero length if not specified.
+    char  ambient_map [128]; // map_Ka
+    char  diffuse_map [128]; // map_Kd
+    char  specular_map[128]; // map_Ks
+    
        } GLMmaterial;
 
        /* GLMtriangle: Structure that defines a triangle in a model.

Modified: trunk/Model/Textures/CMakeLists.txt
==============================================================================
--- trunk/Model/Textures/CMakeLists.txt (original)
+++ trunk/Model/Textures/CMakeLists.txt Mon Dec 12 17:07:44 2005
@@ -1,19 +1,21 @@
 
 
 SET( Manta_Textures_SRCS
-#     Textures/CheckerTexture.cc
+     Textures/CheckerTexture.cc
      Textures/CheckerTexture.h
-#     Textures/Constant.cc
+     Textures/Constant.cc
      Textures/Constant.h
-#     Textures/ImageTexture.cc
+     Textures/ImageTexture.cc
      Textures/ImageTexture.h
-#     Textures/MarbleTexture.cc
+     Textures/MarbleTexture.cc
      Textures/MarbleTexture.h
-#     Textures/OakTexture.cc
+     Textures/OakTexture.cc
      Textures/OakTexture.h
-#     Textures/TriVerTexture.cc
+     Textures/TexCoordTexture.cc
+     Textures/TexCoordTexture.h
+     Textures/TriVerTexture.cc
      Textures/TriVerTexture.h
-#     Textures/WoodTexture.cc
+     Textures/WoodTexture.cc
      Textures/WoodTexture.h
      )
 

Modified: trunk/Model/Textures/CheckerTexture.cc
==============================================================================
--- trunk/Model/Textures/CheckerTexture.cc      (original)
+++ trunk/Model/Textures/CheckerTexture.cc      Mon Dec 12 17:07:44 2005
@@ -1,49 +1,4 @@
 
 #include <Model/Textures/CheckerTexture.h>
-#include <Interface/RayPacket.h>
 
-namespace Manta {
-  template<class ValueType>
-  CheckerTexture<ValueType>::CheckerTexture(const ValueType& value1,
-                                           const ValueType& value2,
-                                           const Vector& v1,
-                                           const Vector& v2)
-    : v1(v1), v2(v2)
-  {
-    values[0] = value1;
-    values[1] = value2;
-    if(v1.z() == 0 && v2.z() == 0)
-      need_w = false;
-    else
-      need_w = true;
-  }
-  
-  template<class ValueType>
-  CheckerTexture<ValueType>::~CheckerTexture()
-  {
-  }
-  
-  template<class ValueType>
-  void CheckerTexture<ValueType>::mapValues(const RenderContext& context,
-                                           RayPacket& rays,
-                                           ValueType results[]) const
-  {
-    if(need_w)
-      rays.computeTextureCoordinates3(context);
-    else
-      rays.computeTextureCoordinates2(context);
-    for(int i=0;i<rays.getSize();i++){
-      RayPacket::Element& e = rays.get(i);
-      Real vv1 = Dot(e.texCoords, v1);
-      Real vv2 = Dot(e.texCoords, v2);
-      if(vv1<0)
-        vv1=-vv1+1;
-      if(vv2<0)
-        vv2=-vv2+1;
-      int i1 = (int)vv1;
-      int i2 = (int)vv2;
-      int which = (i1+i2)%2;
-      results[i] = values[which];
-    }
-  }
-}
+

Modified: trunk/Model/Textures/CheckerTexture.h
==============================================================================
--- trunk/Model/Textures/CheckerTexture.h       (original)
+++ trunk/Model/Textures/CheckerTexture.h       Mon Dec 12 17:07:44 2005
@@ -4,6 +4,7 @@
 
 #include <Interface/Texture.h>
 #include <Core/Geometry/PointVector.h>
+#include <Interface/RayPacket.h>
 
 namespace Manta {
   class RayPacket;
@@ -27,11 +28,53 @@
     Vector v2;
     bool need_w;
   };
+
+  template<class ValueType>
+  CheckerTexture<ValueType>::CheckerTexture(const ValueType& value1,
+                                           const ValueType& value2,
+                                           const Vector& v1,
+                                           const Vector& v2)
+    : v1(v1), v2(v2)
+  {
+    values[0] = value1;
+    values[1] = value2;
+    if(v1.z() == 0 && v2.z() == 0)
+      need_w = false;
+    else
+      need_w = true;
+  }
+  
+  template<class ValueType>
+  CheckerTexture<ValueType>::~CheckerTexture()
+  {
+  }
+  
+  template<class ValueType>
+  void CheckerTexture<ValueType>::mapValues(const RenderContext& context,
+                                           RayPacket& rays,
+                                           ValueType results[]) const
+  {
+    if(need_w)
+      rays.computeTextureCoordinates3(context);
+    else
+      rays.computeTextureCoordinates2(context);
+    for(int i=0;i<rays.getSize();i++){
+      RayPacket::Element& e = rays.get(i);
+      Real vv1 = Dot(e.texCoords, v1);
+      Real vv2 = Dot(e.texCoords, v2);
+      if(vv1<0)
+        vv1=-vv1+1;
+      if(vv2<0)
+        vv2=-vv2+1;
+      int i1 = (int)vv1;
+      int i2 = (int)vv2;
+      int which = (i1+i2)%2;
+      results[i] = values[which];
+    }
+  }
+
+
 }
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/CheckerTexture.cc>
-#endif
 
 #endif

Modified: trunk/Model/Textures/Constant.cc
==============================================================================
--- trunk/Model/Textures/Constant.cc    (original)
+++ trunk/Model/Textures/Constant.cc    Mon Dec 12 17:07:44 2005
@@ -3,23 +3,5 @@
 #include <Interface/RayPacket.h>
 
 namespace Manta {
-  template<class ValueType>
-  Constant<ValueType>::Constant(const ValueType& value)
-    : value(value)
-  {
-  }
-  
-  template<class ValueType>
-  Constant<ValueType>::~Constant()
-  {
-  }
-  
-  template<class ValueType>
-  void Constant<ValueType>::mapValues(const RenderContext&,
-                                     RayPacket& rays,
-                                     ValueType results[]) const
-  {
-    for(int i=0;i<rays.getSize();i++)
-      results[i] = value;
-  }
+
 }

Modified: trunk/Model/Textures/Constant.h
==============================================================================
--- trunk/Model/Textures/Constant.h     (original)
+++ trunk/Model/Textures/Constant.h     Mon Dec 12 17:07:44 2005
@@ -25,11 +25,27 @@
 
     ValueType value;
   };
+
+  template<class ValueType>
+  Constant<ValueType>::Constant(const ValueType& value)
+    : value(value)
+  {
+  }
+  
+  template<class ValueType>
+  Constant<ValueType>::~Constant()
+  {
+  }
+  
+  template<class ValueType>
+  void Constant<ValueType>::mapValues(const RenderContext&,
+                                     RayPacket& rays,
+                                     ValueType results[]) const
+  {
+    for(int i=0;i<rays.getSize();i++)
+      results[i] = value;
+  }
 }
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/Constant.cc>
-#endif
 
 #endif

Modified: trunk/Model/Textures/ImageTexture.cc
==============================================================================
--- trunk/Model/Textures/ImageTexture.cc        (original)
+++ trunk/Model/Textures/ImageTexture.cc        Mon Dec 12 17:07:44 2005
@@ -37,115 +37,8 @@
 #include <Core/Math/Trig.h>
 
 namespace Manta {
-  template< class ValueType >
-  ImageTexture< ValueType >::ImageTexture(const Image* image):
-    scale(VectorT< ScalarType, 2 >(1,1)),
-    interpolation_method(NearestNeighbor),
-    u_edge(Wrap), v_edge(Wrap)
-  {
-    bool stereo;
-    int xres, yres;
-    image->getResolution(stereo, xres, yres);
-    if (stereo) {
-      throw SCIRun::InternalError( "ImageTexture doesn't support stereo 
currently", __FILE__, __LINE__);
-    }
-    texture.resize(xres, yres);
 
-    // Now copy over the data
-    for(int y = 0; y < yres; y++) {
-      for(int x = 0; x < xres; x+=Fragment::MaxFragmentSize) {
-        int end = x + Fragment::MaxFragmentSize;
-        if (end > xres) end = xres;
-        Fragment fragment(0, x, end, y);
-        image->get(fragment);
-        for(int i = 0; i < fragment.getSize(); i++) {
-          texture(x+i, y) = fragment.get(i).color;
-        }
-      }
-    }
-  }
-
-  template< class ValueType >
-  void ImageTexture< ValueType >::mapValues(RenderContext const &context,
-                                            RayPacket &rays,
-                                            ValueType results[] ) const
-  {
-    rays.computeTextureCoordinates2( context );
-    PointT<ScalarType, 2> tex_coords[RayPacket::MaxSize];
-
-    // Grab the texture coordinates
-    for( int i = 0; i < rays.getSize(); ++i ) {
-      RayPacket::Element &e = rays.get( i );
-      tex_coords[i] = PointT<ScalarType, 2>(e.texCoords.x(), 
e.texCoords.y());
-      tex_coords[i].multiplyBy(scale);
-    }
-
-    int xres = texture.dim1();
-    int yres = texture.dim2();
-
-    // Grab the textures and do the interpolation as needed
-    switch (interpolation_method) {
-    case Bilinear:
-      {
-        for( int i = 0; i < rays.getSize(); ++i) {
-          ScalarType x = tex_coords[i].x();
-          ScalarType y = tex_coords[i].y();
-          int x_low, y_low, x_high, y_high;
-          ScalarType x_weight_high, y_weight_high;
-
-          BL_edge_behavior(x, u_edge, xres, x_low, x_high, x_weight_high);
-          BL_edge_behavior(y, v_edge, yres, y_low, y_high, y_weight_high);
-
-          // Do the interpolation
-          Color a, b;
-          a = ( texture(x_low,  y_low )*(1-x_weight_high) +
-                texture(x_high, y_low )*   x_weight_high);
-          b = ( texture(x_low,  y_high)*(1-x_weight_high) +
-                texture(x_high, y_high)*   x_weight_high);
-          results[i] = a*(1-y_weight_high) + b*y_weight_high;
-        }
-      }
-      break;
-    case NearestNeighbor:
-      {
-        for( int i = 0; i < rays.getSize(); ++i) {
-          int tx = NN_edge_behavior(static_cast<int>(tex_coords[i].x()*xres),
-                                    u_edge, texture.dim1());
-          int ty = NN_edge_behavior(static_cast<int>(tex_coords[i].y()*yres),
-                                    v_edge, texture.dim2());
-          results[i] = texture(tx, ty);
-        }
-      }
-      break;
-    }
-  } // end mapValues
-
-  template< class ValueType >
-  void ImageTexture< ValueType >::setEdgeBehavior(int new_behavior,
-                                                  int& edge) {
-    switch (new_behavior) {
-    case Wrap:
-    case Clamp:
-      edge = new_behavior;
-      break;
-    default:
-      throw SCIRun::InternalError( "ImageTexture::setEdgeBehavior doesn't 
support this edge behavior", __FILE__, __LINE__);
-      break;
-    }
-  }
-
-  template< class ValueType >
-  void ImageTexture< ValueType >::setInterpolationMethod(int new_method) {
-    switch (new_method) {
-    case NearestNeighbor:
-    case Bilinear:
-      interpolation_method = new_method;
-      break;
-    default:
-      throw SCIRun::InternalError( "ImageTexture::setInterpolationMethod 
doesn't support this interpolation method", __FILE__, __LINE__);
-      break;
-    }
-  }
+  template ImageTexture<Color>;
   
 } // end namespace Manta
 

Modified: trunk/Model/Textures/ImageTexture.h
==============================================================================
--- trunk/Model/Textures/ImageTexture.h (original)
+++ trunk/Model/Textures/ImageTexture.h Mon Dec 12 17:07:44 2005
@@ -43,9 +43,21 @@
   across the edges.
 */
 
+
+
 #ifndef Manta_Model_ImageTexture_h
 #define Manta_Model_ImageTexture_h
 
+#include <Model/Textures/ImageTexture.h>
+#include <Interface/RayPacket.h>
+#include <Interface/Image.h>
+
+#include <Core/Exceptions/InternalError.h>
+
+#include <Core/Geometry/PointVector.h>
+#include <Core/Math/MiscMath.h>
+#include <Core/Math/Trig.h>
+
 #include <Interface/Texture.h>
 #include <Core/Geometry/PointVector.h>
 
@@ -185,11 +197,116 @@
     int u_edge, v_edge;
   };
 
-} // end namespace Manta
+  template< class ValueType >
+  ImageTexture< ValueType >::ImageTexture(const Image* image):
+    scale(VectorT< ScalarType, 2 >(1,1)),
+    interpolation_method(NearestNeighbor),
+    u_edge(Wrap), v_edge(Wrap)
+  {
+    bool stereo;
+    int xres, yres;
+    image->getResolution(stereo, xres, yres);
+    if (stereo) {
+      throw SCIRun::InternalError( "ImageTexture doesn't support stereo 
currently", __FILE__, __LINE__);
+    }
+    texture.resize(xres, yres);
+
+    // Now copy over the data
+    for(int y = 0; y < yres; y++) {
+      for(int x = 0; x < xres; x+=Fragment::MaxFragmentSize) {
+        int end = x + Fragment::MaxFragmentSize;
+        if (end > xres) end = xres;
+        Fragment fragment(0, x, end, y);
+        image->get(fragment);
+        for(int i = 0; i < fragment.getSize(); i++) {
+          texture(x+i, y) = fragment.get(i).color;
+        }
+      }
+    }
+  }
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/ImageTexture.cc>
-#endif
+  template< class ValueType >
+  void ImageTexture< ValueType >::mapValues(RenderContext const &context,
+                                            RayPacket &rays,
+                                            ValueType results[] ) const
+  {
+    rays.computeTextureCoordinates2( context );
+    PointT<ScalarType, 2> tex_coords[RayPacket::MaxSize];
+
+    // Grab the texture coordinates
+    for( int i = 0; i < rays.getSize(); ++i ) {
+      RayPacket::Element &e = rays.get( i );
+      tex_coords[i] = PointT<ScalarType, 2>(e.texCoords.x(), 
e.texCoords.y());
+      tex_coords[i].multiplyBy(scale);
+    }
+
+    int xres = texture.dim1();
+    int yres = texture.dim2();
+
+    // Grab the textures and do the interpolation as needed
+    switch (interpolation_method) {
+    case Bilinear:
+      {
+        for( int i = 0; i < rays.getSize(); ++i) {
+          ScalarType x = tex_coords[i].x();
+          ScalarType y = tex_coords[i].y();
+          int x_low, y_low, x_high, y_high;
+          ScalarType x_weight_high, y_weight_high;
+
+          BL_edge_behavior(x, u_edge, xres, x_low, x_high, x_weight_high);
+          BL_edge_behavior(y, v_edge, yres, y_low, y_high, y_weight_high);
+
+          // Do the interpolation
+          Color a, b;
+          a = ( texture(x_low,  y_low )*(1-x_weight_high) +
+                texture(x_high, y_low )*   x_weight_high);
+          b = ( texture(x_low,  y_high)*(1-x_weight_high) +
+                texture(x_high, y_high)*   x_weight_high);
+          results[i] = a*(1-y_weight_high) + b*y_weight_high;
+        }
+      }
+      break;
+    case NearestNeighbor:
+      {
+        for( int i = 0; i < rays.getSize(); ++i) {
+          int tx = NN_edge_behavior(static_cast<int>(tex_coords[i].x()*xres),
+                                    u_edge, texture.dim1());
+          int ty = NN_edge_behavior(static_cast<int>(tex_coords[i].y()*yres),
+                                    v_edge, texture.dim2());
+          results[i] = texture(tx, ty);
+        }
+      }
+      break;
+    }
+  } // end mapValues
+
+  template< class ValueType >
+  void ImageTexture< ValueType >::setEdgeBehavior(int new_behavior,
+                                                  int& edge) {
+    switch (new_behavior) {
+    case Wrap:
+    case Clamp:
+      edge = new_behavior;
+      break;
+    default:
+      throw SCIRun::InternalError( "ImageTexture::setEdgeBehavior doesn't 
support this edge behavior", __FILE__, __LINE__);
+      break;
+    }
+  }
+
+  template< class ValueType >
+  void ImageTexture< ValueType >::setInterpolationMethod(int new_method) {
+    switch (new_method) {
+    case NearestNeighbor:
+    case Bilinear:
+      interpolation_method = new_method;
+      break;
+    default:
+      throw SCIRun::InternalError( "ImageTexture::setInterpolationMethod 
doesn't support this interpolation method", __FILE__, __LINE__);
+      break;
+    }
+  }
+  
+} // end namespace Manta
 
 #endif // Manta_Model_ImageTexture_h

Modified: trunk/Model/Textures/MarbleTexture.cc
==============================================================================
--- trunk/Model/Textures/MarbleTexture.cc       (original)
+++ trunk/Model/Textures/MarbleTexture.cc       Mon Dec 12 17:07:44 2005
@@ -1,53 +1,7 @@
 
 #include <Model/Textures/MarbleTexture.h>
-#include <Interface/RayPacket.h>
-#include <Core/Geometry/PointVector.h>
-#include <Core/Math/Noise.h>
-#include <Core/Math/MiscMath.h>
-#include <Core/Math/Trig.h>
 
 namespace Manta {
 
-  template< class ValueType >
-  MarbleTexture< ValueType >::MarbleTexture(
-      ValueType const &value1,
-      ValueType const &value2,
-      Real const scale,
-      Real const fscale,
-      Real const tscale,
-      int const octaves,
-      Real const lacunarity,
-      Real const gain )
-    : value1( value1 ),
-      value2( value2 ),
-      scale ( scale ),
-      fscale( fscale ),
-      tscale( tscale ),
-      octaves( octaves ),
-      lacunarity( lacunarity ),
-      gain( gain )
-  {
-  }
-  
-  template< class ValueType >
-  MarbleTexture< ValueType >::~MarbleTexture()
-  {
-  }
-  
-  template< class ValueType >
-  void MarbleTexture< ValueType >::mapValues(
-    RenderContext const &context,
-    RayPacket &rays,
-    ValueType results[] ) const
-  {
-    rays.computeTextureCoordinates3( context );
-    for( int i = 0; i < rays.getSize(); i++ ) {
-      RayPacket::Element &e = rays.get( i );
-      Point T = e.texCoords.multipliedBy(scale * fscale);
-      ColorComponent value = (Real)0.25 *
-        Cos( e.texCoords.x() * scale + tscale *
-             (Real)Turbulence( T, octaves, lacunarity, gain ) );
-      results[ i ] = SCIRun::Interpolate( value1, value2, value );
-    }
-  }
+
 }

Modified: trunk/Model/Textures/MarbleTexture.h
==============================================================================
--- trunk/Model/Textures/MarbleTexture.h        (original)
+++ trunk/Model/Textures/MarbleTexture.h        Mon Dec 12 17:07:44 2005
@@ -3,6 +3,12 @@
 #define Manta_Model_MarbleTexture_h
 
 #include <Interface/Texture.h>
+#include <Interface/RayPacket.h>
+#include <Core/Geometry/PointVector.h>
+#include <Core/Math/Noise.h>
+#include <Core/Math/MiscMath.h>
+#include <Core/Math/Trig.h>
+
 
 namespace Manta {
   class RayPacket;
@@ -39,11 +45,49 @@
     Real lacunarity;
     Real gain;
   };
-}
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/MarbleTexture.cc>
-#endif
+  template< class ValueType >
+  MarbleTexture< ValueType >::MarbleTexture(
+      ValueType const &value1,
+      ValueType const &value2,
+      Real const scale,
+      Real const fscale,
+      Real const tscale,
+      int const octaves,
+      Real const lacunarity,
+      Real const gain )
+    : value1( value1 ),
+      value2( value2 ),
+      scale ( scale ),
+      fscale( fscale ),
+      tscale( tscale ),
+      octaves( octaves ),
+      lacunarity( lacunarity ),
+      gain( gain )
+  {
+  }
+  
+  template< class ValueType >
+  MarbleTexture< ValueType >::~MarbleTexture()
+  {
+  }
+  
+  template< class ValueType >
+  void MarbleTexture< ValueType >::mapValues(
+    RenderContext const &context,
+    RayPacket &rays,
+    ValueType results[] ) const
+  {
+    rays.computeTextureCoordinates3( context );
+    for( int i = 0; i < rays.getSize(); i++ ) {
+      RayPacket::Element &e = rays.get( i );
+      Point T = e.texCoords.multipliedBy(scale * fscale);
+      ColorComponent value = (Real)0.25 *
+        Cos( e.texCoords.x() * scale + tscale *
+             (Real)Turbulence( T, octaves, lacunarity, gain ) );
+      results[ i ] = SCIRun::Interpolate( value1, value2, value );
+    }
+  }
+}
 
 #endif

Modified: trunk/Model/Textures/OakTexture.cc
==============================================================================
--- trunk/Model/Textures/OakTexture.cc  (original)
+++ trunk/Model/Textures/OakTexture.cc  Mon Dec 12 17:07:44 2005
@@ -1,90 +1,7 @@
 
 #include <Model/Textures/OakTexture.h>
-#include <Interface/RayPacket.h>
-#include <Core/Geometry/PointVector.h>
-#include <Core/Math/Noise.h>
-#include <Core/Math/MiscMath.h>
-
 namespace Manta {
 
-  template< class ValueType >
-  OakTexture< ValueType >::OakTexture(
-      ValueType const &value1,
-      ValueType const &value2,
-      double const ringfreq,
-      double const ringunevenness,
-      double const grainfreq,
-      double const ringnoise,
-      double const ringnoisefreq,
-      double const trunkwobble,
-      double const trunkwobblefreq,
-      double const angularwobble,
-      double const angularwobblefreq,
-      double const ringy,
-      double const grainy )
-    : value1( value1 ),
-      value2( value2 ),
-      ringfreq( ringfreq ),
-      ringunevenness( ringunevenness ),
-      grainfreq( grainfreq ),
-      ringnoise( ringnoise ),
-      ringnoisefreq( ringnoisefreq ),
-      trunkwobble( trunkwobble ),
-      trunkwobblefreq( trunkwobblefreq ),
-      angularwobble( angularwobble ),
-      angularwobblefreq( angularwobblefreq ),
-      ringy( ringy ),
-      grainy( grainy )
-  {
-  }
-
-  template< class ValueType >
-  OakTexture< ValueType >::~OakTexture()
-  {
-  }
-
-  template< class ValueType >
-  void OakTexture< ValueType >::mapValues(
-    RenderContext const &context,
-    RayPacket &rays,
-    ValueType results[] ) const
-  {
-    using SCIRun::Clamp;
-    using SCIRun::Interpolate;
-    using SCIRun::SmoothStep;
-    rays.computeTextureCoordinates3( context );
-    for( int i = 0; i < rays.getSize(); i++ ) {
-      RayPacket::Element &e = rays.get( i );
 
-      Vector offset = VectorFBM( e.texCoords.multipliedBy(ringnoisefreq), 2, 
4.0, 0.5 );
-      Point Pring = e.texCoords + ringnoise * offset;
-      Vector vsnoise = VectorNoise( Point( 0.5, 0.5, e.texCoords.z() * 
trunkwobblefreq ) );
-      Pring += Vector( trunkwobble * vsnoise.x(), trunkwobble * vsnoise.y(), 
0.0 );
-      double r = sqrt( Pring.x() * Pring.x() + Pring.y() * Pring.y() ) * 
ringfreq;
-      r += angularwobble * SmoothStep( r, 0, 5 ) * ScalarNoise( Point( 
angularwobble * Pring.x(),
-                                                                       
angularwobble * Pring.y(),
-                                                                       
angularwobble * Pring.z() * 0.1 ) );
-      r += 0.5 * ScalarNoise( Point( 0.5, 0.5, r ) );
-      double rfrac = r - floor( r );
-      double inring = SmoothStep( rfrac, 0.1, 0.55 ) - SmoothStep( rfrac, 
0.7, 0.95 );
-      Point Pgrain( e.texCoords.multipliedBy(Vector(grainfreq, grainfreq, 
grainfreq*0.05)));
-      double grain = 0.0;
-      double amp = 1.0;
-      for ( int it = 0; it < 2; ++it )
-      {
-          double g = 0.8 * ScalarNoise( Pgrain );
-          g *= ( 0.3 + 0.7 * inring );
-          g = Clamp( 0.8 - g, 0.0, 1.0 );
-          g = grainy * SmoothStep( g * g, 0.5, 1.0 );
-          if ( it == 0 )
-              inring *= 0.7;
-          grain = max( grain, g );
-          Pgrain.multiplyBy(2.0);
-          amp *= 0.5;
-      }
-      double value = Interpolate( 1.0, grain, inring * ringy );
-      results[ i ] = Interpolate( value2, value1, value );
-    }
-  }
 
 }

Modified: trunk/Model/Textures/OakTexture.h
==============================================================================
--- trunk/Model/Textures/OakTexture.h   (original)
+++ trunk/Model/Textures/OakTexture.h   Mon Dec 12 17:07:44 2005
@@ -3,6 +3,11 @@
 #define Manta_Model_OakTexture_h
 
 #include <Interface/Texture.h>
+#include <Interface/RayPacket.h>
+#include <Core/Geometry/PointVector.h>
+#include <Core/Math/Noise.h>
+#include <Core/Math/MiscMath.h>
+
 
 namespace Manta {
   class RayPacket;
@@ -49,11 +54,87 @@
     double const ringy;
     double const grainy;
   };
-}
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/OakTexture.cc>
-#endif
+
+  template< class ValueType >
+  OakTexture< ValueType >::OakTexture(
+      ValueType const &value1,
+      ValueType const &value2,
+      double const ringfreq,
+      double const ringunevenness,
+      double const grainfreq,
+      double const ringnoise,
+      double const ringnoisefreq,
+      double const trunkwobble,
+      double const trunkwobblefreq,
+      double const angularwobble,
+      double const angularwobblefreq,
+      double const ringy,
+      double const grainy )
+    : value1( value1 ),
+      value2( value2 ),
+      ringfreq( ringfreq ),
+      ringunevenness( ringunevenness ),
+      grainfreq( grainfreq ),
+      ringnoise( ringnoise ),
+      ringnoisefreq( ringnoisefreq ),
+      trunkwobble( trunkwobble ),
+      trunkwobblefreq( trunkwobblefreq ),
+      angularwobble( angularwobble ),
+      angularwobblefreq( angularwobblefreq ),
+      ringy( ringy ),
+      grainy( grainy )
+  {
+  }
+
+  template< class ValueType >
+  OakTexture< ValueType >::~OakTexture()
+  {
+  }
+
+  template< class ValueType >
+  void OakTexture< ValueType >::mapValues(
+    RenderContext const &context,
+    RayPacket &rays,
+    ValueType results[] ) const
+  {
+    using SCIRun::Clamp;
+    using SCIRun::Interpolate;
+    using SCIRun::SmoothStep;
+    rays.computeTextureCoordinates3( context );
+    for( int i = 0; i < rays.getSize(); i++ ) {
+      RayPacket::Element &e = rays.get( i );
+
+      Vector offset = VectorFBM( e.texCoords.multipliedBy(ringnoisefreq), 2, 
4.0, 0.5 );
+      Point Pring = e.texCoords + ringnoise * offset;
+      Vector vsnoise = VectorNoise( Point( 0.5, 0.5, e.texCoords.z() * 
trunkwobblefreq ) );
+      Pring += Vector( trunkwobble * vsnoise.x(), trunkwobble * vsnoise.y(), 
0.0 );
+      double r = sqrt( Pring.x() * Pring.x() + Pring.y() * Pring.y() ) * 
ringfreq;
+      r += angularwobble * SmoothStep( r, 0, 5 ) * ScalarNoise( Point( 
angularwobble * Pring.x(),
+                                                                       
angularwobble * Pring.y(),
+                                                                       
angularwobble * Pring.z() * 0.1 ) );
+      r += 0.5 * ScalarNoise( Point( 0.5, 0.5, r ) );
+      double rfrac = r - floor( r );
+      double inring = SmoothStep( rfrac, 0.1, 0.55 ) - SmoothStep( rfrac, 
0.7, 0.95 );
+      Point Pgrain( e.texCoords.multipliedBy(Vector(grainfreq, grainfreq, 
grainfreq*0.05)));
+      double grain = 0.0;
+      double amp = 1.0;
+      for ( int it = 0; it < 2; ++it )
+      {
+          double g = 0.8 * ScalarNoise( Pgrain );
+          g *= ( 0.3 + 0.7 * inring );
+          g = Clamp( 0.8 - g, 0.0, 1.0 );
+          g = grainy * SmoothStep( g * g, 0.5, 1.0 );
+          if ( it == 0 )
+              inring *= 0.7;
+          grain = max( grain, g );
+          Pgrain.multiplyBy(2.0);
+          amp *= 0.5;
+      }
+      double value = Interpolate( 1.0, grain, inring * ringy );
+      results[ i ] = Interpolate( value2, value1, value );
+    }
+  }
+}
 
 #endif

Modified: trunk/Model/Textures/TriVerTexture.cc
==============================================================================
--- trunk/Model/Textures/TriVerTexture.cc       (original)
+++ trunk/Model/Textures/TriVerTexture.cc       Mon Dec 12 17:07:44 2005
@@ -1,9 +1,8 @@
 
 #include <Model/Textures/TriVerTexture.h>
-#include <Interface/RayPacket.h>
-#include <Model/Primitives/VertexColoredTriangle.h>
 
 namespace Manta {
+
   TriVerTexture::TriVerTexture()
   {
   }
@@ -27,5 +26,5 @@
       results[i] = vct->getVertexColor(0)*(1 - th.a - th.b) + 
                    vct->getVertexColor(1)*th.a + vct->getVertexColor(2)*th.b;
     }
-  }
+  }  
 }

Modified: trunk/Model/Textures/TriVerTexture.h
==============================================================================
--- trunk/Model/Textures/TriVerTexture.h        (original)
+++ trunk/Model/Textures/TriVerTexture.h        Mon Dec 12 17:07:44 2005
@@ -1,8 +1,10 @@
+
 #ifndef Manta_Model_TriVerTexture_h
 #define Manta_Model_TriVerTexture_h
 
 #include <Interface/Texture.h>
-
+#include <Model/Primitives/VertexColoredTriangle.h>
+#include <Interface/RayPacket.h>
 
 //TriVerTexture returns a color interpolated from three vertices.
 
@@ -21,11 +23,8 @@
     TriVerTexture(const TriVerTexture&);
     TriVerTexture& operator=(const TriVerTexture&);
   };
+
 }
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/TriVerTexture.cc>
-#endif
 
 #endif

Modified: trunk/Model/Textures/WoodTexture.cc
==============================================================================
--- trunk/Model/Textures/WoodTexture.cc (original)
+++ trunk/Model/Textures/WoodTexture.cc Mon Dec 12 17:07:44 2005
@@ -1,55 +1,5 @@
 
-#include <Model/Textures/WoodTexture.h>
-#include <Interface/RayPacket.h>
-#include <Core/Geometry/PointVector.h>
-#include <Core/Math/Noise.h>
-#include <Core/Math/MiscMath.h>
-
-namespace Manta {
 
-  template< class ValueType >
-  WoodTexture< ValueType >::WoodTexture(
-      ValueType const &value1,
-      ValueType const &value2,
-      double const scale,
-      double const rscale,
-      double const tscale,
-      double const sharpness,
-      int const octaves,
-      double const lacunarity,
-      double const gain )
-    : value1( value1 ),
-      value2( value2 ),
-      scale ( scale ),
-      rscale( rscale ),
-      tscale( tscale ),
-      sharpness( sharpness ),
-      octaves( octaves ),
-      lacunarity( lacunarity ),
-      gain( gain )
-  {
-  }
-  
-  template< class ValueType >
-  WoodTexture< ValueType >::~WoodTexture()
-  {
-  }
+#include <Model/Textures/WoodTexture.h>
 
-  template< class ValueType >
-  void WoodTexture< ValueType >::mapValues(
-    RenderContext const &context,
-    RayPacket &rays,
-    ValueType results[] ) const
-  {
-    rays.computeTextureCoordinates3( context );
-    for( int i = 0; i < rays.getSize(); i++ ) {
-      RayPacket::Element &e = rays.get( i );
-      Point T = e.texCoords.multipliedBy(scale);
-      double distance = sqrt( T.x() * T.x() + T.y() * T.y() ) * rscale;
-      double fbm = tscale * ScalarFBM( T, octaves, lacunarity, gain );
-      double value = 0.5 * cos( distance + fbm ) + 0.5;
-      results[ i ] = SCIRun::Interpolate( value2, value1, pow( value, 
sharpness ) );
-    }
-  }
 
-}

Modified: trunk/Model/Textures/WoodTexture.h
==============================================================================
--- trunk/Model/Textures/WoodTexture.h  (original)
+++ trunk/Model/Textures/WoodTexture.h  Mon Dec 12 17:07:44 2005
@@ -3,6 +3,11 @@
 #define Manta_Model_WoodTexture_h
 
 #include <Interface/Texture.h>
+#include <Interface/RayPacket.h>
+#include <Core/Geometry/PointVector.h>
+#include <Core/Math/Noise.h>
+#include <Core/Math/MiscMath.h>
+
 
 namespace Manta {
   class RayPacket;
@@ -41,11 +46,52 @@
     double lacunarity;
     double gain;
   };
-}
 
-#ifdef __GNUG__
-// This should instead be a configure variable...
-#include <Model/Textures/WoodTexture.cc>
-#endif
+  template< class ValueType >
+  WoodTexture< ValueType >::WoodTexture(
+      ValueType const &value1,
+      ValueType const &value2,
+      double const scale,
+      double const rscale,
+      double const tscale,
+      double const sharpness,
+      int const octaves,
+      double const lacunarity,
+      double const gain )
+    : value1( value1 ),
+      value2( value2 ),
+      scale ( scale ),
+      rscale( rscale ),
+      tscale( tscale ),
+      sharpness( sharpness ),
+      octaves( octaves ),
+      lacunarity( lacunarity ),
+      gain( gain )
+  {
+  }
+  
+  template< class ValueType >
+  WoodTexture< ValueType >::~WoodTexture()
+  {
+  }
+
+  template< class ValueType >
+  void WoodTexture< ValueType >::mapValues(
+    RenderContext const &context,
+    RayPacket &rays,
+    ValueType results[] ) const
+  {
+    rays.computeTextureCoordinates3( context );
+    for( int i = 0; i < rays.getSize(); i++ ) {
+      RayPacket::Element &e = rays.get( i );
+      Point T = e.texCoords.multipliedBy(scale);
+      double distance = sqrt( T.x() * T.x() + T.y() * T.y() ) * rscale;
+      double fbm = tscale * ScalarFBM( T, octaves, lacunarity, gain );
+      double value = 0.5 * cos( distance + fbm ) + 0.5;
+      results[ i ] = SCIRun::Interpolate( value2, value1, pow( value, 
sharpness ) );
+    }
+  }
+
+}
 
 #endif

Modified: trunk/fox/FMantaWindow.cc
==============================================================================
--- trunk/fox/FMantaWindow.cc   (original)
+++ trunk/fox/FMantaWindow.cc   Mon Dec 12 17:07:44 2005
@@ -185,7 +185,7 @@
   frame = new FXHorizontalFrame( controls, LAYOUT_FILL_X );
   new FXLabel( frame, "Control Speed: " );
   speed_slider = new FXRealSlider( frame, this, ID_SPEED_SLIDER, 
REALSLIDER_HORIZONTAL|LAYOUT_FILL_X );
-  speed_slider->setRange( 0.001, 10.0 );
+  speed_slider->setRange( 0.001, 15.0 );
   speed_slider->setIncrement( 0.001 );
   speed_slider->setValue( 1.0 );
        

Modified: trunk/fox/dm_demo.cc
==============================================================================
--- trunk/fox/dm_demo.cc        (original)
+++ trunk/fox/dm_demo.cc        Mon Dec 12 17:07:44 2005
@@ -353,7 +353,7 @@
   scene->setBackground(new 
ConstantBackground(ColorDB::getNamedColor("SkyBlue3")*0.5));
   Material* red=new Phong(Color(RGBColor(.6,0,0)),
                           Color(RGBColor(.6,.6,.6)), 32, 
(ColorComponent)0.4);
-       
+
   Material* plane_matl = new Phong(new 
CheckerTexture<Color>(Color(RGBColor(.6,.6,.6)),
                                                                              
                                                                              
                                                                              
       Color(RGBColor(0,0,0)),
                                                                              
                                                                              
                                                                              
       Vector(1,0,0),
@@ -366,10 +366,10 @@
                                     Vector(1,0,0),
                                     Vector(0,1,0)));
        
-       
   Group* world = new Group();
   Primitive* floor = new Parallelogram(plane_matl, Point(-20,-20,0),
-                                                                             
                                                                           
Vector(40,0,0), Vector(0,40,0));
+                                                                             
                                                                           
Vector(40,0,0), Vector(0,40,0));
+
   // Setup world-space texture coordinates for the checkerboard floor
   UniformMapper* uniformmap = new UniformMapper();
   floor->setTexCoordMapper(uniformmap);

Modified: trunk/scenes/objviewer.cc
==============================================================================
--- trunk/scenes/objviewer.cc   (original)
+++ trunk/scenes/objviewer.cc   Mon Dec 12 17:07:44 2005
@@ -1,4 +1,32 @@
 
+/*
+  For more information, please see: http://software.sci.utah.edu
+
+  The MIT License
+
+  Copyright (c) 2005
+  Scientific Computing and Imaging Institute, University of Utah
+
+  License for the specific language governing rights and limitations under
+  Permission is hereby granted, free of charge, to any person obtaining a
+  copy of this software and associated documentation files (the "Software"),
+  to deal in the Software without restriction, including without limitation
+  the rights to use, copy, modify, merge, publish, distribute, sublicense,
+  and/or sell copies of the Software, and to permit persons to whom the
+  Software is furnished to do so, subject to the following conditions:
+
+  The above copyright notice and this permission notice shall be included
+  in all copies or substantial portions of the Software.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+  THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+  DEALINGS IN THE SOFTWARE.
+*/
+
 #include <MantaTypes.h>
 
 #include <Core/Geometry/PointVector.h>
@@ -10,8 +38,13 @@
 #include <Interface/MantaInterface.h>
 #include <Interface/Scene.h>
 #include <Interface/Material.h>
+#include <Interface/Context.h>
+
+#include <SCIRun/Core/Thread/Time.h>
 
 #include <Model/Primitives/Triangle.h>
+#include <Model/Primitives/HeavyTriangle.h>
+#include <Model/Primitives/TexTriangle.h>
 #include <Model/Primitives/Parallelogram.h>
 #include <Model/Primitives/Cube.h>
 #include <Model/Primitives/BvhTriangleMesh.h>
@@ -19,6 +52,7 @@
 #include <Model/Materials/Phong.h>
 #include <Model/Materials/Dielectric.h>
 #include <Model/Materials/NormalMaterial.h>
+#include <Model/Materials/Flat.h>
 #include <Model/Groups/Group.h>
 #include <Model/Groups/RealisticBvh.h>
 #include <Model/Lights/HeadLight.h>
@@ -27,8 +61,12 @@
 #include <Model/Readers/glm/glm.h>
 #include <Model/Textures/CheckerTexture.h>
 #include <Model/Textures/Constant.h>
+#include <Model/Textures/ImageTexture.h>
+#include <Model/Textures/TexCoordTexture.h>
+#include <Model/Cameras/PinholeCamera.h>
 
-#include <SCIRun/Core/Thread/Time.h>
+#include <Image/TGAFile.h>
+#include <Image/NRRDFile.h>
 
 #include <vector>
 #include <string>
@@ -38,21 +76,34 @@
 using namespace Manta;
 using namespace SCIRun;
 using namespace Glm;
-  
+
 static Object *create_single_bvh( GLMmodel *model );
 static Object *create_bvh_meshs ( GLMmodel *model );
+static void create_materials( GLMmodel *model );
+
+template< typename ValueType >
+static ImageTexture<ValueType> *load_image_texture( const string& file_name 
);
 
 static BBox bounds;
 
+typedef PointT<float,3> Pointf;
+
+static Material **material_array = 0;
+
+
+string file_name;
+bool use_single_bvh      = true;
+bool use_lambertian      = false;
+bool display_bounds      = false;
+bool fix_normals         = false;
+int  fix_normals_degrees = 90;
+bool flip_faces          = false;
 
 ///////////////////////////////////////////////////////////////////////////
 // This function loads a specified .obj file into a runtime acceleration
 // structure for rendering.
 extern "C" 
-Scene* make_scene(const ReadContext& /*context*/, const vector<string>& 
args) {
-
-       string file_name;
-       bool use_single_bvh = false;
+Scene* make_scene(const ReadContext& context, const vector<string>& args) {
 
        // Check the arguments.
        for (int i=0;i<args.size();++i) {
@@ -62,23 +113,64 @@
                        if (!getStringArg(i, args, file_name))
                                throw IllegalArgument("objviewer -file 
<filename>", i, args);
                }
-               if (args[i] == "-single") {
+               else if (args[i] == "-single") {
                        use_single_bvh = true;
                }
+    else if (args[i] == "-bounds") {
+      display_bounds = true;
+    }
+    else if (args[i] == "-lambertian") {
+      use_lambertian = true;
+    }
+    else if (args[i] == "-fixnormals") {
+      fix_normals = true;
+      
+      getIntArg( i, args, fix_normals_degrees );
+    }
+    else if (args[i] == "-flip") {
+      flip_faces = true;
+    }
        }
-       
+
+  
/////////////////////////////////////////////////////////////////////////////
        // Load in the file using glm.
        GLMmodel *model = glmReadOBJ( file_name.c_str() );
        if (model == 0) {
                std::cout << "Error cannot read model from file." << 
std::endl;
                return 0;
        }
-       
+
        // Flip the face winding.
-       glmReverseWinding( model );
-       
-       Object *bvh = 0;
-       
+  if (flip_faces) {
+    glmReverseWinding( model );
+  }
+
+  // Compute vertex normals.
+  if (fix_normals) {
+    glmFacetNormals( model );
+    glmVertexNormals( model, fix_normals_degrees );
+  }
+
+  // Compute model bounds
+  Pointf bmax, bmin;
+  glmBoundingBox( model, (float *)&bmin, (float *)&bmax );
+
+  
/////////////////////////////////////////////////////////////////////////////
+  // Center the model
+  Vector translate = ((Vector(bmax) + Vector(bmin)) * 0.5);
+
+  std::cerr << "Min: " << bmin << " Max: " << bmax << " translate: " << 
translate << std::endl;
+  
+  Pointf *vertex;  
+  for (int i=0;i<model->numvertices;++i) {
+    vertex = (Pointf *)&model->vertices[i*3];
+
+    (*vertex) = (*vertex) - translate;
+  }
+
+  
/////////////////////////////////////////////////////////////////////////////
+  // Create the bvh.
+       Object *bvh = 0;        
        if (use_single_bvh) 
                bvh = create_single_bvh( model );
        else 
@@ -90,84 +182,217 @@
        
        // Add a head light.
        LightSet *lights = new LightSet();
-       lights->add( new HeadLight( 2.0, Color(RGB(1.0,1.0,1.0)) ));
-       lights->setAmbientLight( new ConstantAmbient( Color(RGB(0.2,0.2,0.2) 
) ));
+       lights->add( new HeadLight( 0.0, Color(RGB(1.0,1.0,1.0)) ));
+       lights->setAmbientLight( new ConstantAmbient( Color(RGB(0.4,0.4,0.4) 
) ));
        scene->setLights( lights );
        
-  //   Material* red=new Lambertian(Color(RGBColor(.6,0,0)));
+  Material* red=new Lambertian(Color(RGBColor(.6,0,0)));
        Material* yellow=new Lambertian(Color(RGBColor(.6,.6,0)));
-       
-       
+
+  // Add a floor.
   Parallelogram* floor = new Parallelogram(yellow, 
Point(-20,-20,bounds[0][2]),
                                                                              
                                                                           
Vector(40,0,0), Vector(0,40,0));
        Group *manta_group = new Group();
-       manta_group->add( floor );
-       // manta_group->add( new Cube( red, bounds[0], bounds[1] ) );
-       manta_group->add( bvh );
+       // manta_group->add( floor );
+
+  if (display_bounds) {
+    manta_group->add( new Cube( red, bounds[0], bounds[1] ) );
+  }
+  else {
+    manta_group->add( bvh );
+  }
        
        // Add the bvh to the scene.
        scene->setObject( manta_group );
        
        // Background.
        scene->setBackground( new ConstantBackground( Color(RGB(0.8, 0.8, 
0.8)) ) );
-       
+
        return scene;
 }
 
-static Material **material_array = 0;
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// Texture loading functions
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// Load a Color texture from a nrrd.
+template<>
+ImageTexture<Color> *load_image_texture<Color>( const string& file_name ) {
+
+  Image *image = 0;
+
+  // Load the image.
+  if (file_name.rfind(".tga") == (file_name.size()-4)) {
+    // Try to read a tga file.
+    image = readTGA( file_name );
+  }
+  else {
+    // Try reading the image using teem.
+    image = readNRRD( file_name );
+  }
+    
+  // Create the texture.
+  ImageTexture<Color> *texture = new ImageTexture<Color>( image );
+
+  // Free time image.
+  delete image;
+
+  return texture;
+}
+
+// Check to see if the specified file can be loaded, otherwise use the 
specified color.
+Texture<Color> *check_for_texture( const string &path_name, const string 
&file_name, const Color &constant_color ) {
 
+  Texture<Color> *texture = 0;
+
+  if (file_name.size()) {
+    // Load the image texture.
+    try {
+      texture = load_image_texture<Color>( path_name + file_name );
+      // texture = new TexCoordTexture;
+    }
+    catch (SCIRun::Exception &e) {
+      std::cerr << "Could not load diffuse map: "
+                << file_name
+                << ": " << e.message() << std::endl;
+    }
+  }
+  
+  if (texture == 0) {
+    // Otherwise use a constant color.
+    texture = new Constant<Color>( constant_color );
+  }
+
+  return texture;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+// Create Materials from the obj file
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
 static void create_materials( GLMmodel *model ) {
 
+  
/////////////////////////////////////////////////////////////////////////////
+  // Path to the model for loading textures.
+  string model_path = model->pathname;
+
+  int pos = model_path.rfind( '/' );
+  if (pos != string::npos) {
+    model_path = model_path.substr( 0, pos+1 );
+  }
+  
        material_array = new Material *[ model->nummaterials ];
 
        // Read in the materials.
        for (int i=0;i<model->nummaterials;++i) {
-               
-               float c0 = model->materials[i].diffuse[0];
-               float c1 = model->materials[i].diffuse[1];
-               float c2 = model->materials[i].diffuse[2];
-               
-               Color diffuse(RGB( c0, c1, c2 ));
-               
-// #if 0               
-               // Check the material name.
+
+    
///////////////////////////////////////////////////////////////////////////
+    // Copy out material attributes.
                string mtl_name = model->materials[i].name;
-               if (mtl_name.find("Clear")==0) {
-               
-                       // Note that the first material added by blender is 
always an
-                       // unused default material..
-                       material_array[i-1] = new Dielectric( (Real)1.1, 
(Real)1.0, diffuse );
-                       // material_array[i-1] = new Dielectric( diffuse, 
Color(RGB(0.6,0.6,0.6)), Color(RGB(log(c0),log(c1),log(c2))), 28, 1.3, 1.0 );
-               }
-               else {
-                       // material_array[i-1] = new Lambertian( diffuse );
-                       material_array[i-1] = new Phong( diffuse, 
Color(RGB(1,1,1)), 32, 0 );
-               }
-// #endif              
-               // material_array[i-1] = new Lambertian( diffuse );
+
+    // Color ambient (RGB( model->materials[i].ambient[0],
+    //                     model->materials[i].ambient[1],
+    //                     model->materials[i].ambient[2] ));
+
+    Color diffuse (RGB( model->materials[i].diffuse[0],
+                        model->materials[i].diffuse[1],
+                        model->materials[i].diffuse[2] ));
+    Color specular(RGB( model->materials[i].specular[0],
+                        model->materials[i].specular[1],
+                        model->materials[i].specular[2] ));
+
+    float Ns     = model->materials[i].shininess;
+    float Tr     = model->materials[i].refraction;
+    float alpha  = model->materials[i].alpha;
+    int   shader = model->materials[i].shader;
+
+    // Copy out texture names.
+    // string ambient_map_name  = (model->materials[i].ambient_map[0]  != 
'\0') ?
+    //   model->materials[i].ambient_map : "";
+    string diffuse_map_name  = (model->materials[i].diffuse_map[0]  != '\0') 
?
+      model->materials[i].diffuse_map : "";
+    string specular_map_name = (model->materials[i].specular_map[0] != '\0') 
?
+      model->materials[i].specular_map : "";    
+    
+    // Note that the first material added by blender is always an
+    // unused default material..
+    int index = i-1;
+
+
+
+    Texture<Color> *diffuse_map  = check_for_texture( model_path, 
diffuse_map_name, diffuse );
+    
+    // Lambertian Shader.
+    material_array[index] = new Flat( diffuse_map );
+
+#if 0
+
+    
///////////////////////////////////////////////////////////////////////////
+    // Check for a dielectric.
+    if (Tr != 0) {
+
+      // Constant textures for refraction parameters.
+      Texture<Real> *n  = new Constant<Real>( 1.0 );
+      Texture<Real> *nt = new Constant<Real>( Tr );
+      Texture<Color> *diffuse_map = check_for_texture( model_path, 
diffuse_map_name, diffuse );
+
+      // Create a dielectric shader.
+      material_array[index] = new Dielectric( n, nt, diffuse_map );
+    }
+
+    
///////////////////////////////////////////////////////////////////////////
+    // Check for a specular term.
+    else if (Ns != 0) {
+
+      Texture<Color> *diffuse_map  = check_for_texture( model_path, 
diffuse_map_name, diffuse );
+      Texture<Color> *specular_map = check_for_texture( model_path, 
specular_map_name, specular );
+      Texture<ColorComponent> *reflection = new Constant<ColorComponent>( 
0.2 );
+
+      // Phong shader.
+      material_array[index] = new Phong( diffuse_map, specular_map, Ns, 
reflection );      
+    }
+
+    
///////////////////////////////////////////////////////////////////////////
+    // Use a lambertian shader.
+    else {
+      Texture<Color> *diffuse_map  = check_for_texture( model_path, 
diffuse_map_name, diffuse );
+
+      // Lambertian Shader.
+      material_array[index] = new Lambertian( diffuse_map );
+    }
+#endif 
        }
-}
 
+}
 
 
///////////////////////////////////////////////////////////////////////////////
 // Create a single bvh to contain the mesh.
 Object *create_single_bvh( GLMmodel *model ) {
 
-       Triangle *triangle_array;
+       TexTriangle *triangle_array;
        
        
/////////////////////////////////////////////////////////////////////////////
        // Allocate storage for primitives and materials.
        int total_triangles = model->numtriangles;
-       triangle_array = new Triangle[ total_triangles ];
+       triangle_array = new TexTriangle[ total_triangles ];
        
        create_materials( model );
        
        int tri = 0;
        int mtl = 0;
-       
-       // Lambertian *default_material = new Lambertian( Color(RGB( 1.0, 
0.0, 0.0 ) )  );
-       Material *default_material = new NormalMaterial();
-       
+
+  Material *default_material = 0;
+  if (use_lambertian) {
+    default_material = new Lambertian( Color(RGB( 1.0, 0.0, 0.0 ) )  );
+  }
+  else {
+    default_material = new NormalMaterial();
+  }
+
+  
        // Read in the groups.
        GLMgroup *group = model->groups;
        while (group != 0) {
@@ -185,7 +410,13 @@
                int total_faces = group->numtriangles;
                for (int i=0;i<total_faces;++i) {
                        
-                       Point vertex[3];
+                       Point  vertex[3];
+      Vector normal[3];
+      Vector texcoord[3];
+
+      // Only use two texture coords.
+      texcoord[2] = Vector( 0, 0, 0 );
+
                        for (int v=0;v<3;++v) {
                                int    index = model->triangles[ 
group->triangles[i] ].vindices[v];
                                float *f     = model->vertices+(index*3);
@@ -194,11 +425,38 @@
                                vertex[v][0] = f[0];
                                vertex[v][1] = f[1];
                                vertex[v][2] = f[2];
+
+        index = model->triangles[ group->triangles[i] ].nindices[v];
+        f = model->normals+(index*3);
+
+        // Copy out the normal.
+        normal[v][0] = f[0];
+                               normal[v][1] = f[1];
+                               normal[v][2] = f[2];
+
+      }
+
+      for (int v=0; v<2; ++v) {
+        
+        int index = model->triangles[ group->triangles[i] ].tindices[v];
+        float *f = model->texcoords+(index*3);
+
+        // Copy out the texcoord
+        texcoord[v][0] = f[0];
+                               texcoord[v][1] = f[1];
+
                        }
                        
                        // Create a new triangle.
-                       triangle_array[tri++] = 
-                               Triangle( material, vertex[0], vertex[1], 
vertex[2] );
+                       triangle_array[tri] = 
+                               TexTriangle( material,
+                     vertex[0], vertex[1]-vertex[0], vertex[2]-vertex[0],
+                     normal[0], normal[1], normal[2],
+                     texcoord[0], texcoord[1], texcoord[2]
+                     );
+      triangle_array[tri].setTexCoordMapper( &triangle_array[tri] );
+
+      ++tri;
                }
                
                // Move to the next group.
@@ -460,4 +718,6 @@
        
        return obj;
 }
+
+
 




  • [MANTA] r771 - in trunk: . Core Core/Exceptions Image Interface Model/Groups Model/Materials Model/Primitives Model/Readers Model/Readers/glm Model/Textures fox scenes, abe, 12/12/2005

Archive powered by MHonArc 2.6.16.

Top of page