Index: /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.sln
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.sln	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.sln	(revision 774)
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GTGeometry", "GTGeometry.vcproj", "{A1B6E932-F612-4CBC-9260-DF91CD4E748F}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{A1B6E932-F612-4CBC-9260-DF91CD4E748F}.Debug.ActiveCfg = Debug|Win32
+		{A1B6E932-F612-4CBC-9260-DF91CD4E748F}.Debug.Build.0 = Debug|Win32
+		{A1B6E932-F612-4CBC-9260-DF91CD4E748F}.Release.ActiveCfg = Release|Win32
+		{A1B6E932-F612-4CBC-9260-DF91CD4E748F}.Release.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeConstructor.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeConstructor.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeConstructor.h	(revision 774)
@@ -0,0 +1,56 @@
+#ifndef __GEO_TREE_CONSTRUCTOR__
+#define __GEO_TREE_CONSTRUCTOR__
+
+#include "GeoTreeSimpSequence.h"
+#include "GeoMesh.h"
+
+namespace Geometry
+{
+/// Construction module for multiresolution tree models.
+/** This module stores general tree multiresolution representations using our own specific file format.
+	It takes as inputs the TreeSimplificationSequence computed by the TreeSimplification module and writes a file
+	with the simplification sequence.\n
+
+	The LodTree file begins with a line stating the name of the mesh with leaves it refers to and also the name of the mesh with the trunk and the name of the LodStrips file refered to this mesh.
+
+	File format:\n
+		-# Tree reference.\n
+		-# Number of collapses.\n
+		-# Number of triangles added to the model (new leaves).\n
+		-# Triangle data.
+		-# Collapses: the two leaves that collapses and the new leaf.\n
+		.
+	\n
+
+Inputs:\n
+	- The leaves collapse sequence computed by the simplification module (Geometry::TreeSimplificationSequence).
+	.	
+Outputs:\n
+	- The module writes a file with the simplification sequence.
+	.  */
+	class LodTreeConstructor : public Serializable
+	{
+	public:
+		/// Constructor, gets a mesh and a simplification sequence, and generates a multiresolution model.
+		LodTreeConstructor(const Mesh *, const TreeSimplificationSequence *); 
+
+		/// Class Destructor
+		~LodTreeConstructor(void);
+
+		/// Copy constructor
+		//LodTreeConstructor(const LodTreeConstructor&);
+
+		/// Assignment operator
+		//LodTreeConstructor& operator =(const LodTreeConstructor&);
+		
+		/// Saves the multiresolution model into a file. 
+		/// It writes the change sequence using the serializer as a parameter.
+		void Save (Serializer &s);
+
+		/// Load 
+		void Load(Serializer &s);
+	};
+
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializable.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializable.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializable.h	(revision 774)
@@ -0,0 +1,28 @@
+#ifndef __GEO_SERIALIZABLE_H__
+#define __GEO_SERIALIZABLE_H__
+
+#include "GeoSerializer.h"
+
+namespace Geometry {
+
+	/// Serializable interface
+	/** Base class of objects to simplify input/output. */
+	class Serializable
+	{
+	public:
+
+		/// Copy constructor
+		//Serializable(const Serializable&);
+
+		/// Assignment operator
+		//Serializable& operator =(const Serializable&);
+
+		/// Loads data from a Serializer.
+		virtual void Load(Serializer &s) = 0;
+
+		/// Saves data to a Serializer.
+		virtual void Save(Serializer &s) = 0;
+	};
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSubMesh.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSubMesh.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSubMesh.h	(revision 774)
@@ -0,0 +1,53 @@
+#ifndef __GEO_SUBMESH__
+#define __GEO_SUBMESH__
+
+#include <vector>
+#include <ostream>
+
+#include "GeoBase.h"
+#include "GeoVertexBuffer.h"
+#include "GeoSerializable.h"
+
+namespace Geometry {
+
+	/// SubMesh interface
+	/** SubMesh is part of a Mesh, and stores vertex and index geometric information. */
+	class SubMesh : public Serializable
+	{
+	public:
+		/// Default constructor
+		SubMesh();
+
+		/// Default destructor
+		~SubMesh();
+
+		/// Copy constructor
+		//SubMesh(const SubMesh&);
+
+		/// Assignment operator
+		//SubMesh& operator =(const SubMesh&);
+
+		/// Loads data from a Serializer
+		void Load(Serializer &s);
+
+		/// Saves data to a Serializer
+		void Save(Serializer &s);
+
+		/// VertexBuffer used to store vertex Data. Is a reference to a shared VertexData if
+		/// mSharedVertexBuffer == true, and must be not deallocated in that case.
+		VertexBuffer *mVertexBuffer; 
+
+		bool mSharedVertexBuffer; ///< true if VertexBuffer it's shared with Mesh and other SubMeshes
+
+		Index  *mIndex;     ///< Array of Index 
+		size_t mIndexCount; ///< Index count
+		
+		Index  **mStrip;    ///< Array of pointers to mIndex that represents each strip
+		size_t mStripCount; ///< number of Strips
+
+		//OSCAR
+		std::vector <VertexBoneAssignment> mBones;
+	};
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVertexBuffer.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVertexBuffer.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVertexBuffer.h	(revision 774)
@@ -0,0 +1,51 @@
+#ifndef __GEO_VERTEX_BUFFER__
+#define __GEO_VERTEX_BUFFER__
+
+#include "GeoBase.h"
+#include "GeoVector3.h"
+#include "GeoVector2.h"
+#include "GeoSerializable.h"
+
+
+namespace Geometry {
+
+	/// VertexBuffer interface Class
+	/**
+	  * This Structure holds the vertex information used by Meshes and SubMesehs.
+	  */
+	class VertexBuffer : public Serializable
+	{
+	public:
+
+		/// Default Constructor
+		inline VertexBuffer(): 
+			mVertexInfo(VERTEX_EMPTY),
+			mVertexCount(0),
+			mPosition(0),
+			mNormal(0),
+			mTexCoords(0)
+		{
+		}
+
+		/// Default destructor, releases allocated memory.
+		~VertexBuffer();
+
+		/// Returns a new VertexBuffer with the same data.
+		VertexBuffer* Clone() const;
+
+		/// Fills this VertexBuffer from a Serializer
+		void Load(Serializer &s);
+
+		/// Stores data 
+		void Save(Serializer &s);
+		
+        unsigned int mVertexInfo;  ///< Type of info stored by vertex
+		size_t  mVertexCount;      ///< Number of vertices
+		Vector3 *mPosition; ///< Position array of each Vertex, only valid if (vertexInfo & VERTEX_POSITON) == true
+		Vector3 *mNormal;   ///< Normal array of each Vertex, only valid if (vertexInfo & VERTEX_NORMAL) == true
+		Vector2 *mTexCoords;///< Texture Coordinates array of each Vertex, only valid if (vertexInfo & VERTEX_TEXCOORDS) == true
+	};
+
+} // end of Geometry namespace;
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsLibrary.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsLibrary.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsLibrary.h	(revision 774)
@@ -0,0 +1,155 @@
+/*	==========================================================================
+ *	(C) 2005 Universidad Jaime I de Castellón
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:
+	*
+	*
+	*	@file	GeoLodStripsLibrary.h
+/*===========================================================================*/
+
+#include	"GeoMesh.h"
+#include	<vector>
+#include	<time.h>
+
+namespace Geometry
+{
+	//typedef unsigned long int SmallInt;
+	typedef unsigned long SmallInt;
+	typedef unsigned long			ULong;
+	typedef	long							Long;
+	
+	typedef struct
+	{
+		SmallInt strip;
+		SmallInt position;
+		SmallInt rep; //For the vertex repetition
+	} PositionType;
+
+	typedef	struct
+	{
+		unsigned	long	strip;
+		char						position;
+		char						vertexRepetition;
+		char						edgeRepetition;
+	}	LODRegisterType;
+
+	typedef struct
+	{
+		float Vertex[3];
+		SmallInt Next;
+	} VertexType;
+
+	typedef std::vector	<SmallInt>				SmallIntVector;
+	typedef	std::vector	<LODRegisterType>	LODRegisterVector;
+	typedef	std::vector	<Long>						LongVector;
+
+	/// LodStripsLibrary interface class.
+	/** This module contains functions that handle the levels of detail of the input multiresolution objects made of polygonal meshes. For any given resolution and object, this module returns a set of triangle strips representing the object at that resolution, that is, at the level of detail requested. These models use triangle strips to reduce storage usage and to speed up realistic rendering.
+	\n\n
+
+Inputs:\n
+	- The module receives a file describing a multiresolution object.
+	.
+
+Outputs:\n
+	- The module returns a strip set that represents the level of detail requested.
+	.
+
+	*/
+	class LodStripsLibrary
+	{
+		private:
+
+			String	mName; /// The name of the object.
+
+			///Structures with the data read from the file
+			///We won't work with these structures
+			SmallIntVector									mFileVertices;
+			std::vector	<LODRegisterType>		mFileChangesLOD;
+			std::vector	<SmallIntVector>		mFileStrips;
+			LongVector											mData;
+
+			///Structures with the data to work with
+			SmallInt	mTotalStrips;		///Total strips of the multiresolution object.
+			SmallInt	mTotalVertices;	///Total vertices of the multiresolution object.
+			SmallInt	mTotalChanges;	///Total changes of the multiresolution object.
+			SmallInt	mLods;					///Available Lods.
+			SmallInt	mMaxLod;				///Max level of detail.
+			SmallInt	mMinLod;				///Min level of detail.
+			SmallInt	mCurrentLod;		///Current Lod.
+
+			//	For the efficient version.
+			SmallInt				mTotalFaces;
+			SmallInt				*mCurrentData;
+			SmallInt				*mStripsChanges;
+			LODRegisterType	*mCurrentRegLOD;
+			SmallInt				*mVertex;
+		
+			//	Changes of Strips in LOD file (p).
+			SmallInt	*mPChanges;
+
+			///Total of vertices shown at the moment.
+			long	int	mTotal;
+
+			//	Global mesh object.
+			Mesh	*mGeoMesh;
+
+			/*
+				Copa STL vectors to C arrays.
+			*/
+			void	CopyVectors2Arrays();
+
+			/*
+				Loads Mesh
+			*/
+			void	LoadStripMesh(char *name, Mesh *geomesh);
+
+		public:
+
+			//	Strips vector.
+			SmallIntVector	*mStrips;
+			
+			/// Constructor, receives as a parameter the name of the file including the multiresolution object.
+			LodStripsLibrary(std::string, Mesh *geomesh);
+
+			/// Destructor.
+			~LodStripsLibrary(void);
+
+			/// Copy constructor
+			//LodStripsLibrary(const LodStripsLibrary&);
+
+			/// Assignment operator
+			//LodStripsLibrary& operator =(const LodStripsLibrary&);
+
+			/// Returns the highest LOD.
+			uint32	MaxLod();
+
+			/// Returns the lowest LOD.
+			uint32	MinLod();
+
+			/// Returns de current LOD and changes to the specified LOD.
+			uint32	GoToLod(uint32);
+
+			/// Establishes the new LOD range.
+			/// Only the LODs in that range are stored and used.
+			void		TrimByLod(uint32, uint32);
+
+			/// Returns the number of triangles of the highest LOD.
+			uint32	MaxFaces();
+
+			/// Returns the number of triangles of the lowest LOD.
+			uint32	MinFaces();
+
+			/// Returns the number of vertices of the highest LOD.
+			uint32	MaxVertices();
+
+			/// Returns the number of vertices of the lowest LOD.
+			uint32	MinVertices();
+
+			//	(New)	Get the number of strips.
+			uint32	GetStripCount();
+	};
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializer.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializer.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoSerializer.h	(revision 774)
@@ -0,0 +1,84 @@
+#ifndef __GEO_SERIALIZER_H__
+#define __GEO_SERIALIZER_H__
+
+#include "GeoBase.h"
+#include "GeoVector2.h"
+#include "GeoVector3.h"
+
+namespace Geometry {
+
+	/// Serializer interface
+	/** Serializer is a helper class than manages file input/output.
+	*/
+    class Serializer
+    {
+    public:
+
+		enum Mode
+		{
+			READ,
+			WRITE,
+			APPEND
+		};
+
+		///Constructor
+		Serializer(String name, Mode mode);
+
+		///Destructor
+		virtual ~Serializer();
+
+		/// Copy constructor
+		//Serializer(const Serializer&);
+
+		/// Assignment operator
+		//Serializer& operator =(const Serializer&);
+
+
+	public:
+		void WriteData(const void* const buf, size_t size, size_t count);
+        void WriteArray(const float* const pfloat, size_t count);
+        void WriteArray(const uint16* const pShort, size_t count);
+        void WriteArray(const uint32* const pInt, size_t count); 
+        void WriteArray(const bool* const pLong, size_t count);
+		void WriteArray(const Vector3* const pvector3, size_t count);
+		void WriteArray(const Vector2* const pvector3, size_t count);
+		   
+		void ReadData(void *buf, size_t size, size_t count);
+		void miReadData2(void *buf, size_t size, size_t count);
+		char *miReadData(char *pDest, size_t pDestsize);
+        void ReadArray(bool *pDest, size_t count);
+        void ReadArray(float *pDest, size_t count);
+        void ReadArray(uint16 *pDest, size_t count);
+        void ReadArray(uint32 *pDest, size_t count);
+		void ReadArray(Vector3 *pDest, size_t count);
+		void ReadArray(Vector2 *pDest, size_t count);
+
+		//	GPR.
+		void	WriteData(const	String	&string);
+		//	fin GPR.
+
+		virtual size_t GetSize() 
+		{
+			return mSize;
+		}
+
+		int serializereof() {
+			return feof(mFile);
+		}
+
+    protected:
+
+		size_t mSize;
+        FILE   *mFile;
+		Mode   mMode;
+
+		void FlipToLittleEndian(void *pData, size_t size, size_t count = 1);
+		void FlipFromLittleEndian(void *pData, size_t size, size_t count = 1);
+		void FlipEndian(void *pData, size_t size, size_t count);
+		void FlipEndian(void *pData, size_t size);
+    };
+
+}
+
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoBase.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoBase.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoBase.h	(revision 774)
@@ -0,0 +1,67 @@
+#ifndef __GEO_BASE__
+#define __GEO_BASE__
+
+#include <string>
+
+/// This namespace contains all classes related to geometry operations.
+/** Geometry namespace includes classes for the following modules:
+- Serialization: for file loading and saving.
+- Simplification: for mesh simplification algorithms.
+- Stripification: methods for finding triangle strips from a mesh.
+- Construction: builds a LODStrip file from the output of simplification and stripification modules.
+.
+*/
+namespace Geometry {
+
+	//Basic types
+	typedef float 					Real;
+	typedef unsigned int		Index;
+	typedef	int							int32;
+	typedef unsigned int		uint32;
+	typedef unsigned short	uint16;
+	typedef std::string			String;
+
+	//Vertex Info
+	static const unsigned short VERTEX_EMPTY     = 0x00;
+	static const unsigned short VERTEX_POSITION  = 0x01;
+	static const unsigned short VERTEX_NORMAL    = 0x02;
+	static const unsigned short VERTEX_TEXCOORDS = 0x04;
+	static const unsigned short VERTEX_ALL = VERTEX_POSITION | VERTEX_NORMAL | VERTEX_TEXCOORDS;
+
+	//Mmesh primitives
+	typedef enum 
+	{
+		GEO_TRIANGLE_LIST,
+		GEO_TRIANGLE_STRIPS
+	} MeshType;
+
+		//OSCAR
+	struct VertexBoneAssignment
+	{
+		unsigned int vertexIndex;
+		unsigned short boneIndex;
+		Real weight;
+
+	};
+
+	//	2006-02-14
+	//	Gustavo Puche.
+	//	Needed to update the progress bar.
+	typedef float updateProgressBar(float);
+	typedef updateProgressBar *TIPOFUNC;
+	//-----------------------------------//
+
+} // end of Geometry namespace
+
+
+#define GEO_ENDIAN_LITTLE 1
+#define GEO_ENDIAN_BIG 2
+
+// Default = Little endian (define CONFIG_BIG_ENDIAN to change it)
+#ifdef CONFIG_BIG_ENDIAN
+#	define GEO_ENDIAN GEO_ENDIAN_BIG
+#else
+#	define GEO_ENDIAN GEO_ENDIAN_LITTLE
+#endif
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimpSequence.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimpSequence.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimpSequence.h	(revision 774)
@@ -0,0 +1,78 @@
+#ifndef __GEO_MESH_SIMP_SEQUENCE__
+#define __GEO_MESH_SIMP_SEQUENCE__
+
+#include <string>
+#include <vector>
+#include "GeoBase.h"
+#include "GeoSerializable.h"
+#include <iostream>
+#include <fstream>
+
+namespace Geometry
+{
+	/// Represents the simplification sequence applied to a given mesh.
+	/** This class stores information about the simplification process, giving for each step the vertex that collapses, 
+	the vertex that remains unchanged, the two triangles that disappear and the new triangles that come out. 
+	It also offers a method to generate a mesh simplification sequence format file. 
+	\n
+	This file begins with a line stating the name of the mesh file it refers to.
+
+    Every line gives the following information: \n
+	\n 
+		-# Vertex that collapses. -> asumo mV0\n
+		-# Vertex that remains unchanged. -> asumo mV1\n
+		-# The two triangles that disappear.\n -> no tiene por qué ser 2 ??????
+		-# & as a separator.\n
+		-# The list of new triangles.\n
+		.
+	\n
+	*/
+
+	class MeshSimplificationSequence: public Serializable
+	{
+		public:
+
+			/// Class constructor.
+			MeshSimplificationSequence(void);
+
+			/// Class destructor.
+			~MeshSimplificationSequence(void);
+
+			/// Copy constructor
+			//MeshSimplificationSequence(const MeshSimplificationSequence&);
+
+			/// Assignment operator
+			//MeshSimplificationSequence& operator =(const MeshSimplificationSequence&);
+
+			/// Represents a simplification step in the sequence.
+			struct Step
+			{
+				Index mV0, mV1;
+				Index mT0, mT1;
+				float x,y,z;
+				std::vector<Index> mModfaces;
+
+				//	Indicates the the step is obligatory to execute
+				//	joined width the following step.
+				unsigned int obligatorio;
+			};
+
+			char* meshName; // Nombre del mesh para guardar en el fichero de la secuencia de simplificación.
+
+			/// Stores all the simplification steps.
+			std::vector<Step> mSteps;
+
+			/// Loads a simplification sequence from a Serializer.
+			void Load(Serializer &s);
+
+			/// Saves the contents of the data structures.
+			void Save(Serializer &s);
+
+			// 'Inserts the mesh name into the meshsimplificationsequence
+			void putMeshName(char *);
+
+			char *getMeshName(void);
+	};
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimplifier.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimplifier.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshSimplifier.h	(revision 774)
@@ -0,0 +1,120 @@
+#ifndef __GEO_MESH_SIMPLIFIER__
+#define __GEO_MESH_SIMPLIFIER__
+
+#include "GeoMesh.h"
+#include "GeoMeshSimpSequence.h"
+//#include "SimplificationMethod.h"
+
+namespace Geometry
+{
+	/// Mesh simplificator interface.
+	/** This module is used by both models, general mesh models and the plant and tree models for the trunk and the branches. It contains functions that generate simplified versions of 3D objects made out of triangles. Given a 3D object, this module computes a sequence of geometric transformations that reduce the objects geometric detail while preserving its appearance. For each simplification step, returns a simplification sequence containing the edge to be collapse, the two triangles being removed and the new triangles remapped to the model.\n\n
+
+Inputs:\n
+	- A pointer to the Geometry::Mesh object containing the 3D model to be simplified.
+	.
+    	
+Outputs:\n
+	-# The simplified mesh, contained in a Geometry::Mesh object.
+	-# Simplification sequence, represented by a Geometry::MeshSimplificationSequence object.
+	
+	*/
+
+	class MeshSimplifier
+	{
+		public:
+			/// Class constructor. Retrieves a pointer to a valid Geometry::Mesh object to simplify.
+			MeshSimplifier(	const Geometry::Mesh	*,
+											Geometry::TIPOFUNC		upb=0);
+
+			/// Virtual class destructor.
+			virtual ~MeshSimplifier (void);
+
+			/// Copy constructor
+			//MeshSimplifier(const MeshSimplifier&);
+
+			/// Assignment operator
+			//MeshSimplifier& operator =(const MeshSimplifier&);
+
+			/// Starts the simplification process. Receives as a parameter the LOD factor in a range of [0,1]. This is a pure virtual method and must be overloaded in a derived class that implements a simplification algorithm.
+			virtual void Simplify (Geometry::Real)=0;
+
+			/// Starts the simplification process. Receives as a parameter the number of vertices of the resulting mesh. This is a pure virtual method and must be overloaded in a derived class that implements a simplification algorithm.
+			virtual void Simplify (Geometry::uint32)=0;
+
+			/// Returns the simplified mesh.
+			Mesh *GetMesh ();
+
+			/// Returns the simplification sequence for general meshes.
+			MeshSimplificationSequence *GetSimplificationSequence();
+
+			// Sets what is the mesh that stores the leaves
+			void setMeshLeaves(Geometry::Index);
+
+		protected:
+
+			//private: // fer protected
+			Mesh *meshsalida;
+			MeshSimplificationSequence *msimpsequence;
+			const Mesh *objmesh;
+
+			Geometry::Index indexMeshLeaves;
+
+			//	Progress bar function.
+			Geometry::TIPOFUNC	mUPB;
+	};
+
+	/// Implementation of a simplification algorithm based on images.
+	/** This class implements a simplification algorithm based on an image evaluation technique. */
+	class ImageBasedSimplifier : public MeshSimplifier
+	{
+	public:
+		/// Class constructor. Will call Simplifier class constructor.
+		ImageBasedSimplifier (const Geometry::Mesh 	*,
+													Geometry::TIPOFUNC		upb=0);
+
+		/// Class destructor.
+		virtual ~ImageBasedSimplifier (void);
+
+		/// Copy constructor
+		//ImageBasedSimplifier(const ImageBasedSimplifier&);
+
+		/// Assignment operator
+		//ImageBasedSimplifier& operator =(const ImageBasedSimplifier&);
+
+		/// Starts the simplification process. Receives as a parameter the LOD factor in a range of [0,1]. Implements the Simplifier::Simplify method to perform an image based simplification.
+		void Simplify (Geometry::Real);
+
+		/// Starts the simplification process. Receives as a parameter the number of vertices of the resulting mesh. Implements the Simplifier::Simplify method to perform an image based simplification.
+		void Simplify (Geometry::uint32);
+
+	};
+
+
+	/// Implementation of a simplification algorithm based on geometry information.
+	/** This class implements a simplification algorithm based on a classic geometry evaluation technique. */
+	class GeometryBasedSimplifier : public MeshSimplifier
+	{
+	public:
+		/// Class constructor. Will call Simplifier class constructor.
+		GeometryBasedSimplifier (	const Geometry::Mesh	*,
+															Geometry::TIPOFUNC		upb=0);
+
+		/// Class destructor.
+		virtual ~GeometryBasedSimplifier (void);
+
+		/// Copy constructor
+		//GeometryBasedSimplifier(const GeometryBasedSimplifier&);
+
+		/// Assignment operator
+		//GeometryBasedSimplifier& operator =(const GeometryBasedSimplifier&);
+
+		/// Starts the simplification process. Receives as a parameter the LOD factor in a range of [0,1]. Implements the Simplifier::Simplify method to perform an image based simplification.
+		void Simplify (Geometry::Real);
+
+		/// Starts the simplification process. Receives as a parameter the number of vertices of the resulting mesh. Implements the Simplifier::Simplify method to perform an image based simplification.
+		void Simplify (Geometry::uint32);
+	};
+} // end of Geometry namespace;
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimpSequence.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimpSequence.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimpSequence.h	(revision 774)
@@ -0,0 +1,79 @@
+#ifndef __GEO_TREE_SIMP_SEQUENCE__
+#define __GEO_TREE_SIMP_SEQUENCE__
+
+#include <string>
+#include <vector>
+#include "GeoBase.h"
+#include "GeoSerializable.h"
+
+namespace Geometry
+{
+	/// Represents the simplification sequence applied to a given mesh.
+	/** This class stores information about the simplification process, giving for each step the four triangles that compose the two leaves that will be collapsed
+	and the two triangles of the new leaf. 
+	It also offers a method to generate a tree simplification sequence format file.
+	\n
+	This file begins with a line stating the name of the mesh file it refers to.
+
+This file stores the leaves geometry and at the end of the file one line for each leaf collapse operation. \n
+\n
+begin\n
+v	/ vertex sequence
+v\n
+v 
+\n
+f	// faces sequence (two faces compose one leaf) including new faces\n
+f	// added due to the simplification process\n
+f 
+\n
+end\n
+// one collapse record per line\n
+\n
+Those records gives the following information:\n
+
+	-# The four triangles that compose the two leaves that will be collapsed.\n
+	-# & as a separator.\n
+	-# The two triangles for the new leaf.\n
+	.
+
+	*/
+	class TreeSimplificationSequence : public Serializable
+	{
+	public:
+		/// Class constructor
+		TreeSimplificationSequence(void);
+
+		/// Class destructor
+		~TreeSimplificationSequence(void);
+
+		/// Copy constructor
+		//TreeSimplificationSequence(const TreeSimplificationSequence&);
+
+		/// Assignment operator
+		//TreeSimplificationSequence& operator =(const TreeSimplificationSequence&);
+
+		/// Represents a Simplification Step in the sequence.
+		struct Step
+		{
+			Index mV0, mV1;
+			Index mT0, mT1;
+			Index mNewQuad[4];
+		};
+
+		/// Stores all the simplification steps.
+		std::vector<Step> mSteps;
+
+		/// Loads a Simplification Sequence from a Serializer.
+		void Load(Serializer &s);
+
+		/// Saves the contents of the data structures.
+		void Save(Serializer &s);
+
+		char* meshName; // Nombre del mesh para guardar en el fichero de la secuencia de simplificación.
+		// 'Inserts the mesh name into the meshsimplificationsequence
+		void putMeshName(char *);
+		char *getMeshName(void);
+	};
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/auxiliar.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/auxiliar.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/auxiliar.h	(revision 774)
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <iostream>
+#include <list>
+#include <vector>
+#include <algorithm>
+
+#include	<GeoBase.h>
+
+#include <set>
+
+using namespace std;
+using	namespace	Geometry;
+
+#define X 0
+#define Y 1
+#define Z 2
+
+#define MAXUINT 2^4-1
+
+#pragma pack(1)
+typedef struct
+{
+	uint32	strip;
+	char		nP,nL1,nL2,obligatory;
+} LODData;
+#pragma pack()
+
+typedef vector <LODData> LODChanges;
+
+//-----------------
+
+typedef struct
+{
+	float Vertex[3];
+	float Normal[3];
+	float TexCoords[2];
+	unsigned int obligatorio;
+	int numMesh;
+	uint32 Next;
+	bool repetido;
+} tipoVertice;
+
+typedef struct
+{
+	float	Vertex[3];
+} tipoNormal;
+
+//--- Para calcular la simplificacion
+typedef struct
+{
+	uint32				vQslimNext;
+	uint32				vQslim;
+	uint32				vLSNext;
+	uint32				vLS;
+	unsigned int	obligatorio;
+	float					x;
+	char					*cambio;
+} tipoOrden;
+
+typedef vector <int32> VECTORINT;
+typedef vector<int32> VECTORUNINT;
+typedef vector<tipoVertice> VECTORVERTEX;
+typedef list <int32> LISTINT;
+typedef set <int32> SET_INT;
+
+//// FUNCIONES DE ALLOCATE
+uint32 **Allocate2DArrayINT( uint32 nRows, uint32 nCols);
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeLibrary.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeLibrary.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodTreeLibrary.h	(revision 774)
@@ -0,0 +1,87 @@
+#include "GeoBase.h"
+
+namespace Geometry
+{
+	/// LodTreeLibrary interface class.
+	/** This module contains functions that handle the levels of detail of the input multiresolution trees.
+	For Any given resolution and object this module returns two thins: a set of triangle strips representing the trunk 
+	and the branches at that resolution, and a triangle list representing the leaves at the same resolution. 
+	\n\n
+
+Inputs:\n
+	- The module receives a file describing a multiresolution tree object.
+	.
+
+Outputs:\n
+	- The module returns a strip set that represents the level of deatil demanded for the trunk and a triangle list 
+	that representes the level of detail for leaves.
+	.
+
+	*/
+	class LodTreeLibrary
+	{
+	public:
+		/// Constructor, receives as a parameter the name of the file including the multiresolution object.
+		LodTreeLibrary (std::string);
+
+		/// Destructor.
+		~LodTreeLibrary (void);
+
+		/// Copy constructor
+		//LodTreeLibrary(const LodTreeLibrary&);
+
+		/// Assignment operator
+		//LodTreeLibrary& operator =(const LodTreeLibrary&);
+
+		/// Returns the highest LOD of the foliage.
+		uint32 MaxFoliageLod();
+
+		/// Returns the highest LOD of the trunk.
+		uint32 MaxTrunkLod();
+
+		/// Returns the lowest LOD of the foliage.
+		uint32 MinFoliageLod();
+
+		/// Returns the lowest LOD of the trunk.
+		uint32 MinTrunkLod();
+
+		/// Returns de current foliage LOD and changes to the specified LOD.
+		uint32 GoToFoliageLod(uint32);
+
+		/// Returns de current trunk LOD and changes to the specified LOD.
+		uint32 GoToTrunkLod(uint32);
+
+		/// Establishes the new LOD range.
+		/// Only the LODs in that range are stored and used.
+		void TrimFoliageByLod(uint32, uint32);
+
+		/// Establishes the new LOD range.
+		/// Only the LODs in that range are stored and used.
+		void TrimTrunkByLod(uint32, uint32);
+
+		/// Returns the number of triangles of the foliage at the highest LOD.
+		uint32 MaxFoliageFaces();
+
+		/// Returns the number of triangles of the trunk at the highest LOD.
+		uint32 MaxTrunkFaces();
+
+		/// Returns the number of triangles of the foliage at the lowest LOD.
+		uint32 MinFoliageFaces();
+
+		/// Returns the number of triangles of the trunk at the lowest LOD.
+		uint32 MinTrunkFaces();
+
+		/// Returns the number of vertices of the foliage at the highest LOD.
+		uint32 MaxFoliageVertices();
+
+		/// Returns the number of vertices of the trunk at the highest LOD.
+		uint32 MaxTrunkVertices();
+
+		/// Returns the number of vertices of the foliage at the lowest LOD.
+		uint32 MinFoliageVertices();
+
+		/// Returns the number of vertices of the trunk at the lowest LOD.
+		uint32 MinTrunkVertices();
+
+	};
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimplifier.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimplifier.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoTreeSimplifier.h	(revision 774)
@@ -0,0 +1,97 @@
+#ifndef __GEO_TREE_SIMPLIFIER__
+#define __GEO_TREE_SIMPLIFIER__
+
+#include "GeoMesh.h"
+#include "GeoTreeSimpSequence.h"
+#include "Hoja.h"
+
+#define K1		0.8f //distancia
+#define K2		0.2f // coplanar
+
+namespace Geometry
+{
+	/// Tree Simplifier interface 
+	/*** This module is used by LODTree to simplify leaves of a tree. It contains functions that generate simplified
+	versions of 3D objects made out of quads (represented as pairs of texture-mapped triangles). Given a 3D object, this
+	module computes	a sequence of geometric transformations	that reduce the objects geometric detail while preserving
+	its appearance.\n\n
+
+	For each simplification step, the module returns a simplification sequence containing the leaf collapsed, the two 
+	leaves being removed, and the resulting leaf for that contraction.\n\n
+
+	
+Inputs:\n
+	- A pointer to the Geometry::Mesh object containing the tree to be simplified.
+	.
+
+Outputs:\n
+	-# The simplified mesh, contained in a Geometry::Mesh object.
+	-# Simplification sequence, represented by a Geometry::TreeSimplificationSequence object.
+	*/
+
+	class TreeSimplifier
+	{
+	public:
+		/// Class constructor. Retrieves a pointer to a valid Mesh object to simplify
+		TreeSimplifier(	const Geometry::Mesh 	*,
+										Geometry::TIPOFUNC		upb=0);
+
+		/// Class destructor.
+		~TreeSimplifier(void);
+
+		/// Copy constructor
+		//TreeSimplifier(const TreeSimplifier&);
+
+		/// Assignment operator
+		//TreeSimplifier& operator =(const TreeSimplifier&);
+
+		/// Starts the simplification process. Receives as a parameter the LOD factor in a range of [0,1].
+		void Simplify(Geometry::Real,Geometry::Index);
+	
+		/// Returns the simplified mesh.
+		Mesh *GetMesh();
+
+		/// Returns the simplification sequence for leaves.
+		TreeSimplificationSequence *GetSimplificationSequence();
+
+	//private:
+		void Centroh(Hoja	&);
+		void GetNormal(Hoja	&);
+		void DistanciaEntreHojas(void);
+		void CoplanarEntreHojas(FILE*);
+		float DiametroEsferaEnvolvente();
+		void EstableceCriterio(float);
+
+		float max(float, float);
+		float min(float, float);
+
+		//long int Colapsa (TreeSimplificationSequence *, float);
+		long int Colapsa(float);
+		void DosMayores(float*, int* );
+		void ElijeVertices(Hoja& , Hoja& , long int);
+		float Hausdorff(Hoja &, Hoja&);
+		float distan(float, float, float, float, float, float);
+		long int MinimaDistancia(void);
+		void NormalizaDistancia(float diametro);
+		void EstableceCriterio2(float, long int);
+		long int MinimoCriterio(void);
+
+		void Mesh2Estructura(	const Geometry::Mesh *,
+													Index);
+		
+		void EscribeMesh(int);
+
+		Mesh			*mesh; // objeto mesh simplificado (para la salida)
+		const			Mesh *objmesh;
+		float			(*Vertex)[3];
+		Hoja			*Hojasa;  // las activas
+		long int	activas, counth;
+		TreeSimplificationSequence	*mtreesimpsequence;
+		
+	private:
+		//	Update progress bar.
+		Geometry::TIPOFUNC	mUPB;
+	};
+}
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector2.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector2.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector2.h	(revision 774)
@@ -0,0 +1,409 @@
+#ifndef __GEO_VECTOR2__
+#define __GEO_VECTOR2__
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+
+#include "GeoBase.h"
+#include <cmath>
+#include <cassert>
+#include <ostream>
+
+namespace Geometry
+{
+
+	class Vector2
+    {
+    public:
+        union {
+            struct {
+                Real x, y;        
+            };
+            Real val[2];
+        };
+
+    public:
+        inline Vector2()
+        {
+        }
+
+        inline Vector2( Real fX, Real fY ) 
+            : x( fX ), y( fY )
+        {
+        }
+
+        inline Vector2( const Real* const r )
+            : x( r[0] ), y( r[1] )
+        {
+        }
+
+        inline Vector2( const Vector2& rkVector )
+            : x( rkVector.x ), y( rkVector.y )
+        {
+        }
+
+		inline Real operator [] ( size_t i ) const
+        {
+            assert( i < 2 );
+
+            return *(&x+i);
+        }
+
+		inline Real& operator [] ( size_t i )
+        {
+            assert( i < 2 );
+
+            return *(&x+i);
+        }
+
+        /** Assigns the value of the other vector.
+            @param
+                rkVector The other vector
+        */
+        inline Vector2& operator = ( const Vector2& rkVector )
+        {
+            x = rkVector.x;
+            y = rkVector.y;        
+
+            return *this;
+        }
+
+        inline bool operator == ( const Vector2& rkVector ) const
+        {
+            return ( x == rkVector.x && y == rkVector.y );
+        }
+
+        inline bool operator != ( const Vector2& rkVector ) const
+        {
+            return ( x != rkVector.x || y != rkVector.y  );
+        }
+
+        // arithmetic operations
+        inline Vector2 operator + ( const Vector2& rkVector ) const
+        {
+            Vector2 kSum;
+
+            kSum.x = x + rkVector.x;
+            kSum.y = y + rkVector.y;
+
+            return kSum;
+        }
+
+        inline Vector2 operator - ( const Vector2& rkVector ) const
+        {
+            Vector2 kDiff;
+
+            kDiff.x = x - rkVector.x;
+            kDiff.y = y - rkVector.y;
+
+            return kDiff;
+        }
+
+        inline Vector2 operator * ( Real fScalar ) const
+        {
+            Vector2 kProd;
+
+            kProd.x = fScalar*x;
+            kProd.y = fScalar*y;
+
+            return kProd;
+        }
+
+        inline Vector2 operator * ( const Vector2& rhs) const
+        {
+            Vector2 kProd;
+
+            kProd.x = rhs.x * x;
+            kProd.y = rhs.y * y;
+
+            return kProd;
+        }
+
+        inline Vector2 operator / ( Real fScalar ) const
+        {
+            assert( fScalar != 0.0f );
+
+            Vector2 kDiv;
+
+            Real fInv = 1.0f / fScalar;
+            kDiv.x = x * fInv;
+            kDiv.y = y * fInv;
+
+            return kDiv;
+        }
+
+        inline Vector2 operator - () const
+        {
+            Vector2 kNeg;
+
+            kNeg.x = -x;
+            kNeg.y = -y;
+
+            return kNeg;
+        }
+
+        inline friend Vector2 operator * ( Real fScalar, const Vector2& rkVector )
+        {
+            Vector2 kProd;
+
+            kProd.x = fScalar * rkVector.x;
+            kProd.y = fScalar * rkVector.y;
+
+            return kProd;
+        }
+
+        // arithmetic updates
+        inline Vector2& operator += ( const Vector2& rkVector )
+        {
+            x += rkVector.x;
+            y += rkVector.y;
+
+            return *this;
+        }
+
+        inline Vector2& operator -= ( const Vector2& rkVector )
+        {
+            x -= rkVector.x;
+            y -= rkVector.y;
+
+            return *this;
+        }
+
+        inline Vector2& operator *= ( Real fScalar )
+        {
+            x *= fScalar;
+            y *= fScalar;
+
+            return *this;
+        }
+
+        inline Vector2& operator /= ( Real fScalar )
+        {
+            assert( fScalar != 0.0f );
+
+            Real fInv = 1.0f / fScalar;
+
+            x *= fInv;
+            y *= fInv;
+
+            return *this;
+        }
+
+        /** Returns the length (magnitude) of the vector.
+            @warning
+                This operation requires a square root and is expensive in
+                terms of CPU operations. If you don't need to know the exact
+                length (e.g. for just comparing lengths) use squaredLength()
+                instead.
+        */
+        inline Real length () const
+        {
+            return sqrt( x * x + y * y );
+        }
+
+        /** Returns the square of the length(magnitude) of the vector.
+            @remarks
+                This  method is for efficiency - calculating the actual
+                length of a vector requires a square root, which is expensive
+                in terms of the operations required. This method returns the
+                square of the length of the vector, i.e. the same as the
+                length but before the square root is taken. Use this if you
+                want to find the longest / shortest vector without incurring
+                the square root.
+        */
+        inline Real squaredLength () const
+        {
+            return x * x + y * y;
+        }
+
+        /** Calculates the dot (scalar) product of this vector with another.
+            @remarks
+                The dot product can be used to calculate the angle between 2
+                vectors. If both are unit vectors, the dot product is the
+                cosine of the angle; otherwise the dot product must be
+                divided by the product of the lengths of both vectors to get
+                the cosine of the angle. This result can further be used to
+                calculate the distance of a point from a plane.
+            @param
+                vec Vector with which to calculate the dot product (together
+                with this one).
+            @returns
+                A float representing the dot product value.
+        */
+        inline Real dotProduct(const Vector2& vec) const
+        {
+            return x * vec.x + y * vec.y;
+        }
+
+        /** Normalises the vector.
+            @remarks
+                This method normalises the vector such that it's
+                length / magnitude is 1. The result is called a unit vector.
+            @note
+                This function will not crash for zero-sized vectors, but there
+                will be no changes made to their components.
+            @returns The previous length of the vector.
+        */
+        inline Real normalise()
+        {
+            Real fLength = sqrt( x * x + y * y);
+
+            // Will also work for zero-sized vectors, but will change nothing
+            if ( fLength > 1e-08f )
+            {
+                Real fInvLength = 1.0f / fLength;
+                x *= fInvLength;
+                y *= fInvLength;
+            }
+
+            return fLength;
+        }
+
+    
+   
+        /** Returns a vector at a point half way between this and the passed
+            in vector.
+        */
+        inline Vector2 midPoint( const Vector2& vec ) const
+        {
+            return Vector2( 
+                ( x + vec.x ) * 0.5f, 
+                ( y + vec.y ) * 0.5f );
+        }
+
+        /** Returns true if the vector's scalar components are all greater
+            that the ones of the vector it is compared against.
+        */
+        inline bool operator < ( const Vector2& rhs ) const
+        {
+            if( x < rhs.x && y < rhs.y )
+                return true;
+            return false;
+        }
+
+        /** Returns true if the vector's scalar components are all smaller
+            that the ones of the vector it is compared against.
+        */
+        inline bool operator > ( const Vector2& rhs ) const
+        {
+            if( x > rhs.x && y > rhs.y )
+                return true;
+            return false;
+        }
+
+        /** Sets this vector's components to the minimum of its own and the 
+            ones of the passed in vector.
+            @remarks
+                'Minimum' in this case means the combination of the lowest
+                value of x, y and z from both vectors. Lowest is taken just
+                numerically, not magnitude, so -1 < 0.
+        */
+        inline void makeFloor( const Vector2& cmp )
+        {
+            if( cmp.x < x ) x = cmp.x;
+            if( cmp.y < y ) y = cmp.y;
+        }
+
+        /** Sets this vector's components to the maximum of its own and the 
+            ones of the passed in vector.
+            @remarks
+                'Maximum' in this case means the combination of the highest
+                value of x, y and z from both vectors. Highest is taken just
+                numerically, not magnitude, so 1 > -3.
+        */
+        inline void makeCeil( const Vector2& cmp )
+        {
+            if( cmp.x > x ) x = cmp.x;
+            if( cmp.y > y ) y = cmp.y;
+        }
+
+        /** Generates a vector perpendicular to this vector (eg an 'up' vector).
+            @remarks
+                This method will return a vector which is perpendicular to this
+                vector. There are an infinite number of possibilities but this 
+                method will guarantee to generate one of them. If you need more 
+                control you should use the Quaternion class.
+        */
+        inline Vector2 perpendicular(void) const
+        {         
+            return Vector2 (-y, x);
+        }
+        /** Calculates the cross-product of 2 vectors, i.e. the vector that
+            lies perpendicular to them both.
+            @remarks
+                The cross-product is normally used to calculate the normal
+                vector of a plane, by calculating the cross-product of 2
+                non-equivalent vectors which lie on the plane (e.g. 2 edges
+                of a triangle).
+            @param
+                vec Vector which, together with this one, will be used to
+                calculate the cross-product.
+            @returns
+                A vector which is the result of the cross-product. This
+                vector will <b>NOT</b> be normalised, to maximise efficiency
+                - call Vector3::normalise on the result if you wish this to
+                be done. As for which side the resultant vector will be on, the
+                returned vector will be on the side from which the arc from 'this'
+                to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z) 
+                = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X.
+            @par
+                For a clearer explanation, look a the left and the bottom edges
+                of your monitor's screen. Assume that the first vector is the
+                left edge and the second vector is the bottom edge, both of
+                them starting from the lower-left corner of the screen. The
+                resulting vector is going to be perpendicular to both of them
+                and will go <i>inside</i> the screen, towards the cathode tube
+                (assuming you're using a CRT monitor, of course).
+        */
+        inline Vector2 crossProduct( const Vector2& rkVector ) const
+        {
+            return Vector2(-rkVector.y, rkVector.x);
+        }
+               
+        /** Returns true if this vector is zero length. */
+        inline bool isZeroLength(void) const
+        {
+            Real sqlen = (x * x) + (y * y);
+            return (sqlen < (1e-06 * 1e-06));
+
+        }
+
+        /** As normalise, except that this vector is unaffected and the
+            normalised vector is returned as a copy. */
+        inline Vector2 normalisedCopy(void) const
+        {
+            Vector2 ret = *this;
+            ret.normalise();
+            return ret;
+        }
+
+        /** Calculates a reflection vector to the plane with the given normal . 
+        @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
+        */
+        inline Vector2 reflect(const Vector2& normal)
+        {
+            return Vector2( *this - ( 2 * this->dotProduct(normal) * normal ) );
+        }
+
+        // special points
+        static const Vector2 ZERO;
+        static const Vector2 UNIT_X;
+        static const Vector2 UNIT_Y;
+        static const Vector2 NEGATIVE_UNIT_X;
+        static const Vector2 NEGATIVE_UNIT_Y;
+        static const Vector2 UNIT_SCALE;
+
+        /** Function for writing to a stream.
+		 */
+        inline friend std::ostream& operator <<
+            ( std::ostream& o, const Vector2& v )
+        {
+            o << "Vector2(" << v.x << ", " << v.y <<  ")";
+            return o;
+        }
+	
+		
+    };
+
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector3.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector3.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoVector3.h	(revision 774)
@@ -0,0 +1,470 @@
+#ifndef __GEO_VECTOR3__
+#define __GEO_VECTOR3__
+#ifndef DOXYGEN_SHOULD_SKIP_THIS
+
+#include "GeoBase.h"
+#include <cmath>
+#include <cassert>
+#include <ostream>
+
+namespace Geometry
+{
+
+    class Vector3
+    {
+    public:
+        union {
+            struct {
+                Real x, y, z;        
+            };
+            Real val[3];
+        };
+
+    public:
+        inline Vector3()
+        {
+        }
+
+        inline Vector3( Real fX, Real fY, Real fZ ) 
+            : x( fX ), y( fY ), z( fZ )
+        {
+        }
+
+        inline Vector3( const Real* const r )
+            : x( r[0] ), y( r[1] ), z( r[2] )
+        {
+        }
+
+        inline Vector3( const Vector3& rkVector )
+            : x( rkVector.x ), y( rkVector.y ), z( rkVector.z )
+        {
+        }
+
+		inline Real operator [] ( size_t i ) const
+        {
+            assert( i < 3 );
+            return *(&x+i);
+        }
+
+		inline Real& operator [] ( size_t i )
+        {
+            assert( i < 3 );
+            return *(&x+i);
+        }
+
+        /** Assigns the value of the other vector.
+            @param
+                rkVector The other vector
+        */
+        inline Vector3& operator = ( const Vector3& rkVector )
+        {
+            x = rkVector.x;
+            y = rkVector.y;
+            z = rkVector.z;            
+
+            return *this;
+        }
+
+        inline bool operator == ( const Vector3& rkVector ) const
+        {
+            return ( x == rkVector.x && y == rkVector.y && z == rkVector.z );
+        }
+
+        inline bool operator != ( const Vector3& rkVector ) const
+        {
+            return ( x != rkVector.x || y != rkVector.y || z != rkVector.z );
+        }
+
+        // arithmetic operations
+        inline Vector3 operator + ( const Vector3& rkVector ) const
+        {
+            Vector3 kSum;
+
+            kSum.x = x + rkVector.x;
+            kSum.y = y + rkVector.y;
+            kSum.z = z + rkVector.z;
+
+            return kSum;
+        }
+
+        inline Vector3 operator - ( const Vector3& rkVector ) const
+        {
+            Vector3 kDiff;
+
+            kDiff.x = x - rkVector.x;
+            kDiff.y = y - rkVector.y;
+            kDiff.z = z - rkVector.z;
+
+            return kDiff;
+        }
+
+        inline Vector3 operator * ( Real fScalar ) const
+        {
+            Vector3 kProd;
+
+            kProd.x = fScalar*x;
+            kProd.y = fScalar*y;
+            kProd.z = fScalar*z;
+
+            return kProd;
+        }
+
+        inline Vector3 operator * ( const Vector3& rhs) const
+        {
+            Vector3 kProd;
+
+            kProd.x = rhs.x * x;
+            kProd.y = rhs.y * y;
+            kProd.z = rhs.z * z;
+
+            return kProd;
+        }
+
+        inline Vector3 operator / ( Real fScalar ) const
+        {
+            assert( fScalar != 0.0f );
+
+            Vector3 kDiv;
+
+            Real fInv = 1.0f / fScalar;
+            kDiv.x = x * fInv;
+            kDiv.y = y * fInv;
+            kDiv.z = z * fInv;
+
+            return kDiv;
+        }
+
+        inline Vector3 operator / ( const Vector3& rhs) const
+        {
+            Vector3 kDiv;
+
+            kDiv.x = x / rhs.x;
+            kDiv.y = y / rhs.y;
+            kDiv.z = z / rhs.z;
+
+            return kDiv;
+        }
+
+
+        inline Vector3 operator - () const
+        {
+            Vector3 kNeg;
+
+            kNeg.x = -x;
+            kNeg.y = -y;
+            kNeg.z = -z;
+
+            return kNeg;
+        }
+
+        inline friend Vector3 operator * ( Real fScalar, const Vector3& rkVector )
+        {
+            Vector3 kProd;
+
+            kProd.x = fScalar * rkVector.x;
+            kProd.y = fScalar * rkVector.y;
+            kProd.z = fScalar * rkVector.z;
+
+            return kProd;
+        }
+
+        // arithmetic updates
+        inline Vector3& operator += ( const Vector3& rkVector )
+        {
+            x += rkVector.x;
+            y += rkVector.y;
+            z += rkVector.z;
+
+            return *this;
+        }
+
+        inline Vector3& operator -= ( const Vector3& rkVector )
+        {
+            x -= rkVector.x;
+            y -= rkVector.y;
+            z -= rkVector.z;
+
+            return *this;
+        }
+
+        inline Vector3& operator *= ( Real fScalar )
+        {
+            x *= fScalar;
+            y *= fScalar;
+            z *= fScalar;
+            return *this;
+        }
+
+        inline Vector3& operator *= ( const Vector3& rkVector )
+        {
+            x *= rkVector.x;
+            y *= rkVector.y;
+            z *= rkVector.z;
+
+            return *this;
+        }
+
+        inline Vector3& operator /= ( Real fScalar )
+        {
+            assert( fScalar != 0.0f );
+
+            Real fInv = 1.0f / fScalar;
+
+            x *= fInv;
+            y *= fInv;
+            z *= fInv;
+
+            return *this;
+        }
+
+        inline Vector3& operator /= ( const Vector3& rkVector )
+        {
+            x /= rkVector.x;
+            y /= rkVector.y;
+            z /= rkVector.z;
+
+            return *this;
+        }
+
+
+        /** Returns the length (magnitude) of the vector.
+            @warning
+                This operation requires a square root and is expensive in
+                terms of CPU operations. If you don't need to know the exact
+                length (e.g. for just comparing lengths) use squaredLength()
+                instead.
+        */
+        inline Real length () const
+        {
+            return sqrt( x * x + y * y + z * z );
+        }
+
+        /** Returns the square of the length(magnitude) of the vector.
+            @remarks
+                This  method is for efficiency - calculating the actual
+                length of a vector requires a square root, which is expensive
+                in terms of the operations required. This method returns the
+                square of the length of the vector, i.e. the same as the
+                length but before the square root is taken. Use this if you
+                want to find the longest / shortest vector without incurring
+                the square root.
+        */
+        inline Real squaredLength () const
+        {
+            return x * x + y * y + z * z;
+        }
+
+        /** Calculates the dot (scalar) product of this vector with another.
+            @remarks
+                The dot product can be used to calculate the angle between 2
+                vectors. If both are unit vectors, the dot product is the
+                cosine of the angle; otherwise the dot product must be
+                divided by the product of the lengths of both vectors to get
+                the cosine of the angle. This result can further be used to
+                calculate the distance of a point from a plane.
+            @param
+                vec Vector with which to calculate the dot product (together
+                with this one).
+            @returns
+                A float representing the dot product value.
+        */
+        inline Real dotProduct(const Vector3& vec) const
+        {
+            return x * vec.x + y * vec.y + z * vec.z;
+        }
+
+        /** Normalises the vector.
+            @remarks
+                This method normalises the vector such that it's
+                length / magnitude is 1. The result is called a unit vector.
+            @note
+                This function will not crash for zero-sized vectors, but there
+                will be no changes made to their components.
+            @returns The previous length of the vector.
+        */
+        inline Real normalise()
+        {
+            Real fLength = sqrt( x * x + y * y + z * z );
+
+            // Will also work for zero-sized vectors, but will change nothing
+            if ( fLength > 1e-08 )
+            {
+                Real fInvLength = 1.0f / fLength;
+                x *= fInvLength;
+                y *= fInvLength;
+                z *= fInvLength;
+            }
+
+            return fLength;
+        }
+
+        /** Calculates the cross-product of 2 vectors, i.e. the vector that
+            lies perpendicular to them both.
+            @remarks
+                The cross-product is normally used to calculate the normal
+                vector of a plane, by calculating the cross-product of 2
+                non-equivalent vectors which lie on the plane (e.g. 2 edges
+                of a triangle).
+            @param
+                vec Vector which, together with this one, will be used to
+                calculate the cross-product.
+            @returns
+                A vector which is the result of the cross-product. This
+                vector will <b>NOT</b> be normalised, to maximise efficiency
+                - call Vector3::normalise on the result if you wish this to
+                be done. As for which side the resultant vector will be on, the
+                returned vector will be on the side from which the arc from 'this'
+                to rkVector is anticlockwise, e.g. UNIT_Y.crossProduct(UNIT_Z) 
+                = UNIT_X, whilst UNIT_Z.crossProduct(UNIT_Y) = -UNIT_X.
+            @par
+                For a clearer explanation, look a the left and the bottom edges
+                of your monitor's screen. Assume that the first vector is the
+                left edge and the second vector is the bottom edge, both of
+                them starting from the lower-left corner of the screen. The
+                resulting vector is going to be perpendicular to both of them
+                and will go <i>inside</i> the screen, towards the cathode tube
+                (assuming you're using a CRT monitor, of course).
+        */
+        inline Vector3 crossProduct( const Vector3& rkVector ) const
+        {
+            Vector3 kCross;
+
+            kCross.x = y * rkVector.z - z * rkVector.y;
+            kCross.y = z * rkVector.x - x * rkVector.z;
+            kCross.z = x * rkVector.y - y * rkVector.x;
+
+            return kCross;
+        }
+
+        /** Returns a vector at a point half way between this and the passed
+            in vector.
+        */
+        inline Vector3 midPoint( const Vector3& vec ) const
+        {
+            return Vector3( 
+                ( x + vec.x ) * 0.5f, 
+                ( y + vec.y ) * 0.5f, 
+                ( z + vec.z ) * 0.5f );
+        }
+
+        /** Returns true if the vector's scalar components are all greater
+            that the ones of the vector it is compared against.
+        */
+        inline bool operator < ( const Vector3& rhs ) const
+        {
+            if( x < rhs.x && y < rhs.y && z < rhs.z )
+                return true;
+            return false;
+        }
+
+        /** Returns true if the vector's scalar components are all smaller
+            that the ones of the vector it is compared against.
+        */
+        inline bool operator > ( const Vector3& rhs ) const
+        {
+            if( x > rhs.x && y > rhs.y && z > rhs.z )
+                return true;
+            return false;
+        }
+
+        /** Sets this vector's components to the minimum of its own and the 
+            ones of the passed in vector.
+            @remarks
+                'Minimum' in this case means the combination of the lowest
+                value of x, y and z from both vectors. Lowest is taken just
+                numerically, not magnitude, so -1 < 0.
+        */
+        inline void makeFloor( const Vector3& cmp )
+        {
+            if( cmp.x < x ) x = cmp.x;
+            if( cmp.y < y ) y = cmp.y;
+            if( cmp.z < z ) z = cmp.z;
+        }
+
+        /** Sets this vector's components to the maximum of its own and the 
+            ones of the passed in vector.
+            @remarks
+                'Maximum' in this case means the combination of the highest
+                value of x, y and z from both vectors. Highest is taken just
+                numerically, not magnitude, so 1 > -3.
+        */
+        inline void makeCeil( const Vector3& cmp )
+        {
+            if( cmp.x > x ) x = cmp.x;
+            if( cmp.y > y ) y = cmp.y;
+            if( cmp.z > z ) z = cmp.z;
+        }
+
+        /** Generates a vector perpendicular to this vector (eg an 'up' vector).
+            @remarks
+                This method will return a vector which is perpendicular to this
+                vector. There are an infinite number of possibilities but this 
+                method will guarantee to generate one of them. If you need more 
+                control you should use the Quaternion class.
+        */
+        inline Vector3 perpendicular(void) const
+        {
+            static const Real fSquareZero = 1e-06f * 1e-06f;
+
+            Vector3 perp = this->crossProduct( Vector3::UNIT_X );
+
+            // Check length
+            if( perp.squaredLength() < fSquareZero )
+            {
+                /* This vector is the Y axis multiplied by a scalar, so we have 
+                   to use another axis.
+                */
+                perp = this->crossProduct( Vector3::UNIT_Y );
+            }
+
+            return perp;
+        }
+                
+        /** Returns true if this vector is zero length. */
+        inline bool isZeroLength(void) const
+        {
+            Real sqlen = (x * x) + (y * y) + (z * z);
+            return (sqlen < (1e-06 * 1e-06));
+
+        }
+
+        /** As normalise, except that this vector is unaffected and the
+            normalised vector is returned as a copy. */
+        inline Vector3 normalisedCopy(void) const
+        {
+            Vector3 ret = *this;
+            ret.normalise();
+            return ret;
+        }
+
+        /** Calculates a reflection vector to the plane with the given normal . 
+        @remarks NB assumes 'this' is pointing AWAY FROM the plane, invert if it is not.
+        */
+        inline Vector3 reflect(const Vector3& normal)
+        {
+            return Vector3( *this - ( 2 * this->dotProduct(normal) * normal ) );
+        }
+
+        // special points
+        static const Vector3 ZERO;
+        static const Vector3 UNIT_X;
+        static const Vector3 UNIT_Y;
+        static const Vector3 UNIT_Z;
+        static const Vector3 NEGATIVE_UNIT_X;
+        static const Vector3 NEGATIVE_UNIT_Y;
+        static const Vector3 NEGATIVE_UNIT_Z;
+        static const Vector3 UNIT_SCALE;
+
+        /** Function for writing to a stream.
+        */
+        inline friend std::ostream& operator <<
+            ( std::ostream& o, const Vector3& v )
+        {
+            o << "Vector3(" << v.x << ", " << v.y << ", " << v.z << ")";
+            return o;
+        }
+    };
+
+}
+#endif /* DOXYGEN_SHOULD_SKIP_THIS */ 
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/hoja.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/hoja.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/hoja.h	(revision 774)
@@ -0,0 +1,34 @@
+#ifndef HOJA_H
+#define HOJA_H
+
+
+class Hoja
+{
+	public :
+		// Variable members
+    	long int  Vertices[4]; // Array of pointers to vertices
+		float Normal[3];
+		long int  Cuantas_hojas;
+		float Centro[3];
+		int hoja_cerca;
+		float coplanar;
+		long int hoja_cop;
+		float dist;
+		bool existe;
+		float criterio;
+		long int hoja_crit;
+
+		// Identificadores de los triángulos que forman la hoja
+		long int id_triangulo[2];
+
+	public :
+		// Constructors
+		Hoja (void); // Void constructor
+		Hoja (const Hoja& aHoja); // Copy constructor
+		virtual ~Hoja (void); // Destructor
+		//
+		float Distancia (Hoja&);
+		float Coplanaridad (Hoja&);
+};
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsConstructor.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsConstructor.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoLodStripsConstructor.h	(revision 774)
@@ -0,0 +1,148 @@
+#ifndef __GEO_LODSTRIPS_CONSTRUCTOR__
+#define __GEO_LODSTRIPS_CONSTRUCTOR__
+
+#include <windows.h>
+#include "GeoMeshSimpSequence.h"
+#include "GeoMesh.h"
+#include "auxiliar.h"
+
+namespace Geometry
+{
+	/// Construction module for general multiresolution models.
+	/** This module stores general mesh multiresolution
+	 *	representations using our own specific file format.
+	 It takes as inputs the strips provided by the
+	 stripification module and the edge collapse
+	 sequence computed by the simplification module.
+	 It builds a multiresolution representation and generates
+	 a LODStrips file.\n
+
+	 The LodStrips file begins with a line stating the name
+	 of the mesh file it refers to.
+	 This filetype has three different kinds of records
+	 storing the information required for the multiresolution
+	 model. All the records of the same kind are output following
+	 the right order.
+
+	 Those lines starting with a 'd' include:\n
+
+	 -# Strip to modify.\n
+	 -# Number of collapses.\n
+	 -# Number of vertex repetitions.\n
+	 -# Number of edge repetitions.\n
+	 .
+	 \n
+	 Those beginning with a 'p' include the number of 
+	 strips affected by a LOD change.\n\n
+
+	 And finally, the ones starting with a 'b' include
+	 all the information needed for collapses and repetitions.
+	 \n\n
+
+Inputs:\n
+- A strip set provided by the stripification module
+(Geometry::Mesh class).\n
+- An edge collapse sequence computed by 
+the simplification module
+(Geometry::MeshSimplificationSequence class).
+
+Outputs:\n
+- The module writes a file with the LODStrips information.
+- It also writes the LODStrips mesh into a file.
+*/
+	class LodStripsConstructor : public Serializable
+	{
+		protected:
+
+			int igual(Geometry::Vector3,Geometry::Vector3);
+			int igual(Geometry::Vector2,Geometry::Vector2);
+
+		private:
+
+			//	Lista de flyVectors, un flyVector tiene 4 componentes:
+			//  x,y,z: coordenadas 3D del vertice
+			//  w: se guarda el nº del vertice que simplifica a éste,
+			//  el siguiente
+			//	Lista que contiene el modelo en varias tiras y cada tira
+			//	contiene la secuencia
+
+			// de vertices que la forma
+			uint32 MARCA; //Para delimitar el final de tira.
+			uint32 TOTALTIRAS;
+			uint32 TOTALVERTS;
+			uint32 TOTALCAMBIOS;
+			uint32 TOTALCARAS;
+			uint32 MARCAVACIO;
+			uint32 TOTALINDICES;
+
+			Mesh	*geoMesh;
+			const	Geometry::Mesh *meshoriginal;
+			const	MeshSimplificationSequence *geoMeshSQ;
+			int		NumVertsRepetidos;
+
+			VECTORVERTEX				cVerts;
+			vector	<VECTORINT>	cStrips;
+
+			VECTORINT *lStripsV;
+			uint32 **vStrips;
+			tipoVertice *vVerts;
+
+			vector <tipoOrden> Ordenacion;
+
+			uint32 *pCurrentData;
+			uint32 *pCambios;
+			LODData *vCambios;
+			vector <LODData> cCambios;
+			VECTORUNINT cDatos;
+			uint32 *vDatos;
+
+			//0: No test 1: plano  2: esfera
+			//-------------------------------
+			//Lods disponibles
+			uint32 LodsDisp;
+
+			void GenerarModeloCompleto(Geometry::TIPOFUNC	upb);
+
+			void CalcularCambiosLODsVNuevaED(Geometry::TIPOFUNC	upb);
+
+			void OrdenarModeloVQSLIM(Geometry::TIPOFUNC	upb);
+
+			void GenerarModeloV(Geometry::TIPOFUNC	upb);
+
+			void CopiarVectors2ArraysNUEVAED();
+
+			void leeVerticesyTirasDeMesh();
+
+		public:
+
+			/// Constructor, gets a stripified mesh 
+			//	and a simplification sequence,
+			//	and generates the multiresolution model.
+			LodStripsConstructor(	const Mesh 			*,
+					const MeshSimplificationSequence	*,
+					Geometry::TIPOFUNC								upb);
+
+			// Destructor
+			~LodStripsConstructor();
+
+			/// Copy constructor
+			//LodStripsConstructor(const LodStripsConstructor&);
+
+			/// Assignment operator
+			//LodStripsConstructor& operator =(const LodStripsConstructor&);
+
+			/// Load 
+			void Load(Serializer &s);
+
+			/// Saves the multiresolution model into a LODStrip file and the
+			//	LODStrips mesh using the serializer given as a parameter.
+			void Save (Serializer &s);
+
+			///	GetMesh: Return de current Mesh.
+			Mesh	*	GetMesh();
+	};
+
+}
+
+#endif
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMesh.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMesh.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMesh.h	(revision 774)
@@ -0,0 +1,58 @@
+#ifndef __GEO_MESH__
+#define __GEO_MESH__
+
+#include <vector>
+#include <ostream>
+#include <iostream>
+#include <fstream>
+
+#include "GeoBase.h"
+#include "GeoVertexBuffer.h"
+#include "GeoSerializable.h"
+#include "GeoSubMesh.h"
+
+namespace Geometry {
+	
+	/// Mesh class interface
+	class Mesh : public Serializable
+	{
+	public:
+		/// Constructor
+		Mesh();
+
+		/// Destructor
+		~Mesh();
+
+		/// Copy constructor
+		Mesh(const Mesh&);
+
+		/// Assignment operator
+		Mesh& operator =(const Mesh&);
+
+		/// Loads data from a Serializer
+		void Load(Serializer &s);
+
+		/// Saves data to a Serializer
+		void Save(Serializer &s);
+
+		// Exports mesh to obj format file
+		void exportToOBJ(char *nomfich);
+
+		// Generate a shared vertex mesh
+		Geometry::Mesh *toSharedVertex(void);
+
+
+		VertexBuffer  *mVertexBuffer; ///< Shared VertexBuffer
+		SubMesh *mSubMesh;        ///< Array of subMesehs
+		size_t   mSubMeshCount;   ///< Total count of subMeshes
+		MeshType mType;           ///< Type of mesh
+
+		//OSCAR
+		char mSkeletonName[255];
+		bool hasSkeleton;
+		std::vector<VertexBoneAssignment> mBones;
+	};
+
+} //end of Geometry namespace
+
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshStripifier.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshStripifier.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/include/GeoMeshStripifier.h	(revision 774)
@@ -0,0 +1,95 @@
+/*	==========================================================================
+ *	(C) 2005 Universidad Jaime I de Castellón
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:	Make triangle strips meshes from triangle list meshes.
+	*
+	*
+	*	@file	GeoMeshStripifier.h
+/*===========================================================================*/
+
+#ifndef __GEO_STRIPIFIER__
+#define __GEO_STRIPIFIER__
+
+#include <GeoMesh.h>
+
+namespace Geometry
+{
+
+	/// Stripifier interface class.
+	/** This module implements methods that extract triangle strips from triangle meshes. 
+		\n
+
+Inputs:\n
+	- This module receives a pointer to a Geometry::Mesh object containing the model to be stripified.
+	.
+
+Outputs:\n
+	- The stripified mesh, contained also in a Geometry::Mesh object.
+	.
+
+	*/
+	class MeshStripifier
+	{
+		public:
+			/// Class constructor, receives as a parameter a const pointer to the object that describes a mesh.
+			MeshStripifier ();
+			MeshStripifier (const Geometry::Mesh *);
+
+			/// virtual class destructor.
+			virtual ~MeshStripifier (void);
+
+			/// Copy constructor
+			//MeshStripifier(const MeshStripifier&);
+
+			/// Assignment operator
+			//MeshStripifier& operator =(const MeshStripifier&);
+
+			/// Starts the stripification process. This is a pure virtual method and must be overloaded in a derived class that implements a stripification algorithm.
+			virtual int Stripify()=0;
+
+			/// Returns the stripified mesh.
+			Mesh *	GetMesh ();
+
+		protected:
+
+			//	Progress bar function.
+			Geometry::TIPOFUNC mUPB;
+
+			//	Mesh object.
+			Geometry::Mesh		*mGeoMesh;
+	};
+
+	class CustomStripifier : public MeshStripifier
+	{
+		public:
+			
+			/// Class constructor, receives as a parameter a const pointer to the object that describes a mesh.
+			CustomStripifier();
+
+			CustomStripifier(	const Geometry::Mesh	*geoMesh);
+
+			/// Class destructor.
+			~CustomStripifier(void);
+
+			/// Copy constructor
+			//CustomStripifier(const CustomStripifier&);
+
+			/// Assignment operator
+			//CustomStripifier& operator =(const CustomStripifier&);
+
+			/// Starts the stripification process. This is a custom stripification method.
+			int Stripify();
+
+			/// Returns the stripified mesh.
+			Mesh *	GetMesh();
+			
+			//	Set the progress bar function.
+			void	SetProgressFunc(Geometry::TIPOFUNC upb);
+	};
+
+}
+
+#endif
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/policy.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/policy.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/policy.cpp	(revision 774)
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: policy.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#include "detail/policy.h"
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+void policy::Challenge(strip Strip, size_t Degree, size_t CacheHits)
+{
+	if (Strip.Size() < m_MinStripSize)
+		return;
+
+	// Cache is disabled, take the longest strip
+	if (! m_Cache) {
+
+		if (Strip.Size() > m_Strip.Size())
+			m_Strip = Strip;
+
+	// Cache simulator enabled
+	} else {
+
+		// Priority 1: Keep the strip with the best cache hit count
+		if (CacheHits > m_CacheHits) {
+			m_Strip = Strip;
+			m_Degree = Degree;
+			m_CacheHits = CacheHits;
+
+		} else if (CacheHits == m_CacheHits) {
+
+			// Priority 2: Keep the strip with the loneliest start triangle
+			if ((m_Strip.Size() != 0) && (Degree < m_Degree)) {
+				m_Strip = Strip;
+				m_Degree = Degree;
+
+			// Priority 3: Keep the longest strip 
+			} else if (Strip.Size() > m_Strip.Size()) {
+				m_Strip = Strip;
+				m_Degree = Degree;
+			}
+		}
+	}
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/connectivity_graph.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/connectivity_graph.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/connectivity_graph.cpp	(revision 774)
@@ -0,0 +1,132 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: connectivity_graph.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#include "detail/connectivity_graph.h"
+
+#include <algorithm>
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+namespace
+{
+
+	class tri_edge : public triangle_edge
+	{
+	public:
+		tri_edge(index A, index B, size_t TriPos)
+			: triangle_edge(A, B), m_TriPos(TriPos) { }
+
+		size_t TriPos() const { return m_TriPos; }
+
+	private:
+		size_t	m_TriPos;
+	};
+
+
+	class cmp_tri_edge_lt
+	{
+	public:
+		bool operator() (const tri_edge & a, const tri_edge & b) const;
+	};
+
+
+	typedef std::vector<tri_edge> edge_map;
+
+
+	void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge);
+
+}
+
+
+
+
+void make_connectivity_graph(graph_array<triangle> & Triangles, const indices & Indices)
+{
+	assert(Triangles.size() == (Indices.size() / 3));
+
+	// Fill the triangle data
+	for (size_t i = 0; i < Triangles.size(); ++i)
+		Triangles[i] = triangle(Indices[i * 3 + 0], Indices[i * 3 + 1], Indices[i * 3 + 2]);
+
+	// Build an edge lookup table
+	edge_map EdgeMap;
+	EdgeMap.reserve(Triangles.size() * 3);
+
+	for (size_t i = 0; i < Triangles.size(); ++i) {
+
+		const triangle & Tri = * Triangles[i];
+
+		EdgeMap.push_back(tri_edge(Tri.A(), Tri.B(), i)); 
+		EdgeMap.push_back(tri_edge(Tri.B(), Tri.C(), i)); 
+		EdgeMap.push_back(tri_edge(Tri.C(), Tri.A(), i)); 
+	}
+
+	std::sort(EdgeMap.begin(), EdgeMap.end(), cmp_tri_edge_lt());
+
+	// Link neighbour triangles together using the lookup table
+	for (size_t i = 0; i < Triangles.size(); ++i) {
+
+		const triangle & Tri = * Triangles[i];
+
+		LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.B(), Tri.A(), i)); 
+		LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.C(), Tri.B(), i)); 
+		LinkNeighbours(Triangles, EdgeMap, tri_edge(Tri.A(), Tri.C(), i)); 
+	}
+}
+
+
+
+namespace
+{
+	
+	inline bool cmp_tri_edge_lt::operator() (const tri_edge & a, const tri_edge & b) const
+	{
+		const index A1 = a.A();
+		const index B1 = a.B();
+		const index A2 = b.A();
+		const index B2 = b.B();
+
+		if ((A1 < A2) || ((A1 == A2) && (B1 < B2)))
+			return true;
+		else
+			return false;
+	}
+
+
+	void LinkNeighbours(graph_array<triangle> & Triangles, const edge_map & EdgeMap, const tri_edge Edge)
+	{
+		// Find the first edge equal to Edge
+		edge_map::const_iterator it = std::lower_bound(EdgeMap.begin(), EdgeMap.end(), Edge, cmp_tri_edge_lt());
+
+		// See if there are any other edges that are equal
+		// (if so, it means that more than 2 triangles are sharing the same edge,
+		//  which is unlikely but not impossible)
+		for (; (it != EdgeMap.end()) && (Edge == (* it)); ++it)
+			Triangles.insert_arc(Edge.TriPos(), it->TriPos());
+
+		// Note: degenerated triangles will also point themselves as neighbour triangles
+	}
+
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace detail
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeConstructor.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeConstructor.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeConstructor.cpp	(revision 774)
@@ -0,0 +1,1 @@
+#include "GeoLodTreeConstructor.h"
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSubMesh.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSubMesh.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSubMesh.cpp	(revision 774)
@@ -0,0 +1,53 @@
+#include "GeoSubMesh.h"
+
+using namespace Geometry;
+
+SubMesh::SubMesh():
+	mIndex(0), mVertexBuffer(0), mIndexCount(0),mSharedVertexBuffer(false), mStrip(0), mStripCount(0)
+{
+}
+
+SubMesh::~SubMesh()
+{
+	delete[] mIndex;
+	if (!mSharedVertexBuffer) delete mVertexBuffer;
+}
+
+void SubMesh::Load(Serializer &s)
+{
+	//Clear Data:
+	delete[] mIndex; mIndex = 0;
+	if (!mSharedVertexBuffer)
+	{
+		delete mVertexBuffer;
+		mVertexBuffer = 0;
+	}
+	mIndexCount = 0;
+
+	//Load Data from Serializer
+	s.ReadArray(&mSharedVertexBuffer,1);
+	if (mSharedVertexBuffer)
+	{
+		mVertexBuffer = 0;
+	}
+	else
+	{
+		mVertexBuffer = new VertexBuffer();
+		mVertexBuffer->Load(s);
+	};
+
+	s.ReadArray(&mIndexCount,1);
+	mIndex = new Index[mIndexCount];
+	s.ReadArray(mIndex,mIndexCount);
+}
+
+void SubMesh::Save(Serializer &s)
+{
+	s.WriteArray(&mSharedVertexBuffer,1);
+	if (!mSharedVertexBuffer)
+	{
+		mVertexBuffer->Save(s);
+	}
+	s.WriteArray(&mIndexCount,1);
+	s.WriteArray(mIndex,mIndexCount);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVertexBuffer.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVertexBuffer.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVertexBuffer.cpp	(revision 774)
@@ -0,0 +1,73 @@
+#include "GeoVertexBuffer.h"
+
+using namespace Geometry;
+
+//---------------------------------------------------------------------
+VertexBuffer::~VertexBuffer()
+{
+	delete[] mPosition;
+	delete[] mNormal;
+	delete[] mTexCoords;
+}
+
+//---------------------------------------------------------------------
+void VertexBuffer::Save(Serializer &s)
+{
+	s.WriteArray(&mVertexInfo,1);
+	s.WriteArray(&mVertexCount,1);
+	if (mVertexInfo & VERTEX_POSITION)
+	{
+		s.WriteArray(mPosition, mVertexCount);
+	}
+	if (mVertexInfo & VERTEX_NORMAL)
+	{
+		s.WriteArray(mNormal, mVertexCount);
+	}
+	if (mVertexInfo & VERTEX_TEXCOORDS)
+	{
+		s.WriteArray(mTexCoords, mVertexCount);
+	}
+}
+
+//---------------------------------------------------------------------
+void VertexBuffer::Load(Serializer &s)
+{
+	//Clear data
+	delete[] mPosition;  mPosition = 0;
+	delete[] mNormal;    mNormal = 0;
+	delete[] mTexCoords; mTexCoords = 0;
+
+	s.ReadArray(&mVertexInfo,1);
+	s.ReadArray(&mVertexCount,1);
+	if (mVertexInfo & VERTEX_POSITION)
+	{
+		mPosition = new Vector3[mVertexCount];
+		s.ReadArray(mPosition, mVertexCount);
+	}
+	if (mVertexInfo & VERTEX_NORMAL)
+	{
+		mNormal = new Vector3[mVertexCount];
+		s.ReadArray(mNormal, mVertexCount);
+	}
+	if (mVertexInfo & VERTEX_TEXCOORDS)
+	{
+		mTexCoords = new Vector2[mVertexCount];
+		s.ReadArray(mTexCoords, mVertexCount);
+	}
+}
+
+//---------------------------------------------------------------------
+VertexBuffer *VertexBuffer::Clone() const
+{
+	VertexBuffer *vnew = new VertexBuffer();
+	vnew->mVertexInfo = mVertexInfo;
+	vnew->mVertexCount = mVertexCount;
+	vnew->mPosition = new Vector3[mVertexCount];
+	vnew->mNormal = new Vector3[mVertexCount];
+	vnew->mTexCoords = new Vector2[mVertexCount];
+
+	memcpy(vnew->mPosition, mPosition, mVertexCount*sizeof(Vector3));
+	memcpy(vnew->mNormal, mNormal, mVertexCount*sizeof(Vector3));
+	memcpy(vnew->mTexCoords, mTexCoords, mVertexCount*sizeof(Vector2));
+	return vnew;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsLibrary.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsLibrary.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsLibrary.cpp	(revision 774)
@@ -0,0 +1,649 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:	
+	*
+	*
+	*	@file	GeoLodStripsLibrary.cpp
+/*===========================================================================*/
+
+#include "GeoLodStripsLibrary.h"
+
+using namespace Geometry;
+
+//-----------------------------------------------------------------------------
+//	Constructors.
+//-----------------------------------------------------------------------------
+LodStripsLibrary::LodStripsLibrary(	std::string	name,
+																		Mesh				*geomesh)
+{
+	const	char	*name_of_file;
+
+	//	Sets the current lod.
+	mCurrentLod	=	0;
+
+	//	Converts a String to const char *.
+	name_of_file	=	name.data();
+
+	//	Sets the global mesh.
+	mGeoMesh = geomesh;
+	
+	//	Loads the Level Of Detail file.
+	LodStripsLibrary::LoadStripMesh((char*)name_of_file,mGeoMesh);
+}
+
+//-----------------------------------------------------------------------------
+//	Destroyer.
+//-----------------------------------------------------------------------------
+LodStripsLibrary::~LodStripsLibrary()
+{
+		delete[] mStrips;
+}
+
+//-----------------------------------------------------------------------------
+//	Public.
+//-----------------------------------------------------------------------------
+
+/*
+	Go to the level of detail.
+*/
+uint32 LodStripsLibrary::GoToLod(uint32 newLOD)
+{
+	register	int							j;
+	register	int							offset;
+	long			int							i;
+	long			int							k;
+	long			int							l;
+	long			int							b_change_ok	=	1;
+	long			int							lod;
+	long			int							t;
+	long			int							p;
+	long			int							r;
+	long			int							sig;
+	long			int							p_end;
+	long			int							p_init;
+	long			int							p_end_all;
+	long			int							el1;
+	long			int							el2;
+	long			int							total_changes;
+	long			int							totalR;
+	int												b256;
+	SmallIntVector						*strip;
+	SmallIntVector::iterator	start;
+	SmallInt									*p_data;
+	uint32										return_value;
+
+	//	Initialize the return value to the current LOD.
+	return_value	=	mCurrentLod;
+
+	if (newLOD != mCurrentLod)
+	{
+		if (newLOD > mCurrentLod)
+		{
+			//HACIA ADELANTE
+			//CurrentRegLOD
+			//Incrementamos el LOD -> Calcular siguientes
+			for (lod = mCurrentLod; lod < newLOD; lod++)
+			{
+				sig				=	mVertex[lod];
+				total_changes	=	mPChanges[lod];
+
+				for (i = 0; i < total_changes; i++)
+				{
+					//	Strip q Cambia.
+					t			=	mCurrentRegLOD->strip; 
+					strip	=	&(mStrips[t]);
+					start	=	strip->begin();				
+				
+					//	Position.
+					totalR	=	mCurrentRegLOD->position;
+
+					for (j = totalR - 1; j >= 0; j--)
+					{
+						start[*mCurrentData]	=	sig;
+						
+						++mCurrentData;
+					}
+					
+					//	L1.
+					totalR	=	mCurrentRegLOD->vertexRepetition;
+					
+					for (j = totalR - 1; j >= 0; j--)
+					{
+						offset	=	*mCurrentData + 1;
+
+						strip->erase(	start + offset,
+													start
+													+
+													offset
+													+
+													(*(mCurrentData + 1)));
+
+						++mCurrentData;
+						++mCurrentData;
+					}
+					
+					//	L2
+					totalR	=	mCurrentRegLOD->edgeRepetition;
+					
+					for (j = totalR - 1; j >= 0; j--)
+					{
+						offset	=	*mCurrentData + 2;
+						strip->erase(	start	+	offset,
+													start
+													+
+													offset
+													+
+													2*(*(mCurrentData + 1)));
+
+						++mCurrentData;
+						++mCurrentData;
+					}
+
+					++mCurrentRegLOD;
+					
+					mStripsChanges[t]	=	1;
+				
+				}
+				
+				mCurrentLod	=	lod + 1;
+			}
+
+		}
+		//	Si el nuevo LOD es menos que el actual.
+		else
+		{ 
+			--mCurrentRegLOD;
+			--mCurrentData;
+			
+			//	Decrementamos el LOD -> Calcular anteriores.
+			for (lod = mCurrentLod; lod > newLOD; lod--)
+			{
+				total_changes	=	mPChanges[lod - 1];
+				
+				for (i = 0; i < total_changes; i++)
+				{
+					t			=	mCurrentRegLOD->strip;
+					strip	=	&(mStrips[t]);
+					start	=	mStrips[t].begin();
+
+					//	L2.
+					totalR	=	mCurrentRegLOD->edgeRepetition;
+					
+					for (j = 0; j < totalR; j++)
+					{
+						el1	=	(*strip)[*(mCurrentData - 1)];
+						el2	=	(*strip)[*(mCurrentData - 1) + 1];
+						r		=	*(mCurrentData);
+						
+						for (k = 0; k < r; k++)
+						{
+							(*strip).insert(start+*(mCurrentData - 1),el2);
+							(*strip).insert(start+*(mCurrentData - 1),el1);
+						}
+						
+						--mCurrentData;
+						--mCurrentData;
+					}
+
+					//	Vertex Repetition.
+					totalR	=	mCurrentRegLOD->vertexRepetition;
+					
+					for (j = 0; j < totalR; j++)
+					{
+						el1	=	(*strip)[*(mCurrentData-1)];
+						r		=	*(mCurrentData);
+						
+						for (k = 0; k < r; k++)
+						{
+							(*strip).insert(start+*(mCurrentData-1),el1);
+						}
+
+						--mCurrentData;
+						--mCurrentData;
+					}
+					
+					//	POS.
+					totalR	=	mCurrentRegLOD->position;
+					
+					for (j = 0; j < totalR; j++)
+					{
+						(*strip)[*mCurrentData]	=	lod - 1;
+						--mCurrentData;
+					}
+					
+					--mCurrentRegLOD;
+					mStripsChanges[t]	=	1;
+				}			
+				
+				//	Actualizar LOD.
+				mCurrentLod	=	lod - 1;
+			}
+			
+			++mCurrentData;
+			++mCurrentRegLOD;
+		} 
+
+	}	
+
+	/*
+	// Visualizar.
+	k		=	0;
+
+	for (uint32 i	=	0; i < mTotalStrips; i++)
+	{
+		l			=	mStrips[i].size();
+		
+		//	Los dos degenerados.
+		k			=	k + l + 2;
+		
+		//	If is not the first strip.
+		if (i != 0)
+		{
+			start	=	mStrips[i].begin();
+
+			//	Degenerado.
+			mStrips[i].insert(start,mStrips[i][0]);
+		}
+
+		//	If is not the last strip.
+		if (i != (mTotalStrips - 1))
+		{
+			//	Degenerado.
+			mStrips[i].push_back(mStrips[i][mStrips[i].size() - 1]);
+		}
+
+	}
+	*/
+	
+	/*
+	 * Write in the hardware buffer.
+	 *
+	int contTira	= 0;
+	
+	//	Vuelca los datos en el buffer de pantalla.
+	//Ogre::HardwareIndexBufferSharedPtr	ibuf;
+	for(unsigned int j = 0; j < mGeoMesh->mSubMeshCount; j++)
+	{
+		k	=	0;
+		for(unsigned int s = 0; s < mGeoMesh->mSubMesh[j].mStripCount; s++)
+		{
+			l	=	mStrips[contTira].size();
+
+			mIndexBuffer[j]->writeData(k*sizeof(unsigned long),
+					l*sizeof(unsigned long),
+					&mStrips[contTira][0]);
+
+			k	=	k + l;
+
+			contTira++;
+		}
+
+		indexes[j]->indexCount	=	k;
+	}
+	*/
+	
+	/*
+	//	Para el bunny.
+	start	=	mStrips[0].begin();
+	mStrips[0].erase(start);
+	*/
+	/*
+	for (uint32 i	=	0; i < mTotalStrips; i++)
+	{
+		start	=	mStrips[i].begin();
+		
+		//	If is not the first strip.
+		if (i != 0)
+		{
+			mStrips[i].erase(start);
+		}
+
+		//	If is not the last strip.
+		if (i != (mTotalStrips - 1))
+		{
+			mStrips[i].pop_back();
+		}
+
+	}
+	*/
+	
+	return	return_value;
+}
+
+
+/*
+	Gets the maximum level of detail.
+*/
+uint32 LodStripsLibrary::MaxLod()
+{
+	return	mMaxLod;
+}
+
+/*
+	Gets the minimum level of detail.
+*/
+uint32 LodStripsLibrary::MinLod()
+{
+	return	mMinLod;
+}
+
+/// Returns the number of vertices of the highest LOD.
+uint32	LodStripsLibrary::MaxVertices()
+{
+	uint32	number_of_vertices;
+
+	number_of_vertices	=	mTotalVertices;
+
+	return	number_of_vertices;
+}
+
+/// Returns the number of vertices of the lowest LOD.
+uint32	LodStripsLibrary::MinVertices()
+{
+	uint32	current_lod;
+	uint32	number_of_vertices;
+
+	//	Total vertices less total lod.
+	number_of_vertices	=	mTotalVertices - (mMaxLod + 1);
+
+	return	number_of_vertices;
+}
+
+/// Returns the number of triangles of the highest LOD.
+uint32	LodStripsLibrary::MaxFaces()
+{
+	uint32	number_of_faces;
+
+	uint32	current_lod;
+
+	current_lod	=	GoToLod(MaxLod());
+
+	//	Initialize number of faces count.
+	number_of_faces	=	0;
+
+	//	For each strip.
+	for (int strip	=	0; strip < mTotalStrips; strip++)
+	{
+		number_of_faces	+=	mStrips[strip].size() - 2;
+	}
+
+	GoToLod(current_lod);
+
+	return	number_of_faces;
+}
+
+/// Returns the number of triangles of the lowest LOD.
+uint32	LodStripsLibrary::MinFaces()
+{
+	uint32	current_lod;
+	uint32	number_of_faces;
+
+	current_lod	=	GoToLod(MinLod());
+
+	//	Initialize number of faces count.
+	number_of_faces	=	0;
+
+	//	For each strip.
+	for (int strip	=	0; strip < mTotalStrips; strip++)
+	{
+		number_of_faces	+=	mStrips[strip].size() - 2;
+	}
+
+	GoToLod(current_lod);
+
+	return	number_of_faces;
+}
+
+/// Establishes the new LOD range.
+/// Only the LODs in that range are stored and used.
+void		LodStripsLibrary::TrimByLod(uint32 minLod, uint32 maxLod)
+{
+	mMinLod	=	minLod;
+	mMaxLod	=	maxLod;
+}
+
+uint32	LodStripsLibrary::GetStripCount()
+{
+	return	(uint32)	mTotalStrips;
+}
+
+//-----------------------------------------------------------------------------
+//	Private.
+//-----------------------------------------------------------------------------
+
+/*
+	Copy a STL vector to a C array.
+*/
+void LodStripsLibrary::CopyVectors2Arrays()
+{
+	int								i;
+	int								j;
+	int								*vertex;
+	int								t_actual;
+	SmallInt 					max;
+	SmallInt 					t;
+	SmallInt 					strip;
+	SmallInt 					*data_array;
+	SmallIntVector 		tira;
+	LODRegisterType		lod_register;
+	LODRegisterType		*changes_array;
+	LODRegisterVector	list_changes;
+
+	mTotalStrips		=	mFileStrips.size();
+	mVertex					=	new SmallInt[mTotalVertices];
+	mStripsChanges	=	new SmallInt[mTotalChanges];
+	mStrips					=	new SmallIntVector[mTotalStrips];
+	data_array			=	new SmallInt[mData.size()];
+	
+	//Calcular el tamaño maximo de tira y el numero de caras total
+	max					=	0;
+	mTotalFaces	=	0;
+	
+	for (i = 0; i < mFileStrips.size(); i++)
+	{
+		t	=	mFileStrips[i].size();
+		
+		if (t>max)
+		{
+			max	=	t;
+		}
+
+		mTotalFaces	+=	t - 2;
+	}
+
+	//Nueva version de ALLOCATE.
+	changes_array	=	new LODRegisterType[mFileChangesLOD.size()];
+	
+	//Rellenar vChanges
+	for (i = 0; i < mFileChangesLOD.size(); ++i)
+	{
+		changes_array[i]	=	mFileChangesLOD[i];
+	}
+
+	mCurrentRegLOD	=	changes_array;
+	
+	//COPY----------------------------------
+	//Copiar las tiras
+	for (i = 0; i < mFileStrips.size(); i++)
+	{
+		for (j = 0; j < mFileStrips[i].size(); j++)
+		{
+			//Rellenar el vVector
+			mStrips[i].push_back(mFileStrips[i][j]);
+		}
+		
+		//Poner a 0 los flags de modificados.
+		mStripsChanges[i]	=	0;
+	}
+
+	for (i = 0; i < mData.size(); i++)
+	{
+		data_array[i]	=	mData[i];
+	}
+	
+	mCurrentData	=	data_array;
+
+	//Meter los vertices en mVertex 
+	for(i = 0; i < mFileVertices.size(); i++)
+	{
+		mVertex[i]	=	mFileVertices[i];
+	}
+}
+
+//-----------------------------------------------------------------------------
+// LoadStripMesh
+//-----------------------------------------------------------------------------
+void LodStripsLibrary::LoadStripMesh(char *name, Mesh *geomesh)
+{
+	FILE															*fp;
+	VertexType												vertex_aux;
+	SmallIntVector										strip_aux;
+	LODRegisterType										lod_register;
+	std::vector			<LODRegisterType>	list_pos;
+	std::vector			<unsigned int>		p_changes;
+	int																value;
+	int																v		=	0;
+	int																t		=	-1;
+	int																s		=	0;
+	int																sig	=	0;
+	int																c		=	-1;
+	char															buff[80];
+	char															*ptr;
+	Index															*index;
+	Index															*indexBegin;
+	Index															*indexEnd;
+	SubMesh														*geoSubMesh;
+
+	//	For each one of the submeshes.
+	for (int submesh	=	0; submesh < geomesh->mSubMeshCount; submesh++)
+	{
+		geoSubMesh	=	&geomesh->mSubMesh[submesh];
+
+		//	For each one of the strips.
+		for (int strip = 0; strip < geoSubMesh->mStripCount; strip++)
+		{
+			// Insert an empty strip.
+			t++;
+			strip_aux.clear();
+			mFileStrips.push_back(strip_aux);
+
+			//	First index of the strip.
+			indexBegin	=	geoSubMesh->mStrip[strip];
+
+			//	If the strips is not the first.
+			if (strip != 0)
+			{
+				indexBegin++;
+			}
+
+			//	If is the final strip
+			if (strip	== (geoSubMesh->mStripCount - 1))
+			{
+				//	The end of the index array.
+				indexEnd	= &geoSubMesh->mIndex[geoSubMesh->mIndexCount];
+			}
+			else
+			{
+				//	The beginning of the next strip.
+				indexEnd	= geoSubMesh->mStrip[strip + 1];
+
+				//	Remove degenerated
+				indexEnd--;
+			}
+			
+			int i;
+			i	= 0;
+			//	For each index of the strip.
+			for (index = indexBegin; index < indexEnd; index++)
+			{
+				mFileStrips[t].push_back(indexBegin[i]);
+				i++;
+			}
+		}
+	}
+
+	//	Open the LOD file.
+	if ((fp = fopen (name, "r")) == NULL)
+	{
+		//	Error in open.
+	}
+	else
+	{
+		mTotalChanges	=	0;
+		
+
+		while (!feof (fp))
+		{
+			fgets (buff, 80, fp);
+			
+			if (*buff == 'v')
+			{
+				//VERTICES
+				sscanf (buff+2,"%d",&value);
+				
+				mFileVertices.push_back(value);
+				v++;
+			}
+			else if ( (*buff == 'c') || (*buff == 'd'))
+			{
+				if (*buff == 'c')
+				{
+					// c indica que empieza un nuevo cambio
+					c++;
+				}
+				else
+				{
+					unsigned	int	a;
+					unsigned	int	b;
+					unsigned	int	c;
+					unsigned	int	d;
+					
+					sscanf (buff+2,"%u %u %u %u\n",&a,&b,&c,&d);
+					lod_register.strip						=	a;
+					lod_register.position					=	b;
+					lod_register.vertexRepetition	=	c;
+					lod_register.edgeRepetition		=	d;
+					
+					mFileChangesLOD.push_back(lod_register);
+				}
+			}
+			else if (*buff=='b')
+			{
+				sscanf(buff+2,"%u",&value);
+				mData.push_back(value);
+			}
+			else if (*buff=='p')
+			{
+				sscanf (buff+2,"%u",&value);
+				p_changes.push_back(value);
+			}//Fin ElseIf
+
+		} // End WhileEOF
+		
+		fclose(fp);
+		
+		//	Max / Min values for LOD.
+		mLods											=	p_changes.size();
+		mMinLod										=	0;
+		mMaxLod										=	mLods;
+
+		//// CHAPUZA PROVISIONAL: EL ULTIMO ELEMENTO SE REPITE 2 VECES V.v
+		mPChanges			=	new SmallInt[mLods];
+		
+		for (unsigned int i = 0; i < mLods; i++)
+		{
+			mPChanges[i] = p_changes[i];
+		}
+
+		mTotalVertices			=	mFileVertices.size();
+		mTotalStrips				=	mFileStrips.size();
+		mTotalChanges				=	mFileChangesLOD.size();
+
+		//Copy the data to the structure we will use
+		CopyVectors2Arrays();
+	}
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSerializer.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSerializer.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoSerializer.cpp	(revision 774)
@@ -0,0 +1,230 @@
+#include "GeoSerializer.h"
+
+
+namespace Geometry {
+
+    //---------------------------------------------------------------------
+	Serializer::Serializer(String name, Mode mode)
+		: mMode(mode)
+	{
+		char *char_mode = 0;
+		switch (mMode)
+		{
+		case READ : 
+			char_mode = "rb"; 
+			break;
+		case APPEND:
+			char_mode = "a+b";
+			break;
+		case WRITE:
+			char_mode = "wb";
+			break;
+		}
+
+		mFile = fopen(name.c_str(),char_mode);
+		mSize = 0;
+		assert(mFile);
+	}
+
+    //---------------------------------------------------------------------
+    Serializer::~Serializer()
+    {
+		fflush(mFile);
+		fclose(mFile);
+    }
+
+    //---------------------------------------------------------------------
+    void Serializer::WriteArray(const float* const pFloat, size_t count)
+    {
+#	if GEO_ENDIAN == GEO_ENDIAN_BIG
+            float *float_to_write = (float *)malloc(sizeof(float) * count);
+            memcpy(float_to_write, pFloat, sizeof(float) * count);
+            
+            flipToLittleEndian(float_to_write, sizeof(float), count);
+            writeData(float_to_write, sizeof(float), count);
+            
+            free(float_to_write);
+# 	else
+            WriteData(pFloat, sizeof(float), count);
+#	endif
+    }
+
+    //---------------------------------------------------------------------
+    void Serializer::WriteArray(const uint16* const pShort, size_t count = 1)
+    {
+#	if GEO_ENDIAN == GEO_ENDIAN_BIG
+            unsigned short *short_to_write = (unsigned short *)malloc(sizeof(unsigned short) * count);
+            memcpy(short_to_write, pShort, sizeof(unsigned short) * count);
+            
+            flipToLittleEndian(short_to_write, sizeof(unsigned short), count);
+            WriteData(short_to_write, sizeof(unsigned short), count);
+            
+            free(short_to_write);
+# 	else
+            WriteData(pShort, sizeof(unsigned short), count);
+#	endif
+    }
+    //---------------------------------------------------------------------
+    void Serializer::WriteArray(const uint32* const pInt, size_t count = 1)
+    {
+#	if GEO_ENDIAN == GEO_ENDIAN_BIG
+            unsigned int *int_to_write = (unsigned int *)malloc(sizeof(unsigned int) * count);
+            memcpy(int_to_write, pInt, sizeof(unsigned int) * count);
+            
+            FlipToLittleEndian(int_to_write, sizeof(unsigned int), count);
+            WriteData(int_to_write, sizeof(unsigned int), count);
+            
+            free(int_to_write);
+# 	else
+            WriteData(pInt, sizeof(unsigned int), count);
+#	endif
+    }
+
+    //---------------------------------------------------------------------
+    void Serializer::WriteArray(const bool* const pBool, size_t count = 1)
+	{
+		//TODO: Apple has problems 
+        WriteData(pBool, sizeof(bool), count);
+	}
+	//---------------------------------------------------------------------
+	void Serializer::WriteArray(const Vector3* const pDest, size_t count)
+    {
+        for(size_t i = 0; i < count; ++i)
+		{
+			WriteArray(pDest[i].val,3);
+		}
+    }
+	//---------------------------------------------------------------------
+	void Serializer::WriteArray(const Vector2* const pDest, size_t count)
+    {
+        for(size_t i = 0; i < count; ++i)
+		{
+			WriteArray(pDest[i].val,2);
+		}
+    }
+
+    //---------------------------------------------------------------------
+    void Serializer::WriteData(const void* const buf, size_t size, size_t count)
+    {
+		size_t wcount = fwrite((void* const)buf, size, count, mFile);
+		assert(wcount == count);
+		mSize += size*count;
+    }
+
+	//---------------------------------------------------------------------
+	void Serializer::ReadData(void *pDest, size_t size, size_t count)
+	{
+		size_t rcount = fread(pDest,size,count,mFile);
+		assert(rcount == count);
+		mSize += size*count;
+	};
+
+
+	// JGA
+	char * Serializer::miReadData(char *pDest, size_t pDestsize)
+	{
+		return fgets(pDest, (int)pDestsize, mFile);
+	};
+
+	void Serializer::miReadData2(void *pDest, size_t size, size_t count)
+	{
+		size_t rcount = fread(pDest,size,count,mFile);
+		assert(rcount == count);
+		mSize += size*count;
+	};
+	// fin JGA
+
+	//	GPR.
+	void	Serializer::WriteData(const	String	&string)
+	{
+			fputs(string.c_str(), mFile);
+
+			// Write terminating newline char
+			fputc('\n', mFile);
+			
+			mSize	+=	string.length() + 1;
+	}
+	//	fin	GPR
+
+
+     //---------------------------------------------------------------------
+    void Serializer::ReadArray(bool *pDest, size_t count)
+    {
+		//TODO:: Apple has problmes with bools
+        ReadData(pDest,sizeof(bool), count);
+    }
+	
+    //---------------------------------------------------------------------
+    void Serializer::ReadArray(float *pDest, size_t count)
+    {
+        ReadData(pDest, sizeof(float), count);
+        FlipFromLittleEndian(pDest, sizeof(float), count);
+    }
+    //---------------------------------------------------------------------
+    void Serializer::ReadArray(unsigned short *pDest, size_t count)
+    {
+        ReadData(pDest, sizeof(unsigned short), count);
+        FlipFromLittleEndian(pDest, sizeof(unsigned short), count);
+    }
+    //---------------------------------------------------------------------
+    void Serializer::ReadArray(unsigned int *pDest, size_t count)
+    {
+        ReadData(pDest, sizeof(unsigned int), count);
+        FlipFromLittleEndian(pDest, sizeof(unsigned int), count);
+    }
+    //---------------------------------------------------------------------
+    void Serializer::ReadArray(Vector3 *pDest, size_t count)
+    {
+        for(size_t i = 0; i < count; ++i)
+		{
+			ReadArray(pDest[i].val,3);
+		}
+    }
+	//---------------------------------------------------------------------
+	void Serializer::ReadArray(Vector2 *pDest, size_t count)
+    {
+        for(size_t i = 0; i < count; ++i)
+		{
+			ReadArray(pDest[i].val,2);
+		}
+    }
+
+
+//---------------------------------------------------------------------
+
+
+    void Serializer::FlipToLittleEndian(void *pData, size_t size, size_t count)
+    {
+#	if GEO_ENDIAN == GEO_ENDIAN_BIG
+        FlipEndian(pData, size, count);
+#	endif
+    }
+    
+    void Serializer::FlipFromLittleEndian(void *pData, size_t size, size_t count)
+    {
+#	if GEO_ENDIAN == GEO_ENDIAN_BIG
+        FlipEndian(pData, size, count);
+#	endif
+    }
+    
+    void Serializer::FlipEndian(void *pData, size_t size, size_t count)
+    {
+        for(unsigned int index = 0; index < count; index++)
+        {
+            FlipEndian((void *)((char*)pData + (index * size)), size);
+        }
+    }
+    
+    void Serializer::FlipEndian(void *pData, size_t size)
+    {
+        char swapByte;
+        for(unsigned int byteIndex = 0; byteIndex < size/2; byteIndex++)
+        {
+            swapByte = *((char *)pData + byteIndex);
+            *((char *)pData + byteIndex) = *((char *)pData + size - byteIndex - 1);
+            *((char *)pData + size - byteIndex - 1) = swapByte;
+        }
+    }
+    
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.h	(revision 774)
@@ -0,0 +1,177 @@
+#ifndef NAUTILUS_ADJPRIMS_INCLUDED // -*- C++ -*-
+#define NAUTILUS_ADJPRIMS_INCLUDED
+
+/************************************************************************
+
+  Primitive entities for adjacency models (AdjModel).
+  $Id: AdjPrims.h,v 1.4 1997/03/18 18:39:34 garland Exp $
+
+  Adapted from:
+     mlab: (Id: primitives.h,v 1.7 1997/02/06 16:30:14 garland Exp)
+  via
+     QSlim: (Id: primitives.h,v 1.3 1997/02/18 21:11:29 garland Exp)
+
+ ************************************************************************/
+
+//#include "Nautilus.h"
+#include "NPrim.h"
+#include <gfx/tools/Buffer.h>
+#include <gfx/math/Vec3.h>
+#include <gfx/math/Vec2.h>
+#include <gfx/geom/3D.h>
+
+namespace qslim
+{
+	class Vertex;
+	class Edge;
+	class Face;
+
+
+	typedef buffer<Vertex *> vert_buffer;
+	typedef buffer<Edge *> edge_buffer;
+	typedef buffer<Face *> face_buffer;
+	typedef buffer<Vec3> vec3_buffer;
+	typedef buffer<Vec2> vec2_buffer;
+
+	extern void untagFaceLoop(Vertex *v);
+	extern void collectFaceLoop(Vertex *v, face_buffer& faces);
+
+	#define EDGE_BOGUS 0
+	#define EDGE_BORDER 1
+	#define EDGE_MANIFOLD 2
+	#define EDGE_NONMANIFOLD 3
+	extern int classifyEdge(Edge *);
+
+	#define VERTEX_INTERIOR 0
+	#define VERTEX_BORDER 1
+	#define VERTEX_BORDER_ONLY 2
+	extern int classifyVertex(Vertex *);
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// The actual class definitions
+	//
+
+	class VProp
+	{
+	public:
+		Vec3 color;
+	};
+
+	class FProp
+	{
+	public:
+		Vec3 color;
+	};
+
+	class Vertex : public Vec3, public NTaggedPrim
+	{
+		edge_buffer edge_uses;
+    
+	public:
+	#ifdef SUPPORT_VCOLOR
+		VProp *props;
+	#endif
+
+		Vertex(real x, real y, real z) : Vec3(x, y, z), edge_uses(6) {
+	#ifdef SUPPORT_VCOLOR
+		props = NULL;
+	#endif
+		}
+		//
+		// Standard methods for all objects
+		//
+		void kill();
+		edge_buffer& edgeUses() { return edge_uses; }
+
+		//
+		// Basic primitives for manipulating model topology
+		//
+		void linkEdge(Edge *);
+		void unlinkEdge(Edge *);
+		void remapTo(Vertex *v);
+
+		unsigned int vID;
+	};
+
+
+	class Edge : public NPrim
+	{
+	private:
+
+		Vertex *v1;
+
+		face_buffer *face_uses;
+		Edge *twin;
+
+		Edge(Edge *twin, Vertex *org); // the twin constructor
+
+	public:
+		Edge(Vertex *, Vertex *);
+		~Edge();
+
+		//
+		// Fundamental Edge accessors
+		//
+		Vertex *org()  { return v1;       }
+		Vertex *dest() { return twin->v1; }
+		Edge *sym()    { return twin;     }
+
+		//
+		// Standard methods for all objects
+		//
+		void kill();
+		face_buffer& faceUses() { return *face_uses; }
+
+		//
+		// Basic primitives for manipulating model topology
+		//
+		void linkFace(Face *);
+		void unlinkFace(Face *);
+		void remapEndpoint(Vertex *from, Vertex *to);
+		void remapTo(Edge *);
+	};
+
+	class Face : public Face3, public NTaggedPrim
+	{
+		Edge *edges[3];
+
+
+	public:
+	#ifdef SUPPORT_FCOLOR
+		FProp *props;
+	#endif
+
+		Face(Edge *, Edge *, Edge *);
+
+		//
+		// Basic Face accessors
+		//
+		const Vec3& vertexPos(int i) const { return *edges[i]->org(); }
+		void vertexPos(int, const Vec3&) {
+			fatal_error("Face: can't directly set vertex position.");
+		}
+
+		Vertex *vertex(int i) { return edges[i]->org(); }
+		const Vertex *vertex(int i) const { return edges[i]->org(); }
+		Edge *edge(int i)               { return edges[i];        }
+
+
+		//
+		// Standard methods for all objects
+		//
+		void kill();
+
+		void remapEdge(Edge *from, Edge *to);
+
+		int igeo; // SUS
+		Vec3 vertex_normals[3];		// SUS
+		Vec2 vertex_texts[3];		//Carlos
+		int normals[3];
+		int texcoords[3];
+	};
+}
+
+
+// NAUTILUS_ADJPRIMS_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.cxx	(revision 774)
@@ -0,0 +1,495 @@
+/************************************************************************
+
+  Adjacency model representation.
+  $Id: AdjModel.cxx,v 1.1 1997/06/25 15:24:52 garland Exp $
+
+  Adapted from:
+     mlab: (Id: polymodel.cc,v 1.21 1997/02/06 16:34:14 garland Exp)
+  via
+     QSlim: (Id: polymodel.cc,v 1.5 1997/02/25 20:36:36 garland Exp)
+
+ ************************************************************************/
+
+#include "AdjModel.h"
+
+using namespace qslim;
+
+int Model::in_Vertex(const Vec3& p)
+{
+    Vertex *v = newVertex(p[X], p[Y], p[Z]);
+    bounds.addPoint(p);
+    return vertCount() - 1;
+}
+
+int Model::in_Normal(const Vec3& n)
+{
+	normals.add(n);
+	return normCount()-1;
+}
+
+int Model::in_TexCoord(const Vec2& t)
+{
+	texcoords.add(t);
+	return texcoordCount()-1;
+}
+
+int Model::in_Face(int a, int b, int c, int n1, int n2, int n3, int t1, int t2, int t3)
+{
+    Vertex *v1 = vertices(a-1);
+    Vertex *v2 = vertices(b-1);
+    Vertex *v3 = vertices(c-1);
+	
+    Face *t = newFace(v1, v2, v3);
+
+	t->normals[0] = n1;
+	t->normals[1] = n2;
+	t->normals[2] = n3;
+
+	t->texcoords[0] = t1;
+	t->texcoords[1] = t2;	
+	t->texcoords[2] = t3;
+
+	return faceCount() - 1;
+}
+
+int Model::miin_Face(int a, int b, int c)
+{
+    Vertex *v1 = vertices(a-1);
+    Vertex *v2 = vertices(b-1);
+    Vertex *v3 = vertices(c-1);
+	
+    Face *t = newFace(v1, v2, v3);
+
+	t->normals[0] = a;
+	t->normals[1] = b;
+	t->normals[2] = c;
+
+	t->texcoords[0] = a;
+	t->texcoords[1] = b;	
+	t->texcoords[2] = c;
+
+	return faceCount() - 1;
+}
+
+#ifdef SUPPORT_FCOLOR
+int Model::in_FColor(const Vec3& c)
+{
+    Face *f = faces(faces.length()-1);
+
+    if( !f->props )
+	f->props = new FProp;
+
+    f->props->color = c;
+    return 0;
+}
+#endif
+
+#ifdef SUPPORT_VCOLOR
+int Model::in_VColor(const Vec3& c)
+{
+    Vertex *v = vertices(vertices.length()-1);
+
+    if( !v->props )
+	v->props = new VProp;
+
+    v->props->color = c;
+    return 0;
+}
+#endif
+
+Vec3 Model::synthesizeNormal(Vertex *v)
+{
+    Vec3 n(0,0,0);
+    int n_count = 0;
+
+    edge_buffer& edges = v->edgeUses();
+    for(int i=0; i<edges.length(); i++)
+    {
+	face_buffer& faces = edges(i)->faceUses();
+
+	for(int j=0; j<faces.length(); j++)
+	{
+	    n += faces(j)->plane().normal();
+	    n_count++;
+	}
+    }
+
+    if( n_count )
+	n /= (real)n_count;
+    else
+    {
+		std::cerr << "Vertex with no normals!!: " << v->uniqID;
+		std::cerr << " / " << v->tempID << std::endl;
+    }
+    return n;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Model Transmogrification:
+//
+// These routines are the basic model munging procedures.
+// All model simplification is implemented in terms of these
+// transmogrification primitives.
+////////////////////////////////////////////////////////////////////////
+
+
+Vertex *Model::newVertex(real x, real y, real z)
+{
+    Vertex *v = new Vertex(x, y, z);
+
+    v->vID = v->uniqID = vertices.add(v);
+
+/*    if( logfile && selected_output&OUTPUT_MODEL_DEFN )
+		*logfile << "v " << x << " " << y << " " << z << std::endl;
+*/
+    validVertCount++;
+
+    return v;
+}
+
+Edge *Model::newEdge(Vertex *a, Vertex *b)
+{
+    Edge *e = new Edge(a, b);
+
+    e->uniqID = edges.add(e);
+    e->sym()->uniqID = e->uniqID;
+
+    validEdgeCount++;
+
+    return e;
+}
+
+static Edge *get_edge(Model *m, Vertex *org, Vertex *v)
+{
+    edge_buffer& edge_uses = org->edgeUses();
+
+    for(int i=0; i<edge_uses.length(); i++)
+	if( edge_uses(i)->dest() == v )
+	    return edge_uses(i);
+
+    Edge *e = m->newEdge(org, v);
+
+    return e;
+}
+
+
+Face *Model::newFace(Vertex *v1, Vertex *v2, Vertex *v3)
+{
+    Edge *e0 = get_edge(this, v1, v2);   // v1->edgeTo(m, v2);
+    Edge *e1 = get_edge(this, v2, v3);   // v2->edgeTo(m, v3);
+    Edge *e2 = get_edge(this, v3, v1);   // v3->edgeTo(m, v1);
+  
+    Face *t = new Face(e0, e1, e2);
+
+    t->uniqID = faces.add(t);
+
+/*    if( logfile && selected_output&OUTPUT_MODEL_DEFN )
+	*logfile << "f " << v1->uniqID+1 << " "
+	<< v2->uniqID+1 << " " << v3->uniqID+1 << std::endl;
+*/
+    validFaceCount++;
+
+    return t;
+}
+
+
+void Model::killVertex(Vertex *v)
+{
+    if( v->isValid() )
+    {
+/*	if( logfile && selected_output&OUTPUT_CONTRACTIONS )
+		*logfile << "v- " << v->uniqID+1 << std::endl;
+*/
+	v->kill();
+	validVertCount--;
+    }
+}
+
+void Model::killEdge(Edge *e)
+{
+    if( e->isValid() )
+    {
+	e->kill();
+	validEdgeCount--;
+    }
+}
+
+void Model::killFace(Face *f)
+{
+    if( f->isValid() )
+    {
+/*	if( logfile && selected_output&OUTPUT_CONTRACTIONS )
+		*logfile << "f- " << f->uniqID+1 << std::endl;
+*/
+	f->kill();
+	validFaceCount--;
+    }
+}
+
+void Model::reshapeVertex(Vertex *v, real x, real y, real z)
+{
+    v->set(x, y, z);
+
+#ifdef LOG_LOWLEVEL_OPS
+    if( logfile )
+	*logfile << "v! " << v->uniqID+1 << " "
+		 << x << " " << y << " " << z << endl;
+#endif
+}
+
+void Model::remapVertex(Vertex *from, Vertex *to)
+{
+    from->remapTo(to);
+
+#ifdef LOG_LOWLEVEL_OPS
+    if( logfile )
+	*logfile << "v> " << from->uniqID+1 << " " << to->uniqID+1 << endl;
+#endif
+}
+
+
+
+void Model::contract(Vertex *v1,
+		     const vert_buffer& rest,
+		     const Vec3& to,
+		     face_buffer& changed)
+{
+    int i;
+
+/*    if( logfile && selected_output&OUTPUT_CONTRACTIONS )
+    {
+	*logfile << "v% (" << v1->uniqID+1;
+	for(i=0; i<rest.length(); i++)
+	    *logfile << " " << rest(i)->uniqID+1;
+	
+	*logfile << ") " << to[X] << " " << to[Y] << " " << to[Z] << std::endl;
+    }
+*/
+
+    //
+    // Collect all the faces that are going to be changed
+    //
+    contractionRegion(v1, rest, changed);
+
+    reshapeVertex(v1, to[X], to[Y], to[Z]);
+
+    for(i=0; i<rest.length(); i++)
+		rest(i)->remapTo(v1);
+
+    removeDegeneracy(changed);
+}
+
+void Model::maybeFixFace(Face *F)
+{
+    //
+    // Invalid faces do not need to be fixed.
+#ifdef SAFETY
+    assert( F->isValid() );
+#endif
+
+    Vertex *v0=F->vertex(0); Vertex *v1=F->vertex(1); Vertex *v2=F->vertex(2);
+    Edge *e0 = F->edge(0); Edge *e1 = F->edge(1); Edge *e2 = F->edge(2);
+
+    bool a=(v0 == v1),  b=(v0 == v2),  c=(v1 == v2);
+
+    if( a && c )
+    {
+	// This triangle has been reduced to a point
+	killEdge(e0);
+	killEdge(e1);
+	killEdge(e2);
+
+	killFace(F);
+    }
+    //
+    // In the following 3 cases, the triangle has become an edge
+    else if( a )
+    {
+	killEdge(e0);
+	e1->remapTo(e2->sym());
+	killFace(F);
+    }
+    else if( b )
+    {
+	killEdge(e2);
+	e0->remapTo(e1->sym());
+	killFace(F);
+    }
+    else if( c )
+    {
+	killEdge(e1);
+	e0->remapTo(e2->sym());
+	killFace(F);
+    }
+    else
+    {
+	// This triangle remains non-degenerate
+/*		// SUS: recalcular la normal en los triangulos cambiados no degenerados
+
+		qslim::Vertex * auxv0 = F->vertex(0);
+		qslim::Vertex * auxv1 = F->vertex(1);
+		qslim::Vertex * auxv2 = F->vertex(2);
+		qslim::Vec3 vd1(auxv1->operator[](qslim::X) - auxv0->operator[](qslim::X), 
+						auxv1->operator[](qslim::Y) - auxv0->operator[](qslim::Y),
+						auxv1->operator[](qslim::Z) - auxv0->operator[](qslim::Z));
+		qslim::Vec3 vd2(auxv2->operator[](qslim::X) - auxv0->operator[](qslim::X), 
+						auxv2->operator[](qslim::Y) - auxv0->operator[](qslim::Y),
+						auxv2->operator[](qslim::Z) - auxv0->operator[](qslim::Z));
+
+		qslim::unitize(vd1);
+		qslim::unitize(vd2);
+
+		qslim::Vec3 vn = vd1 ^ vd2;
+		qslim::unitize(vn);
+		
+		//auxf->vertex_normals[0] = vn;
+		//auxf->vertex_normals[1] = vn;
+		//auxf->vertex_normals[2] = vn;
+		F->vertex_normals[0][qslim::X] = vn[qslim::X];
+		F->vertex_normals[0][qslim::Y] = vn[qslim::Y];
+		F->vertex_normals[0][qslim::Z] = vn[qslim::Z];
+		F->vertex_normals[1][qslim::X] = vn[qslim::X];
+		F->vertex_normals[1][qslim::Y] = vn[qslim::Y];
+		F->vertex_normals[1][qslim::Z] = vn[qslim::Z];
+		F->vertex_normals[2][qslim::X] = vn[qslim::X];
+		F->vertex_normals[2][qslim::Y] = vn[qslim::Y];
+		F->vertex_normals[2][qslim::Z] = vn[qslim::Z];*/
+
+    }
+}
+
+void Model::removeDegeneracy(face_buffer& changed)
+{
+    for(int i=0; i<changed.length(); i++)
+		maybeFixFace(changed(i));
+}
+
+void Model::contractionRegion(Vertex *v1,
+			      const vert_buffer& vertices,
+			      face_buffer& changed)
+{
+    changed.reset();
+
+    //
+    // First, reset the marks on all reachable vertices
+    int i;
+
+    untagFaceLoop(v1);
+    for(i=0; i<vertices.length(); i++)
+		untagFaceLoop(vertices(i));
+
+    //
+    // Now, pick out all the unique reachable faces
+    collectFaceLoop(v1, changed);
+    for(i=0; i<vertices.length(); i++)
+		collectFaceLoop(vertices(i), changed);
+}
+
+
+void Model::contractionRegion(Vertex *v1, Vertex *v2, face_buffer& changed)
+{
+    changed.reset();
+
+    //
+    // Clear marks on all reachable faces
+    untagFaceLoop(v1);
+    untagFaceLoop(v2);
+
+    //
+    // Collect all the unique reachable faces
+    collectFaceLoop(v1, changed);
+    collectFaceLoop(v2, changed);
+}
+
+void Model::contract(Vertex *v1, Vertex *v2, const Vec3& to,
+		     face_buffer& changed)
+{
+#ifdef SAFETY
+    assert( v1 != v2);
+#endif
+
+/*    if( logfile && selected_output&OUTPUT_CONTRACTIONS )
+	*logfile << "v% (" << v1->uniqID+1 << " " << v2->uniqID+1 << ") "
+		 << to[X] << " "
+		 << to[Y] << " "
+		 << to[Z] << std::endl;
+*/
+    //
+    // Collect all the faces that are going to be changed
+    //
+    contractionRegion(v1, v2, changed);
+
+    reshapeVertex(v1, to[X], to[Y], to[Z]);
+
+    //
+    // Map v2 ---> v1.  This accomplishes the topological change that we want.
+    v2->remapTo(v1);
+
+    removeDegeneracy(changed);
+}
+
+
+/*
+ostream& operator<<(ostream& out, Model& M)
+{
+    int i;
+    int uniqVerts = 0;
+
+    out << "#$SMF 1.0" << endl;
+
+    out_annotate(out, M);
+
+    for(i=0; i<M.vertCount(); i++)
+    {
+	if( M.vertex(i)->isValid() )
+	{
+	    M.vertex(i)->tempID = ++uniqVerts;
+
+	    out_annotate(out, M.vertex(i));
+	    const Vertex& v = *M.vertex(i);
+	    out << "v " << v[X] << " " << v[Y] << " " << v[Z] << endl;
+
+#ifdef SUPPORT_VCOLOR
+	    if( v.props )
+		out << ":vc "
+		    << v.props->color[X] << " "
+		    << v.props->color[Y] << " "
+		    << v.props->color[Z] << endl;
+#endif
+	}
+	else
+	    M.vertex(i)->tempID = -1;
+
+    }
+
+    for(i=0; i<M.faceCount(); i++)
+    {
+	if( M.face(i)->isValid() )
+	{
+	    Face *f = M.face(i);
+	    out_annotate(out, f);
+	    out << "f ";
+	    Vertex *v0 = (Vertex *)f->vertex(0);
+	    Vertex *v1 = (Vertex *)f->vertex(1);
+	    Vertex *v2 = (Vertex *)f->vertex(2);
+#ifdef SAFETY
+	    assert( v0->tempID >= 0 );
+	    assert( v1->tempID >= 0 );
+	    assert( v2->tempID >= 0 );
+#endif
+	    out<<v0->tempID << " " <<v1->tempID<< " " <<v2->tempID<< endl;
+#ifdef SUPPORT_FCOLOR
+	    if( f->props )
+		out << ":fc "
+		    << f->props->color[X] << " "
+		    << f->props->color[Y] << " "
+		    << f->props->color[Z] << endl;
+#endif
+	}
+    }
+
+    return out;
+}
+*/
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/SimplificationMethod.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/SimplificationMethod.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/SimplificationMethod.h	(revision 774)
@@ -0,0 +1,63 @@
+#pragma once
+
+#include <set>
+#include <map>
+#include <vector>
+#include <list>
+#include <iostream>
+#include <qslim.h>
+#include <GeoMeshSimplifier.h>
+
+class SimplificationMethod
+{
+private:
+	void compute_pair_info(qslim::pair_info*);
+	qslim::Model M0;
+	qslim::array<qslim::vert_info> vinfo;
+	qslim::Heap *heap;
+	qslim::real proximity_limit;    // distance threshold squared
+	int initialVertCount;
+	int initialEdgeCount;
+	int initialFaceCount;
+
+	inline qslim::vert_info& vertex_info(qslim::Vertex *v){	return vinfo(v->validID()); }
+	qslim::real pair_mesh_penalty(qslim::Model& M, qslim::Vertex *v1, qslim::Vertex *v2, qslim::Vec3& vnew);
+	int predict_face(qslim::Face& F, qslim::Vertex *v1, qslim::Vertex *v2, qslim::Vec3& vnew, qslim::Vec3& f1, qslim::Vec3& f2, qslim::Vec3& f3);
+	bool check_for_pair(qslim::Vertex *v0, qslim::Vertex *v1);
+	qslim::pair_info *new_pair(qslim::Vertex *v0, qslim::Vertex *v1);
+	void delete_pair(qslim::pair_info *pair);
+	void do_contract(qslim::Model& m, qslim::pair_info *pair);
+	bool decimate_quadric(qslim::Vertex *v, qslim::Mat4& Q);
+	void decimate_contract(qslim::Model& m);
+	qslim::real decimate_error(qslim::Vertex *v);
+	qslim::real decimate_min_error();
+	qslim::real decimate_max_error(qslim::Model& m);
+	void decimate_init(qslim::Model& m, qslim::real limit);
+	bool pair_is_valid(qslim::Vertex *u, qslim::Vertex *v);
+	void simplfmethod_run(int,	Geometry::TIPOFUNC	upb=0);
+	void simplfmethod_runv(int,	Geometry::TIPOFUNC	upb=0);
+	void simplfmethod_init(void);
+
+	//To map the mesh with de simplification method structure
+	std::map<int,std::vector<int> > submeshmap; //submeshes which pertains each vertex
+	std::map<int,std::vector<int> > vertexbuffermap; //vertices of the VertexBuffer that point at this vertex of the simplification method
+
+	//simplification sequence of the simplification method
+	std::vector<Geometry::MeshSimplificationSequence::Step> decim_data;
+	std::string meshName;
+	void WriteOBJ(void);
+	unsigned int *first_index_submesh;
+	//std::vector<qslim::pair_info *> pointers_to_remove;
+
+	int indexMeshLeaves;
+public:
+	const Geometry::Mesh *objmesh;
+	int number_of_triangles; //total number of triangles of all the submeshes
+	SimplificationMethod(const Geometry::Mesh *m);
+	void geomesh2simplifModel(void);
+	Geometry::MeshSimplificationSequence *Decimate(float lod, Geometry::Mesh **mesh, int simpliftype,Geometry::TIPOFUNC	upb=0);
+	void setMeshLeaves(int meshLeaves);
+
+	///Destructor
+	~SimplificationMethod();
+};
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.h	(revision 774)
@@ -0,0 +1,33 @@
+// -*- C++ -*-
+// $Id: quadrics.h,v 1.7 1997/10/01 14:07:29 garland Exp $
+
+#include "AdjModel.h"
+#include <gfx/math/Mat4.h>
+
+namespace qslim
+{
+	extern Mat4 quadrix_vertex_constraint(const Vec3&);
+	extern Mat4 quadrix_plane_constraint(real a, real b, real c, real d);
+	extern Mat4 quadrix_plane_constraint(Face& T);
+	extern Mat4 quadrix_plane_constraint(const Vec3& n, real);
+	extern Mat4 quadrix_plane_constraint(const Vec3&, const Vec3&, const Vec3&);
+	extern real quadrix_evaluate_vertex(const Vec3& v, const Mat4& K);
+
+
+	extern bool check_for_discontinuity(Edge *);
+	extern Mat4 quadrix_discontinuity_constraint(Edge *, const Vec3&);
+	extern Mat4 quadrix_discontinuity_constraint(Edge *);
+
+
+	extern bool quadrix_find_local_fit(const Mat4& Q,
+					   const Vec3& v1, const Vec3& v2,
+					   Vec3& candidate);
+	extern bool quadrix_find_line_fit(const Mat4& Q,
+					  const Vec3& v1, const Vec3& v2,
+					  Vec3& candidate);
+	extern bool quadrix_find_best_fit(const Mat4& Q, Vec3& candidate);
+	extern real quadrix_pair_target(const Mat4& Q,
+					Vertex *v1,
+					Vertex *v2,
+					Vec3& candidate);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.h	(revision 774)
@@ -0,0 +1,35 @@
+//#include "Nvars.h"
+#include <gfx/SMF/smf.h>
+
+namespace qslim
+{
+//	extern ostream *outfile;
+
+	extern int face_target;
+	extern real error_tolerance;
+
+
+	extern bool will_use_plane_constraint;
+	extern bool will_use_vertex_constraint;
+
+	extern bool will_preserve_boundaries;
+	extern bool will_preserve_mesh_quality;
+	extern bool will_constrain_boundaries;
+	extern real boundary_constraint_weight;
+
+	extern bool will_weight_by_area;
+
+	#define PLACE_ENDPOINTS 0
+	#define PLACE_ENDORMID  1
+	#define PLACE_LINE      2
+	#define PLACE_OPTIMAL   3
+
+	extern int placement_policy;
+
+	extern real pair_selection_tolerance;
+}
+
+
+//extern void process_cmdline(int argc, char **argv);
+
+//extern void read_model(SMF_Reader&);
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/heap_array.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/heap_array.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/heap_array.h	(revision 774)
@@ -0,0 +1,297 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: heap_array.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H
+#define TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H
+
+#include <vector>
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+// mutable heap
+// can be interfaced pretty muck like an array
+template <class T, class CmpT = std::less<T> > 
+class heap_array
+{
+public:
+
+	// Pre = PreCondition, Post = PostCondition 
+
+	heap_array() : m_Locked(false) { }		// Post: ((size() == 0) && ! locked())
+
+	void clear();							// Post: ((size() == 0) && ! locked())
+
+	void reserve(size_t Size);
+	size_t size() const;
+
+	bool empty() const;
+	bool locked() const;
+	bool removed(size_t i) const;			// Pre: (valid(i))
+	bool valid(size_t i) const;
+
+	size_t position(size_t i) const;		// Pre: (valid(i))
+
+	const T & top() const;					// Pre: (! empty())
+	const T & peek(size_t i) const;			// Pre: (! removed(i))
+	const T & operator [] (size_t i) const;	// Pre: (! removed(i))
+
+	void lock();							// Pre: (! locked())   Post: (locked())
+	size_t push(const T & Elem);			// Pre: (! locked())
+
+	void pop();								// Pre: (locked() && ! empty())
+	void erase(size_t i);					// Pre: (locked() && ! removed(i))
+	void update(size_t i, const T & Elem);	// Pre: (locked() && ! removed(i))
+
+protected:
+
+	heap_array(const heap_array &);
+	heap_array & operator = (const heap_array &);
+
+	class linker
+	{
+	public:
+		linker(const T & Elem, size_t i)
+			: m_Elem(Elem), m_Index(i) { }
+
+		T		m_Elem;
+		size_t	m_Index;
+	};
+
+	typedef std::vector<linker> linked_heap;
+	typedef std::vector<size_t> finder;
+
+	void Adjust(size_t i);
+	void Swap(size_t a, size_t b);
+	bool Less(const linker & a, const linker & b) const;
+
+	linked_heap	m_Heap;
+	finder		m_Finder;
+	CmpT		m_Compare;
+	bool		m_Locked;
+};
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// heap_indexed inline functions
+//////////////////////////////////////////////////////////////////////////
+
+template <class T, class CmpT> 
+inline void heap_array<T, CmpT>::clear()
+{
+	m_Heap.clear();
+	m_Finder.clear();
+	m_Locked = false;
+}
+
+
+template <class T, class CmpT> 
+inline bool heap_array<T, CmpT>::empty() const
+{
+	return m_Heap.empty();
+}
+
+
+template <class T, class CmpT>
+inline bool heap_array<T, CmpT>::locked() const
+{
+	return m_Locked;
+}
+
+
+template <class T, class CmpT>
+inline void heap_array<T, CmpT>::reserve(const size_t Size)
+{
+	m_Heap.reserve(Size);
+	m_Finder.reserve(Size);
+}
+
+
+template <class T, class CmpT> 
+inline size_t heap_array<T, CmpT>::size() const
+{
+	return m_Heap.size();
+}
+
+
+template <class T, class CmpT> 
+inline const T & heap_array<T, CmpT>::top() const
+{
+	assert(! empty());
+
+	return m_Heap.front().m_Elem;
+}
+
+
+template <class T, class CmpT> 
+inline const T & heap_array<T, CmpT>::peek(const size_t i) const
+{
+	assert(! removed(i));
+
+	return (m_Heap[m_Finder[i]].m_Elem);
+}
+
+
+template <class T, class CmpT> 
+inline const T & heap_array<T, CmpT>::operator [] (const size_t i) const
+{
+	return peek(i);
+}
+
+
+template <class T, class CmpT> 
+inline void heap_array<T, CmpT>::pop()
+{
+	assert(locked());
+	assert(! empty());
+
+	Swap(0, size() - 1);
+	m_Heap.pop_back();
+
+	if (! empty())
+		Adjust(0);
+}
+
+
+template <class T, class CmpT>
+inline void heap_array<T, CmpT>::lock()
+{
+	assert(! locked());
+
+	m_Locked =true;
+}
+
+
+template <class T, class CmpT> 
+inline size_t heap_array<T, CmpT>::push(const T & Elem)
+{
+	assert(! locked());
+
+	const size_t Id = size();
+	m_Finder.push_back(Id);
+	m_Heap.push_back(linker(Elem, Id));
+	Adjust(Id);
+
+	return Id;
+}
+
+
+template <class T, class CmpT>
+inline void heap_array<T, CmpT>::erase(const size_t i)
+{
+	assert(locked());
+	assert(! removed(i));
+
+	const size_t j = m_Finder[i];
+	Swap(j, size() - 1);
+	m_Heap.pop_back();
+
+	if (j != size())
+		Adjust(j);
+}
+
+
+template <class T, class CmpT>
+inline bool heap_array<T, CmpT>::removed(const size_t i) const
+{
+	assert(valid(i));
+
+	return (m_Finder[i] >= m_Heap.size());
+}
+
+
+template <class T, class CmpT>
+inline bool heap_array<T, CmpT>::valid(const size_t i) const
+{
+	return (i < m_Finder.size());
+}
+
+
+template <class T, class CmpT>
+inline size_t heap_array<T, CmpT>::position(const size_t i) const
+{
+	assert(valid(i));
+
+	return (m_Heap[i].m_Index);
+}
+
+
+template <class T, class CmpT> 
+inline void heap_array<T, CmpT>::update(const size_t i, const T & Elem)
+{
+	assert(locked());
+	assert(! removed(i));
+
+	const size_t j = m_Finder[i];
+	m_Heap[j].m_Elem = Elem;
+	Adjust(j);
+}
+
+
+template <class T, class CmpT> 
+inline void heap_array<T, CmpT>::Adjust(size_t i)
+{
+	assert(i < m_Heap.size());
+
+	size_t j;
+
+	// Check the upper part of the heap
+	for (j = i; (j > 0) && (Less(m_Heap[(j - 1) / 2], m_Heap[j])); j = ((j - 1) / 2))
+		Swap(j, (j - 1) / 2);
+
+	// Check the lower part of the heap
+	for (i = j; (j = 2 * i + 1) < size(); i = j) {
+ 		if ((j + 1 < size()) && (Less(m_Heap[j], m_Heap[j + 1])))
+			++j;
+
+		if (Less(m_Heap[j], m_Heap[i]))
+			return;
+
+		Swap(i, j);
+	}
+}
+
+
+template <class T, class CmpT> 
+inline void heap_array<T, CmpT>::Swap(const size_t a, const size_t b)
+{
+	std::swap(m_Heap[a], m_Heap[b]);
+
+	m_Finder[(m_Heap[a].m_Index)] = a;
+	m_Finder[(m_Heap[b].m_Index)] = b;
+}
+
+
+template <class T, class CmpT>
+inline bool heap_array<T, CmpT>::Less(const linker & a, const linker & b) const
+{
+	return m_Compare(a.m_Elem, b.m_Elem);
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_HEAP_ARRAY_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/connectivity_graph.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/connectivity_graph.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/connectivity_graph.h	(revision 774)
@@ -0,0 +1,36 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: connectivity_graph.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H
+#define TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H
+
+#include "public_types.h"
+
+#include "graph_array.h"
+#include "types.h"
+
+
+
+
+namespace triangle_stripper
+{
+
+	namespace detail
+	{
+
+		void make_connectivity_graph(graph_array<triangle> & Triangles, const indices & Indices);
+
+	}
+
+}
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_CONNECTIVITY_GRAPH_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/graph_array.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/graph_array.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/graph_array.h	(revision 774)
@@ -0,0 +1,460 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: graph_array.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H
+#define TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H
+
+#include <cassert>
+#include <algorithm>
+#include <functional>
+#include <limits>
+#include <vector>
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+// graph_array main class
+template <class nodetype>
+class graph_array 
+{
+public:
+
+	class arc;
+	class node;
+
+	// New types
+	typedef size_t											nodeid;
+	typedef nodetype										value_type;
+	typedef std::vector<node>								node_vector;
+	typedef typename node_vector::iterator					node_iterator;
+	typedef typename node_vector::const_iterator			const_node_iterator;
+	typedef typename node_vector::reverse_iterator			node_reverse_iterator;
+	typedef typename node_vector::const_reverse_iterator	const_node_reverse_iterator;
+
+	typedef graph_array<nodetype> graph_type;
+	
+
+	// graph_array::arc class
+	class arc
+	{
+	public:
+		node_iterator terminal() const;
+
+	protected:
+		friend class graph_array<nodetype>;
+
+		arc(node_iterator Terminal);
+	
+		node_iterator	m_Terminal;
+	};
+
+
+	// New types
+	typedef std::vector<arc>					arc_list;
+	typedef typename arc_list::iterator			out_arc_iterator;
+	typedef typename arc_list::const_iterator	const_out_arc_iterator;
+
+
+	// graph_array::node class
+	class node
+	{
+	public:
+		void mark();
+		void unmark();
+		bool marked() const;
+
+		bool out_empty() const;
+		size_t out_size() const;
+
+		out_arc_iterator out_begin();
+		out_arc_iterator out_end();
+		const_out_arc_iterator out_begin() const;
+		const_out_arc_iterator out_end() const;
+
+		value_type & operator * ();
+		value_type * operator -> ();
+		const value_type & operator * () const;
+		const value_type * operator -> () const;
+
+		value_type & operator = (const value_type & Elem);
+
+	protected:
+		friend class graph_array<nodetype>;
+		friend class std::vector<node>;
+
+		node(arc_list & Arcs);
+
+		arc_list &		m_Arcs;
+		size_t			m_Begin;
+		size_t			m_End;
+
+		value_type		m_Elem;
+		bool			m_Marker;
+	};
+
+
+	graph_array();
+	explicit graph_array(size_t NbNodes);
+
+	// Node related member functions
+	bool empty() const;
+	size_t size() const;
+
+	node & operator [] (nodeid i);
+	const node & operator [] (nodeid i) const;
+
+	node_iterator begin();
+	node_iterator end();
+	const_node_iterator begin() const;
+	const_node_iterator end() const;
+
+	node_reverse_iterator rbegin();
+	node_reverse_iterator rend();
+	const_node_reverse_iterator rbegin() const;
+	const_node_reverse_iterator rend() const;
+
+	// Arc related member functions
+	out_arc_iterator insert_arc(nodeid Initial, nodeid Terminal);
+	out_arc_iterator insert_arc(node_iterator Initial, node_iterator Terminal);
+
+	// Optimized (overloaded) functions
+	void swap(graph_type & Right);
+	friend void swap(graph_type & Left, graph_type & Right)										{ Left.swap(Right); }
+
+protected:
+	graph_array(const graph_type &);
+	graph_type & operator = (const graph_type &);
+
+	node_vector		m_Nodes;
+	arc_list		m_Arcs;
+};
+
+
+
+// Additional "low level", graph related, functions
+template <class nodetype>
+void unmark_nodes(graph_array<nodetype> & G);
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// graph_array::arc inline functions
+//////////////////////////////////////////////////////////////////////////
+
+template <class N>
+inline graph_array<N>::arc::arc(node_iterator Terminal)
+	: m_Terminal(Terminal) { }
+
+
+template <class N>
+inline typename graph_array<N>::node_iterator graph_array<N>::arc::terminal() const
+{
+	return m_Terminal;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// graph_array::node inline functions
+//////////////////////////////////////////////////////////////////////////
+
+template <class N>
+inline graph_array<N>::node::node(arc_list & Arcs)
+	: m_Arcs(Arcs),
+	  m_Begin(std::numeric_limits<size_t>::max()),
+	  m_End(std::numeric_limits<size_t>::max()),
+	  m_Marker(false)
+{
+
+}
+
+
+template <class N>
+inline void graph_array<N>::node::mark()
+{
+	m_Marker = true;
+}
+
+
+template <class N>
+inline void graph_array<N>::node::unmark()
+{
+	m_Marker = false;
+}
+
+
+template <class N>
+inline bool graph_array<N>::node::marked() const
+{
+	return m_Marker;
+}
+
+
+template <class N>
+inline bool graph_array<N>::node::out_empty() const
+{
+	return (m_Begin == m_End);
+}
+
+
+template <class N>
+inline size_t graph_array<N>::node::out_size() const
+{
+	return (m_End - m_Begin);
+}
+
+
+template <class N>
+inline typename graph_array<N>::out_arc_iterator graph_array<N>::node::out_begin()
+{
+	return (m_Arcs.begin() + m_Begin);
+}
+
+
+template <class N>
+inline typename graph_array<N>::out_arc_iterator graph_array<N>::node::out_end()
+{
+	return (m_Arcs.begin() + m_End);
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_out_arc_iterator graph_array<N>::node::out_begin() const
+{
+	return (m_Arcs.begin() + m_Begin);
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_out_arc_iterator graph_array<N>::node::out_end() const
+{
+	return (m_Arcs.begin() + m_End);
+}
+
+
+template <class N>
+inline N & graph_array<N>::node::operator * ()
+{
+	return m_Elem;
+}
+
+
+template <class N>
+inline N * graph_array<N>::node::operator -> ()
+{
+	return &m_Elem;
+}
+
+
+template <class N>
+inline const N & graph_array<N>::node::operator * () const
+{
+	return m_Elem;
+}
+
+
+template <class N>
+inline const N * graph_array<N>::node::operator -> () const
+{
+	return &m_Elem;
+}
+
+
+template <class N>
+inline N & graph_array<N>::node::operator = (const N & Elem)
+{
+	return (m_Elem = Elem);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// graph_array inline functions
+//////////////////////////////////////////////////////////////////////////
+
+template <class N>
+inline graph_array<N>::graph_array() { }
+
+
+template <class N>
+inline graph_array<N>::graph_array(const size_t NbNodes)
+	: m_Nodes(NbNodes, node(m_Arcs))
+{
+	// optimisation: we consider that, averagely, a triangle may have at least 2 neighbours
+	// otherwise we are just wasting a bit of memory, but not that much
+	m_Arcs.reserve(NbNodes * 2);
+}
+
+
+template <class N>
+inline bool graph_array<N>::empty() const
+{
+	return m_Nodes.empty();
+}
+
+
+template <class N>
+inline size_t graph_array<N>::size() const 
+{
+	return m_Nodes.size();
+}
+
+
+template <class N>
+inline typename graph_array<N>::node & graph_array<N>::operator [] (const nodeid i)
+{
+	assert(i < size());
+
+	return m_Nodes[i];
+}
+
+
+template <class N>
+inline const typename graph_array<N>::node & graph_array<N>::operator [] (const nodeid i) const
+{
+	assert(i < size());
+
+	return m_Nodes[i];
+}
+
+
+template <class N>
+inline typename graph_array<N>::node_iterator graph_array<N>::begin()
+{
+	return m_Nodes.begin();
+}
+
+
+template <class N>
+inline typename graph_array<N>::node_iterator graph_array<N>::end()
+{
+	return m_Nodes.end();
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_node_iterator graph_array<N>::begin() const
+{
+	return m_Nodes.begin();
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_node_iterator graph_array<N>::end() const
+{
+	return m_Nodes.end();
+}
+
+
+template <class N>
+inline typename graph_array<N>::node_reverse_iterator graph_array<N>::rbegin()
+{
+	return m_Nodes.rbegin();
+}
+
+
+template <class N>
+inline typename graph_array<N>::node_reverse_iterator graph_array<N>::rend()
+{
+	return m_Nodes.rend();
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_node_reverse_iterator graph_array<N>::rbegin() const
+{
+	return m_Nodes.rbegin();
+}
+
+
+template <class N>
+inline typename graph_array<N>::const_node_reverse_iterator graph_array<N>::rend() const
+{
+	return m_Nodes.rend();
+}
+
+
+template <class N>
+inline typename graph_array<N>::out_arc_iterator graph_array<N>::insert_arc(const nodeid Initial, const nodeid Terminal)
+{
+	assert(Initial < size());
+	assert(Terminal < size());
+
+	return insert_arc(m_Nodes.begin() + Initial, m_Nodes.begin() + Terminal);
+}
+
+
+template <class N>
+inline typename graph_array<N>::out_arc_iterator graph_array<N>::insert_arc(const node_iterator Initial, const node_iterator Terminal)
+{
+	assert((Initial >= begin()) && (Initial < end()));
+	assert((Terminal >= begin()) && (Terminal < end()));
+
+	node & Node = * Initial;
+
+	if (Node.out_empty()) {
+
+		Node.m_Begin = m_Arcs.size();
+		Node.m_End = m_Arcs.size() + 1;
+
+	} else {
+
+		// we optimise here for make_connectivity_graph()
+		// we know all the arcs for a given node are successively and sequentially added
+		assert(Node.m_End == m_Arcs.size());
+		
+		++(Node.m_End);
+	}
+
+	m_Arcs.push_back(arc(Terminal));
+
+	out_arc_iterator it = m_Arcs.end();
+	return (--it);
+}
+
+
+template <class N>
+inline void graph_array<N>::swap(graph_type & Right)
+{
+	std::swap(m_Nodes, Right.m_Nodes);
+	std::swap(m_Arcs, Right.m_Arcs);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// additional functions
+//////////////////////////////////////////////////////////////////////////
+
+template <class N>
+inline void unmark_nodes(graph_array<N> & G)
+{
+	std::for_each(G.begin(), G.end(), std::mem_fun_ref(&graph_array<N>::node::unmark));
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_GRAPH_ARRAY_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/policy.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/policy.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/policy.h	(revision 774)
@@ -0,0 +1,66 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: policy.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_POLICY_H
+#define TRI_STRIPPER_HEADER_GUARD_POLICY_H
+
+#include "public_types.h"
+#include "types.h"
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+class policy
+{
+public:
+	policy(size_t MinStripSize, bool Cache);
+
+	strip BestStrip() const;
+	void Challenge(strip Strip, size_t Degree, size_t CacheHits);
+
+private:
+	strip	m_Strip;
+	size_t	m_Degree;
+	size_t	m_CacheHits;
+
+	const size_t	m_MinStripSize;
+	const bool		m_Cache;
+};
+
+
+
+
+
+inline policy::policy(size_t MinStripSize, bool Cache)
+: m_Degree(0), m_CacheHits(0), m_MinStripSize(MinStripSize), m_Cache(Cache) { }
+
+
+inline strip policy::BestStrip() const
+{
+	return m_Strip;
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_POLICY_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/cache_simulator.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/cache_simulator.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/cache_simulator.h	(revision 774)
@@ -0,0 +1,154 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: cache_simulator.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H
+#define TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H
+
+#include <algorithm>
+#include <limits>
+#include <deque>
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+class cache_simulator
+{
+public:
+	cache_simulator();
+
+	void clear();
+	void resize(size_t Size);
+	void reset();
+	void push_cache_hits(bool Enabled = true);
+	size_t size() const;
+
+	void push(index i, bool CountCacheHit = false);
+	void merge(const cache_simulator & Backward, size_t PossibleOverlap);
+
+	void reset_hitcount();
+	size_t hitcount() const;
+
+protected:
+	typedef std::deque<index> indices_deque;
+
+	indices_deque	m_Cache;
+	size_t			m_NbHits;
+	bool			m_PushHits;
+};
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// cache_simulator inline functions
+//////////////////////////////////////////////////////////////////////////
+
+inline cache_simulator::cache_simulator()
+	: m_NbHits(0),
+	  m_PushHits(true)
+{
+
+}
+
+
+inline void cache_simulator::clear()
+{
+	reset_hitcount();
+	m_Cache.clear();
+}
+
+
+inline void cache_simulator::resize(const size_t Size)
+{
+	m_Cache.resize(Size, std::numeric_limits<index>::max());
+}
+
+
+inline void cache_simulator::reset()
+{
+	std::fill(m_Cache.begin(), m_Cache.end(), std::numeric_limits<index>::max());
+	reset_hitcount();
+}
+
+
+inline void cache_simulator::push_cache_hits(bool Enabled)
+{
+	m_PushHits = Enabled;
+}
+
+
+inline size_t cache_simulator::size() const
+{
+	return m_Cache.size();
+}
+
+
+inline void cache_simulator::push(const index i, const bool CountCacheHit)
+{
+	if (CountCacheHit || m_PushHits) {
+
+		if (std::find(m_Cache.begin(), m_Cache.end(), i) != m_Cache.end()) {
+
+			// Should we count the cache hits?
+			if (CountCacheHit)
+				++m_NbHits;
+			
+			// Should we not push the index into the cache if it's a cache hit?
+			if (! m_PushHits)
+				return;
+		}
+	}
+	    
+	// Manage the indices cache as a FIFO structure
+	m_Cache.push_front(i);
+	m_Cache.pop_back();
+}
+
+
+inline void cache_simulator::merge(const cache_simulator & Backward, const size_t PossibleOverlap)
+{
+	const size_t Overlap = std::min(PossibleOverlap, size());
+
+	for (size_t i = 0; i < Overlap; ++i)
+		push(Backward.m_Cache[i], true);
+
+	m_NbHits += Backward.m_NbHits;
+}
+
+
+inline void cache_simulator::reset_hitcount()
+{
+	m_NbHits = 0;
+}
+
+
+inline size_t cache_simulator::hitcount() const
+{
+	return m_NbHits;
+}
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_CACHE_SIMULATOR_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/types.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/types.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/detail/types.h	(revision 774)
@@ -0,0 +1,101 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: types.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_TYPES_H
+#define TRI_STRIPPER_HEADER_GUARD_TYPES_H
+
+
+
+
+namespace triangle_stripper {
+
+	namespace detail {
+
+
+
+
+class triangle
+{
+public:
+	triangle() { }
+	triangle(index A, index B, index C)
+		: m_A(A), m_B(B), m_C(C), m_StripID(0) { }
+
+	void ResetStripID()							{ m_StripID = 0; }
+	void SetStripID(size_t StripID)				{ m_StripID = StripID; }	
+	size_t StripID() const						{ return m_StripID; }
+
+	index A() const								{ return m_A; }
+	index B() const								{ return m_B; }
+	index C() const								{ return m_C; }
+	
+private:
+	index	m_A;
+	index	m_B;
+	index	m_C;
+
+	size_t	m_StripID;
+};
+
+
+
+class triangle_edge
+{
+public:
+	triangle_edge(index A, index B)
+		: m_A(A), m_B(B) { }
+
+	index A() const								{ return m_A; }
+	index B() const								{ return m_B; }
+
+	bool operator == (const triangle_edge & Right) const {
+		return ((A() == Right.A()) && (B() == Right.B()));
+	}
+
+private:
+	index	m_A;
+	index	m_B;
+};
+
+
+
+enum triangle_order { ABC, BCA, CAB };
+
+
+
+class strip
+{
+public:
+	strip()
+		: m_Start(0), m_Order(ABC), m_Size(0) { }
+
+	strip(size_t Start, triangle_order Order, size_t Size)
+		: m_Start(Start), m_Order(Order), m_Size(Size) { }
+
+	size_t Start() const						{ return m_Start; }
+	triangle_order Order() const				{ return m_Order; }
+	size_t Size() const							{ return m_Size; }
+
+private:
+	size_t			m_Start;
+	triangle_order	m_Order;
+	size_t			m_Size;
+};
+
+
+
+
+	} // namespace detail
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_TYPES_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/std.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/std.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/std.h	(revision 774)
@@ -0,0 +1,143 @@
+#ifndef GFX_STD_INCLUDED // -*- C++ -*-
+#define GFX_STD_INCLUDED
+
+/************************************************************************
+
+  Standard base include file for all gfx-based programs.  This defines
+  various common stuff that is used elsewhere.
+
+  $Id: std.h,v 1.8 1997/06/25 14:12:31 garland Exp $
+
+ ************************************************************************/
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <iostream>
+
+
+namespace qslim
+{
+	//
+	// Define the real (ie. default floating point) type
+	//
+	#ifdef GFX_REAL_FLOAT
+	typedef float real;
+	#else
+	#define GFX_REAL_DOUBLE
+	typedef double real;
+	#endif
+
+	//
+	// Define the boolean type and true/false constants.
+	// 
+	/*#ifndef GFX_NO_BOOL
+	typedef int bool;
+	const int false = 0;
+	const int true  = 1;
+	#endif
+	*/
+	// Define True/False as synonyms for true/false
+	#ifndef GFX_NO_BOOL_MACROS
+	#  ifndef True
+	#    define True true
+	#    define False false
+	#  endif
+	#endif
+
+	// Handle platforms which don't define M_PI in <math.h>
+	#ifndef M_PI
+	#define M_PI 3.14159265358979323846
+	#endif
+
+	//
+	// Define min/max.
+	// These are defined as inlined template functions because that's a more
+	// C++ish thing to do.
+	//
+	#ifndef GFX_NO_MINMAX
+	#  ifndef min
+	template<class T>
+	inline T min(T a, T b) { return (a < b)?a:b; }
+
+	template<class T>
+	inline T max(T a, T b) { return (a > b)?a:b; }
+	#  endif
+	#endif
+
+	//
+	// For the old school, we also have MIN/MAX defined as macros.
+	//
+	#ifndef MIN
+	#define MIN(a,b) (((a)>(b))?(b):(a))
+	#define MAX(a,b) (((a)>(b))?(a):(b))
+	#endif
+
+
+	#ifndef ABS
+	#define ABS(x) (((x)<0)?-(x):(x))
+	#endif
+
+	#ifdef GFX_DEF_FMATH
+	#define fabsf(a) ((float)fabs((double)a))
+	#define cosf(a) ((float)cos(double)a)
+	#define sinf(a) ((float)sin(double)a)
+	#endif
+
+	#ifndef FEQ_EPS
+	#define FEQ_EPS 1e-6
+	#define FEQ_EPS2 1e-12
+	#endif
+	inline bool FEQ(double a,double b,double eps=FEQ_EPS) { return fabs(a-b)<eps; }
+	inline bool FEQ(float a,float b,float eps=FEQ_EPS) { return fabsf(a-b)<eps; }
+
+	#ifndef GFX_NO_AXIS_NAMES
+	enum Axis {X=0, Y=1, Z=2, W=3};
+	#endif
+
+
+
+	#define fatal_error(s)  report_error(s,__FILE__,__LINE__)
+
+//	#ifdef assert
+//	#  undef assert
+//	#endif
+//	#define  assert(i)  (i)?((void)NULL):assert_failed(# i,__FILE__,__LINE__)
+
+	#ifdef SAFETY
+	#  define AssertBound(t) assert(t)
+	#else
+	#  define AssertBound(t)
+	#endif
+
+	//
+	// Define the report_error and assert_failed functions.
+	//
+	inline void report_error(char *msg,char *file,int line)
+	{
+		std::cerr << msg << " ("<<file<<":"<<line<<")"<<std::endl;
+		exit(1);
+	}
+
+	inline void assert_failed(char *text,char *file,int line)
+	{
+		std::cerr << "Assertion failed: {" << text <<"} at ";
+		std::cerr << file << ":" << line << std::endl;
+		abort();
+	}
+
+	inline void assertf(int test, char *msg,
+						char *file=__FILE__, int line=__LINE__)
+	{
+		if( !test )
+		{
+			std::cerr << "Assertion failed: " << msg << " at ";
+			std::cerr << file << ":" << line << std::endl;
+			abort();
+		}
+	}
+	}
+
+// GFX_STD_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Buffer.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Buffer.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Buffer.h	(revision 774)
@@ -0,0 +1,98 @@
+#ifndef GFXTOOLS_BUFFER_INCLUDED // -*- C++ -*-
+#define GFXTOOLS_BUFFER_INCLUDED
+
+#include <gfx/tools/Array.h>
+
+namespace qslim
+{
+	template<class T>
+	class buffer : public array<T> {
+	protected:
+		int fill;
+	public:
+		buffer() { init(8); }
+		buffer(int l) { init(l); }
+    
+		inline void init(int l) { array<T>::init(l); fill=0; }
+
+		inline int add(const T& t);
+		inline void reset();
+		inline int find(const T&);
+		inline T remove(int i);
+		inline int addAll(const buffer<T>& buf);
+		inline void removeDuplicates();
+
+		inline int length() const { return fill; }
+		inline int maxLength() const { return len; }
+	};
+
+
+	template<class T>
+	inline int buffer<T>::add(const T& t)
+	{
+		if( fill == len )
+		resize( len*2 );
+
+		data[fill] = t;
+
+		return fill++;
+	}
+
+	template<class T>
+	inline void buffer<T>::reset()
+	{
+		fill = 0;
+	}
+
+	template<class T>
+	inline int buffer<T>::find(const T& t)
+	{
+		for(int i=0;i<fill;i++)
+		if( data[i] == t )
+			return i;
+
+		return -1;
+	}
+
+	template<class T>
+	inline T buffer<T>::remove(int i)
+	{
+	#ifdef SAFETY
+		assert( i>=0 );
+		assert( i<fill );
+	#endif
+
+		fill--;
+		T temp = data[i];
+		data[i] = data[fill];
+
+		return temp;
+	}
+
+	template<class T>
+	inline int buffer<T>::addAll(const buffer<T>& buf)
+	{
+		for(int i=0; i<buf.fill; i++)
+		add(buf(i));
+
+		return fill;
+	}
+
+	template<class T>
+	inline void buffer<T>::removeDuplicates()
+	{
+		for(int i=0; i<fill; i++)
+		{
+		for(int j=i+1; j<fill; )
+		{
+			if( data[j] == data[i] )
+			remove(j);
+			else
+			j++;
+		}
+		}
+	}
+}
+
+// GFXTOOLS_BUFFER_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Heap.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Heap.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Heap.h	(revision 774)
@@ -0,0 +1,77 @@
+#ifndef GFXTOOLS_HEAP_INCLUDED // -*- C++ -*-
+#define GFXTOOLS_HEAP_INCLUDED
+
+#include <gfx/tools/Array.h>
+
+#define NOT_IN_HEAP -47
+
+//
+//
+// This file extracted from Terra
+//
+//
+
+namespace qslim
+{
+	class Heapable
+	{
+	private:
+		int token;
+
+	public:
+		Heapable() { notInHeap(); }
+
+		inline int isInHeap() { return token!=NOT_IN_HEAP; }
+		inline void notInHeap() { token = NOT_IN_HEAP; }
+		inline int getHeapPos() { return token; }
+		inline void setHeapPos(int t) { token=t; }
+	};
+
+
+	class heap_node {
+	public:
+		float import;
+		Heapable *obj;
+
+		heap_node() { obj=NULL; import=0.0; }
+		heap_node(Heapable *t, float i=0.0) { obj=t; import=i; }
+		heap_node(const heap_node& h) { import=h.import; obj=h.obj; }
+	};
+
+
+
+	class Heap : public array<heap_node> {
+
+		//
+		// The actual size of the heap.  array::length()
+		// simply returns the amount of allocated space
+		int size;
+
+		void swap(int i, int j);
+
+		int parent(int i) { return (i-1)/2; }
+		int left(int i) { return 2*i+1; }
+		int right(int i) { return 2*i+2; }
+
+		void upheap(int i);
+		void downheap(int i);
+
+	public:
+
+		Heap() { size=0; }
+		Heap(int s) : array<heap_node>(s) { size=0; }
+
+
+		void insert(Heapable *, float);
+		void update(Heapable *, float);
+
+		heap_node *extract();
+		heap_node *top() { return size<1 ? (heap_node *)NULL : &ref(0); }
+		heap_node *kill(int i);
+	};
+
+}
+
+
+// GFXTOOLS_HEAP_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array.h	(revision 774)
@@ -0,0 +1,86 @@
+#ifndef GFXTOOLS_ARRAY_INCLUDED // -*- C++ -*-
+#define GFXTOOLS_ARRAY_INCLUDED
+
+#include <string.h>
+#include "../std.h"
+
+namespace qslim
+{
+	template<class T>
+	class array {
+	protected:
+		T *data;
+		int len;
+	public:
+		array() { data=NULL; len=0; }
+		array(int l) { init(l); }
+		~array() { f_r_e_e(); }
+
+
+		inline void init(int l);
+		inline void f_r_e_e();
+		inline void resize(int l);
+
+		inline T& ref(int i);
+		inline T& operator[](int i) { return data[i]; }
+		inline T& operator()(int i) { return ref(i); }
+
+		inline const T& ref(int i) const;
+		inline const T& operator[](int i) const { return data[i]; }
+		inline const T& operator()(int i) const { return ref(i); }
+
+
+		inline int length() const { return len; }
+		inline int maxLength() const { return len; }
+	};
+
+	template<class T>
+	inline void array<T>::init(int l)
+	{
+		data = new T[l];
+		len = l;
+	}
+
+	template<class T>
+	inline void array<T>::f_r_e_e()
+	{
+		if( data )
+		{
+		delete[] data;
+		data = NULL;
+		}
+	}
+
+	template<class T>
+	inline T& array<T>::ref(int i)
+	{
+	#ifdef SAFETY
+		assert( data );
+		assert( i>=0 && i<len );
+	#endif
+		return data[i];
+	}
+
+	template<class T>
+	inline const T& array<T>::ref(int i) const
+	{
+	#ifdef SAFETY
+		assert( data );
+		assert( i>=0 && i<len );
+	#endif
+		return data[i];
+	}
+
+	template<class T>
+	inline void array<T>::resize(int l)
+	{
+		T *old = data;
+		data = new T[l];
+		data = (T *)memcpy(data,old,MIN(len,l)*sizeof(T));
+		len = l;
+		delete[] old;
+	}
+}
+
+// GFXTOOLS_ARRAY_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array2.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array2.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array2.h	(revision 774)
@@ -0,0 +1,53 @@
+#ifndef GFXTOOLS_ARRAY2_INCLUDED // -*- C++ -*-
+#define GFXTOOLS_ARRAY2_INCLUDED
+
+template<class T>
+class array2 {
+protected:
+    T *data;
+    int w, h;
+public:
+    array2() { data=NULL; w=h=0; }
+    array2(int w, int h) { init(w,h); }
+    ~array2() { free(); }
+
+    inline void init(int w, int h);
+    inline void free();
+
+    inline T& ref(int i, int j);
+    inline T& operator()(int i,int j) { return ref(i,j); }
+    inline int width() const { return w; }
+    inline int height() const { return h; }
+};
+
+template<class T>
+inline void array2<T>::init(int width,int height)
+{
+    w = width;
+    h = height;
+    data = new T[w*h];
+}
+
+template<class T>
+inline void array2<T>::free()
+{
+    if( data )
+    {
+	delete[] data;
+	data = NULL;
+    }
+}
+
+template<class T>
+inline T& array2<T>::ref(int i, int j)
+{
+#ifdef SAFETY
+    assert( data );
+    assert( i>=0 && i<w );
+    assert( j>=0 && j<h );
+#endif
+    return data[j*w + i];
+}
+
+// GFXTOOLS_ARRAY2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array3.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array3.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/Array3.h	(revision 774)
@@ -0,0 +1,62 @@
+#ifndef GFXTOOLS_ARRAY3_INCLUDED // -*- C++ -*-
+#define GFXTOOLS_ARRAY3_INCLUDED
+
+template<class T>
+class array3
+{
+protected:
+    T *data;
+    int w, h, d;
+
+public:
+    array3() { data=NULL; w=h=d=0; }
+    array3(int w, int h, int d) { init(w,h,d); }
+    ~array3() { free(); }
+
+    inline void init(int w, int h, int d);
+    inline void free();
+
+
+    inline T& ref(int i, int j, int k);
+    inline T& operator()(int i,int j, int k) { return ref(i,j, k); }
+
+    inline int width() const { return w; }
+    inline int height() const { return h; }
+    inline int depth() const { return d; }
+};
+
+template<class T>
+inline void array3<T>::init(int width, int height, int depth)
+{
+    w = width;
+    h = height;
+    d = depth;
+    data = new T[w*h*d];
+}
+
+template<class T>
+inline void array3<T>::free()
+{
+    if( data )
+    {
+	delete[] data;
+	data = NULL;
+	w = h = d = 0;
+    }
+
+}
+
+template<class T>
+inline T& array3<T>::ref(int i, int j, int k)
+{
+#ifdef SAFETY
+    assert( data );
+    assert( i>=0 && i<w );
+    assert( j>=0 && j<h );
+    assert( k>=0 && k<d );
+#endif
+    return data[k*w*h + j*w + i];
+}
+
+// GFXTOOLS_ARRAY3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/heap.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/heap.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/tools/heap.cxx	(revision 774)
@@ -0,0 +1,121 @@
+//#include <iostream.h>
+#include <gfx/std.h>
+#include <gfx/tools/Heap.h>
+
+using namespace qslim;
+
+void Heap::swap(int i,int j)
+{
+    heap_node tmp = ref(i);
+
+    ref(i) = ref(j);
+    ref(j) = tmp;
+
+    ref(i).obj->setHeapPos(i);
+    ref(j).obj->setHeapPos(j);
+}
+
+void Heap::upheap(int i)
+{
+    if( i==0 ) return;
+
+    if( ref(i).import > ref(parent(i)).import ) {
+        swap(i,parent(i));
+        upheap(parent(i));
+    }
+}
+
+void Heap::downheap(int i)
+{
+    if (i>=size) return;        // perhaps just extracted the last
+
+    int largest = i,
+        l = left(i),
+        r = right(i);
+
+    if( l<size && ref(l).import > ref(largest).import ) largest = l;
+    if( r<size && ref(r).import > ref(largest).import ) largest = r;
+
+    if( largest != i ) {
+        swap(i,largest);
+        downheap(largest);
+    }
+}
+
+
+
+void Heap::insert(Heapable *t,float v)
+{
+    if( size == maxLength() )
+    {
+	std::cerr << "NOTE: Growing heap from " << size << " to " << 2*size << std::endl;
+	resize(2*size);
+    }
+
+    int i = size++;
+
+    ref(i).obj = t;
+    ref(i).import = v;
+
+    ref(i).obj->setHeapPos(i);
+
+    upheap(i);
+}
+
+void Heap::update(Heapable *t,float v)
+{
+    int i = t->getHeapPos();
+
+    if( i >= size )
+    {
+		std::cerr << "WARNING: Attempting to update past end of heap!" << std::endl;
+		return;
+    }
+    else if( i == NOT_IN_HEAP )
+    {
+		std::cerr << "WARNING: Attempting to update object not in heap!" << std::endl;
+		return;
+    }
+
+    float old=ref(i).import;
+    ref(i).import = v;
+
+    if( v<old )
+        downheap(i);
+    else
+        upheap(i);
+}
+
+
+
+heap_node *Heap::extract()
+{
+    if( size<1 ) return 0;
+
+    swap(0,size-1);
+    size--;
+
+    downheap(0);
+
+    ref(size).obj->notInHeap();
+
+    return &ref(size);
+}
+
+heap_node *Heap::kill(int i)
+{
+    if( i>=size )
+		std::cerr << "WARNING: Attempt to delete invalid heap node." << std::endl;
+
+    swap(i, size-1);
+    size--;
+    ref(size).obj->notInHeap();
+
+    if( ref(i).import < ref(size).import )
+		downheap(i);
+    else
+		upheap(i);
+
+
+    return &ref(size);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.cxx	(revision 774)
@@ -0,0 +1,56 @@
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+//#include <fstream.h>
+
+#include <gfx/std.h>
+//#include <gfx/sys/futils.h>
+#include <gfx/SMF/smf.h>
+#include <gfx/SMF/smfstate.h>
+
+using namespace qslim;
+
+inline int streq(const char *a,const char *b) { return strcmp(a,b)==0; }
+
+float qslim::SMF_version = 1.0;
+char *qslim::SMF_version_string = "1.0";
+char *SMF_source_revision = "$Id: smf.cxx,v 1.1 1997/06/16 22:11:40 garland Exp $";
+
+
+int SMF_Model::in_Face(const buffer<int>&)
+{
+    fatal_error("SMF: Arbitrary face definitions not supported.");
+    return False;
+}
+
+int SMF_Model::in_Unparsed(const char *, string_buffer&)
+{
+    return False;
+}
+
+int SMF_Model::note_Vertices(int) { return True; }
+int SMF_Model::note_Faces(int) { return True; }
+int SMF_Model::note_BBox(const Vec3&, const Vec3&) { return True; }
+int SMF_Model::note_BSphere(const Vec3&, real) { return True; }
+int SMF_Model::note_PXform(const Mat4&) { return True; }
+int SMF_Model::note_MXform(const Mat4&) { return True; }
+int SMF_Model::note_Unparsed(const char *,string_buffer&) { return True; }
+
+
+static Mat4 mat_from_args(string_buffer& argv)
+{
+    Mat4 M;
+
+    int n=0, i, j;
+    for(i=0; i<4; i++)
+	for(j=0; j<4; j++)
+	    M(i,j) = atof(argv(n++));
+
+    return M;
+}
+
+static
+void bad_annotation(char *cmd)
+{
+	std::cerr << "SMF: Malformed annotation ["<< cmd << "]" << std::endl;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.cxx	(revision 774)
@@ -0,0 +1,78 @@
+//#include <iostream.h>
+#include <string.h>
+
+#include <gfx/std.h>
+#include <gfx/SMF/smf.h>
+#include <gfx/SMF/smfstate.h>
+
+inline int streq(const char *a,const char *b) { return strcmp(a,b)==0; }
+
+using namespace qslim;
+
+SMF_State::SMF_State(const SMF_ivars& ivar, SMF_State *link)
+{
+    next = link;
+    first_vertex = ivar.next_vertex;
+    if( next )
+    {
+	vertex_correction = next->vertex_correction;
+	xform = next->xform;
+    }
+    else
+    {
+	vertex_correction = 0;
+	xform = Mat4::identity;
+    }
+
+}
+
+void SMF_State::vertex(Vec3& v)
+{
+    Vec4 v2 = xform * Vec4(v,1);
+
+    v[X] = v2[X]/v2[W];
+    v[Y] = v2[Y]/v2[W];
+    v[Z] = v2[Z]/v2[W];
+}
+
+void SMF_State::normal(Vec3& v)
+{
+    Vec4 v2 = xform * Vec4(v,0);
+
+//     v[X] = v2[X]/v2[W];
+//     v[Y] = v2[Y]/v2[W];
+//     v[Z] = v2[Z]/v2[W];
+
+    v[X] = v2[X];
+    v[Y] = v2[Y];
+    v[Z] = v2[Z];
+}
+
+void SMF_State::face(buffer<int>& verts, const SMF_ivars& ivar)
+{
+    for(int i=0; i<verts.length(); i++)
+    {
+	if( verts(i) < 0 )
+	    verts(i) += ivar.next_vertex;
+	else
+	    verts(i) += vertex_correction + (first_vertex - 1);
+    }
+}
+
+void SMF_State::set(string_buffer& argv)
+{
+    char *cmd = argv(0);
+
+    if( streq(cmd, "vertex_correction") )
+	vertex_correction = atoi(argv(1));
+}
+
+void SMF_State::mmult(const Mat4& M)
+{
+    xform = xform * M;
+}
+
+void SMF_State::mload(const Mat4& M)
+{
+    xform = M;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smf.h	(revision 774)
@@ -0,0 +1,77 @@
+#ifndef GFX_SMF_INCLUDED // -*- C++ -*-
+#define GFX_SMF_INCLUDED
+
+/************************************************************************
+
+  SMF file parser.
+
+  $Id: smf.h,v 1.8 1997/03/17 20:35:57 garland Exp $
+
+ ************************************************************************/
+
+//#include <iostream.h>
+#include <gfx/tools/Buffer.h>
+#include <gfx/math/Vec3.h>
+#include <gfx/math/Vec2.h>
+#include <gfx/math/Mat4.h>
+
+
+namespace qslim
+{
+	#define SMF_MAXLINE 4096
+
+	extern float SMF_version;
+	extern char *SMF_version_string;
+	extern char *SMF_source_revision;
+
+	typedef buffer<char *> string_buffer;
+
+
+	class SMF_Model
+	{
+	public:
+
+		////////////////////////////////////////////////////////////////////////
+		//
+		// SMF input methods
+		//
+
+		//
+		// These are the REQUIRED methods
+		virtual int in_Vertex(const Vec3&) = 0;
+		virtual int in_Normal(const Vec3&) = 0;
+		virtual int in_TexCoord(const Vec2&) = 0;
+		virtual int in_Face(int v1, int v2, int v3, int n1, int n2, int n3, int t1, int t2, int t3) = 0;
+
+		//
+		// By default, arbitrary faces are flagged as errors
+		virtual int in_Face(const buffer<int> &);
+		// 
+		// as are unknown commands
+		virtual int in_Unparsed(const char *, string_buffer&);
+
+		virtual int note_Vertices(int);
+		virtual int note_Faces(int);
+		virtual int note_BBox(const Vec3& min, const Vec3& max);
+		virtual int note_BSphere(const Vec3&, real);
+		virtual int note_PXform(const Mat4&);
+		virtual int note_MXform(const Mat4&);
+		virtual int note_Unparsed(const char *,string_buffer&);
+	};
+
+	class SMF_State;
+
+	//
+	// Internal SMF variables
+	// (not accessible via 'set' commands)
+	//
+	struct SMF_ivars
+	{
+		int next_vertex;
+		int next_face;
+	};
+}
+
+
+// GFX_SMF_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/SMF/smfstate.h	(revision 774)
@@ -0,0 +1,36 @@
+#ifndef GFXSMF_STATE_INCLUDED // -*- C++ -*-
+#define GFXSMF_STATE_INCLUDED
+
+namespace qslim
+{
+	class SMF_State
+	{
+	private:
+		SMF_State *next;
+
+		//
+		// Standard state variables
+		int first_vertex;
+		int vertex_correction;
+		Mat4 xform;
+
+	public:
+		SMF_State(const SMF_ivars& ivar,SMF_State *link=NULL);
+		SMF_State *pop() { return next; }
+
+		void set(string_buffer& argv);
+		void inc(const char *var, int delta=1);
+		void dec(const char *var, int delta=1);
+
+		void mmult(const Mat4&);
+		void mload(const Mat4&);
+
+		void vertex(Vec3&);
+		void normal(Vec3&);
+		void face(buffer<int>&, const SMF_ivars& ivar);
+	};
+}
+
+
+// GFXSMF_STATE_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProjectH.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProjectH.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProjectH.cxx	(revision 774)
@@ -0,0 +1,158 @@
+/*
+ * The projection code in this file was originally due to Hugues Hoppe
+ * and was distributed under the following terms:
+ *
+ *      Copyright (c) 1992, 1993, 1994, Hugues Hoppe, University of Washington.
+ *      Copying, use, and development for non-commercial purposes permitted.
+ *                       All rights for commercial use reserved.
+ *
+ * Anoop Bhattacharjya <anoop@epal.smos.com> made some small changes.
+ *
+ * I made some small modifications, primarily to fix some C++ const-related
+ * issues.  And I added the function __gfx_hoppe_dist() to tie it in with
+ * my GFX library code.
+ *
+ *      - Michael Garland
+ *
+ */
+
+#include <stdio.h>
+#include <gfx/std.h>
+#include <gfx/geom/3D.h>
+
+#ifdef DOTP
+#undef DOTP
+#endif
+
+#define DOTP(a, b) (a[0] * b[0] + a[1] * b[1] + a[2] * b[2])
+
+using namespace qslim;
+
+static real Distance2(real x[3], real *y)
+{
+    real a, b, c;
+	
+    a = x[0] - y[0];  b = x[1] - y[1];  c = x[2] - y[2];
+    return (a * a + b * b + c * c);
+}
+
+static void interp(real *proj, const real *p1, const real *p2,
+		   const real *p3, const real *bary)
+{
+    proj[0] = p1[0] * bary[0] + p2[0] * bary[1] + p3[0] * bary[2];
+    proj[1] = p1[1] * bary[0] + p2[1] * bary[1] + p3[1] * bary[2];
+    proj[2] = p1[2] * bary[0] + p2[2] * bary[1] + p3[2] * bary[2];
+}
+
+static void Projecth(const real *v1, const real *v2, const real *v3,real *bary)
+{
+    int     i;
+    real   vvi[3],vppi[3];
+    real   d12sq, don12,d2, mind2, a;
+    real   proj[3];
+    real   pf[3][3];
+    real   ba[3];
+    real   cba[3];
+
+    mind2 = 1e30;
+    interp(proj,v1,v2,v3,bary);
+    pf[0][0] = v1[0]; pf[0][1] = v1[1]; pf[0][2] = v1[2];
+    pf[1][0] = v2[0]; pf[1][1] = v2[1]; pf[1][2] = v2[2];
+    pf[2][0] = v3[0]; pf[2][1] = v3[1]; pf[2][2] = v3[2];
+
+    ba[0] = bary[0]; ba[1] = bary[1]; ba[2] = bary[2];
+
+    for (i = 0; i < 3; i++){
+	if (ba[(i+2)%3] >= 0) continue;
+	/* project proj onto segment pf[(i+0)%3]--pf[(i+1)%3]  */
+         
+	vvi[0] = pf[(i+1) % 3][0] - pf[i][0];
+	vvi[1] = pf[(i+1) % 3][1] - pf[i][1];
+	vvi[2] = pf[(i+1) % 3][2] - pf[i][2];
+         
+	vppi[0] = proj[0] - pf[i][0];
+	vppi[1] = proj[1] - pf[i][1];
+	vppi[2] = proj[2] - pf[i][2];
+
+	d12sq = DOTP(vvi, vvi);
+	don12 = DOTP(vvi, vppi);
+
+	if (don12<=0) {
+	    d2 = Distance2(pf[i], proj);
+	    if (d2 >= mind2) continue;
+	    mind2=d2; cba[i]=1; cba[(i+1)%3]=0; cba[(i+2)%3]=0;
+	}
+	else {
+	    if (don12 >= d12sq) {
+		d2 = Distance2(pf[(i+1)%3], proj);
+		if (d2>=mind2) continue;
+		mind2=d2; cba[i]=0; cba[(i+1)%3]=1; cba[(i+2)%3]=0;
+	    }
+	    else {
+		a = don12/d12sq;
+		cba[i]=1-a; cba[(i+1)%3]=a; cba[(i+2)%3]=0;
+		break;
+	    }
+	}
+    }
+
+    bary[0] = cba[0]; bary[1] = cba[1]; bary[2] = cba[2];
+}
+
+static void ProjectPtri(const real *point,  const real *v1, 
+			const real *v2,  const real *v3, real *bary)
+{
+    int    i;
+    real  localv2[3], localv3[3], vpp1[3];
+    real  v22,v33,v23,v2pp1,v3pp1;
+    real  a1,a2,a3,denom;
+
+    for (i = 0; i < 3; i++){
+	localv2[i] = v2[i] - v1[i];
+	localv3[i] = v3[i] - v1[i];
+	vpp1[i] = point[i] - v1[i];
+    }
+	
+    v22   = DOTP(localv2, localv2);
+    v33   = DOTP(localv3, localv3);
+    v23   = DOTP(localv2, localv3);
+    v2pp1 = DOTP(localv2, vpp1);
+    v3pp1 = DOTP(localv3, vpp1);
+	
+    if (!v22) v22=1;        /* recover if v2==0 */
+    if (!v33) v33=1;        /* recover if v3==0 */
+
+    denom = ( v33 - v23 * v23 / v22);
+    if (!denom) {
+	a2 = a3 = 1.0/3.0;    /* recover if v23*v23==v22*v33 */
+    }
+    else {
+	a3=(v3pp1-v23/v22*v2pp1)/denom;
+	a2=(v2pp1-a3*v23)/v22;
+    }
+    a1 = 1 - a2 - a3;
+
+    bary[0] = a1; bary[1] = a2; bary[2] = a3;
+
+    if ((a1 < 0) || (a2 < 0) || (a3 < 0)){
+	Projecth(v1,v2,v3,bary);
+	return;
+    }
+}
+
+real __gfx_hoppe_dist(const Face3& f, const Vec3& v)
+{
+    Vec3 bary;
+
+    const Vec3& v0 = f.vertexPos(0);
+    const Vec3& v1 = f.vertexPos(1);
+    const Vec3& v2 = f.vertexPos(2);
+
+    ProjectPtri(v.raw(), v0.raw(), v1.raw(), v2.raw(), bary.raw());
+
+    Vec3 p = bary[X]*v0 + bary[Y]*v1 + bary[Z]*v2;
+
+    Vec3 diff = v - p;
+
+    return diff*diff;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.cxx	(revision 774)
@@ -0,0 +1,99 @@
+//#include <iostream.h>
+#include <gfx/std.h>
+#include <gfx/math/Vec3.h>
+#include <gfx/tools/Buffer.h>
+#include <gfx/tools/Array3.h>
+#include <gfx/geom/ProxGrid.h>
+
+using namespace qslim;
+
+ProxGrid::ProxGrid(const Vec3& lo, const Vec3& hi, real dist)
+{
+    cellsize = dist;
+    cellsize2 = dist*dist;
+
+    min = lo;
+    max = hi;
+
+    xdiv = (int)ceil((max[X] - min[X])/dist);
+    ydiv = (int)ceil((max[Y] - min[Y])/dist);
+    zdiv = (int)ceil((max[Z] - min[Z])/dist);
+
+    cells.init(xdiv, ydiv, zdiv);
+}
+
+
+void ProxGrid::cell_for_point(const Vec3& v,int *i_out,int *j_out,int *k_out)
+{
+    int i = (int)floor((v[X] - min[X]) / cellsize);
+    int j = (int)floor((v[Y] - min[Y]) / cellsize);
+    int k = (int)floor((v[Z] - min[Z]) / cellsize);
+   
+    // In case we hit the max bounds
+    if( i==xdiv ) i--;
+    if( j==ydiv ) j--;
+    if( k==zdiv ) k--;
+  
+
+    *i_out = i;
+    *j_out = j;
+    *k_out = k;
+}
+
+void ProxGrid::addPoint(Vec3 *v)
+{
+    int i, j, k;
+    cell_for_point(*v, &i, &j, &k);
+    ProxGrid_Cell& cell = cells(i,j,k);
+
+    cell.add(v);
+}
+
+void ProxGrid::removePoint(Vec3 *v)
+{
+    int i, j, k;
+    cell_for_point(*v, &i, &j, &k);
+    ProxGrid_Cell& cell = cells(i,j,k);
+
+
+    int index = cell.find(v);
+    if( index >= 0 )
+	cell.remove(index);
+    else
+		std::cerr << "WARNING: ProxGrid -- removing non-member point." << std::endl;
+}
+
+
+
+void ProxGrid::maybe_collect_points(Vec3 *v, buffer<Vec3 *>& close,
+				    ProxGrid_Cell& cell)
+{
+    for(int i=0; i<cell.length(); i++)
+    {
+	Vec3 *u = cell(i);
+
+	if( u!=v && norm2(*u - *v) < cellsize2 )
+	    close.add(u);
+    }
+}
+
+
+
+void ProxGrid::proximalPoints(Vec3 *v, buffer<Vec3 *>& close)
+{
+    int i, j, k;
+    cell_for_point(*v, &i, &j, &k);
+
+    for(int dk=-1; dk<2; dk++)
+	for(int dj=-1; dj<2; dj++)
+	    for(int di=-1; di<2; di++)
+	    {
+		if( i+di>=0 && j+dj>=0 && k+dk>=0
+		    && i+di<cells.width()
+		    && j+dj<cells.height()
+		    && k+dk<cells.depth() )
+		{
+		    maybe_collect_points(v, close, cells(i+di, j+dj, k+dk));
+		}
+	    }
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/ProxGrid.h	(revision 774)
@@ -0,0 +1,57 @@
+#ifndef GFXGEOM_PROXGRID_INCLUDED // -*- C++ -*-
+#define GFXGEOM_PROXGRID_INCLUDED
+
+#include <gfx/math/Vec3.h>
+#include <gfx/tools/Buffer.h>
+#include <gfx/tools/Array3.h>
+
+
+namespace qslim
+{
+	class ProxGrid_Cell : public buffer<Vec3 *>
+	{
+
+	public:
+
+		ProxGrid_Cell()
+		: buffer<Vec3 *>(8)
+		{ }
+	};
+
+
+
+
+
+	class ProxGrid
+	{
+		array3<ProxGrid_Cell> cells;
+		int xdiv, ydiv, zdiv;
+		real cellsize;
+		real cellsize2;
+
+		Vec3 min, max;
+
+		void cell_for_point(const Vec3&, int *i, int *j, int *k);
+		void maybe_collect_points(Vec3 *v, buffer<Vec3 *>& close,
+					  ProxGrid_Cell& cell);
+
+	public:
+
+		ProxGrid(const Vec3& min, const Vec3& max, real dist);
+		~ProxGrid() { cells.free(); }
+
+		void addPoint(Vec3 *);
+		void removePoint(Vec3 *);
+		void proximalPoints(Vec3 *, buffer<Vec3 *>&);
+
+	};
+}
+
+
+
+
+
+
+
+// GFXGEOM_PROXGRID_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.cxx	(revision 774)
@@ -0,0 +1,155 @@
+#include <gfx/std.h>
+#include <gfx/math/random.h>
+#include <gfx/geom/3D.h>
+
+using namespace qslim;
+
+Vec3 randomPoint(const Vec3& v1, const Vec3& v2)
+{
+    real a = random1();
+
+    return a*v1 + (1-a)*v2;
+}
+
+Vec3 randomPoint(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    real b1 = 1 - sqrt( 1-random1() );
+    real b2 = (1-b1) * random1();
+    real b3 = 1 - b1 - b2;
+
+    return b1*v1 + b2*v2 + b3*v3;
+}
+
+real qslim::triangleArea(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    Vec3 a = v2 - v1;
+    Vec3 b = v3 - v1;
+
+    return 0.5 * length(a ^ b);
+}
+
+#define ROOT3 1.732050807568877
+#define FOUR_ROOT3 6.928203230275509
+
+real triangleCompactness(const Vec3& v1, const Vec3& v2, const Vec3& v3)
+{
+    real L1 = norm2(v2-v1);
+    real L2 = norm2(v3-v2);
+    real L3 = norm2(v1-v3);
+
+    return FOUR_ROOT3 * qslim::triangleArea(v1,v2,v3) / (L1+L2+L3);
+}
+
+
+
+////////////////////////////////////////////////////////////////////////.
+//
+// class: Bounds
+//
+
+void Bounds::reset()
+{
+    min[X] = min[Y] = min[Z] = HUGE;
+    max[X] = max[Y] = max[Z] = -HUGE;
+
+    center[X] = center[Y] = center[Z] = 0.0;
+    radius = 0.0;
+
+    points = 0;
+}
+
+void Bounds::addPoint(const Vec3& v)
+{
+    if( v[X] < min[X] ) min[X] = v[X];
+    if( v[Y] < min[Y] ) min[Y] = v[Y];
+    if( v[Z] < min[Z] ) min[Z] = v[Z];
+
+    if( v[X] > max[X] ) max[X] = v[X];
+    if( v[Y] > max[Y] ) max[Y] = v[Y];
+    if( v[Z] > max[Z] ) max[Z] = v[Z];
+
+
+    center += v;
+
+    points++;
+}
+
+void Bounds::complete()
+{
+    center /= (real)points;
+
+    Vec3 R1 = max-center;
+    Vec3 R2 = min-center;
+
+    radius = MAX(length(R1), length(R2));
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// class: Plane
+//
+
+void Plane::calcFrom(const Vec3& p1, const Vec3& p2, const Vec3& p3)
+{
+    Vec3 v1 = p2-p1;
+    Vec3 v2 = p3-p1;
+
+    n = v1 ^ v2;
+    unitize(n);
+
+    d = -n*p1;
+}
+
+void Plane::calcFrom(const array<Vec3>& verts)
+{
+    n[X] = n[Y] = n[Z] = 0.0;
+
+    int i;
+    for(i=0; i<verts.length()-1; i++)
+    {
+        const Vec3& cur = verts[i];
+        const Vec3& next = verts[i+1];
+
+        n[X] += (cur[Y] - next[Y]) * (cur[Z] + next[Z]);
+        n[Y] += (cur[Z] - next[Z]) * (cur[X] + next[X]);
+        n[Z] += (cur[X] - next[X]) * (cur[Y] + next[Y]);
+    }
+
+    const Vec3& cur = verts[verts.length()-1];
+    const Vec3& next = verts[0];
+    n[X] += (cur[Y] - next[Y]) * (cur[Z] + next[Z]);
+    n[Y] += (cur[Z] - next[Z]) * (cur[X] + next[X]);
+    n[Z] += (cur[X] - next[X]) * (cur[Y] + next[Y]);
+
+    unitize(n);
+
+    d = -n*verts[0];
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// class: Face3
+//
+
+real Face3::area()
+{
+    return triangleArea(vertexPos(0),vertexPos(1),vertexPos(2));
+}
+
+
+//
+// Use Anoop's distance code
+//
+
+extern real __gfx_hoppe_dist(const Face3& f, const Vec3& v);
+
+real Face3::distTo(const Vec3& v) const
+{
+    return __gfx_hoppe_dist(*this, v);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/geom/3D.h	(revision 774)
@@ -0,0 +1,99 @@
+#ifndef GFXGEOM_3D_INCLUDED // -*- C++ -*-
+#define GFXGEOM_3D_INCLUDED
+
+#include <gfx/math/Vec3.h>
+#include <gfx/math/Vec4.h>
+#include <gfx/tools/Array.h>
+
+//
+// Generally useful geometric functions
+//
+
+namespace qslim
+{
+	extern Vec3 randomPoint(const Vec3&, const Vec3&);  // on segment
+	extern Vec3 randomPoint(const Vec3&, const Vec3&, const Vec3&); // in triangle
+
+	extern real triangleArea(const Vec3&, const Vec3&, const Vec3&);
+	extern real triangleCompactness(const Vec3&, const Vec3&, const Vec3&);
+
+	class Bounds
+	{
+	public:
+
+		Vec3 min, max;
+		Vec3 center;
+		real radius;
+		unsigned int points;
+
+		Bounds() { reset(); }
+
+		void reset();
+		void addPoint(const Vec3&);
+		void complete();
+	};
+
+	class Plane
+	{
+		//
+		// A plane is defined by the equation:  n*p + d = 0
+		Vec3 n;
+		real d;
+
+	public:
+
+		Plane() : n(0,0,1) { d=0; } // -- this will define the XY plane
+		Plane(const Vec3& p, const Vec3& q, const Vec3& r) { calcFrom(p,q,r); }
+		Plane(const array<Vec3>& verts) { calcFrom(verts); }
+		Plane(const Plane& p) { n=p.n; d=p.d; }
+
+		void calcFrom(const Vec3& p, const Vec3& q, const Vec3& r);
+		void calcFrom(const array<Vec3>&);
+
+		bool isValid() const { return n[X]!=0.0 || n[Y]!=0.0 || n[Z]!= 0.0; }
+		void markInvalid() { n[X] = n[Y] = n[Z] = 0.0; }
+
+		real distTo(const Vec3& p) const { return n*p + d; }
+		const Vec3& normal() const { return n; }
+
+		void coeffs(real *a, real *b, real *c, real *dd) const {
+			*a=n[X]; *b=n[Y]; *c=n[Z]; *dd=d;
+		}
+		Vec4 coeffs() const { return Vec4(n,d); }
+	};
+
+
+	//
+	// A triangular face in 3D (ie. a 2-simplex in E3)
+	//
+	class Face3
+	{
+	protected:
+		Plane P;
+
+	private:
+		void recalcPlane() { P.calcFrom(vertexPos(0),vertexPos(1),vertexPos(2)); }
+		void recalcPlane(const Vec3& a,const Vec3& b,const Vec3& c)
+		{ P.calcFrom(a,b,c); }
+
+	public:
+		Face3(const Vec3& a,const Vec3& b,const Vec3& c)
+		: P(a,b,c)
+		{ }
+
+		//
+		// Basic primitive operations on faces
+		virtual const Vec3& vertexPos(int i) const = 0;
+		virtual void vertexPos(int i, const Vec3&) = 0; 
+		const Plane& plane() { if(!P.isValid()) recalcPlane();   return P;}
+		void invalidatePlane() { P.markInvalid(); }
+
+		real distTo(const Vec3& p) const;
+		real area();
+	};
+}
+
+
+
+// GFXGEOM_3D_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/cholesky.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/cholesky.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/cholesky.cxx	(revision 774)
@@ -0,0 +1,39 @@
+#include <gfx/std.h>
+#include <gfx/math/Mat4.h>
+
+// Adapted directly from Numerical Recipes in C
+//
+// Takes a symmetric positive definite matrix a
+// (only the upper triangle is actually necessary)
+// and computes the Cholesky decomposition of a.
+// A return value of False indicates that the decomposition does not exist.
+// On return, the lower triangle of a contains the factor and the
+// vector p contains the diagonal elements of the factor.
+//
+
+using namespace qslim;
+
+bool cholesky(Mat4& a, Vec4& p)
+{
+    int n = 4;
+    int i,j,k;
+    real sum;
+
+    for(i=0; i<n; i++)
+    {
+        for(j=i; j<n; j++)
+        {
+            for(sum=a(i,j), k=i-1; k>=0; k--) sum -= a(i,k)*a(j,k);
+            if( i==j )
+            {
+                if( sum<=0.0 )
+                    return False;
+                p[i] = sqrt(sum);
+            }
+            else
+                a(j,i) = sum/p[i];
+        }
+    }
+
+    return True;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.cxx	(revision 774)
@@ -0,0 +1,45 @@
+#include <gfx/std.h>
+#include <gfx/math/Mat2.h>
+
+using namespace qslim;
+
+Mat2 Mat2::identity(Vec2(1,0), Vec2(0,1));
+Mat2 Mat2::zero(Vec2(0,0), Vec2(0,0));
+Mat2 Mat2::unit(Vec2(1,1), Vec2(1,1));
+
+Mat2 Mat2::operator*(const Mat2& m) const
+{
+    Mat2 A;
+    int i,j;
+
+    for(i=0;i<2;i++)
+	for(j=0;j<2;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+real Mat2::det()
+{
+    return (row[0][0]*row[1][1] - row[0][1]*row[1][0]);
+}
+
+Mat2 Mat2::transpose()
+{
+    return Mat2(col(0), col(1));
+}
+
+real Mat2::inverse(Mat2& inv)
+{
+    real d = det();
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv.row[0][0] = row[1][1]/d;
+    inv.row[0][1] = -row[1][0]/d;
+    inv.row[1][0] = -row[0][1]/d;
+    inv.row[1][1] = row[0][0]/d;
+
+    return d;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.cxx	(revision 774)
@@ -0,0 +1,67 @@
+#include <gfx/std.h>
+#include <gfx/math/Mat3.h>
+
+using namespace qslim;
+
+Mat3 Mat3::identity(Vec3(1,0,0), Vec3(0,1,0), Vec3(0,0,1));
+Mat3 Mat3::zero(Vec3(0,0,0), Vec3(0,0,0), Vec3(0,0,0));
+Mat3 Mat3::unit(Vec3(1,1,1), Vec3(1,1,1), Vec3(1,1,1));
+
+Mat3 Mat3::diag(const Vec3& v)
+{
+    Mat3 M(zero);
+
+    M(0,0) = v[X];
+    M(1,1) = v[Y];
+    M(2,2) = v[Z];
+
+    return M;
+}
+
+Mat3 Mat3::extend(const Vec3& v)
+{
+    return Mat3(v,v,v);
+}
+
+
+
+Mat3 Mat3::operator*(const Mat3& m) const
+{
+    Mat3 A;
+    int i,j;
+
+    for(i=0;i<3;i++)
+	for(j=0;j<3;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+real Mat3::det()
+{
+    return row[0] * (row[1] ^ row[2]);
+}
+
+Mat3 Mat3::transpose()
+{
+    return Mat3(col(0), col(1), col(2));
+}
+
+Mat3 Mat3::adjoint()
+{
+    return Mat3(row[1]^row[2],
+		row[2]^row[0],
+		row[0]^row[1]);
+}
+
+real Mat3::inverse(Mat3& inv)
+{
+    Mat3 A = adjoint();
+    real d = A.row[0] * row[0];
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv = A.transpose() / d;
+    return d;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec2.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec2.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec2.h	(revision 774)
@@ -0,0 +1,205 @@
+#ifndef GFXMATH_VEC2_INCLUDED // -*- C++ -*-
+#define GFXMATH_VEC2_INCLUDED
+
+/************************************************************************
+
+  2D Vector class.
+
+  $Id: Vec2.h,v 1.6 1997/03/17 22:52:25 garland Exp $
+
+ ************************************************************************/
+
+namespace qslim
+{
+	class Vec2 {
+	private:
+		real elt[2];
+
+	protected:
+		inline void copy(const Vec2& v);
+
+	public:
+		//
+		// Standard constructors
+		//
+		Vec2(real x=0, real y=0) { elt[0]=x; elt[1]=y; }
+		Vec2(const Vec2& v) { copy(v); }
+		Vec2(const real *v) { elt[0]=v[0]; elt[1]=v[1]; }
+
+		//
+		// Access methods
+		//
+	#ifdef SAFETY
+		real& operator()(int i)       { assert(i>=0 && i<2); return elt[i]; }
+		real  operator()(int i) const { assert(i>=0 && i<2); return elt[i]; }
+	#else
+		real& operator()(int i)       { return elt[i]; }
+		real  operator()(int i) const { return elt[i]; }
+	#endif
+		real& operator[](int i)       { return elt[i]; }
+		real  operator[](int i) const { return elt[i]; }
+
+		real *raw()             { return elt; }
+		const real *raw() const { return elt; }
+
+
+		//
+		// Comparison operators
+		//
+		inline bool operator==(const Vec2& v) const;
+		inline bool operator!=(const Vec2& v) const;
+
+		//
+		// Assignment and in-place arithmetic methods
+		//
+		inline void set(real x, real y) { elt[0]=x; elt[1]=y; }
+		inline Vec2& operator=(const Vec2& v);
+		inline Vec2& operator+=(const Vec2& v);
+		inline Vec2& operator-=(const Vec2& v);
+		inline Vec2& operator*=(real s);
+		inline Vec2& operator/=(real s);
+
+		//
+		// Binary arithmetic methods
+		//
+		inline Vec2 operator+(const Vec2& v) const;
+		inline Vec2 operator-(const Vec2& v) const;
+		inline Vec2 operator-() const;
+
+		inline Vec2 operator*(real s) const;
+		inline Vec2 operator/(real s) const;
+		inline real operator*(const Vec2& v) const;
+	};
+}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Method definitions
+	//
+
+	inline void qslim::Vec2::copy(const qslim::Vec2& v)
+	{
+		elt[0]=v.elt[0]; elt[1]=v.elt[1];
+	}
+
+	inline bool qslim::Vec2::operator==(const qslim::Vec2& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y];
+		return (dx*dx + dy*dy) < FEQ_EPS2;
+	}
+
+	inline bool qslim::Vec2::operator!=(const qslim::Vec2& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y];
+		return (dx*dx + dy*dy) > FEQ_EPS2;
+	}
+
+	inline qslim::Vec2& qslim::Vec2::operator=(const qslim::Vec2& v)
+	{
+		copy(v);
+		return *this;
+	}
+
+	inline qslim::Vec2& qslim::Vec2::operator+=(const qslim::Vec2& v)
+	{
+		elt[0] += v[0];   elt[1] += v[1];
+		return *this;
+	}
+
+	inline qslim::Vec2& qslim::Vec2::operator-=(const qslim::Vec2& v)
+	{
+		elt[0] -= v[0];   elt[1] -= v[1];
+		return *this;
+	}
+
+	inline qslim::Vec2& qslim::Vec2::operator*=(qslim::real s)
+	{
+		elt[0] *= s;   elt[1] *= s;
+		return *this;
+	}
+
+	inline qslim::Vec2& qslim::Vec2::operator/=(qslim::real s)
+	{
+		elt[0] /= s;   elt[1] /= s;
+		return *this;
+	}
+
+	inline qslim::Vec2 qslim::Vec2::operator+(const qslim::Vec2& v) const
+	{
+		return Vec2(elt[0]+v[0], elt[1]+v[1]);
+	}
+
+	inline qslim::Vec2 qslim::Vec2::operator-(const qslim::Vec2& v) const
+	{
+		return Vec2(elt[0]-v[0], elt[1]-v[1]);
+	}
+
+	inline qslim::Vec2 qslim::Vec2::operator-() const
+	{
+		return qslim::Vec2(-elt[0], -elt[1]);
+	}
+
+	inline qslim::Vec2 qslim::Vec2::operator*(qslim::real s) const
+	{
+		return Vec2(elt[0]*s, elt[1]*s);
+	}
+
+	inline qslim::Vec2 qslim::Vec2::operator/(qslim::real s) const
+	{
+		return Vec2(elt[0]/s, elt[1]/s);
+	}
+
+	inline qslim::real qslim::Vec2::operator*(const qslim::Vec2& v) const
+	{
+		return elt[0]*v[0] + elt[1]*v[1];
+	}
+
+	// Make scalar multiplication commutative
+	inline qslim::Vec2 operator*(qslim::real s, const qslim::Vec2& v) { return v*s; }
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Primitive function definitions
+	//
+
+namespace qslim
+{
+	inline real norm(const qslim::Vec2& v) { return sqrt(v[0]*v[0] + v[1]*v[1]); }
+	inline real norm2(const qslim::Vec2& v) { return v[0]*v[0] + v[1]*v[1]; }
+	inline real length(const qslim::Vec2& v) { return norm(v); }
+
+	inline real unitize(qslim::Vec2& v)
+	{
+		qslim::real l=norm2(v);
+		if( l!=1.0 && l!=0.0 )
+		{
+		l = sqrt(l);
+		v /= l;
+		}
+		return l;
+	}
+}
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Misc. function definitions
+	//
+
+/*	inline ostream& operator<<(ostream& out, const Vec2& v)
+	{
+		return out << "[" << v[0] << " " << v[1] << "]";
+	}
+
+	inline istream& operator>>(istream& in, Vec2& v)
+	{
+		return in >> "[" >> v[0] >> v[1] >> "]";
+	}
+*/
+	#ifdef GFXGL_INCLUDED
+	inline void glV(const Vec2& v) { glVertex(v[X], v[Y]); }
+	#endif
+
+	// GFXMATH_VEC2_INCLUDED
+	#endif
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.cxx	(revision 774)
@@ -0,0 +1,175 @@
+#include <gfx/std.h>
+#include <gfx/math/Mat4.h>
+
+using namespace qslim;
+
+Mat4 Mat4::identity(Vec4(1,0,0,0),Vec4(0,1,0,0),Vec4(0,0,1,0),Vec4(0,0,0,1));
+Mat4 Mat4::zero(Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0),Vec4(0,0,0,0));
+Mat4 Mat4::unit(Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1),Vec4(1,1,1,1));
+
+Mat4 Mat4::trans(real x, real y, real z)
+{
+    return Mat4(Vec4(1,0,0,x),
+		Vec4(0,1,0,y),
+		Vec4(0,0,1,z),
+		Vec4(0,0,0,1));
+}
+
+Mat4 Mat4::scale(real x, real y, real z)
+{
+    return Mat4(Vec4(x,0,0,0),
+		Vec4(0,y,0,0),
+		Vec4(0,0,z,0),
+		Vec4(0,0,0,1));
+}
+
+Mat4 Mat4::xrot(real a)
+{
+    real c = cos(a);
+    real s = sin(a);
+
+    return Mat4(Vec4(1, 0, 0, 0),
+		Vec4(0, c,-s, 0),
+		Vec4(0, s, c, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::yrot(real a)
+{
+    real c = cos(a);
+    real s = sin(a);
+
+    return Mat4(Vec4(c, 0, s, 0),
+		Vec4(0, 1, 0, 0),
+		Vec4(-s,0, c, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::zrot(real a)
+{
+    real c = cos(a);
+    real s = sin(a);
+
+    return Mat4(Vec4(c,-s, 0, 0),
+		Vec4(s, c, 0, 0),
+		Vec4(0, 0, 1, 0),
+		Vec4(0, 0, 0, 1));
+}
+
+Mat4 Mat4::operator*(const Mat4& m) const
+{
+    Mat4 A;
+    int i,j;
+
+    for(i=0;i<4;i++)
+	for(j=0;j<4;j++)
+	    A(i,j) = row[i]*m.col(j);
+
+    return A;
+}
+
+real Mat4::det() const
+{
+    return row[0] * cross(row[1], row[2], row[3]);
+}
+
+Mat4 Mat4::transpose() const
+{
+    return Mat4(col(0), col(1), col(2), col(3));
+}
+
+Mat4 Mat4::adjoint() const
+{
+    Mat4 A;
+
+    A.row[0] = cross( row[1], row[2], row[3]);
+    A.row[1] = cross(-row[0], row[2], row[3]);
+    A.row[2] = cross( row[0], row[1], row[3]);
+    A.row[3] = cross(-row[0], row[1], row[2]);
+        
+    return A;
+}
+
+real Mat4::cramerInverse(Mat4& inv) const
+{
+    Mat4 A = adjoint();
+    real d = A.row[0] * row[0];
+
+    if( d==0.0 )
+	return 0.0;
+
+    inv = A.transpose() / d;
+    return d;
+}
+
+
+
+
+// Matrix inversion code for 4x4 matrices.
+// Originally ripped off and degeneralized from Paul's matrix library
+// for the view synthesis (Chen) software.
+//
+// Returns determinant of a, and b=a inverse.
+// If matrix is singular, returns 0 and leaves trash in b.
+//
+// Uses Gaussian elimination with partial pivoting.
+
+#define SWAP(a, b, t)   {t = a; a = b; b = t;}
+real Mat4::inverse(Mat4& B) const
+{
+    Mat4 A(*this);
+
+    int i, j, k;
+    real max, t, det, pivot;
+
+    /*---------- forward elimination ----------*/
+
+    for (i=0; i<4; i++)                 /* put identity matrix in B */
+        for (j=0; j<4; j++)
+            B(i, j) = (real)(i==j);
+
+    det = 1.0;
+    for (i=0; i<4; i++) {               /* eliminate in column i, below diag */
+        max = -1.;
+        for (k=i; k<4; k++)             /* find pivot for column i */
+            if (fabs(A(k, i)) > max) {
+                max = fabs(A(k, i));
+                j = k;
+            }
+        if (max<=0.) return 0.;         /* if no nonzero pivot, PUNT */
+        if (j!=i) {                     /* swap rows i and j */
+            for (k=i; k<4; k++)
+                SWAP(A(i, k), A(j, k), t);
+            for (k=0; k<4; k++)
+                SWAP(B(i, k), B(j, k), t);
+            det = -det;
+        }
+        pivot = A(i, i);
+        det *= pivot;
+        for (k=i+1; k<4; k++)           /* only do elems to right of pivot */
+            A(i, k) /= pivot;
+        for (k=0; k<4; k++)
+            B(i, k) /= pivot;
+        /* we know that A(i, i) will be set to 1, so don't bother to do it */
+
+        for (j=i+1; j<4; j++) {         /* eliminate in rows below i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=i+1; k<4; k++)       /* subtract scaled row i from row j */
+                A(j, k) -= A(i, k)*t;   /* (ignore k<=i, we know they're 0) */
+            for (k=0; k<4; k++)
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    /*---------- backward elimination ----------*/
+
+    for (i=4-1; i>0; i--) {             /* eliminate in column i, above diag */
+        for (j=0; j<i; j++) {           /* eliminate in rows above i */
+            t = A(j, i);                /* we're gonna zero this guy */
+            for (k=0; k<4; k++)         /* subtract scaled row i from row j */
+                B(j, k) -= B(i, k)*t;
+        }
+    }
+
+    return det;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec3.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec3.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec3.h	(revision 774)
@@ -0,0 +1,231 @@
+#ifndef GFXMATH_VEC3_INCLUDED // -*- C++ -*-
+#define GFXMATH_VEC3_INCLUDED
+
+/************************************************************************
+
+  3D Vector class.
+
+  $Id: Vec3.h,v 1.6 1997/03/17 22:52:26 garland Exp $
+
+ ************************************************************************/
+
+#include "../std.h"
+
+namespace qslim
+{
+	class Vec3 {
+	private:
+		real elt[3];
+
+	protected:
+		inline void copy(const Vec3& v);
+
+	public:
+		//
+		// Standard constructors
+		//
+		Vec3(real x=0, real y=0, real z=0) { elt[0]=x; elt[1]=y; elt[2]=z; }
+	#ifdef GFXMATH_VEC2_INCLUDED
+		Vec3(const Vec2& v, real z) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=z; }
+	#endif
+		Vec3(const Vec3& v) { copy(v); }
+		Vec3(const real *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; }
+
+		//
+		// Access methods
+		//
+	#ifdef SAFETY
+		real& operator()(int i)       { assert(i>=0 && i<3); return elt[i]; }
+		real  operator()(int i) const { assert(i>=0 && i<3); return elt[i]; }
+	#else
+		real& operator()(int i)       { return elt[i]; }
+		real  operator()(int i) const { return elt[i]; }
+	#endif
+		real& operator[](int i)       { return elt[i]; }
+		real  operator[](int i) const { return elt[i]; }
+
+		real *raw()             { return elt; }
+		const real *raw() const { return elt; }
+
+		//
+		// Comparison operators
+		//
+		inline bool operator==(const Vec3& v) const;
+		inline bool operator!=(const Vec3& v) const;
+
+		//
+		// Assignment and in-place arithmetic methods
+		//
+		inline void set(real x, real y, real z) { elt[0]=x; elt[1]=y; elt[2]=z; }
+		inline Vec3& operator=(const Vec3& v);
+		inline Vec3& operator+=(const Vec3& v);
+		inline Vec3& operator-=(const Vec3& v);
+		inline Vec3& operator*=(real s);
+		inline Vec3& operator/=(real s);
+
+		//
+		// Binary arithmetic methods
+		//
+		inline Vec3 operator+(const Vec3& v) const;
+		inline Vec3 operator-(const Vec3& v) const;
+		inline Vec3 operator-() const;
+
+		inline Vec3 operator*(real s) const;
+		inline Vec3 operator/(real s) const;
+		inline real operator*(const Vec3& v) const;
+		inline Vec3 operator^(const Vec3& v) const;
+	};
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Method definitions
+	//
+
+	inline void Vec3::copy(const Vec3& v)
+	{
+		elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2];
+	}
+
+	inline bool Vec3::operator==(const Vec3& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z];
+		return (dx*dx + dy*dy + dz*dz) < FEQ_EPS2;
+	}
+
+	inline bool Vec3::operator!=(const Vec3& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z];
+		return (dx*dx + dy*dy + dz*dz) > FEQ_EPS2;
+	}
+
+	inline Vec3& Vec3::operator=(const Vec3& v)
+	{
+		copy(v);
+		return *this;
+	}
+
+	inline Vec3& Vec3::operator+=(const Vec3& v)
+	{
+		elt[0] += v[0];   elt[1] += v[1];   elt[2] += v[2];
+		return *this;
+	}
+
+	inline Vec3& Vec3::operator-=(const Vec3& v)
+	{
+		elt[0] -= v[0];   elt[1] -= v[1];   elt[2] -= v[2];
+		return *this;
+	}
+
+	inline Vec3& Vec3::operator*=(real s)
+	{
+		elt[0] *= s;   elt[1] *= s;   elt[2] *= s;
+		return *this;
+	}
+
+	inline Vec3& Vec3::operator/=(real s)
+	{
+		elt[0] /= s;   elt[1] /= s;   elt[2] /= s;
+		return *this;
+	}
+
+
+	inline Vec3 Vec3::operator+(const Vec3& v) const
+	{
+		return Vec3(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2]);
+	}
+
+	inline Vec3 Vec3::operator-(const Vec3& v) const
+	{
+		return Vec3(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2]);
+	}
+
+	inline Vec3 Vec3::operator-() const
+	{
+		return Vec3(-elt[0], -elt[1], -elt[2]);
+	}
+
+	inline Vec3 Vec3::operator*(real s) const
+	{
+		return Vec3(elt[0]*s, elt[1]*s, elt[2]*s);
+	}
+
+	inline Vec3 Vec3::operator/(real s) const
+	{
+		return Vec3(elt[0]/s, elt[1]/s, elt[2]/s);
+	}
+
+	inline real Vec3::operator*(const Vec3& v) const
+	{
+		return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2];
+	}
+
+	inline Vec3 Vec3::operator^(const Vec3& v) const
+	{
+		Vec3 w( elt[1]*v[2] - v[1]*elt[2],
+		   -elt[0]*v[2] + v[0]*elt[2],
+			elt[0]*v[1] - v[0]*elt[1] );
+		return w;
+	}
+
+	// Make scalar multiplication commutative
+	inline Vec3 operator*(real s, const Vec3& v) { return v*s; }
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Primitive function definitions
+	//
+
+	inline real norm(const Vec3& v)
+	{
+		return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2]);
+	}
+
+	inline real norm2(const Vec3& v)
+	{
+		return v[0]*v[0] + v[1]*v[1] + v[2]*v[2];
+	}
+
+	inline real length(const Vec3& v) { return norm(v); }
+
+
+	inline real unitize(Vec3& v)
+	{
+		real l=norm2(v);
+		if( l!=1.0 && l!=0.0 )
+		{
+		l = sqrt(l);
+		v /= l;
+		}
+		return l;
+	}
+	
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Misc. function definitions
+	//
+
+/*	inline ostream& operator<<(ostream& out, const Vec3& v)
+	{
+		return out << "[" << v[0] << " " << v[1] << " " << v[2] << "]";
+	}
+
+	inline istream& operator>>(istream& in, Vec3& v)
+	{
+		return in >> "[" >> v[0] >> v[1] >> v[2] >> "]";
+	}
+
+	#ifdef GFXGL_INCLUDED
+	inline void glV(const Vec3& v) { glVertex(v[X], v[Y], v[Z]); }
+	inline void glN(const Vec3& v) { glNormal(v[X], v[Y], v[Z]); }
+	inline void glC(const Vec3& v) { glColor(v[X], v[Y], v[Z]); }
+	#endif*/
+}
+
+
+// GFXMATH_VEC3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/random.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/random.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/random.h	(revision 774)
@@ -0,0 +1,24 @@
+#ifndef GFXMATH_RANDOM_INCLUDED // -*- C++ -*-
+#define GFXMATH_RANDOM_INCLUDED
+
+#include <stdlib.h>
+#include <limits.h>
+
+namespace qslim
+{
+	//
+	// Generate random numbers in [0..1]
+	inline real random1()
+	{
+	#if defined(WIN32) || defined(GFX_USE_RAND)
+		return (real)rand() / (real)LONG_MAX;
+	#else
+		return (real)random() / (real)LONG_MAX;
+	#endif
+	}
+
+}
+
+
+// GFXMATH_RANDOM_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec4.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec4.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Vec4.h	(revision 774)
@@ -0,0 +1,242 @@
+#ifndef GFXMATH_VEC4_INCLUDED // -*- C++ -*-
+#define GFXMATH_VEC4_INCLUDED
+
+/************************************************************************
+
+  4D Vector class.
+
+  $Id: Vec4.h,v 1.10 1997/03/17 22:52:27 garland Exp $
+
+ ************************************************************************/
+
+namespace qslim
+{
+	class Vec4 {
+	private:
+		real elt[4];
+
+	protected:
+		inline void copy(const Vec4& v);
+
+	public:
+		//
+		// Standard constructors
+		//
+		Vec4(real x=0, real y=0, real z=0, real w=0) {
+		elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w;
+		}
+	#ifdef GFXMATH_VEC3_INCLUDED
+		Vec4(const Vec3& v,real w) {elt[0]=v[0];elt[1]=v[1];elt[2]=v[2];elt[3]=w;}
+	#endif
+		Vec4(const Vec4& v) { copy(v); }
+		Vec4(const real *v) { elt[0]=v[0]; elt[1]=v[1]; elt[2]=v[2]; elt[3]=v[3]; }
+
+		//
+		// Access methods
+		//
+	#ifdef SAFETY
+		real& operator()(int i)       { assert(i>=0 && i<4); return elt[i]; }
+		real  operator()(int i) const { assert(i>=0 && i<4); return elt[i]; }
+	#else
+		real& operator()(int i)       { return elt[i]; }
+		real  operator()(int i) const { return elt[i]; }
+	#endif
+		real& operator[](int i)             { return elt[i]; }
+		const real& operator[](int i) const { return elt[i]; }
+
+		real *raw()             { return elt; }
+		const real *raw() const { return elt; }
+
+		//
+		// Comparison methods
+		//
+		inline bool operator==(const Vec4&) const;
+		inline bool operator!=(const Vec4&) const;
+
+		//
+		// Assignment and in-place arithmetic methods
+		//
+		inline void set(real x, real y, real z, real w){
+		elt[0]=x; elt[1]=y; elt[2]=z; elt[3]=w;
+		}
+		inline Vec4& operator=(const Vec4& v);
+		inline Vec4& operator+=(const Vec4& v);
+		inline Vec4& operator-=(const Vec4& v);
+		inline Vec4& operator*=(real s);
+		inline Vec4& operator/=(real s);
+
+		//
+		// Binary arithmetic methods
+		//
+		inline Vec4 operator+(const Vec4& v) const;
+		inline Vec4 operator-(const Vec4& v) const;
+		inline Vec4 operator-() const;
+
+		inline Vec4 operator*(real s) const;
+		inline Vec4 operator/(real s) const;
+		inline real operator*(const Vec4& v) const;
+	};
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Method definitions
+	//
+
+	inline void Vec4::copy(const Vec4& v)
+	{
+		elt[0]=v.elt[0]; elt[1]=v.elt[1]; elt[2]=v.elt[2]; elt[3]=v.elt[3];
+	}
+
+	inline bool Vec4::operator==(const Vec4& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z],  dw=elt[W]-v[W];
+		return (dx*dx + dy*dy + dz*dz + dw*dw) < FEQ_EPS2;
+	}
+
+	inline bool Vec4::operator!=(const Vec4& v) const
+	{
+		real dx=elt[X]-v[X],  dy=elt[Y]-v[Y],  dz=elt[Z]-v[Z],  dw=elt[W]-v[W];
+		return (dx*dx + dy*dy + dz*dz + dw*dw) > FEQ_EPS2;
+	}
+
+	inline Vec4& Vec4::operator=(const Vec4& v)
+	{
+		copy(v);
+		return *this;
+	}
+
+	inline Vec4& Vec4::operator+=(const Vec4& v)
+	{
+		elt[0] += v[0];   elt[1] += v[1];   elt[2] += v[2];   elt[3] += v[3];
+		return *this;
+	}
+
+	inline Vec4& Vec4::operator-=(const Vec4& v)
+	{
+		elt[0] -= v[0];   elt[1] -= v[1];   elt[2] -= v[2];   elt[3] -= v[3];
+		return *this;
+	}
+
+	inline Vec4& Vec4::operator*=(real s)
+	{
+		elt[0] *= s;   elt[1] *= s;   elt[2] *= s;  elt[3] *= s;
+		return *this;
+	}
+
+	inline Vec4& Vec4::operator/=(real s)
+	{
+		elt[0] /= s;   elt[1] /= s;   elt[2] /= s;   elt[3] /= s;
+		return *this;
+	}
+
+	inline Vec4 Vec4::operator+(const Vec4& v) const
+	{
+		return Vec4(elt[0]+v[0], elt[1]+v[1], elt[2]+v[2], elt[3]+v[3]);
+	}
+
+	inline Vec4 Vec4::operator-(const Vec4& v) const
+	{
+		return Vec4(elt[0]-v[0], elt[1]-v[1], elt[2]-v[2], elt[3]-v[3]);
+	}
+
+	inline Vec4 Vec4::operator-() const
+	{
+		return Vec4(-elt[0], -elt[1], -elt[2], -elt[3]);
+	}
+
+	inline Vec4 Vec4::operator*(real s) const
+	{
+		return Vec4(elt[0]*s, elt[1]*s, elt[2]*s, elt[3]*s);
+	}
+
+	inline Vec4 Vec4::operator/(real s) const
+	{
+		return Vec4(elt[0]/s, elt[1]/s, elt[2]/s, elt[3]/s);
+	}
+
+	inline real Vec4::operator*(const Vec4& v) const
+	{
+		return elt[0]*v[0] + elt[1]*v[1] + elt[2]*v[2] + elt[3]*v[3];
+	}
+
+	// Make scalar multiplication commutative
+	inline Vec4 operator*(real s, const Vec4& v) { return v*s; }
+
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Primitive function definitions
+	//
+
+	//
+	// Code adapted from VecLib4d.c in Graphics Gems V
+	inline Vec4 cross(const Vec4& a, const Vec4& b, const Vec4& c)
+	{
+		Vec4 result;
+
+		real d1 = (b[Z] * c[W]) - (b[W] * c[Z]);
+		real d2 = (b[Y] * c[W]) - (b[W] * c[Y]);
+		real d3 = (b[Y] * c[Z]) - (b[Z] * c[Y]);
+		real d4 = (b[X] * c[W]) - (b[W] * c[X]);
+		real d5 = (b[X] * c[Z]) - (b[Z] * c[X]);
+		real d6 = (b[X] * c[Y]) - (b[Y] * c[X]);
+
+		result[X] = - a[Y] * d1 + a[Z] * d2 - a[W] * d3;
+		result[Y] =   a[X] * d1 - a[Z] * d4 + a[W] * d5;
+		result[Z] = - a[X] * d2 + a[Y] * d4 - a[W] * d6;
+		result[W] =   a[X] * d3 - a[Y] * d5 + a[Z] * d6;
+
+		return result;
+	}
+
+	inline real norm(const Vec4& v)
+	{
+		return sqrt(v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3]);
+	}
+
+	inline real norm2(const Vec4& v)
+	{
+		return v[0]*v[0] + v[1]*v[1] + v[2]*v[2] + v[3]*v[3];
+	}
+
+	inline real length(const Vec4& v) { return norm(v); }
+
+	inline real unitize(Vec4& v)
+	{
+		real l=norm2(v);
+		if( l!=1.0 && l!=0.0 )
+		{
+		l = sqrt(l);
+		v /= l;
+		}
+		return l;
+	}
+
+
+	////////////////////////////////////////////////////////////////////////
+	//
+	// Misc. function definitions
+	//
+
+/*	inline ostream& operator<<(ostream& out, zVec4& v)
+	{
+		return
+		out << "[" << v[0] << " " << v[1] << " " << v[2] << " " << v[3] << "]";
+	}
+
+	inline istream& operator>>(istream& in, Vec4& v)
+	{
+		return in >> "[" >> v[0] >> v[1] >> v[2] >> v[3] >> "]";
+	}
+*/
+	#ifdef GFXGL_INCLUDED
+	inline void glV(const Vec4& v) { glVertex(v[X], v[Y], v[Z], v[W]); }
+	inline void glC(const Vec4& v) { glColor(v[X], v[Y], v[Z], v[W]); }
+	#endif
+}
+
+// GFXMATH_VEC4_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/jacobi.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/jacobi.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/jacobi.cxx	(revision 774)
@@ -0,0 +1,331 @@
+#include <gfx/std.h>
+#include <gfx/math/Mat3.h>
+#include <gfx/math/Mat4.h>
+
+// Adapted from VTK source code (see vtkMath.cxx)
+// which seems to have been adapted directly from Numerical Recipes in C.
+
+
+#define ROT(a,i,j,k,l) g=a[i][j];h=a[k][l];a[i][j]=g-s*(h+g*tau);a[k][l]=h+s*(g-h*tau);
+
+#define MAX_ROTATIONS 60
+
+
+
+// Description:
+// Jacobi iteration for the solution of eigenvectors/eigenvalues of a 3x3
+// real symmetric matrix. Square 3x3 matrix a; output eigenvalues in w;
+// and output eigenvectors in v. Resulting eigenvalues/vectors are sorted
+// in decreasing order; eigenvectors are normalized.
+//
+
+using namespace qslim;
+
+static
+bool internal_jacobi(real a[3][3], real w[3], real v[3][3])
+{
+    int i, j, k, iq, ip;
+    real tresh, theta, tau, t, sm, s, h, g, c;
+    real b[3], z[3], tmp;
+
+    // initialize
+    for (ip=0; ip<3; ip++) 
+    {
+	for (iq=0; iq<3; iq++) v[ip][iq] = 0.0;
+	v[ip][ip] = 1.0;
+    }
+    for (ip=0; ip<3; ip++) 
+    {
+	b[ip] = w[ip] = a[ip][ip];
+	z[ip] = 0.0;
+    }
+
+    // begin rotation sequence
+    for (i=0; i<MAX_ROTATIONS; i++) 
+    {
+	sm = 0.0;
+	for (ip=0; ip<2; ip++) 
+	{
+	    for (iq=ip+1; iq<3; iq++) sm += fabs(a[ip][iq]);
+	}
+	if (sm == 0.0) break;
+
+	if (i < 4) tresh = 0.2*sm/(9);
+	else tresh = 0.0;
+
+	for (ip=0; ip<2; ip++) 
+	{
+	    for (iq=ip+1; iq<3; iq++) 
+	    {
+		g = 100.0*fabs(a[ip][iq]);
+		if (i > 4 && (fabs(w[ip])+g) == fabs(w[ip])
+		    && (fabs(w[iq])+g) == fabs(w[iq]))
+		{
+		    a[ip][iq] = 0.0;
+		}
+		else if (fabs(a[ip][iq]) > tresh) 
+		{
+		    h = w[iq] - w[ip];
+		    if ( (fabs(h)+g) == fabs(h)) t = (a[ip][iq]) / h;
+		    else 
+		    {
+			theta = 0.5*h / (a[ip][iq]);
+			t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
+			if (theta < 0.0) t = -t;
+		    }
+		    c = 1.0 / sqrt(1+t*t);
+		    s = t*c;
+		    tau = s/(1.0+c);
+		    h = t*a[ip][iq];
+		    z[ip] -= h;
+		    z[iq] += h;
+		    w[ip] -= h;
+		    w[iq] += h;
+		    a[ip][iq]=0.0;
+		    for (j=0;j<ip-1;j++) 
+		    {
+			ROT(a,j,ip,j,iq)
+			    }
+		    for (j=ip+1;j<iq-1;j++) 
+		    {
+			ROT(a,ip,j,j,iq)
+			    }
+		    for (j=iq+1; j<3; j++) 
+		    {
+			ROT(a,ip,j,iq,j)
+			    }
+		    for (j=0; j<3; j++) 
+		    {
+			ROT(v,j,ip,j,iq)
+			    }
+		}
+	    }
+	}
+
+	for (ip=0; ip<3; ip++) 
+	{
+	    b[ip] += z[ip];
+	    w[ip] = b[ip];
+	    z[ip] = 0.0;
+	}
+    }
+
+    if ( i >= MAX_ROTATIONS )
+    {
+		std::cerr << "WARNING -- jacobi() -- Error computing eigenvalues." << std::endl;
+		return false;
+    }
+
+    // sort eigenfunctions
+    for (j=0; j<3; j++) 
+    {
+	k = j;
+	tmp = w[k];
+	for (i=j; i<3; i++)
+	{
+	    if (w[i] >= tmp) 
+	    {
+		k = i;
+		tmp = w[k];
+	    }
+	}
+	if (k != j) 
+	{
+	    w[k] = w[j];
+	    w[j] = tmp;
+	    for (i=0; i<3; i++) 
+	    {
+		tmp = v[i][j];
+		v[i][j] = v[i][k];
+		v[i][k] = tmp;
+	    }
+	}
+    }
+    // insure eigenvector consistency (i.e., Jacobi can compute vectors that
+    // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
+    // reek havoc in hyperstreamline/other stuff. We will select the most
+    // positive eigenvector.
+    int numPos;
+    for (j=0; j<3; j++)
+    {
+	for (numPos=0, i=0; i<3; i++) if ( v[i][j] >= 0.0 ) numPos++;
+	if ( numPos < 2 ) for(i=0; i<3; i++) v[i][j] *= -1.0;
+    }
+
+    return true;
+}
+
+static
+bool internal_jacobi4(real a[4][4], real w[4], real v[4][4])
+{
+    int i, j, k, iq, ip;
+    real tresh, theta, tau, t, sm, s, h, g, c;
+    real b[4], z[4], tmp;
+
+    // initialize
+    for (ip=0; ip<4; ip++) 
+    {
+	for (iq=0; iq<4; iq++) v[ip][iq] = 0.0;
+	v[ip][ip] = 1.0;
+    }
+    for (ip=0; ip<4; ip++) 
+    {
+	b[ip] = w[ip] = a[ip][ip];
+	z[ip] = 0.0;
+    }
+
+    // begin rotation sequence
+    for (i=0; i<MAX_ROTATIONS; i++) 
+    {
+	sm = 0.0;
+	for (ip=0; ip<3; ip++) 
+	{
+	    for (iq=ip+1; iq<4; iq++) sm += fabs(a[ip][iq]);
+	}
+	if (sm == 0.0) break;
+
+	if (i < 4) tresh = 0.2*sm/(16);
+	else tresh = 0.0;
+
+	for (ip=0; ip<3; ip++) 
+	{
+	    for (iq=ip+1; iq<4; iq++) 
+	    {
+		g = 100.0*fabs(a[ip][iq]);
+		if (i > 4 && (fabs(w[ip])+g) == fabs(w[ip])
+		    && (fabs(w[iq])+g) == fabs(w[iq]))
+		{
+		    a[ip][iq] = 0.0;
+		}
+		else if (fabs(a[ip][iq]) > tresh) 
+		{
+		    h = w[iq] - w[ip];
+		    if ( (fabs(h)+g) == fabs(h)) t = (a[ip][iq]) / h;
+		    else 
+		    {
+			theta = 0.5*h / (a[ip][iq]);
+			t = 1.0 / (fabs(theta)+sqrt(1.0+theta*theta));
+			if (theta < 0.0) t = -t;
+		    }
+		    c = 1.0 / sqrt(1+t*t);
+		    s = t*c;
+		    tau = s/(1.0+c);
+		    h = t*a[ip][iq];
+		    z[ip] -= h;
+		    z[iq] += h;
+		    w[ip] -= h;
+		    w[iq] += h;
+		    a[ip][iq]=0.0;
+		    for (j=0;j<ip-1;j++) 
+		    {
+			ROT(a,j,ip,j,iq)
+			    }
+		    for (j=ip+1;j<iq-1;j++) 
+		    {
+			ROT(a,ip,j,j,iq)
+			    }
+		    for (j=iq+1; j<4; j++) 
+		    {
+			ROT(a,ip,j,iq,j)
+			    }
+		    for (j=0; j<4; j++) 
+		    {
+			ROT(v,j,ip,j,iq)
+			    }
+		}
+	    }
+	}
+
+	for (ip=0; ip<4; ip++) 
+	{
+	    b[ip] += z[ip];
+	    w[ip] = b[ip];
+	    z[ip] = 0.0;
+	}
+    }
+
+    if ( i >= MAX_ROTATIONS )
+    {
+		std::cerr << "WARNING -- jacobi() -- Error computing eigenvalues." << std::endl;
+	return false;
+    }
+
+    // sort eigenfunctions
+    for (j=0; j<4; j++) 
+    {
+	k = j;
+	tmp = w[k];
+	for (i=j; i<4; i++)
+	{
+	    if (w[i] >= tmp) 
+	    {
+		k = i;
+		tmp = w[k];
+	    }
+	}
+	if (k != j) 
+	{
+	    w[k] = w[j];
+	    w[j] = tmp;
+	    for (i=0; i<4; i++) 
+	    {
+		tmp = v[i][j];
+		v[i][j] = v[i][k];
+		v[i][k] = tmp;
+	    }
+	}
+    }
+    // insure eigenvector consistency (i.e., Jacobi can compute vectors that
+    // are negative of one another (.707,.707,0) and (-.707,-.707,0). This can
+    // reek havoc in hyperstreamline/other stuff. We will select the most
+    // positive eigenvector.
+    int numPos;
+    for (j=0; j<4; j++)
+    {
+	for (numPos=0, i=0; i<4; i++) if ( v[i][j] >= 0.0 ) numPos++;
+	if ( numPos < 3 ) for(i=0; i<4; i++) v[i][j] *= -1.0;
+    }
+
+    return true;
+}
+
+
+#undef ROT
+#undef MAX_ROTATIONS
+
+
+bool jacobi(const Mat3& m, Vec3& eig_vals, Vec3 eig_vecs[3])
+{
+    real a[3][3], w[3], v[3][3];
+    int i,j;
+
+    for(i=0;i<3;i++) for(j=0;j<3;j++) a[i][j] = m(i,j);
+
+    bool result = internal_jacobi(a, w, v);
+    if( result )
+    {
+	for(i=0;i<3;i++) eig_vals[i] = w[i];
+
+	for(i=0;i<3;i++) for(j=0;j<3;j++) eig_vecs[i][j] = v[j][i];
+    }
+
+    return result;
+}
+
+bool jacobi(const Mat4& m, Vec4& eig_vals, Vec4 eig_vecs[4])
+{
+    real a[4][4], w[4], v[4][4];
+    int i,j;
+
+    for(i=0;i<4;i++) for(j=0;j<4;j++) a[i][j] = m(i,j);
+
+    bool result = internal_jacobi4(a, w, v);
+    if( result )
+    {
+	for(i=0;i<4;i++) eig_vals[i] = w[i];
+
+	for(i=0;i<4;i++) for(j=0;j<4;j++) eig_vecs[i][j] = v[j][i];
+    }
+
+    return result;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat2.h	(revision 774)
@@ -0,0 +1,141 @@
+#ifndef GFXMATH_MAT2_INCLUDED // -*- C++ -*-
+#define GFXMATH_MAT2_INCLUDED
+
+#include <gfx/math/Vec2.h>
+
+namespace qslim
+{
+	class Mat2
+	{
+	private:
+		Vec2 row[2];
+
+	protected:
+
+		inline void copy(const Mat2& m);
+		inline Vec2 col(int i) const {return Vec2(row[0][i],row[1][i]);}
+
+	public:
+		// Standard matrices
+		static Mat2 identity;
+		static Mat2 zero;
+		static Mat2 unit;
+
+		// Standard constructors
+		Mat2() { copy(zero); }
+		Mat2(const Vec2& r0,const Vec2& r1)
+		{ row[0]=r0; row[1]=r1; }
+		Mat2(const Mat2& m) { copy(m); }
+
+		// Access methods
+		// M(i, j) == row i;col j
+		real& operator()(int i, int j)       { return row[i][j]; }
+		real  operator()(int i, int j) const { return row[i][j]; }
+
+		// Assignment methods
+		inline Mat2& operator=(const Mat2& m) { copy(m); return *this; }
+		inline Mat2& operator+=(const Mat2& m);
+		inline Mat2& operator-=(const Mat2& m);
+
+		inline Mat2& operator*=(real s);
+		inline Mat2& operator/=(real s);
+
+
+		// Arithmetic methods
+		inline Mat2 operator+(const Mat2& m) const;
+		inline Mat2 operator-(const Mat2& m) const;
+		inline Mat2 operator-() const;
+
+		inline Mat2 operator*(real s) const;
+		inline Mat2 operator/(real s) const;
+		Mat2 operator*(const Mat2& m) const;
+
+		inline Vec2 operator*(const Vec2& v) const; // [x y]
+
+		// Matrix operations
+		real det();
+		Mat2 transpose();
+		real inverse(Mat2&);
+
+
+		// Input/Output methods
+/*		friend ostream& operator<<(ostream&, const Mat2&);
+		friend istream& operator>>(istream&, Mat2&);*/
+	};
+
+
+	inline void Mat2::copy(const Mat2& m)
+	{
+		row[0] = m.row[0]; row[1] = m.row[1];
+	}
+
+	inline Mat2& Mat2::operator+=(const Mat2& m)
+	{
+		row[0] += m.row[0]; row[1] += m.row[1];
+		return *this;
+	}
+
+	inline Mat2& Mat2::operator-=(const Mat2& m)
+	{
+		row[0] -= m.row[0]; row[1] -= m.row[1];
+		return *this;
+	}
+
+	inline Mat2& Mat2::operator*=(real s)
+	{
+		row[0] *= s; row[1] *= s;
+		return *this;
+	}
+
+	inline Mat2& Mat2::operator/=(real s)
+	{
+		row[0] /= s; row[1] /= s;
+		return *this;
+	}
+
+	inline Mat2 Mat2::operator+(const Mat2& m) const
+	{
+		return Mat2(row[0]+m.row[0],
+			row[1]+m.row[1]);
+	}
+
+	inline Mat2 Mat2::operator-(const Mat2& m) const
+	{
+		return Mat2(row[0]-m.row[0],
+			row[1]-m.row[1]);
+	}
+
+	inline Mat2 Mat2::operator-() const
+	{
+		return Mat2(-row[0], -row[1]);
+	}
+
+	inline Mat2 Mat2::operator*(real s) const
+	{
+		return Mat2(row[0]*s, row[1]*s);
+	}
+
+	inline Mat2 Mat2::operator/(real s) const
+	{
+		return Mat2(row[0]/s, row[1]/s);
+	}
+
+	inline Vec2 Mat2::operator*(const Vec2& v) const
+	{
+		return Vec2(row[0]*v, row[1]*v);
+	}
+}
+/*
+inline ostream& operator<<(ostream& out, const Mat2& M)
+{
+    return out << M.row[0] << endl  << M.row[1];
+}
+
+inline istream& operator>>(istream& in, Mat2& M)
+{
+    return in >> M.row[0] >> M.row[1];
+}
+*/
+
+// GFXMATH_MAT2_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat3.h	(revision 774)
@@ -0,0 +1,150 @@
+#ifndef GFXMATH_MAT3_INCLUDED // -*- C++ -*-
+#define GFXMATH_MAT3_INCLUDED
+
+#include <gfx/math/Vec3.h>
+#include <ostream>
+
+namespace qslim
+{
+	class Mat3
+	{
+	private:
+		Vec3 row[3];
+
+	protected:
+
+		inline void copy(const Mat3& m);
+		inline Vec3 col(int i) const {return Vec3(row[0][i],row[1][i],row[2][i]);}
+
+	public:
+		// Standard matrices
+		static Mat3 identity;
+		static Mat3 zero;
+		static Mat3 unit;
+		static Mat3 diag(const Vec3& v);    // diagonal elements from v
+		static Mat3 extend(const Vec3& v);  // each row becomes v
+
+		// Standard constructors
+		Mat3() { copy(zero); }
+		Mat3(const Vec3& r0,const Vec3& r1,const Vec3& r2)
+		{ row[0]=r0; row[1]=r1; row[2]=r2; }
+		Mat3(const Mat3& m) { copy(m); }
+
+		// Access methods
+		// M(i, j) == row i;col j
+		real& operator()(int i, int j)       { return row[i][j]; }
+		real  operator()(int i, int j) const { return row[i][j]; }
+
+		// Assignment methods
+		inline Mat3& operator=(const Mat3& m) { copy(m); return *this; }
+		inline Mat3& operator+=(const Mat3& m);
+		inline Mat3& operator-=(const Mat3& m);
+
+		inline Mat3& operator*=(real s);
+		inline Mat3& operator/=(real s);
+
+
+		// Arithmetic methods
+		inline Mat3 operator+(const Mat3& m) const;
+		inline Mat3 operator-(const Mat3& m) const;
+		inline Mat3 operator-() const;
+
+		inline Mat3 operator*(real s) const;
+		inline Mat3 operator/(real s) const;
+		Mat3 operator*(const Mat3& m) const;
+
+		inline Vec3 operator*(const Vec3& v) const; // [x y z]
+
+		// Matrix operations
+		real det();
+		Mat3 transpose();
+		Mat3 adjoint();
+		real inverse(Mat3&);
+
+
+//		// Input/Output methods
+//		friend std::ostream& operator<<(std::ostream&, const qslim::Mat3&);
+//		friend std::istream& operator>>(std::istream&, qslim::Mat3&);
+	};
+
+
+	inline void Mat3::copy(const Mat3& m)
+	{
+		row[0] = m.row[0]; row[1] = m.row[1]; row[2] = m.row[2];
+	}
+
+	inline Mat3& Mat3::operator+=(const Mat3& m)
+	{
+		row[0] += m.row[0]; row[1] += m.row[1]; row[2] += m.row[2];
+		return *this;
+	}
+
+	inline Mat3& Mat3::operator-=(const Mat3& m)
+	{
+		row[0] -= m.row[0]; row[1] -= m.row[1]; row[2] -= m.row[2];
+		return *this;
+	}
+
+	inline Mat3& Mat3::operator*=(real s)
+	{
+		row[0] *= s; row[1] *= s; row[2] *= s;
+		return *this;
+	}
+
+	inline Mat3& Mat3::operator/=(real s)
+	{
+		row[0] /= s; row[1] /= s; row[2] /= s;
+		return *this;
+	}
+
+	inline Mat3 Mat3::operator+(const Mat3& m) const
+	{
+		return Mat3(row[0]+m.row[0],
+			row[1]+m.row[1],
+			row[2]+m.row[2]);
+	}
+
+	inline Mat3 Mat3::operator-(const Mat3& m) const
+	{
+		return Mat3(row[0]-m.row[0],
+			row[1]-m.row[1],
+			row[2]-m.row[2]);
+	}
+
+	inline Mat3 Mat3::operator-() const
+	{
+		return Mat3(-row[0], -row[1], -row[2]);
+	}
+
+	inline Mat3 Mat3::operator*(real s) const
+	{
+		return Mat3(row[0]*s, row[1]*s, row[2]*s);
+	}
+
+	inline Mat3 Mat3::operator/(real s) const
+	{
+		return Mat3(row[0]/s, row[1]/s, row[2]/s);
+	}
+
+	inline Vec3 Mat3::operator*(const Vec3& v) const
+	{
+		return Vec3(row[0]*v, row[1]*v, row[2]*v);
+	}
+}
+
+/*
+inline std::ostream& operator<<(std::ostream& out, const qslim::Mat3& M)
+{
+    return out << M.row[0] << endl << M.row[1] << endl << M.row[2];
+}
+
+inline istream& operator>>(istream& in, Mat3& M)
+{
+    return in >> M.row[0] >> M.row[1] >> M.row[2];
+}
+*/
+extern bool jacobi(const qslim::Mat3& m, qslim::Vec3& vals, qslim::Vec3 vecs[3]);
+
+
+// GFXMATH_MAT3_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/gfx/math/Mat4.h	(revision 774)
@@ -0,0 +1,195 @@
+#ifndef GFXMATH_MAT4_INCLUDED // -*- C++ -*-
+#define GFXMATH_MAT4_INCLUDED
+
+/************************************************************************
+
+  4x4 Matrix class
+
+  $Id: Mat4.h,v 1.14 1997/06/18 15:55:22 garland Exp $
+
+ ************************************************************************/
+
+#include <gfx/math/Vec3.h>
+#include <gfx/math/Vec4.h>
+
+namespace qslim
+{
+	class Mat4
+	{
+	private:
+		Vec4 row[4];
+
+	protected:
+
+		inline void copy(const Mat4& m);
+		inline Vec4 col(int i) const
+			{ return Vec4(row[0][i],row[1][i],row[2][i],row[3][i]); }
+
+	public:
+		// Standard matrices
+		static Mat4 identity;
+		static Mat4 zero;
+		static Mat4 unit;
+
+		static Mat4 trans(real,real,real);
+		static Mat4 scale(real,real,real);
+		static Mat4 xrot(real); //
+		static Mat4 yrot(real); // Arguments are in radians
+		static Mat4 zrot(real); //
+
+
+		// Standard constructors
+		Mat4() { copy(zero); }
+		Mat4(const Vec4& r0,const Vec4& r1,const Vec4& r2,const Vec4& r3)
+		{ row[0]=r0; row[1]=r1; row[2]=r2; row[3]=r3; }
+		Mat4(const Mat4& m) { copy(m); }
+
+		// Access methods
+		// M(i, j) == row i;col j
+		real& operator()(int i, int j)       { return row[i][j]; }
+		real  operator()(int i, int j) const { return row[i][j]; }
+		const Vec4& operator[](int i) const { return row[i]; }
+
+		// Comparison methods
+		inline int operator==(const Mat4&);
+
+		// Assignment methods
+		inline Mat4& operator=(const Mat4& m) { copy(m); return *this; }
+		inline Mat4& operator+=(const Mat4& m);
+		inline Mat4& operator-=(const Mat4& m);
+
+		inline Mat4& operator*=(real s);
+		inline Mat4& operator/=(real s);
+
+
+		// Arithmetic methods
+		inline Mat4 operator+(const Mat4& m) const;
+		inline Mat4 operator-(const Mat4& m) const;
+		inline Mat4 operator-() const;
+
+		inline Mat4 operator*(real s) const;
+		inline Mat4 operator/(real s) const;
+		Mat4 operator*(const Mat4& m) const;
+
+		inline Vec4 operator*(const Vec4& v) const; // [x y z w]
+		inline Vec3 operator*(const Vec3& v) const; // [x y z w]
+
+		// Matrix operations
+		real det() const;
+		Mat4 transpose() const;
+		Mat4 adjoint() const;
+		real inverse(Mat4&) const;
+		real cramerInverse(Mat4&) const;
+
+		// Input/Output methods
+//		friend ostream& operator<<(ostream&, const Mat4&);
+//		friend istream& operator>>(istream&, Mat4&);
+	};
+
+
+	inline void Mat4::copy(const Mat4& m)
+	{
+		row[0] = m.row[0]; row[1] = m.row[1];
+		row[2] = m.row[2]; row[3] = m.row[3];
+	}
+
+	inline int Mat4::operator==(const Mat4& m)
+	{
+		return row[0]==m.row[0] &&
+		   row[1]==m.row[1] &&
+		   row[2]==m.row[2] &&
+		   row[3]==m.row[3] ;
+	}
+
+	inline Mat4& Mat4::operator+=(const Mat4& m)
+	{
+		row[0] += m.row[0]; row[1] += m.row[1];
+		row[2] += m.row[2]; row[3] += m.row[3];
+		return *this;
+	}
+
+	inline Mat4& Mat4::operator-=(const Mat4& m)
+	{
+		row[0] -= m.row[0]; row[1] -= m.row[1];
+		row[2] -= m.row[2]; row[3] -= m.row[3];
+		return *this;
+	}
+
+	inline Mat4& Mat4::operator*=(real s)
+	{
+		row[0] *= s; row[1] *= s; row[2] *= s; row[3] *= s;
+		return *this;
+	}
+
+	inline Mat4& Mat4::operator/=(real s)
+	{
+		row[0] /= s; row[1] /= s; row[2] /= s; row[3] /= s;
+		return *this;
+	}
+
+	inline Mat4 Mat4::operator+(const Mat4& m) const
+	{
+		return Mat4(row[0]+m.row[0],
+			row[1]+m.row[1],
+			row[2]+m.row[2],
+			row[3]+m.row[3]);
+	}
+
+	inline Mat4 Mat4::operator-(const Mat4& m) const
+	{
+		return Mat4(row[0]-m.row[0],
+			row[1]-m.row[1],
+			row[2]-m.row[2],
+			row[3]-m.row[3]);
+	}
+
+	inline Mat4 Mat4::operator-() const
+	{
+		return Mat4(-row[0], -row[1], -row[2], -row[3]);
+	}
+
+	inline Mat4 Mat4::operator*(real s) const
+	{
+		return Mat4(row[0]*s, row[1]*s, row[2]*s, row[3]*s);
+	}
+
+	inline Mat4 Mat4::operator/(real s) const
+	{
+		return Mat4(row[0]/s, row[1]/s, row[2]/s, row[3]/s);
+	}
+
+	inline Vec4 Mat4::operator*(const Vec4& v) const
+	{
+		return Vec4(row[0]*v, row[1]*v, row[2]*v, row[3]*v);
+	}
+
+	//
+	// Transform a homogeneous 3-vector and reproject into normal 3-space
+	//
+	inline Vec3 Mat4::operator*(const Vec3& v) const
+	{
+		Vec4 u=Vec4(v,1);
+		real w=row[3]*u;
+
+		if(w==0.0)
+		return Vec3(row[0]*u, row[1]*u, row[2]*u);
+		else
+		return Vec3(row[0]*u/w, row[1]*u/w, row[2]*u/w);
+	}
+
+/*	inline ostream& operator<<(ostream& out, const Mat4& M)
+	{
+		return out<<M.row[0]<<endl<<M.row[1]<<endl<<M.row[2]<<endl<<M.row[3];
+	}
+
+	inline istream& operator>>(istream& in, Mat4& M)
+	{
+		return in >> M.row[0] >> M.row[1] >> M.row[2] >> M.row[3];
+	}
+*/
+	extern bool cholesky(Mat4&, Vec4&);
+	extern bool jacobi(const Mat4& m, Vec4& vals, Vec4 vecs[4]);
+}
+
+// GFXMATH_MAT4_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjModel.h	(revision 774)
@@ -0,0 +1,134 @@
+#ifndef NAUTILUS_ADJMODEL_INCLUDED // -*- C++ -*-
+#define NAUTILUS_ADJMODEL_INCLUDED
+
+/************************************************************************
+
+  Adjacency model representation.
+  $Id: AdjModel.h,v 1.7 1997/07/18 15:27:38 garland Exp $
+
+  Adapted from:
+     mlab: (Id: polymodel.h,v 1.13 1997/02/06 16:30:11 garland Exp)
+  via
+     QSlim: (Id: polymodel.h,v 1.1 1997/02/11 15:21:29 garland Exp)
+
+ ************************************************************************/
+
+#include "AdjPrims.h"
+#include <gfx/SMF/smf.h>
+#include <vector>
+
+namespace qslim
+{
+	class Model : public SMF_Model
+	{
+	protected:
+		vert_buffer vertices;
+		edge_buffer edges;
+		face_buffer faces;
+		vec3_buffer normals; // SUS
+		vec2_buffer texcoords;
+
+	private:
+
+		void maybeFixFace(Face *);
+
+	public:
+		Model() {
+			validVertCount = 0;
+			validEdgeCount = 0;
+			validFaceCount = 0;
+		}
+
+		~Model(){
+			for (int i=0; i<vertices.length(); i++)
+				delete vertices[i];
+			for (int i=0; i<edges.length(); i++)
+				delete edges[i];
+			for (int i=0; i<faces.length(); i++)
+				delete faces[i];
+		}
+
+		Bounds bounds;
+
+		int validVertCount;
+		int validEdgeCount;
+		int validFaceCount;
+
+		//
+		// Basic model accessor functions
+		//
+		qslim::Vertex *vertex(int i) { return vertices(i); }
+		qslim::Vec3 & normal(int i){ return normals(i); }
+		qslim::Vec2 & texcoord(int i){ return texcoords(i); }
+		qslim::Edge *edge(int i) { return edges(i); }
+		qslim::Face *face(int i) { return faces(i); }
+
+		int vertCount() { return vertices.length(); }
+		int normCount() { return normals.length();  }
+		int texcoordCount() { return texcoords.length();  }
+		int edgeCount() { return edges.length();    }
+		int faceCount() { return faces.length();    }
+
+		vert_buffer& allVertices() { return vertices; }
+		edge_buffer& allEdges()    { return edges;    }
+		face_buffer& allFaces()    { return faces;    }
+
+		//
+		// Simplification primitives
+		//
+		Vertex   *newVertex(real x=0.0, real y=0.0, real z=0.0);
+		Edge     *newEdge(Vertex *,Vertex *);
+		Face *newFace(Vertex *, Vertex *, Vertex *);
+
+		void killVertex(Vertex *);
+		void killEdge(Edge *);
+		void killFace(Face *);
+
+		void reshapeVertex(Vertex *, real, real, real);
+		void remapVertex(Vertex *from, Vertex *to);
+
+		void contract(Vertex *v1, Vertex *v2, const Vec3& to,
+			  face_buffer& changed);
+
+		void contract(Vertex *v1, 
+			  const vert_buffer& others,
+			  const Vec3& to,
+			  face_buffer& changed);
+
+
+		//
+		// Simplification convenience procedures
+		//
+		void removeDegeneracy(face_buffer& changed);
+		void contractionRegion(Vertex *v1, Vertex *v2, face_buffer& changed);
+		void contractionRegion(Vertex *v1,
+				   const vert_buffer& vertices,
+				   face_buffer& changed);
+
+		//
+		// SMF reader functions
+		//
+		int in_Vertex(const Vec3&);
+		int in_Normal(const Vec3&);
+		int in_TexCoord(const Vec2&);
+		int in_Face(int v1, int v2, int v3, int n1, int n2, int n3, int t1, int t2, int t3);
+		int miin_Face(int v1, int v2, int v3);
+
+/*	#ifdef SUPPORT_VCOLOR
+		int in_VColor(const Vec3&);
+	#endif
+	#ifdef SUPPORT_FCOLOR
+		int in_FColor(const Vec3&);
+	#endif
+*/
+		//
+		// Some random functions that are mostly temporary
+		//
+
+		Vec3 synthesizeNormal(Vertex *);
+	};
+}
+
+
+// NAUTILUS_ADJMODEL_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/public_types.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/public_types.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/public_types.h	(revision 774)
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: public_types.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H
+#define TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H
+
+#include <vector>
+
+
+
+
+namespace triangle_stripper
+{
+
+	typedef size_t index;
+	typedef std::vector<index> indices;
+
+	enum primitive_type
+	{
+		TRIANGLES		= 0x0004,	// = GL_TRIANGLES
+		TRIANGLE_STRIP	= 0x0005	// = GL_TRIANGLE_STRIP
+	};
+
+	struct primitive_group
+	{
+		indices			Indices;
+		primitive_type	Type;
+	};
+
+	typedef std::vector<primitive_group> primitive_vector;
+
+}
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_PUBLIC_TYPES_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/AdjPrims.cxx	(revision 774)
@@ -0,0 +1,267 @@
+/************************************************************************
+
+  Primitive entities for adjacency models (AdjModel).
+  $Id: AdjPrims.cxx,v 1.1 1997/06/25 15:24:55 garland Exp $
+
+  Adapted from:
+     mlab: (Id: primitives.cc,v 1.7 1997/02/06 16:32:45 garland Exp)
+  via
+     QSlim: (Id: primitives.cc,v 1.2 1997/02/18 21:11:27 garland Exp)
+
+ ************************************************************************/
+
+#include "AdjPrims.h"
+
+using namespace qslim;
+
+void Vertex::kill()
+{
+#ifdef SAFETY
+    assert( edge_uses.length() == 0 );
+#endif
+    markInvalid();
+    edge_uses.reset();
+}
+
+void Vertex::linkEdge(Edge *e)
+{
+    edge_uses.add(e);
+}
+
+void Vertex::unlinkEdge(Edge *e)
+{
+    int index = edge_uses.find(e);
+
+#ifdef SAFETY
+    assert( index >= 0 );
+#endif
+    edge_uses.remove(index);
+    if( edge_uses.length() <= 0 )
+	kill();
+}
+
+#include <assert.h>
+
+void Vertex::remapTo(Vertex *v)
+{
+    if( v != this )
+    {
+		for(int i=0; i<edge_uses.length(); i++)
+		{
+			assert( edge_uses(i)->org() == this );
+			edge_uses(i)->remapEndpoint(this, v);
+		}
+
+		kill();
+    }
+}
+
+
+Edge::Edge(Vertex *a, Vertex *b)
+{
+    v1 = a;
+    v1->linkEdge(this);
+
+    face_uses = new buffer<Face *>(2);
+
+    twin = new Edge(this, b);
+}
+
+Edge::Edge(Edge *sibling, Vertex *org)
+{
+    v1 = org;
+    v1->linkEdge(this);
+
+    face_uses = sibling->face_uses;
+    twin = sibling;
+}
+
+Edge::~Edge()
+{
+    if( twin )
+    {
+	face_uses->f_r_e_e();
+	delete face_uses;
+
+	twin->twin = NULL;
+	delete twin;
+    }
+}
+
+void Edge::kill()
+{
+#ifdef SAFETY
+    assert( face_uses->length() == 0 );
+#endif
+    if( isValid() )
+    {
+	org()->unlinkEdge(this);
+	dest()->unlinkEdge(sym());
+	markInvalid();
+	twin->markInvalid();
+	face_uses->reset();
+    }
+}
+
+void Edge::linkFace(Face *face)
+{
+    face_uses->add(face);
+}
+
+void Edge::unlinkFace(Face *face)
+{
+    int index = face_uses->find(face);
+
+#ifdef SAFETY
+    assert( index>=0 );
+#endif
+    face_uses->remove(index);
+    if( face_uses->length() == 0 )
+	kill();
+}
+
+void Edge::remapTo(Edge *e)
+{
+    if( e != this )
+    {
+	for(int i=0; i<face_uses->length(); i++)
+	{
+	    (*face_uses)(i)->remapEdge(this, e);
+	}
+    
+	// Disconnect from all faces and vertices
+	kill();
+    }
+}
+
+void Edge::remapEndpoint(Vertex *from, Vertex *to)
+{
+    if( org()==from )
+    {
+		v1 = to;
+		to->linkEdge(this);
+    }
+    else if( dest()==from )
+    {
+		twin->v1 = to;
+		to->linkEdge(twin);
+    }
+    else
+    {
+		std::cerr << "WARNING remapEndpoint: Illegal endpoint." << std::endl;
+    }
+
+    //
+    // The cached Plane equations for the faces attached to us may
+    // no longer be valid (in general, chances are pretty slim that they're OK)
+    for(int i=0; i<face_uses->length(); i++)
+    {
+		face_uses->ref(i)->invalidatePlane();
+    }
+}
+
+
+Face::Face(Edge *e0, Edge *e1, Edge *e2)
+    : Face3(*e0->org(), *e1->org(), *e2->org())
+{
+    edges[0] = e0;
+    edges[1] = e1;
+    edges[2] = e2;
+
+    edges[0]->linkFace(this);
+    edges[1]->linkFace(this);
+    edges[2]->linkFace(this);
+
+#ifdef SUPPORT_FCOLOR
+    props = NULL;
+#endif
+}
+
+void Face::kill()
+{
+    if( isValid() )
+    {
+	if( edge(0)->isValid() )
+	    edge(0)->unlinkFace(this);
+
+	if( edge(1)->isValid() )
+	    edge(1)->unlinkFace(this);
+
+	if( edge(2)->isValid() )
+	    edge(2)->unlinkFace(this);
+
+	markInvalid();
+    }
+}
+
+void Face::remapEdge(Edge *from, Edge *to)
+{
+    for(int i=0; i<3; i++)
+    {
+	if( edges[i] == from )
+	{
+	    edges[i] = to;
+	    to->linkFace(this);
+	}
+	else if( edges[i] == from->sym() )
+	{
+	    edges[i] = to->sym();
+	    to->sym()->linkFace(this);
+	}
+    }
+
+    invalidatePlane();
+}
+
+
+void qslim::untagFaceLoop(Vertex *v)
+{
+    edge_buffer& edges = v->edgeUses();
+
+    for(int j=0; j<edges.length(); j++)
+    {	    
+	face_buffer& faces = edges(j)->faceUses();
+	for(int k=0; k<faces.length(); k++)
+	    faces(k)->untag();
+    }
+}
+
+void qslim::collectFaceLoop(Vertex *v, face_buffer& loop)
+{
+    edge_buffer& edges = v->edgeUses();
+
+    for(int j=0; j<edges.length(); j++)
+    {	    
+	face_buffer& faces = edges(j)->faceUses();
+	for(int k=0; k<faces.length(); k++)
+	    if( !faces(k)->isTagged() )
+	    {
+		loop.add(faces(k));
+		faces(k)->tag();
+	    }
+    }
+}
+
+int qslim::classifyEdge(Edge *e)
+{
+    int cls = e->faceUses().length();
+
+    if( cls>3 ) cls=3;
+
+    return cls;
+}
+
+int qslim::classifyVertex(Vertex *v)
+{
+    int border_count = 0;
+    const edge_buffer& edges = v->edgeUses();
+
+    for(int i=0; i<edges.length(); i++)
+	if( classifyEdge(edges(i)) == 1 )
+	    border_count++;
+
+    if( border_count == edges.length() )
+	return VERTEX_BORDER_ONLY;
+    else 
+	return (border_count > 0);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/NPrim.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/NPrim.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/NPrim.h	(revision 774)
@@ -0,0 +1,36 @@
+#ifndef NAUTILUS_NPRIM_INCLUDED // -*- C++ -*-
+#define NAUTILUS_NPRIM_INCLUDED
+
+/************************************************************************
+
+  Common code for modeling primitives.  These are the interfaces that
+  most modeling primitives are expected to inherit.
+  $Id: NPrim.h,v 1.2 1997/06/25 16:19:20 garland Exp $
+
+ ************************************************************************/
+
+class NPrim
+{
+public:
+    int uniqID;
+
+    inline bool isValid()     { return uniqID >= 0; }
+    inline void markInvalid() { if( uniqID>=0 ) uniqID = -uniqID-1; }
+    inline void markValid()   { if( uniqID<0  ) uniqID = -uniqID-1; }
+    inline int  validID()     { return (uniqID<0)?(-uniqID-1):uniqID; }
+};
+
+
+class NTaggedPrim : public NPrim
+{
+public:
+    int tempID;
+
+    inline void untag() { tempID = 0; }
+    inline void tag(int t=1) { tempID = t; }
+    inline bool isTagged() { return tempID!=0; }
+};
+
+
+// NAUTILUS_NPRIM_INCLUDED
+#endif
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/qslim.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/qslim.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/qslim.h	(revision 774)
@@ -0,0 +1,38 @@
+// -*- C++ -*-
+
+//#include "Nautilus.h"
+#include "AdjModel.h"
+#include "avars.h"
+#include <gfx/tools/Heap.h>
+#include <iostream>
+#include <fstream>
+
+namespace qslim
+{
+	class pair_info : public Heapable
+	{
+	public:
+		Vertex *v0, *v1;
+
+		Vec3 candidate;
+		real cost;
+
+		pair_info(Vertex *a,Vertex *b) { v0=a; v1=b; cost=HUGE; }
+
+		bool isValid() { return v0->isValid() && v1->isValid(); }
+	};
+
+	typedef buffer<pair_info *> pair_buffer;
+
+	class vert_info
+	{
+	public:
+
+		pair_buffer pairs;
+
+		Mat4 Q;
+		real norm;
+
+		vert_info() : Q(Mat4::zero) { pairs.init(2); norm=0.0; }
+	};
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/quadrics.cxx	(revision 774)
@@ -0,0 +1,288 @@
+// $Id: quadrics.cxx,v 1.5 1997/10/01 14:07:28 garland Exp $
+
+#include "qslim.h"
+#include "quadrics.h"
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Primitive quadric construction and evaluation routines
+//
+
+//
+// Construct a quadric to evaluate the squared distance of any point
+// to the given point v.  Naturally, the iso-surfaces are just spheres
+// centered at v.
+//
+
+using namespace qslim;
+
+Mat4 qslim::quadrix_vertex_constraint(const Vec3& v)
+{
+    Mat4 L(Mat4::identity);
+
+    L(0,3) = -v[0];
+    L(1,3) = -v[1];
+    L(2,3) = -v[2];
+    L(3,3) = v*v;
+
+    L(3,0) = L(0,3);
+    L(3,1) = L(1,3);
+    L(3,2) = L(2,3);
+
+    return L;
+}
+
+//
+// Construct a quadric to evaluate the squared distance of any point
+// to the given plane [ax+by+cz+d = 0].  This is the "fundamental error
+// quadric" discussed in the paper.
+//
+Mat4 qslim::quadrix_plane_constraint(real a, real b, real c, real d)
+{
+    Mat4 K(Mat4::zero);
+
+    K(0,0) = a*a;   K(0,1) = a*b;   K(0,2) = a*c;  K(0,3) = a*d;
+    K(1,0) =K(0,1); K(1,1) = b*b;   K(1,2) = b*c;  K(1,3) = b*d;
+    K(2,0) =K(0,2); K(2,1) =K(1,2); K(2,2) = c*c;  K(2,3) = c*d;
+    K(3,0) =K(0,3); K(3,1) =K(1,3); K(3,2) =K(2,3);K(3,3) = d*d;
+
+    return K;
+}
+
+//
+// Define some other convenient ways for constructing these plane quadrics.
+//
+Mat4 qslim::quadrix_plane_constraint(const Vec3& n, real d)
+{
+    return qslim::quadrix_plane_constraint(n[X], n[Y], n[Z], d);
+}
+
+Mat4 qslim::quadrix_plane_constraint(Face& T)
+{
+    const Plane& p = T.plane();
+    real a,b,c,d;
+    p.coeffs(&a, &b, &c, &d);
+
+    return qslim::quadrix_plane_constraint(a, b, c, d);
+}
+
+qslim::Mat4 qslim::quadrix_plane_constraint(const qslim::Vec3& v1, const qslim::Vec3& v2, const qslim::Vec3& v3)
+{
+    Plane P(v1,v2,v3);
+    real a,b,c,d;
+    P.coeffs(&a, &b, &c, &d);
+
+    return qslim::quadrix_plane_constraint(a, b, c, d);
+}
+
+real qslim::quadrix_evaluate_vertex(const Vec3& v, const Mat4& K)
+{
+    real x=v[X], y=v[Y], z=v[Z];
+
+#ifndef VECTOR_COST_EVALUATION
+    //
+    // This is the fast way of computing (v^T Q v).
+    // 
+    return x*x*K(0,0) + 2*x*y*K(0,1) + 2*x*z*K(0,2) + 2*x*K(0,3)
+	              + y*y*K(1,1)   + 2*y*z*K(1,2) + 2*y*K(1,3)
+	                             + z*z*K(2,2)   + 2*z*K(2,3)
+	                                            + K(3,3);
+#else
+    //
+    // The equivalent thing using matrix/vector operations.
+    // It's a lot clearer, but it's also slower.
+    //
+    Vec4 v2(x,y,z,1);
+    return v2*(K*v2);
+#endif
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Routines for computing discontinuity constraints
+//
+
+static
+bool is_border(Edge *e )
+{
+    return classifyEdge(e) == EDGE_BORDER;
+}
+
+bool qslim::check_for_discontinuity(Edge *e)
+{
+    return is_border(e);
+}
+
+Mat4 qslim::quadrix_discontinuity_constraint(Edge *edge, const Vec3& n)
+{
+    Vec3& org = *edge->org();
+    Vec3& dest = *edge->dest();
+    Vec3 e = dest - org;
+
+    Vec3 n2 = e ^ n;
+    unitize(n2);
+
+    real d = -n2 * org;
+    return qslim::quadrix_plane_constraint(n2, d);
+}
+
+
+Mat4 qslim::quadrix_discontinuity_constraint(Edge *edge)
+{
+    Mat4 D(Mat4::zero);
+
+    face_buffer& faces = edge->faceUses();
+
+    for(int i=0; i<faces.length(); i++)
+		D += qslim::quadrix_discontinuity_constraint(edge,faces(i)->plane().normal());
+
+    return D;
+}
+
+
+////////////////////////////////////////////////////////////////////////
+//
+// Routines for computing contraction target
+//
+
+bool qslim::quadrix_find_local_fit(const Mat4& K,
+			    const Vec3& v1, const Vec3& v2,
+			    Vec3& candidate)
+{
+
+    Vec3 v3 = (v1 + v2) / 2;
+
+    bool try_midpoint = placement_policy > PLACE_ENDPOINTS;
+
+    real c1 = qslim::quadrix_evaluate_vertex(v1, K);
+    real c2 = qslim::quadrix_evaluate_vertex(v2, K);
+    real c3;
+    if( try_midpoint ) c3 = qslim::quadrix_evaluate_vertex(v3, K);
+
+    if( c1<c2 )
+    {
+	if( try_midpoint && c3<c1 )
+	    candidate=v3;
+	else
+	    candidate=v1;
+    }
+    else
+    {
+	if( try_midpoint && c3<c2 )
+	    candidate=v3;
+	else
+	    candidate=v2;
+    }
+
+    return true;
+}
+
+bool qslim::quadrix_find_line_fit(const Mat4& Q,
+			   const Vec3& v1, const Vec3& v2,
+			   Vec3& candidate)
+{
+    Vec3 d = v1-v2;
+
+    Vec3 Qv2 = Q*v2;
+    Vec3 Qd  = Q*d;
+
+    real denom = 2*d*Qd;
+
+    if( denom == 0.0 )
+	return false;
+
+    real a = (d*Qv2 + v2*Qd) / denom;
+
+    if( a<0.0 ) a=0.0;
+    if( a>1.0 ) a=1.0;
+
+
+    candidate = a*d + v2;
+    return true;
+}
+
+bool qslim::quadrix_find_best_fit(const Mat4& Q, Vec3& candidate)
+{
+    Mat4 K = Q;
+    K(3,0) = K(3,1) = K(3,2) = 0.0;  K(3,3) = 1;
+
+
+    Mat4 M;
+    real det = K.inverse(M);
+    if( FEQ(det, 0.0, 1e-12) )
+	return false;
+
+
+#ifdef SAFETY
+    //
+    // The homogeneous division SHOULDN'T be necessary.
+    // But, when we're being SAFE, we do it anyway just in case.
+    //
+    candidate[X] = M(0,3)/M(3,3);
+    candidate[Y] = M(1,3)/M(3,3);
+    candidate[Z] = M(2,3)/M(3,3);
+#else
+    candidate[X] = M(0,3);
+    candidate[Y] = M(1,3);
+    candidate[Z] = M(2,3);
+#endif
+
+    return true;
+}
+
+#include <assert.h>
+
+real qslim::quadrix_pair_target(const Mat4& Q,
+			 Vertex *v1,
+			 Vertex *v2,
+			 Vec3& candidate)
+{
+    int policy = placement_policy;
+
+    //
+    // This analytic boundary preservation isn't really necessary.  The
+    // boundary constraint quadrics are quite effective.  But, I've left it
+    // in anyway.
+    //
+    if( will_preserve_boundaries )
+    {
+	int c1 = classifyVertex(v1);
+	int c2 = classifyVertex(v2);
+
+	if( c1 > c2 )
+	{
+	    candidate = *v1;
+	    return qslim::quadrix_evaluate_vertex(candidate, Q);
+	}
+	else if( c2 > c1 )
+	{
+	    candidate = *v2;
+	    return qslim::quadrix_evaluate_vertex(candidate, Q);
+	}
+	else if( c1>0 && policy>PLACE_LINE )
+	    policy = PLACE_LINE;
+
+	if( policy == PLACE_OPTIMAL ) assert(c1==0 && c2==0);
+    }
+
+    switch( policy )
+    {
+    case PLACE_OPTIMAL:
+	if( qslim::quadrix_find_best_fit(Q, candidate) )
+	    break;
+
+    case PLACE_LINE:
+	if( qslim::quadrix_find_line_fit(Q, *v1, *v2, candidate) )
+	    break;
+
+    default:
+		qslim::quadrix_find_local_fit(Q, *v1, *v2, candidate);
+		break;
+    }
+
+    return qslim::quadrix_evaluate_vertex(candidate, Q);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/tri_stripper.h
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/tri_stripper.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/tri_stripper.h	(revision 774)
@@ -0,0 +1,199 @@
+
+//////////////////////////////////////////////////////////////////////
+//
+//  Copyright (C) 2004 Tanguy Fautré.
+//
+//  This software is provided 'as-is', without any express or implied
+//  warranty.  In no event will the authors be held liable for any damages
+//  arising from the use of this software.
+//
+//  Permission is granted to anyone to use this software for any purpose,
+//  including commercial applications, and to alter it and redistribute it
+//  freely, subject to the following restrictions:
+//
+//  1. The origin of this software must not be misrepresented; you must not
+//     claim that you wrote the original software. If you use this software
+//     in a product, an acknowledgment in the product documentation would be
+//     appreciated but is not required.
+//  2. Altered source versions must be plainly marked as such, and must not be
+//     misrepresented as being the original software.
+//  3. This notice may not be removed or altered from any source distribution.
+//
+//  Tanguy Fautré
+//  softdev@telenet.be
+//
+//////////////////////////////////////////////////////////////////////
+//
+//							Tri Stripper
+//							************
+//
+// Post TnL cache aware triangle stripifier in O(n.log(n)).
+//          
+// History: see ChangeLog
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: tri_stripper.h 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+// Protection against old C habits
+#if defined(max)
+#error "'max' macro defined! It's against the C++ standard. Please use 'std::max' instead (undefine 'max' macro if it was defined in another library)."
+#endif
+
+// Protection against old C habits
+#if defined(min)
+#error "'min' macro defined! It's against the C++ standard. Please use 'std::min' instead (undefine 'min' macro if it was defined in another library)."
+#endif
+
+
+
+#ifndef TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H
+#define TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H
+
+#include <public_types.h>
+
+#include	<detail/cache_simulator.h>
+#include	<detail/graph_array.h>
+#include	<detail/heap_array.h>
+#include	<detail/types.h>
+
+#include	<iostream>
+#include	<GeoMesh.h>
+
+
+namespace triangle_stripper {
+
+
+
+
+class tri_stripper
+{
+public:
+
+	tri_stripper(const indices & TriIndices);
+
+	void Strip(primitive_vector * out_pPrimitivesVector);
+
+	/* Stripifier Algorithm Settings */
+	
+	// Set the post-T&L cache size (0 disables the cache optimizer).
+	void SetCacheSize(size_t CacheSize = 10);
+
+	// Set the minimum size of a triangle strip (should be at least 2 triangles).
+	// The stripifier discard any candidate strips that does not satisfy the minimum size condition.
+	void SetMinStripSize(size_t MinStripSize = 2);
+
+	// Set the backward search mode in addition to the forward search mode.
+	// In forward mode, the candidate strips are build with the current candidate triangle being the first
+	// triangle of the strip. When the backward mode is enabled, the stripifier also tests candidate strips
+	// where the current candidate triangle is the last triangle of the strip.
+	// Enable this if you want better results at the expense of being slightly slower.
+	// Note: Do *NOT* use this when the cache optimizer is enabled; it only gives worse results.
+	void SetBackwardSearch(bool Enabled = false);
+	
+	// Set the cache simulator FIFO behavior (does nothing if the cache optimizer is disabled).
+	// When enabled, the cache is simulated as a simple FIFO structure. However, when
+	// disabled, indices that trigger cache hits are not pushed into the FIFO structure.
+	// This allows simulating some GPUs that do not duplicate cache entries (e.g. NV25 or greater).
+	void SetPushCacheHits(bool Enabled = true);
+
+	//	Sets the progress bar function and the increment to update.
+	void	SetProgressFunc(Geometry::TIPOFUNC upb,float	increment);
+
+	/* End Settings */
+
+private:
+
+	typedef detail::graph_array<detail::triangle> triangle_graph;
+	typedef detail::heap_array<size_t, std::greater<size_t> > triangle_heap;
+	typedef std::vector<size_t> candidates;
+	typedef triangle_graph::node_iterator tri_iterator;
+	typedef triangle_graph::const_node_iterator const_tri_iterator;
+	typedef triangle_graph::out_arc_iterator link_iterator;
+	typedef triangle_graph::const_out_arc_iterator const_link_iterator;
+
+	void InitTriHeap();
+	void Stripify();
+	void AddLeftTriangles();
+	void ResetStripIDs();
+
+	detail::strip FindBestStrip();
+	detail::strip ExtendToStrip(size_t Start, detail::triangle_order Order);
+	detail::strip BackExtendToStrip(size_t Start, detail::triangle_order Order, bool ClockWise);
+	const_link_iterator LinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order, bool NotSimulation);
+	const_link_iterator BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, detail::triangle_order & Order);
+	void BuildStrip(const detail::strip Strip);
+	void MarkTriAsTaken(size_t i);
+	void AddIndex(index i, bool NotSimulation);
+	void BackAddIndex(index i);
+	void AddTriangle(const detail::triangle & Tri, detail::triangle_order Order, bool NotSimulation);
+	void BackAddTriangle(const detail::triangle & Tri, detail::triangle_order Order);
+
+	bool Cache() const;
+	size_t CacheSize() const;
+
+	static detail::triangle_edge FirstEdge(const detail::triangle & Triangle, detail::triangle_order Order);
+	static detail::triangle_edge LastEdge(const detail::triangle & Triangle, detail::triangle_order Order);
+
+	primitive_vector			m_PrimitivesVector;
+	triangle_graph				m_Triangles;
+	triangle_heap				m_TriHeap;
+	candidates					m_Candidates;
+	detail::cache_simulator		m_Cache;
+	detail::cache_simulator		m_BackCache;
+	size_t						m_StripID;
+	size_t						m_MinStripSize;
+	bool						m_BackwardSearch;
+	bool						m_FirstRun;
+
+	//	Progress bar function.
+	Geometry::TIPOFUNC	mUPB;
+	float								mUPBInc;
+
+};
+
+
+
+
+
+//////////////////////////////////////////////////////////////////////////
+// tri_stripper inline functions
+//////////////////////////////////////////////////////////////////////////
+
+inline void tri_stripper::SetCacheSize(const size_t CacheSize)
+{
+	m_Cache.resize(CacheSize);
+	m_BackCache.resize(CacheSize);
+}
+
+
+inline void tri_stripper::SetMinStripSize(const size_t MinStripSize)
+{
+	if (MinStripSize < 2)
+		m_MinStripSize = 2;
+	else
+		m_MinStripSize = MinStripSize;
+}
+
+
+inline void tri_stripper::SetBackwardSearch(const bool Enabled)
+{
+	m_BackwardSearch = Enabled;
+}
+
+
+
+inline void tri_stripper::SetPushCacheHits(bool Enabled)
+{
+	m_Cache.push_cache_hits(Enabled);
+}
+
+
+
+
+} // namespace triangle_stripper
+
+
+
+
+#endif // TRI_STRIPPER_HEADER_GUARD_TRI_STRIPPER_H
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.cxx
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.cxx	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/libs/avars.cxx	(revision 774)
@@ -0,0 +1,28 @@
+#include <stdlib.h>
+//#include <iostream.h>
+
+#include <gfx/std.h>
+#include "avars.h"
+#include "AdjModel.h"
+
+
+// OPCIONES GLOBALES DE SIMPLIFICACIÓN
+
+int qslim::face_target = 0;
+qslim::real qslim::error_tolerance = HUGE;
+
+
+bool qslim::will_use_plane_constraint = true;
+bool qslim::will_use_vertex_constraint = true;
+
+bool qslim::will_preserve_boundaries = true;
+bool qslim::will_preserve_mesh_quality = true;
+bool qslim::will_constrain_boundaries = true;
+qslim::real qslim::boundary_constraint_weight = 1.0;
+
+bool qslim::will_weight_by_area = false;
+
+//int qslim::placement_policy = PLACE_OPTIMAL;
+int qslim::placement_policy = PLACE_ENDPOINTS; // No cambia los vértices
+
+qslim::real qslim::pair_selection_tolerance = 0.0;
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimpSequence.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimpSequence.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimpSequence.cpp	(revision 774)
@@ -0,0 +1,97 @@
+#include "GeoMeshSimpSequence.h"
+
+using namespace Geometry;
+using namespace std;
+
+MeshSimplificationSequence::MeshSimplificationSequence() 
+{
+	meshName="";
+}
+
+MeshSimplificationSequence::~MeshSimplificationSequence() 
+{
+}
+
+void MeshSimplificationSequence::Load(Serializer &s) 
+{
+	//Loads a simplification sequence from a file
+	char buffer[256];
+	unsigned int modVertex;
+	char name[256];
+
+	if (s.miReadData(buffer,256) != NULL)
+	{
+		sscanf(buffer,"%s",&name);
+		meshName=new char[strlen(name)];
+		strcpy(meshName,name);
+	}
+
+	while (s.miReadData(buffer,256) != NULL)
+	{
+		Geometry::MeshSimplificationSequence::Step simplifstep;
+		//new step
+		sscanf(buffer,"%u %u %u %u %u %f %f %f &",&simplifstep.mV1,&simplifstep.mV0, &simplifstep.mT0,&simplifstep.mT1, &simplifstep.obligatorio,&simplifstep.x, &simplifstep.y, &simplifstep.z);
+		//sscanf(buffer,"%u %u %u %u %u &",&simplifstep.mV1,&simplifstep.mV0, &simplifstep.mT0,&simplifstep.mT1, &simplifstep.obligatorio);
+		//sscanf(buffer + 3,"%u %u %f %f %f %u %u &",&simplifstep.mV0,&simplifstep.mV1,&simplifstep.x, &simplifstep.y, &simplifstep.z, &simplifstep.mT0,&simplifstep.mT1);
+		//sscanf(buffer,"%u %u %u %u %u &",&simplifstep.mV0,&simplifstep.mV1,&simplifstep.mT0,&simplifstep.mT1, &simplifstep.obligatorio);
+
+		buffer[strlen(buffer)-1]='\0';
+
+		//if(!simplifstep.obligatorio)
+		//{
+		char *ptr1;
+		ptr1=strtok(buffer,"&");
+		ptr1=strtok(NULL,"&");
+
+		if (ptr1!=NULL)
+		{
+			char *ptr;
+			ptr=strtok(ptr1," ");
+			
+			while(ptr != NULL )
+			{
+				modVertex = (unsigned int)atoi(ptr);
+				simplifstep.mModfaces.push_back(modVertex);
+				ptr=strtok(NULL," ");
+			}
+		}
+		mSteps.push_back(simplifstep);
+		//}
+
+	}
+
+}
+
+void MeshSimplificationSequence::Save(Serializer &s) 
+{
+	//Stores the simplification sequence in a file
+	char simp[256];
+
+	//Name of the mesh
+	sprintf(simp,"%s\n",meshName);
+	s.WriteData(simp,sizeof(char),strlen(simp));
+
+	for(unsigned int i=0; i<mSteps.size(); i++)
+	{
+		Geometry::MeshSimplificationSequence::Step paso = mSteps.operator [](i);
+		//sprintf(simp,"%u %u %u %u %u &", paso.mV0, paso.mV1, paso.mT0, paso.mT1,paso.obligatorio);
+		sprintf(simp,"%u %u %u %u %u %f &", paso.mV0, paso.mV1, paso.mT0, paso.mT1,paso.obligatorio,paso.x);
+		s.WriteData(simp,sizeof(char),strlen(simp));
+		for (unsigned int j=0; j<paso.mModfaces.size(); j++) 
+		{
+			sprintf(simp," %u",paso.mModfaces.operator [](j));
+			s.WriteData(simp,sizeof(char),strlen(simp));
+		}
+		s.WriteData("\n",sizeof(char),1);
+	}
+}
+
+void MeshSimplificationSequence::putMeshName(char *name) 
+{
+	meshName=name;
+}
+
+char *MeshSimplificationSequence::getMeshName(void) 
+{
+	return meshName;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimplifier.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimplifier.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshSimplifier.cpp	(revision 774)
@@ -0,0 +1,77 @@
+#include "GeoMeshSimplifier.h"
+#include "GeoMeshSimpSequence.h"
+#include "SimplificationMethod.h"
+#include <iostream>
+#include <fstream>
+
+using namespace Geometry;
+using namespace std;
+
+MeshSimplifier::MeshSimplifier(	const Geometry::Mesh	*m,
+																Geometry::TIPOFUNC		upb)
+{
+	objmesh					=	m;
+	meshsalida			=	NULL;
+	msimpsequence		=	NULL;
+	indexMeshLeaves	=	-1;
+
+	//	Sets the actual progress bar function.
+	mUPB	=	upb;
+}
+
+MeshSimplifier::~MeshSimplifier()
+{
+	delete msimpsequence;
+}
+
+// Returns the simplified mesh.
+Geometry::Mesh *MeshSimplifier::GetMesh ()
+{
+	return meshsalida;
+}
+
+void MeshSimplifier::setMeshLeaves(Geometry::Index index)
+{
+	indexMeshLeaves	=	index;
+}
+
+// Returns the simplification sequence for general meshes.
+Geometry::MeshSimplificationSequence *MeshSimplifier::GetSimplificationSequence()
+{
+	return msimpsequence;
+}
+
+ImageBasedSimplifier::ImageBasedSimplifier (const Geometry::Mesh 	*m,
+																						Geometry::TIPOFUNC		upb)
+																						:MeshSimplifier(m,upb)
+{
+}
+
+ImageBasedSimplifier::~ImageBasedSimplifier()
+{
+}
+
+// Starts the simplification process. Receives as a parameter the LOD factor in a range of [0,1]. Implements the Simplifier::Simplify method to perform an image based simplification.
+void ImageBasedSimplifier::Simplify (Geometry::Real paramlod)
+{
+	SimplificationMethod *m_qslim	=	new SimplificationMethod(objmesh);
+	
+	m_qslim->setMeshLeaves(indexMeshLeaves);
+	
+	msimpsequence	=	m_qslim->Decimate(paramlod,&meshsalida,0,mUPB);
+	
+	delete	m_qslim;
+}
+
+// Starts the simplification process. Receives as a parameter the number of vertices of the resulting mesh. Implements the Simplifier::Simplify method to perform an image based simplification.
+void ImageBasedSimplifier::Simplify (Geometry::uint32 numvertices)
+{
+	SimplificationMethod *m_qslim	=	new SimplificationMethod(objmesh);
+	
+	m_qslim->setMeshLeaves(indexMeshLeaves);
+	
+	msimpsequence	=	m_qslim->Decimate((float)numvertices,&meshsalida,1,mUPB);
+	
+	delete m_qslim;
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/SimplificationMethod.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/SimplificationMethod.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/SimplificationMethod.cpp	(revision 774)
@@ -0,0 +1,1144 @@
+#include <stdlib.h>
+#include "SimplificationMethod.h"
+#include <iostream>
+#include <fstream>
+
+using namespace std;
+using namespace Geometry;
+
+#include <gfx/geom/ProxGrid.h>
+#include "quadrics.h"
+
+
+//Constructor
+SimplificationMethod::SimplificationMethod(const Geometry::Mesh *m) 
+{
+	objmesh=m;
+	first_index_submesh = new unsigned int[objmesh->mSubMeshCount];
+	indexMeshLeaves=-1;
+}
+
+//Destructor
+SimplificationMethod::~SimplificationMethod()
+{
+/*	for (std::vector<qslim::pair_info*>::iterator it=pointers_to_remove.begin(); it!=pointers_to_remove.end(); it++)
+	{
+		if (*it!=NULL)
+		{
+			delete *it;
+			*it=NULL;
+		}
+	}
+*/	delete heap;
+	delete [] first_index_submesh;
+}
+
+//Recalculate the cost of the vertices of an edge
+void SimplificationMethod::compute_pair_info(qslim::pair_info *auxpair)
+{
+	qslim::Vertex *v0 = auxpair->v0;
+    qslim::Vertex *v1 = auxpair->v1;
+
+    qslim::vert_info& v0_info = vertex_info(v0);
+    qslim::vert_info& v1_info = vertex_info(v1);
+
+    qslim::Mat4 Q = v0_info.Q + v1_info.Q;
+    qslim::real norm = v0_info.norm + v1_info.norm;
+
+    auxpair->cost = qslim::quadrix_pair_target(Q, v0, v1, auxpair->candidate);
+
+    if( qslim::will_weight_by_area )
+ 	auxpair->cost /= norm;
+
+    if( qslim::will_preserve_mesh_quality )
+	auxpair->cost += pair_mesh_penalty(M0, v0, v1, auxpair->candidate);
+
+
+    //
+    // NOTICE:  In the heap we use the negative cost.  That's because
+    //          the heap is implemented as a MAX heap.
+    //
+    if( auxpair->isInHeap() )
+    {
+	heap->update(auxpair, (float)-auxpair->cost);
+    }
+    else
+    {
+	heap->insert(auxpair, (float)-auxpair->cost);
+    }
+}
+
+//Reasign the new vertex to the adequate face
+int SimplificationMethod::predict_face(qslim::Face& F, qslim::Vertex *v1, qslim::Vertex *v2, qslim::Vec3& vnew, qslim::Vec3& f1, qslim::Vec3& f2, qslim::Vec3& f3)
+{
+    int nmapped = 0;
+
+    if( F.vertex(0) == v1 || F.vertex(0) == v2 )
+    { f1 = vnew;  nmapped++; }
+    else f1 = *F.vertex(0);
+
+    if( F.vertex(1) == v1 || F.vertex(1) == v2 )
+    { f2 = vnew;  nmapped++; }
+    else f2 = *F.vertex(1);
+
+    if( F.vertex(2) == v1 || F.vertex(2) == v2 )
+    { f3 = vnew;  nmapped++; }
+    else f3 = *F.vertex(2);
+
+    return nmapped;
+}
+
+#define MESH_INVERSION_PENALTY 1e9
+
+qslim::real SimplificationMethod::pair_mesh_penalty(qslim::Model& M, qslim::Vertex *v1, qslim::Vertex *v2, qslim::Vec3& vnew)
+{
+    static qslim::face_buffer changed;
+    changed.reset();
+
+    M.contractionRegion(v1, v2, changed);
+
+    // real Nsum = 0;
+	qslim::real Nmin = 0;
+
+    for(int i=0; i<changed.length(); i++)
+    {
+		qslim::Face& F = *changed(i);
+		qslim::Vec3 f1, f2, f3;
+
+		int nmapped = predict_face(F, v1, v2, vnew, f1, f2, f3);
+
+		// Only consider non-degenerate faces
+		if( nmapped < 2 )
+		{
+			qslim::Plane Pnew(f1, f2, f3);
+			qslim::real delta =  Pnew.normal() * F.plane().normal();
+
+			if( Nmin > delta ) Nmin = delta;
+		}
+    }
+
+    //return (-Nmin) * MESH_INVERSION_PENALTY;
+    if( Nmin < 0.0 )
+	return MESH_INVERSION_PENALTY;
+    else
+	return 0.0;
+}
+
+//Returns true if the givens vertices are a valid pair
+bool SimplificationMethod::check_for_pair(qslim::Vertex *v0, qslim::Vertex *v1)
+{
+    const qslim::pair_buffer& pairs = vertex_info(v0).pairs;
+
+    for(int i=0; i<pairs.length(); i++)
+    {
+	if( pairs(i)->v0==v1 || pairs(i)->v1==v1 )
+	    return true;
+    }
+
+    return false;
+}
+
+//Create a new pair with two given vertices
+qslim::pair_info *SimplificationMethod::new_pair(qslim::Vertex *v0, qslim::Vertex *v1)
+{
+    qslim::vert_info& v0_info = vertex_info(v0);
+    qslim::vert_info& v1_info = vertex_info(v1);
+
+	qslim::pair_info *pair = new qslim::pair_info(v0,v1);
+    v0_info.pairs.add(pair);
+    v1_info.pairs.add(pair);
+
+	return pair;
+}
+
+//Remove a given pair
+void SimplificationMethod::delete_pair(qslim::pair_info *auxpair)
+{
+    qslim::vert_info& v0_info = vertex_info(auxpair->v0);
+    qslim::vert_info& v1_info = vertex_info(auxpair->v1);
+
+    v0_info.pairs.remove(v0_info.pairs.find(auxpair));
+    v1_info.pairs.remove(v1_info.pairs.find(auxpair));
+
+    if( auxpair->isInHeap() )
+	heap->kill(auxpair->getHeapPos());
+
+    delete auxpair;
+}
+
+//Contract a given pair
+void SimplificationMethod::do_contract(qslim::Model& m, qslim::pair_info *auxpair)
+{
+    qslim::Vertex *v0 = auxpair->v0;  qslim::Vertex *v1 = auxpair->v1;
+    qslim::vert_info& v0_info = vertex_info(v0);
+    qslim::vert_info& v1_info = vertex_info(v1);
+	qslim::Vec3 vnew = auxpair->candidate;
+    int i;
+
+    // Make v0 be the new vertex
+    v0_info.Q += v1_info.Q;
+    v0_info.norm += v1_info.norm;
+
+	qslim::Vec3 p(vnew);
+	qslim::Vec3 v0antes(v0->operator[](qslim::X),v0->operator[](qslim::Y),v0->operator[](qslim::Z));
+
+	// Find the edge to remove (before remove it (contract()))
+	qslim::Edge *econ=NULL;
+	bool finded = false;
+	for (i=0; i<v0->edgeUses().length(); i++)
+	{		
+		econ = v0->edgeUses()(i);
+		if (v1->vID == econ->org()->vID || v1->vID == econ->dest()->vID)
+		{
+			finded = true;
+			break;
+		}
+	}
+
+	assert(finded);
+	
+	
+	// Perform the actual contraction
+    static qslim::face_buffer changed;
+    changed.reset();
+    m.contract(v0, v1, vnew, changed);
+
+	// Stores the simplification step
+	Geometry::MeshSimplificationSequence::Step simplifstep;
+	qslim::Vec3 vdesp = p - v0antes;
+
+	// Stores the displacement in the simplification step
+	simplifstep.x=(float)vdesp[qslim::X];
+	simplifstep.y = (float)vdesp[qslim::Y];
+	simplifstep.z = (float)vdesp[qslim::Z];
+	simplifstep.mV1 = v0->validID(); // the simplification method returns as v0 the alive vertex
+	simplifstep.mV0 = v1->validID(); // the simplification method returns as v1 the dead vertex
+
+	// Number of triangles that are removed in this simplification step
+	int _numDelTris = 0; // 1 or 2 triangles can be removed
+
+	for (i=0; i<changed.length(); i++)
+	{
+		if (! changed(i)->isValid())
+			_numDelTris++;
+	}
+	int del_index=0;
+	
+	// mModfaces y mT0, mT1 of simplifstep stores the triangles id's -> geomesh has not triangles id's
+	for (i=0; i<changed.length(); i++)
+	{
+		qslim::Face *auxface = changed(i);
+		if (auxface->isValid()) 
+		{
+			// Modified triangles
+			simplifstep.mModfaces.push_back(auxface->validID());
+		}
+		else 
+		{
+			// Removed triangles
+			if (_numDelTris==1) 
+			{
+				simplifstep.mT0=auxface->validID();
+				simplifstep.mT1=auxface->validID();
+			}
+			else 
+			{
+				if(del_index==0) 
+				{
+					simplifstep.mT0=auxface->validID();
+					del_index++;
+				}
+				else 
+				{
+					simplifstep.mT1=auxface->validID();
+				}
+			}
+		}
+	}
+
+	decim_data.push_back(simplifstep); // Simplification sequence that make reference to the simplification method sequence
+	
+#ifdef SUPPORT_VCOLOR
+    //
+    // If the vertices are colored, color the new vertex
+    // using the average of the old colors.
+    v0->props->color += v1->props->color;
+    v0->props->color /= 2;
+#endif
+
+    // Remove the pair that we just contracted
+    delete_pair(auxpair);
+
+    // Recalculate pairs associated with v0
+    for(i=0; i<v0_info.pairs.length(); i++)
+    {
+		qslim::pair_info *p = v0_info.pairs(i);
+		compute_pair_info(p);
+    }
+
+    // Process pairs associated with now dead vertex
+    static qslim::pair_buffer condemned(6); // collect condemned pairs for execution
+    condemned.reset();
+
+	for(i=0; i<v1_info.pairs.length(); i++)
+    {
+		qslim::pair_info *p = v1_info.pairs(i);
+
+		qslim::Vertex *u;
+		if( p->v0 == v1 )      
+			u = p->v1;
+		else 
+			if( p->v1 == v1)  
+				u = p->v0;
+		else
+			std::cerr << "YOW!  This is a bogus pair." << endl;
+
+		if( !check_for_pair(u, v0) )
+		{
+			p->v0 = v0;
+			p->v1 = u;
+			v0_info.pairs.add(p);
+			compute_pair_info(p);
+		}
+		else
+			condemned.add(p);
+    }
+
+    for(i=0; i<condemned.length(); i++)
+		// Do you have any last requests?
+		delete_pair(condemned(i));
+    v1_info.pairs.reset(); // safety precaution
+
+}
+
+
+bool SimplificationMethod::decimate_quadric(qslim::Vertex *v, qslim::Mat4& Q)
+{
+    if( vinfo.length() > 0 )
+    {
+		Q = vinfo(v->uniqID).Q;
+		return true;
+    }
+    else
+		return false;
+}
+
+
+//Extract a pair from the heap, concract it and remove it form the heap
+void SimplificationMethod::decimate_contract(qslim::Model& m)
+{
+	qslim::heap_node *top;
+	qslim::pair_info *pair;
+
+    for(;;)
+    {
+		top = heap->extract();
+		if( !top ) return;
+		pair = (qslim::pair_info *)top->obj;
+
+		//Remove all the vertices of the removed edges
+		bool sharededge= false;
+		for (int i=0; i<pair->v0->edgeUses().length(); i++)
+		{		
+			qslim::Edge *econ = pair->v0->edgeUses()(i);
+			if (pair->v1->vID == econ->org()->vID || pair->v1->vID == econ->dest()->vID)
+				{
+					sharededge= true;
+					break;
+				}
+				
+		}
+
+		if( pair->isValid() && sharededge)
+			break;
+
+		delete_pair(pair);
+    }
+
+    do_contract(m, pair);
+
+    M0.validVertCount--;  // Attempt to maintain valid vertex information
+}
+
+qslim::real SimplificationMethod::decimate_error(qslim::Vertex *v)
+{
+	qslim::vert_info& info = vertex_info(v);
+
+	qslim::real err = qslim::quadrix_evaluate_vertex(*v, info.Q);
+
+    if( qslim::will_weight_by_area )
+		err /= info.norm;
+
+    return err;
+}
+
+//Extract the minimum cost of the the valid nodes (not simplified)
+qslim::real SimplificationMethod::decimate_min_error()
+{
+	qslim::heap_node *top;
+	qslim::pair_info *pair;
+
+    for(;;)
+    {
+		top = heap->top();
+		if( !top ) return -1.0;
+		pair = (qslim::pair_info *)top->obj;
+
+		if( pair->isValid() )
+			break;
+
+		top = heap->extract();
+		delete_pair(pair);
+    }
+
+    return pair->cost;
+}
+
+//Returns the maximum error by vertex
+qslim::real SimplificationMethod::decimate_max_error(qslim::Model& m)
+{
+	qslim::real max_err = 0;
+
+    for(int i=0; i<m.vertCount(); i++)
+		if( m.vertex(i)->isValid() )
+		{
+			max_err = MAX(max_err, decimate_error(m.vertex(i)));
+		}
+
+    return max_err;
+}
+
+//Initializations
+void SimplificationMethod::decimate_init(qslim::Model& m, qslim::real limit)
+{
+    int i,j;
+
+    vinfo.init(m.vertCount());
+
+    if( qslim::will_use_vertex_constraint )
+	for(i=0; i<m.vertCount(); i++)
+	{
+		qslim::Vertex *v = m.vertex(i);
+	    if( v->isValid() )
+			vertex_info(v).Q = qslim::quadrix_vertex_constraint(*v);
+	}
+
+    for(i=0; i<m.faceCount(); i++)
+	if( m.face(i)->isValid() )
+	{
+		if( qslim::will_use_plane_constraint )
+	    {
+			qslim::Mat4 Q = qslim::quadrix_plane_constraint(*m.face(i));
+			qslim::real norm = 0.0;
+
+			if( qslim::will_weight_by_area )
+			{
+				norm = m.face(i)->area();
+				Q *= norm;
+			}
+
+			for(j=0; j<3; j++)
+			{
+				vertex_info(m.face(i)->vertex(j)).Q += Q;
+				vertex_info(m.face(i)->vertex(j)).norm += norm;
+				
+			}
+	    }
+	}
+
+    if( qslim::will_constrain_boundaries )
+    {
+		for(i=0; i<m.edgeCount(); i++)
+			if( m.edge(i)->isValid() && qslim::check_for_discontinuity(m.edge(i)) )
+			{
+				qslim::Mat4 B = qslim::quadrix_discontinuity_constraint(m.edge(i));
+				qslim::real norm = 0.0;
+
+				if( qslim::will_weight_by_area )
+				{
+					norm = qslim::norm2(*m.edge(i)->org() - *m.edge(i)->dest());
+					B *= norm;
+				}
+
+				B *= qslim::boundary_constraint_weight;
+				vertex_info(m.edge(i)->org()).Q += B;
+				vertex_info(m.edge(i)->org()).norm += norm;
+				vertex_info(m.edge(i)->dest()).Q += B;
+				vertex_info(m.edge(i)->dest()).norm += norm;
+			}
+    }
+
+    heap = new qslim::Heap(m.validEdgeCount);
+
+    int pair_count = 0;
+
+    for(i=0; i<m.edgeCount(); i++)
+		if( m.edge(i)->isValid() )
+		{
+			qslim::pair_info *pair = new_pair(m.edge(i)->org(), m.edge(i)->dest());
+			//pointers_to_remove.push_back(pair);
+			compute_pair_info(pair);
+			pair_count++;
+		}
+
+    if( limit<0 )
+    {
+		limit = m.bounds.radius * 0.05;
+    }
+    proximity_limit = limit * limit;
+    if( proximity_limit > 0 )
+    {
+		qslim::ProxGrid grid(m.bounds.min, m.bounds.max, limit);
+		for(i=0; i<m.vertCount(); i++)
+			grid.addPoint(m.vertex(i));
+
+		qslim::buffer<qslim::Vec3 *> nearby(32);
+		for(i=0; i<m.vertCount(); i++)
+		{
+			nearby.reset();
+			grid.proximalPoints(m.vertex(i), nearby);
+
+			for(j=0; j<nearby.length(); j++)
+			{
+				qslim::Vertex *v1 = m.vertex(i);
+				qslim::Vertex *v2 = (qslim::Vertex *)nearby(j);
+
+				if( v1->isValid() && v2->isValid() )
+				{
+		#ifdef SAFETY
+					assert(pair_is_valid(v1,v2));
+		#endif
+					if( !check_for_pair(v1,v2) )
+					{
+						qslim::pair_info *pair = new_pair(v1,v2);
+						compute_pair_info(pair);
+						pair_count++;
+					}
+				}
+
+			}
+		}
+    }
+}
+
+//Initilizations
+void SimplificationMethod::simplfmethod_init(void)
+{
+    int i;
+
+	// Convertir la estructura geomesh a modelo qslim
+	geomesh2simplifModel();
+	
+	M0.bounds.complete();
+
+    initialVertCount = M0.vertCount();
+    initialEdgeCount = M0.edgeCount();
+    initialFaceCount = M0.faceCount();
+
+    // Get rid of degenerate faces
+    for(i=0; i<M0.faceCount(); i++)
+		if( !M0.face(i)->plane().isValid() )
+			M0.killFace(M0.face(i));
+
+    M0.removeDegeneracy(M0.allFaces());
+
+	// Get rid of unused vertices
+    for(i=0; i<M0.vertCount(); i++)
+    {
+		if( M0.vertex(i)->edgeUses().length() == 0 )
+		    M0.vertex(i)->kill();
+    }
+}
+
+//Do the contractions till the required LOD (percentage option)
+void SimplificationMethod::simplfmethod_run(int finalfaces,Geometry::TIPOFUNC upb)
+{
+	decimate_init(M0, qslim::pair_selection_tolerance);
+	unsigned	int	contador	=	0;
+	float					percent; // simplification percentage.
+
+	percent	=	(float)(2.0 * 100.0) / (M0.validFaceCount - finalfaces);
+
+	//	Update progress bar.
+	if (upb)
+	{
+		upb(0.0);
+	}
+
+	for (std::vector<Geometry::MeshSimplificationSequence::Step>::iterator it= decim_data.begin(); it!=decim_data.end(); it++)
+	{
+		it->mModfaces.clear();
+	}
+	decim_data.clear();
+
+	while( M0.validFaceCount > finalfaces/*qslim::face_target*/
+		&& M0.validFaceCount > 1
+		&& decimate_min_error() < qslim::error_tolerance ) 
+	{
+		decimate_contract(M0);
+
+		//	Update progress bar.
+		if (upb)
+		{
+			upb(percent);
+		}
+	}
+	
+	//	Update progress bar.
+	if (upb)
+	{
+		upb(100.0);
+	}
+}
+
+//Do the contractions till the required LOD (number of vertices option)
+void SimplificationMethod::simplfmethod_runv(int numvertices,Geometry::TIPOFUNC upb)
+{
+	decimate_init(M0, qslim::pair_selection_tolerance);
+	unsigned	int	contador	=	0;
+	int						previousValidVertCount;
+	float					percent; // Simplification percentage.
+
+	previousValidVertCount	=	0;
+	
+	percent	=	(float)(2.0 * 100.0) /(float)((M0.validFaceCount - numvertices / 3.0));
+
+	//	Update progress bar.
+	if (upb)
+	{
+		upb(0.0);
+	}
+
+	for (std::vector<Geometry::MeshSimplificationSequence::Step>::iterator it= decim_data.begin(); it!=decim_data.end(); it++)
+	{
+		it->mModfaces.clear();
+	}
+	decim_data.clear();
+
+	while(	M0.validVertCount > numvertices	/*qslim::face_target*/
+					&&
+					decimate_min_error() < qslim::error_tolerance
+					&&
+					previousValidVertCount	!=	M0.validVertCount)
+	{
+		previousValidVertCount	=	M0.validVertCount;
+		
+		decimate_contract(M0);
+
+		//	Update progress bar.
+		if (upb)
+		{
+			upb(percent);
+		}
+	}
+
+	//	Update progress bar.
+	if (upb)
+	{
+		upb(100.0);
+	}
+}
+
+// Class to create a map without repeated vertices
+class _float3_
+{
+public:
+	float x,y,z;
+	_float3_(float x=0.0f, float y=0.0f, float z=0.0f){ this->x = x; this->y = y; this->z = z; }
+	_float3_(const _float3_ &f){ x=f.x; y=f.y; z=f.z; }
+	_float3_ & operator=(const _float3_ &f){ x=f.x; y=f.y; z=f.z; return *this; }
+	bool operator<(const _float3_ &f) const 
+	{ 
+		if (x<f.x) return true;
+		if (x>f.x) return false;
+		if (y<f.y) return true;
+		if (y>f.y) return false;
+		if (z<f.z) return true;
+		if (z>f.z) return false;
+		return false;
+	}
+};
+
+
+//Unify the model to work with it
+//The vertices that have the same space coordinates are stored as an unique vertex
+//in order to not produce holes in the simplification
+//The necessary information to store correctly the decimation data is stored
+void SimplificationMethod::geomesh2simplifModel(void)
+{
+	std::map<_float3_,int> vertices_map; //Unique vertices (without repetitions) from all the submeshes
+	unsigned int num_final_verts = 0; //Number of unique vertices from all the submeshes
+
+	int num_final_verts2=0;
+	int num_repeated_verts=0;
+
+	int simplifindex;
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) //For all the submeshes
+	{
+		if (i	!=	indexMeshLeaves)
+		{
+			//If the model has texture information
+			if (objmesh->mSubMesh[i].mVertexBuffer->mVertexInfo & VERTEX_TEXCOORDS) 
+			{
+				//For all the vertices of each submesh
+				for (size_t j=0; j<objmesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) 
+				{
+					_float3_ auxvert(objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z);
+
+					std::map<_float3_,int>::iterator mit = vertices_map.find(auxvert);
+					if (mit==vertices_map.end())
+					{
+						//If the vertex is not in vertices_map, then is added
+						simplifindex=M0.in_Vertex(qslim::Vec3(objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z));
+						M0.in_Normal(qslim::Vec3(objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].z));
+
+						M0.in_TexCoord(qslim::Vec2(objmesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].y));
+						vertices_map[auxvert] = num_final_verts;
+						num_final_verts ++;
+
+						std::vector<int> v;
+						submeshmap[simplifindex]=v;
+						submeshmap[simplifindex].push_back((int)i); //Add the index of the mesh that contains the vertex
+						std::vector<int> v2;
+						vertexbuffermap[simplifindex]=v2;
+						vertexbuffermap[simplifindex].push_back((int)j); //Add the index of vertex in the submesh
+
+						// Debug
+						num_final_verts2++;
+					}
+					else
+					{
+						//the vertex is already in vertices_map, so store the reference of the first one with the same space coodinates
+						simplifindex = mit->second;
+						submeshmap[simplifindex].push_back((int)i); //Submeshes that contains the vertex
+						vertexbuffermap[simplifindex].push_back((int)j); //Indices of the vertex buffers that contains the vertex
+
+						// Debug
+						num_repeated_verts++;
+					}	
+				}
+			}
+			else //the model has not texture information
+			{ 
+				//For all the vertices of each submesh
+				for (size_t j=0; j<objmesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) 
+				{
+					_float3_ auxvert(objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z);
+
+					std::map<_float3_,int>::iterator mit = vertices_map.find(auxvert);
+					if (mit==vertices_map.end())
+					{
+						//If the vertex is not in vertices_map, then is added
+						simplifindex=M0.in_Vertex(qslim::Vec3(objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z));
+						M0.in_Normal(qslim::Vec3(objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].x, 
+												objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].y,
+												objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].z));
+						M0.in_TexCoord(qslim::Vec2(0.0,0.0));
+						vertices_map[auxvert] = num_final_verts;
+						num_final_verts ++;
+
+						std::vector<int> v;
+						submeshmap[simplifindex]=v;
+						submeshmap[simplifindex].push_back((int)i); //Add the index of the mesh that contains the vertex
+						std::vector<int> v2;
+						vertexbuffermap[simplifindex]=v2;
+						vertexbuffermap[simplifindex].push_back((int)j); //Add the index of vertex in the submesh
+					}
+					else
+					{
+						//the vertex is already in vertices_map, so store the reference of the first one with the same space coodinates
+						simplifindex = mit->second;
+						submeshmap[simplifindex].push_back((int)i); //Submeshes that contains the vertex
+						vertexbuffermap[simplifindex].push_back((int)j); //Indices of the vertex buffers that contains the vertex
+					}	
+				}
+			}
+		}
+		if (objmesh->mSubMesh[i].mSharedVertexBuffer)
+		{
+			printf("Shared break\n");
+			break;
+		}
+	}
+
+	//Create the faces
+	unsigned int base_index=0;
+
+	number_of_triangles=0; //Number of triangles of the model
+	int face_index=0;
+
+	int index_in_vertices_map0,index_in_vertices_map1,index_in_vertices_map2;
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) //For all the submeshes
+	{ 
+		if (i!=indexMeshLeaves)
+		{
+			for (Index j=0; j<objmesh->mSubMesh[i].mIndexCount; j+=3) 
+			{
+				//+1 is required because the first index in the simplification method is 1
+				//Index of the vertex in vertices_map
+				Index indice0=objmesh->mSubMesh[i].mIndex[j];
+				_float3_ auxvert0(objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice0].x, 
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice0].y,
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice0].z);
+				index_in_vertices_map0=vertices_map[auxvert0] + 1;
+
+				Index indice1=objmesh->mSubMesh[i].mIndex[j+1];
+				_float3_ auxvert1(objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice1].x, 
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice1].y,
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice1].z);
+				index_in_vertices_map1=vertices_map[auxvert1] + 1;
+
+				Index indice2=objmesh->mSubMesh[i].mIndex[j+2];
+				_float3_ auxvert2(objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice2].x, 
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice2].y,
+											objmesh->mSubMesh[i].mVertexBuffer->mPosition[indice2].z);
+				index_in_vertices_map2=vertices_map[auxvert2] + 1;
+
+				//Create a triangle with its indices in vertices_map
+				face_index=M0.miin_Face(index_in_vertices_map0,index_in_vertices_map1,index_in_vertices_map2);
+
+				//igeo allows to identify the submesh that contains the triangle
+				M0.face(face_index)->igeo=(int)i;
+			}
+		}
+	}
+	number_of_triangles=face_index;
+}
+
+
+//Wrties a file with the vertices, triangles and the simplification sequence
+void SimplificationMethod::WriteOBJ(void)
+{
+	Geometry::MeshSimplificationSequence::Step stepaux;
+	vector<int> v0,v1,submesh0,submesh1;
+	std::ofstream obj("salida.lod");
+	obj << "begin" << std::endl;
+	//vertices
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) 
+	{
+		for (size_t j=0; j<objmesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) 
+		{	
+			obj << "v " <<  objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x << " " <<
+				objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y << " " <<
+				objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z << " " << std::endl;
+		}
+	}
+
+
+	//faces
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) 
+	{
+		for (size_t j=0; j<objmesh->mSubMesh[i].mIndexCount; j=j+3) 
+		{	
+			obj << "f " <<  objmesh->mSubMesh[i].mIndex[j]+1 << " " << 
+				objmesh->mSubMesh[i].mIndex[j+1]+1 << " " << 
+				objmesh->mSubMesh[i].mIndex[j+2]+1 << std::endl;
+		}
+	}
+
+	obj << "end" << std::endl;
+
+	for (unsigned i=0; i<decim_data.size(); i++) 
+	{
+		stepaux = decim_data.operator [](i);
+		v0=vertexbuffermap[stepaux.mV0];  //vertexbuffer index
+		submesh0=submeshmap[stepaux.mV0]; //displacement for each submesh
+		v1=vertexbuffermap[stepaux.mV1];
+		submesh1=submeshmap[stepaux.mV1];
+		for (unsigned j=0; j<v0.size(); j++)
+		{
+			for (unsigned k=0; k<v1.size(); k++) 
+			{
+				//obtain the index of the VertexBuffer of each submesh and the displacemente by submesh
+				obj << "v% " << v1.operator [](k)+first_index_submesh[submesh1.operator [](k)] << 
+					" " << v0.operator [](j)+first_index_submesh[submesh0.operator [](j)] << " " << 
+                    stepaux.x << " " << stepaux.y << " " << stepaux.z << " " << stepaux.mT0 << " " <<
+					stepaux.mT1 << " & ";
+				if (stepaux.mModfaces.size()>0) 
+				{
+					unsigned int ii=0;
+					for (ii=0; ii<stepaux.mModfaces.size()-1; ii++) 
+					{
+						obj << stepaux.mModfaces.operator [](ii) << " ";
+					}
+					obj << stepaux.mModfaces.operator [](ii) << std::endl;
+				}
+				else 
+				{ 
+					obj << std::endl; 
+				}					
+			}
+		}
+	}
+	obj.close();
+}
+
+//simplifmethod_init is executed to do some initalizations
+//simplifmethod_run is executed to do the decimation
+//Then, the simpified model is created and the decimation information is returned
+Geometry::MeshSimplificationSequence *SimplificationMethod::Decimate(float lod, Geometry::Mesh **mesh, int simpliftype, Geometry::TIPOFUNC upb)
+{
+	simplfmethod_init();
+
+	if (simpliftype==0) 
+	{
+		//Percentage option
+		simplfmethod_run((int)(number_of_triangles*lod),upb);
+	}
+	else 
+	{
+		//Number of vertices option
+		simplfmethod_runv((int)lod,upb);
+	}
+
+
+	typedef std::map<int,int> MAPAINDIND;   //Store unique vertices by submesh (without repetitions)
+	typedef std::vector<int> REPINDLIST; //Store all the indices by submesh (with repetitions)
+
+	MAPAINDIND *unique_verts_inds_by_geo = new MAPAINDIND[objmesh->mSubMeshCount]; 
+	REPINDLIST *ver_inds_repes_x_geo = new REPINDLIST[objmesh->mSubMeshCount]; 
+
+	int *inextvert = new int[objmesh->mSubMeshCount]; //Index counter by submesh
+
+	for (unsigned int i=0; i<objmesh->mSubMeshCount; i++)
+		inextvert[i] = 0; 
+
+	qslim::Vertex *auxvertex;
+
+	//Construct the model
+	for (int i=0; i<M0.faceCount(); i++)
+	{		
+		if (M0.face(i)->isValid())
+		{
+			qslim::Face *auxface = M0.face(i);
+			auxvertex = NULL;
+
+			//Determine to which submesh pertains the triangle
+			int igeo = auxface->igeo;
+			
+			//Insert to each submesh its triangles
+			std::map<int,int>::iterator findit = unique_verts_inds_by_geo[igeo].find(auxface->vertex(0)->validID());
+			if (findit == unique_verts_inds_by_geo[igeo].end())
+			{
+				//if it is not added... add and map it
+				unique_verts_inds_by_geo[igeo][auxface->vertex(0)->validID()] = inextvert[igeo];
+				inextvert[igeo]++;
+			}			
+			findit = unique_verts_inds_by_geo[igeo].find(auxface->vertex(1)->validID());
+			if (findit == unique_verts_inds_by_geo[igeo].end())
+			{
+				//if it is not added... add and map it
+				unique_verts_inds_by_geo[igeo][auxface->vertex(1)->validID()] = inextvert[igeo];
+				inextvert[igeo]++;
+			}			
+			findit = unique_verts_inds_by_geo[igeo].find(auxface->vertex(2)->validID());
+			if (findit == unique_verts_inds_by_geo[igeo].end())
+			{
+				//if it is not added... add and map it
+				unique_verts_inds_by_geo[igeo][auxface->vertex(2)->validID()] = inextvert[igeo];
+				inextvert[igeo]++;
+			}			
+			
+			//Total number of indices by submesh
+			ver_inds_repes_x_geo[igeo].push_back(auxface->vertex(0)->validID());
+			ver_inds_repes_x_geo[igeo].push_back(auxface->vertex(1)->validID());
+			ver_inds_repes_x_geo[igeo].push_back(auxface->vertex(2)->validID());
+		}
+	}
+
+
+	//Output simplified mesh
+
+	*mesh=new Geometry::Mesh();
+	(*mesh)->mVertexBuffer	=	new	Geometry::VertexBuffer();
+	(*mesh)->mType=objmesh->mType;
+
+	(*mesh)->mSubMeshCount = objmesh->mSubMeshCount;
+	//Memory allocation for the submeshes
+	(*mesh)->mSubMesh = new Geometry::SubMesh[objmesh->mSubMeshCount];
+
+	bool copiedShared = false;
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) 
+	{
+		(*mesh)->mSubMesh[i].mSharedVertexBuffer=false; //objmesh->mSubMesh[i].mSharedVertexBuffer;
+		(*mesh)->mSubMesh[i].mStripCount=0;
+		(*mesh)->mSubMesh[i].mStrip=NULL;
+
+		if (i!=indexMeshLeaves)
+		{
+			//Indices vectors
+			(*mesh)->mSubMesh[i].mIndexCount=ver_inds_repes_x_geo[i].size(); 
+			(*mesh)->mSubMesh[i].mIndex=new Geometry::Index[(*mesh)->mSubMesh[i].mIndexCount];
+			//Store the indices
+			for (unsigned int j=0; j<(*mesh)->mSubMesh[i].mIndexCount; j++) 
+			{	
+				//Obtain the indices that point at VertexBuffer
+				(*mesh)->mSubMesh[i].mIndex[j]=unique_verts_inds_by_geo[i].operator [](ver_inds_repes_x_geo[i].operator [](j));
+			}
+			
+
+			//Copy the vertices
+			if ((*mesh)->mSubMesh[i].mSharedVertexBuffer) 
+			{
+				//Shared vertices
+				if (!copiedShared)
+				{
+					(*mesh)->mVertexBuffer = new Geometry::VertexBuffer();
+					copiedShared = true;
+				}
+				(*mesh)->mSubMesh[i].mVertexBuffer = (*mesh)->mVertexBuffer;
+			}
+			else 
+			{
+				//There's no shared vertices
+				(*mesh)->mSubMesh[i].mVertexBuffer=new Geometry::VertexBuffer();
+			}
+
+			(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount=unique_verts_inds_by_geo[i].size();
+			(*mesh)->mSubMesh[i].mVertexBuffer->mVertexInfo=objmesh->mSubMesh[i].mVertexBuffer->mVertexInfo;
+
+			//Allocate memory for position, normal and texutre coordinates
+			(*mesh)->mSubMesh[i].mVertexBuffer->mPosition=new Geometry::Vector3[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+			(*mesh)->mSubMesh[i].mVertexBuffer->mNormal=new Geometry::Vector3[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+			(*mesh)->mSubMesh[i].mVertexBuffer->mTexCoords=new Geometry::Vector2[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+
+			for (MAPAINDIND::iterator mapit = unique_verts_inds_by_geo[i].begin(); mapit != unique_verts_inds_by_geo[i].end(); mapit++) 
+			{
+				//Key and value
+				int isrc = mapit->first;
+				int idst = mapit->second;
+
+				//vertex coordinate
+				//construction of the submeshes
+				Geometry::Vector3 v3((Geometry::Real)M0.vertex(isrc)->operator [](0),	
+											(Geometry::Real)M0.vertex(isrc)->operator [](1),
+											(Geometry::Real)M0.vertex(isrc)->operator [](2));
+				(*mesh)->mSubMesh[i].mVertexBuffer->mPosition[idst]=v3;
+
+				//normal coordinates
+				Geometry::Vector3 v3n((Geometry::Real)M0.normal(isrc)(0), (Geometry::Real)M0.normal(isrc)(1), (Geometry::Real)M0.normal(isrc)(2));
+				(*mesh)->mSubMesh[i].mVertexBuffer->mNormal[idst]=v3n;
+
+				//texture coordinates
+				Geometry::Vector2 v2((Geometry::Real)M0.texcoord(isrc)(0), (Geometry::Real)M0.texcoord(isrc)(1));
+				(*mesh)->mSubMesh[i].mVertexBuffer->mTexCoords[idst]=v2;
+			}
+		}
+		else
+		{
+			//leaves mesh
+			(*mesh)->mSubMesh[i].mIndexCount=objmesh->mSubMesh[i].mIndexCount;
+			(*mesh)->mSubMesh[i].mIndex=new Geometry::Index[(*mesh)->mSubMesh[i].mIndexCount];
+
+			//copy the leaves submesh indexes
+			for (unsigned int j=0; j<(*mesh)->mSubMesh[i].mIndexCount; j++) 
+			{	
+				(*mesh)->mSubMesh[i].mIndex[j]=objmesh->mSubMesh[i].mIndex[j];
+			}
+
+			//copy the leaves submesh vertices
+			(*mesh)->mSubMesh[i].mVertexBuffer=new Geometry::VertexBuffer();
+			(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount=objmesh->mSubMesh[i].mVertexBuffer->mVertexCount;
+			(*mesh)->mSubMesh[i].mVertexBuffer->mVertexInfo=objmesh->mSubMesh[i].mVertexBuffer->mVertexInfo;
+
+			//allocate memory for position, normal and texture coordinates
+			(*mesh)->mSubMesh[i].mVertexBuffer->mPosition=new Geometry::Vector3[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+			(*mesh)->mSubMesh[i].mVertexBuffer->mNormal=new Geometry::Vector3[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+			(*mesh)->mSubMesh[i].mVertexBuffer->mTexCoords=new Geometry::Vector2[(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount];
+			for (unsigned int j=0; j<(*mesh)->mSubMesh[i].mVertexBuffer->mVertexCount; j++) 
+			{	
+				//position
+				(*mesh)->mSubMesh[i].mVertexBuffer->mPosition[j].x=objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].x;
+				(*mesh)->mSubMesh[i].mVertexBuffer->mPosition[j].y=objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].y;
+				(*mesh)->mSubMesh[i].mVertexBuffer->mPosition[j].z=objmesh->mSubMesh[i].mVertexBuffer->mPosition[j].z;
+
+				//normals
+				(*mesh)->mSubMesh[i].mVertexBuffer->mNormal[j].x=objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].x;
+				(*mesh)->mSubMesh[i].mVertexBuffer->mNormal[j].y=objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].y;
+				(*mesh)->mSubMesh[i].mVertexBuffer->mNormal[j].z=objmesh->mSubMesh[i].mVertexBuffer->mNormal[j].z;
+
+				//textures
+				(*mesh)->mSubMesh[i].mVertexBuffer->mTexCoords[j].x=objmesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].x;
+				(*mesh)->mSubMesh[i].mVertexBuffer->mTexCoords[j].y=objmesh->mSubMesh[i].mVertexBuffer->mTexCoords[j].y;
+			}
+		}
+	}
+	delete[] unique_verts_inds_by_geo;
+	delete[] ver_inds_repes_x_geo;
+	delete[] inextvert;
+
+	//Store the simplification steps in MeshSimplificationSequence
+	int acum=0;
+	for (size_t i=0; i<objmesh->mSubMeshCount; i++) 
+	{
+		if (objmesh->mSubMesh[i].mSharedVertexBuffer)
+		{
+			first_index_submesh[i]=0;
+		}
+		else
+		{
+			first_index_submesh[i]=acum;
+		}
+		acum+=(int)objmesh->mSubMesh[i].mVertexBuffer->mVertexCount;
+	}
+	Geometry::MeshSimplificationSequence::Step stepaux, newstep;
+	vector<int> v0,v1,submesh0,submesh1;
+	Geometry::MeshSimplificationSequence *msimpseq;
+	msimpseq=new Geometry::MeshSimplificationSequence();
+
+	for (unsigned i=0; i<decim_data.size(); i++) 
+	{
+		stepaux = decim_data.operator [](i);
+		v0=vertexbuffermap[stepaux.mV0];  // vertexbuffer index
+		submesh0=submeshmap[stepaux.mV0]; // displacement by submesh
+		v1=vertexbuffermap[stepaux.mV1];
+		submesh1=submeshmap[stepaux.mV1];
+		for (unsigned j=0; j<v0.size(); j++)
+		{
+			for (unsigned k=0; k<v1.size(); k++) 
+			{
+				//obtain the submesh index in VertexBuffer and the displacement by submesh
+				newstep.mV0=v0.operator [](j)+first_index_submesh[submesh0.operator [](j)];
+				newstep.mV1=v1.operator [](k)+first_index_submesh[submesh1.operator [](k)];
+				newstep.x=stepaux.x;
+				newstep.y=stepaux.y;
+				newstep.z=stepaux.z;
+				newstep.mT0=stepaux.mT0; // mT0 y mT1 are unique triangles identifiers returned by the simplification method
+				newstep.mT1=stepaux.mT1;
+				if (j==v0.size()-1 && k==v1.size()-1)
+					newstep.obligatorio=0;
+				else
+					newstep.obligatorio=1;
+				if (j==0 && k==0)
+					//First simplification step
+                    newstep.mModfaces=stepaux.mModfaces; //unique triangle identifiers returned by the simplification method
+				else 
+				{
+					std::vector<Geometry::Index> vvacio;
+					newstep.mModfaces=vvacio;
+				}
+					
+				msimpseq->mSteps.push_back(newstep);
+			}
+		}
+	}
+
+	// WriteOBJ();
+	return msimpseq;
+}
+
+void SimplificationMethod::setMeshLeaves(int meshLeaves)
+{
+	indexMeshLeaves=meshLeaves;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimpSequence.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimpSequence.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimpSequence.cpp	(revision 774)
@@ -0,0 +1,92 @@
+#include "GeoTreeSimpSequence.h"
+#include <iostream>
+#include <fstream>
+
+using namespace Geometry;
+using namespace std;
+
+TreeSimplificationSequence::TreeSimplificationSequence() 
+{
+	meshName="";
+}
+
+TreeSimplificationSequence::~TreeSimplificationSequence()
+{
+}
+
+void TreeSimplificationSequence::Load(Serializer &s)
+{
+	// Carga una secuencia de simplificación desde un fichero
+	char buffer[256];
+	char nombre[256];
+	Geometry::Index quad;
+	int cont; 
+
+	if (s.miReadData(buffer,256) != NULL) 
+	{
+		sscanf(buffer,"%s",&nombre);
+		meshName=new char[strlen(nombre)];
+		strcpy(meshName,nombre);
+	}
+
+	while (s.miReadData(buffer,256) != NULL) 
+	{
+		Geometry::TreeSimplificationSequence::Step pasosimp;
+		sscanf(buffer,"%u %u %u %u &",&pasosimp.mV0,&pasosimp.mV1,&pasosimp.mT0,&pasosimp.mT1);
+		// Quitar el salto de línea del final.
+		buffer[strlen(buffer)-1]='\0';
+
+		char *ptr1;
+		ptr1=strtok(buffer,"&");
+		ptr1=strtok(NULL,"&");
+		if (ptr1!=NULL) 
+		{
+			char *ptr;
+			ptr=strtok(ptr1," ");
+			cont=0;
+			while(ptr != NULL ) 
+			{
+				quad = (Index)atoi(ptr);
+				pasosimp.mNewQuad[cont]=quad;
+				ptr=strtok(NULL," ");
+				cont++;
+			}
+		}
+		mSteps.push_back(pasosimp);
+	}
+}
+
+void TreeSimplificationSequence::Save(Serializer &s)
+{
+	// Almacena la secuencia de simplificación en un fichero
+	char simp[256];
+
+	// Nombre del mesh
+	sprintf(simp,"%s\n",meshName);
+	s.WriteData(simp,sizeof(char),strlen(simp));
+
+	for(unsigned int i=0; i<mSteps.size(); i++)
+	{
+		Geometry::TreeSimplificationSequence::Step paso = mSteps.operator [](i);
+
+		// El último %u que recibe el sprintf es para indicar si un paso es dependiente del anterior. REVISAR
+		// ------------------------------------------------------------------------
+		sprintf(simp,"%u %u %u %u &", paso.mV0, paso.mV1, paso.mT0, paso.mT1);
+		s.WriteData(simp,sizeof(char),strlen(simp));
+
+		// los quads
+		sprintf(simp," %u %u %u %u\n",paso.mNewQuad[0],paso.mNewQuad[1],paso.mNewQuad[2],paso.mNewQuad[3]);
+		s.WriteData(simp,sizeof(char),strlen(simp));
+		//s.WriteData("\n",sizeof(char),1);
+	}
+}
+
+void TreeSimplificationSequence::putMeshName(char *name)
+{
+	meshName=name;
+}
+
+char *TreeSimplificationSequence::getMeshName(void)
+{
+	return meshName;
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/auxiliar.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/auxiliar.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/auxiliar.cpp	(revision 774)
@@ -0,0 +1,23 @@
+#include "auxiliar.h"
+
+using	namespace	Geometry;
+
+// FUNCIONES DE ALLOCATE
+
+uint32 **Allocate2DArrayINT(uint32 nRows, uint32 nCols){ 
+//uint32 **Allocate2DArrayINT(uint32 nRows, uint32 nCols){ 
+	uint32 **ppi,*pool,*curPtr; 
+	//unsigned short int **ppi,*pool,*curPtr; 
+	//(step 1) allocate memory for array of elements of column  
+	ppi = new uint32*[nRows];
+    //(step 2) allocate memory for array of elements of each row
+    pool = new uint32 [nRows * nCols];  
+	// Now point the pointers in the right place  
+	curPtr = pool;  
+	for( int i = 0; i < nRows; i++)    {    
+		*(ppi + i) = curPtr;        
+		curPtr += nCols;   
+	}    
+	return ppi;
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeLibrary.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeLibrary.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodTreeLibrary.cpp	(revision 774)
@@ -0,0 +1,1 @@
+#include "GeoLodTreeLibrary.h"
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimplifier.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimplifier.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoTreeSimplifier.cpp	(revision 774)
@@ -0,0 +1,1115 @@
+#include "GeoTreeSimplifier.h"
+#include "Hoja.h"
+
+#include <iostream>
+#include <fstream>
+#include <ctime>
+
+using namespace Geometry;
+using namespace std;
+
+TreeSimplifier::TreeSimplifier(	const	Mesh	*m,
+																TIPOFUNC		upb)
+{
+	objmesh						=	m;
+	mtreesimpsequence	=	new Geometry::TreeSimplificationSequence();
+	//mtreesimpsequence=NULL;
+	activas	=	0;
+	counth	=	0;
+
+	// Mesh de salida
+	mesh	=	new Geometry::Mesh();
+	*mesh	=	*m;
+
+	//	Sets the progress bar.
+	mUPB	=	upb;
+}
+
+TreeSimplifier::~TreeSimplifier()
+{
+	delete	mtreesimpsequence;
+}
+
+// Returns the simplified mesh.
+Geometry::Mesh *TreeSimplifier::GetMesh ()
+{
+	return	mesh;
+}
+
+Geometry::TreeSimplificationSequence *TreeSimplifier::GetSimplificationSequence()
+{
+	return	mtreesimpsequence;
+}
+
+void TreeSimplifier::Simplify(Real paramlod,	Index meshLeaves)
+{
+	// paramlod indica el número de vértices
+	long	int	totalv;
+	long	int	hnueva;
+	float			diam;
+
+	//	2006-02-22
+	float			percent;
+	long	int	update;
+	
+	totalv	=	0;
+	
+	Mesh2Estructura(objmesh, meshLeaves);
+	
+	diam = DiametroEsferaEnvolvente();
+
+	EstableceCriterio(diam);
+
+	// El paramlod lo uso como condición de parada de la simplificación
+	if (paramlod >= 6)
+	{
+		//	2006-02-22
+		update	=	(activas - (6 * paramlod)) / 80;
+		percent	=	0.5;
+		
+		while ( activas > (6*paramlod))
+		{
+			//	2006-02-22
+			if (mUPB	&&	(((long int)(activas - (6 * paramlod)) % update) == 0))
+			{
+				mUPB(percent);
+			}
+			
+			hnueva	=	Colapsa(diam);
+			
+			EstableceCriterio2(diam, hnueva);
+		}
+	}
+	else
+	{
+		//	2006-02-22
+		update	=	(activas - 6) / 80;
+		percent	=	0.5;
+		
+		while ( activas > 6) 
+		{
+			//	2006-02-22
+			if (mUPB	&&	(((activas - 6) % update) == 0))
+			{
+				mUPB(percent);
+			}
+			
+			hnueva	=	Colapsa(diam);
+			
+			EstableceCriterio2(diam, hnueva);
+		}
+	}
+
+	EscribeMesh(meshLeaves);
+	
+	//	2006-02-22
+	//	Fit progress bar to 100%.
+	if (mUPB)
+	{
+		mUPB(40);
+	}
+}
+
+void TreeSimplifier::Mesh2Estructura(	const Mesh	*mesh,
+																			Index				meshLeaves)
+{
+	// Calcular el número de vértices
+	long int countv=0;
+	long int pos=0;
+	long int v1, v2, v3;
+	long int num_triangulo=0; // Identifica los triángulos en las hojas
+
+	//	2006-02-21.
+	float			percent;
+	long	int	update;
+	
+	countv+=(long int)mesh->mSubMesh[meshLeaves].mVertexBuffer->mVertexCount;
+	Vertex  = new float[2*countv][3];
+	
+	//	2006-02-21.
+	update	=	mesh->mSubMesh[meshLeaves].mVertexBuffer->mVertexCount / 20;
+	percent	=	0.5;
+	
+	for (unsigned int j=0; j<mesh->mSubMesh[meshLeaves].mVertexBuffer->mVertexCount; j++)
+	{
+		//	2006-02-21.
+		if (mUPB	&&	((j % update) == 0))
+		{
+			mUPB(percent);
+		}
+		
+		Vertex[pos][0] = mesh->mSubMesh[meshLeaves].mVertexBuffer->mPosition[j].x; 
+		Vertex[pos][1] = mesh->mSubMesh[meshLeaves].mVertexBuffer->mPosition[j].y; 
+		Vertex[pos][2] = mesh->mSubMesh[meshLeaves].mVertexBuffer->mPosition[j].z;
+		pos++;
+	}
+
+	// Calcular el número de hojas
+	counth+=(long)mesh->mSubMesh[meshLeaves].mIndexCount;
+	counth=counth/6; // Se supone que cada 6 índices forman una hoja.
+
+	if ( counth > 0)
+	{
+		Hojasa  = new Hoja[2*counth];
+	}
+
+	activas = counth;
+
+	// Insertar las hojas en la estructura
+	pos=0;
+
+	//	2006-02-21.
+	update	=	mesh->mSubMesh[meshLeaves].mIndexCount	/ 20;
+	percent	=	0.5;
+	
+	// Cada hoja son 6 vértices
+	for (unsigned int j=0; j<mesh->mSubMesh[meshLeaves].mIndexCount; j=j+6) 
+	{
+		//	2006-02-21.
+		if (mUPB	&&	((j % update) == 0))
+		{
+			mUPB(percent);
+		}
+		
+		// Primer triángulo
+		v1=mesh->mSubMesh[meshLeaves].mIndex[j];
+		v2=mesh->mSubMesh[meshLeaves].mIndex[j+1];
+		v3=mesh->mSubMesh[meshLeaves].mIndex[j+2];
+		Hojasa[pos].Vertices[0]=v1;
+		Hojasa[pos].Vertices[1]=v2;
+		Hojasa[pos].Vertices[2]=v3;
+		num_triangulo++;
+		Hojasa[pos].id_triangulo[0]=num_triangulo;
+
+		// Segundo triángulo
+		v3=mesh->mSubMesh[meshLeaves].mIndex[j+5];
+		Hojasa[pos].Vertices[3]=v3;
+		num_triangulo++;
+		Hojasa[pos].id_triangulo[1]=num_triangulo;
+
+		Centroh(Hojasa[pos]);
+		GetNormal(Hojasa[pos]);
+		pos++;
+	}
+}
+
+float TreeSimplifier::max(float a,	float b)
+{
+	if (a>b) return (a);
+	else return(b);
+}
+
+float TreeSimplifier::min(float a,	float b)
+{
+	if (a>b) return (b);
+	else return(a);
+}
+
+float TreeSimplifier::distan(	float	x1,	float	y1,	float	z1,
+															float x2,	float y2,	float z2)
+{
+	float dist = 0;
+
+	dist = ((x2-x1)*(x2-x1)) + ((y2-y1)*(y2-y1)) + ((z2-z1)*(z2-z1));
+
+	return ( dist);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA EL CENTRO DE UNA HOJA
+//--------------------------------------------------------------------------------------------------------------------------------
+
+
+void TreeSimplifier::Centroh(Hoja	&Hoja1)
+{
+	float	max_x;
+	float	max_y;
+	float	max_z;
+	float	min_x;
+	float	min_y;
+	float	min_z;
+	
+	//x1
+	max_x	=	max(max(Vertex[Hoja1.Vertices[0]][0],
+									Vertex[Hoja1.Vertices[1]][0]),
+				  		max(Vertex[Hoja1.Vertices[2]][0],
+									Vertex[Hoja1.Vertices[3]][0]));
+	
+	min_x	=	min(min(Vertex[Hoja1.Vertices[0]][0],
+									Vertex[Hoja1.Vertices[1]][0]),
+				  		min(Vertex[Hoja1.Vertices[2]][0],
+									Vertex[Hoja1.Vertices[3]][0]));
+
+	Hoja1.Centro[0] = (max_x + min_x)/2;
+
+	//y1
+	max_y	=	max(max(Vertex[Hoja1.Vertices[0]][1],
+									Vertex[Hoja1.Vertices[1]][1]),
+				  		max(Vertex[Hoja1.Vertices[2]][1],
+									Vertex[Hoja1.Vertices[3]][1]));
+	
+	min_y	=	min(min(Vertex[Hoja1.Vertices[0]][1],
+									Vertex[Hoja1.Vertices[1]][1]),
+				  		min(Vertex[Hoja1.Vertices[2]][1],
+									Vertex[Hoja1.Vertices[3]][1]));
+
+	Hoja1.Centro[1]	=	(max_y + min_y) / 2;
+	
+	//z1
+	max_z	=	max(max(Vertex[Hoja1.Vertices[0]][2],
+									Vertex[Hoja1.Vertices[1]][2]),
+				  		max(Vertex[Hoja1.Vertices[2]][2],
+									Vertex[Hoja1.Vertices[3]][2]));
+	
+	min_z	=	min(min(Vertex[Hoja1.Vertices[0]][2],
+									Vertex[Hoja1.Vertices[1]][2]),
+				  		min(Vertex[Hoja1.Vertices[2]][2],
+									Vertex[Hoja1.Vertices[3]][2]));
+
+	Hoja1.Centro[2]	=	(max_z + min_z) / 2;
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA NORMAL DE UNA HOJA
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::GetNormal(Hoja &aHoja)
+{
+	float onex, oney, onez;
+	float twox, twoy, twoz;
+	float threex, threey, threez;
+
+	onex=Vertex[aHoja.Vertices[0]][0]; oney= Vertex[aHoja.Vertices[0]][1]; onez = Vertex[aHoja.Vertices[0]][2];
+	twox = Vertex[aHoja.Vertices[1]][0]; twoy = Vertex[aHoja.Vertices[1]][1]; twoz = Vertex[aHoja.Vertices[1]][2];
+	threex = Vertex[aHoja.Vertices[2]][0]; threey = Vertex[aHoja.Vertices[2]][1]; threez = Vertex[aHoja.Vertices[2]][2];
+	
+	aHoja.Normal[0] = ((twoz-onez)*(threey-oney)) - ((twoy-oney)*(threez-onez));
+	aHoja.Normal[1] = ((twox-onex)*(threez-onez)) - ((threex-onex)*(twoz-onez));
+	aHoja.Normal[2] = ((threex-onex)*(twoy-oney)) - ((twox-onex)*(threey-oney));
+
+	
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA distancia de Hausdorff ( distancia entre nubes de puntos)
+//--------------------------------------------------------------------------------------------------------------------------------
+float TreeSimplifier::Hausdorff(Hoja &aHoja, Hoja& h2)
+{
+	float onex, oney, onez;
+	float twox, twoy, twoz;
+	float threex, threey, threez;
+	float fourx, foury, fourz;
+	float x1, y1, z1;
+	float x2, y2, z2;
+	float x3, y3, z3;
+	float x4, y4, z4;
+	float dist1, dist2, dist3, dist4, distmp, dista, distb, dist;
+
+	onex=Vertex[aHoja.Vertices[0]][0]; oney= Vertex[aHoja.Vertices[0]][1]; onez = Vertex[aHoja.Vertices[0]][2];
+	twox = Vertex[aHoja.Vertices[1]][0]; twoy = Vertex[aHoja.Vertices[1]][1]; twoz = Vertex[aHoja.Vertices[1]][2];
+	threex = Vertex[aHoja.Vertices[2]][0]; threey = Vertex[aHoja.Vertices[2]][1]; threez = Vertex[aHoja.Vertices[2]][2];
+	fourx = Vertex[aHoja.Vertices[3]][0]; foury = Vertex[aHoja.Vertices[3]][1]; fourz = Vertex[aHoja.Vertices[3]][2];
+	
+
+	x1 = Vertex[h2.Vertices[0]][0]; y1 = Vertex[h2.Vertices[0]][1]; z1 = Vertex[h2.Vertices[0]][2];
+	x2 = Vertex[h2.Vertices[1]][0]; y2 = Vertex[h2.Vertices[1]][1]; z2 = Vertex[h2.Vertices[1]][2];
+	x3 = Vertex[h2.Vertices[2]][0]; y3 = Vertex[h2.Vertices[2]][1]; z3 = Vertex[h2.Vertices[2]][2];
+	x4 = Vertex[h2.Vertices[3]][0]; y4 = Vertex[h2.Vertices[3]][1]; z4 = Vertex[h2.Vertices[3]][2];
+
+	// guardo las distancias mínimas de cada vértice a los 4 contrarios.
+	dist1 = distan ( onex, oney,onez,x1,y1,z1);
+	// vertice 1 con los 4 de la otra hoja
+
+	distmp = distan ( onex, oney,onez,x2,y2,z2);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( onex, oney,onez,x3,y3,z3);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( onex, oney,onez,x4,y4,z4);
+	if ( distmp < dist1) dist1 = distmp;
+
+	// vertice 2 con los 4 de la otra hoja
+
+	dist2 = distan ( twox, twoy,twoz,x1,y1,z1);
+	
+	distmp = distan ( twox, twoy,twoz,x2,y2,z2);
+	if ( distmp < dist2) dist2 = distmp;
+	
+	distmp = distan ( twox, twoy,twoz,x3,y3,z3);
+	if ( distmp < dist2) dist2 = distmp;
+	
+	distmp = distan ( twox, twoy,twoz,x4,y4,z4);
+	if ( distmp < dist2) dist2 = distmp;
+
+	// vertice 3 con los 4 de la otra hoja
+
+	dist3 = distan ( threex, threey,threez,x1,y1,z1);
+	
+	distmp = distan ( threex, threey,threez,x2,y2,z2);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( threex, threey,threez,x3,y3,z3);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( threex, threey,threez,x4,y4,z4);
+	if ( distmp < dist3) dist3 = distmp;
+
+
+	// vertice 4 con los 4 de la otra hoja
+
+	dist4 = distan ( fourx, foury,fourz,x1,y1,z1);
+	
+	distmp = distan ( fourx, foury,fourz,x2,y2,z2);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( fourx, foury,fourz,x3,y3,z3);
+	if ( distmp < dist4) dist4 = distmp;
+	
+	distmp = distan ( fourx, foury,fourz,x4,y4,z4);
+	if ( distmp < dist4) dist4 = distmp;
+
+	//de entre estos cojo el máximo
+
+	dista =  max(dist1, max(dist2, max(dist3, dist4)));
+
+	//LO MISMO PERO A LA INVERSA
+
+	dist1 = distan ( x1,y1,z1, onex, oney, onez);
+	// vertice 1 con los 4 de la otra hoja
+
+	distmp = distan ( x1,y1,z1, twox, twoy, twoz);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( x1,y1,z1, threex, threey, threez);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( x1,y1,z1, fourx, foury, fourz);
+	if ( distmp < dist1) dist1 = distmp;
+
+	//2
+	dist2 = distan ( x2,y2,z2, onex, oney, onez);
+	// vertice 2 con los 4 de la otra hoja
+
+	distmp = distan ( x2,y2,z2, twox, twoy, twoz);
+	if ( distmp < dist2) dist2 = distmp;
+
+	distmp = distan ( x2,y2,z2, threex, threey, threez);
+	if ( distmp < dist2) dist2 = distmp;
+
+	distmp = distan ( x2,y2,z2, fourx, foury, fourz);
+	if ( distmp < dist2) dist2 = distmp;
+
+
+		//3
+	dist3 = distan ( x3,y3,z3, onex, oney, onez);
+	// vertice 3 con los 4 de la otra hoja
+
+	distmp = distan ( x3,y3,z3, twox, twoy, twoz);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( x3,y3,z3, threex, threey, threez);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( x3,y3,z3, fourx, foury, fourz);
+	if ( distmp < dist3) dist3 = distmp;
+
+		//4
+	dist4 = distan ( x4,y4,z4, onex, oney, onez);
+	// vertice 4 con los 4 de la otra hoja
+
+	distmp = distan ( x4,y4,z4, twox, twoy, twoz);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( x4,y4,z4, threex, threey, threez);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( x4,y4,z4, fourx, foury, fourz);
+	if ( distmp < dist4) dist4 = distmp;
+
+	//
+	distb =  max(dist1, max(dist2, max(dist3, dist4)));
+
+	dist  = max ( dista, distb);
+	return ( dist);
+	
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// CALCULA LA DISTANCIA ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+void TreeSimplifier::DistanciaEntreHojas(void)
+{
+	float dist, distmp ;
+	int j;
+
+	for ( int i=0;i<counth;i++)
+	{
+		if ( Hojasa[i].existe == true) // si la hoja aun existe
+		{
+			// inicializo para poder comparar
+			if ( i == (counth-1)) j = 0; 
+				else j = i+1;
+			while (Hojasa[j].existe == false) j++;
+			//dist = Hojasa[i].Distancia(Hojasa[j]);
+			dist = Hausdorff( Hojasa[i], Hojasa[j]);
+
+			Hojasa[i].hoja_cerca = j;
+			// empiezo los calculos
+			for ( j =0; j<(counth-1);j++)
+			{
+				if ( j == i) 
+					break;
+				if ( Hojasa[j].existe == true) // si la hoja aun existe
+				{
+					distmp = Hausdorff(Hojasa[i], Hojasa[j]);
+					if ( distmp < dist ) 
+					{
+						dist = distmp;
+						Hojasa[i].hoja_cerca = j;
+					}
+				}
+				
+			}
+			Hojasa[i].dist = dist;
+		}
+	}
+
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// DEVUELVE LA HOJA QUE TIENE UNA DISTANCIA MENOR
+//--------------------------------------------------------------------------------------------------------------------------------
+long int TreeSimplifier::MinimaDistancia ( void)
+{
+	float			mindist;
+	long int	cual;
+	int				i;
+
+	mindist =	0;
+	cual		=	-1;
+	i				=	0;
+	
+	//inicializo
+	while (Hojasa[i].existe != true)
+	{
+		i++;
+	}
+	
+	mindist =	Hojasa[i].dist;
+	cual		=	i;
+	
+	//busco la minima
+	for (i = 0; i < counth; i++)
+	{
+		if (Hojasa[i].existe == true)
+		{
+			if ( mindist > Hojasa[i].dist)
+			{
+				mindist = Hojasa[i].dist;
+				cual = i;
+			}
+		}
+
+	}
+	return (cual);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// CALCULA LA COPLANARIDAD ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::CoplanarEntreHojas(FILE	*fp_coplanar)
+{
+	float	cop;
+	float	coptmp;
+	int 	i;
+	int 	j;
+
+	for ( i=0;i<counth;i++)
+	{
+		if ( Hojasa[i].existe == true) // si la hoja aun existe
+		{
+			// inicializo para poder comparar
+			if ( i == (counth-1))
+			{
+				j	=	0;
+			}
+			else
+			{
+				j =	i + 1;
+			}
+			
+			while (Hojasa[j].existe == false)
+			{
+				j++;
+			}
+			
+			cop									=	Hojasa[i].Coplanaridad(Hojasa[j]);
+			Hojasa[i].hoja_cop	=	j;
+			
+			// empiezo los calculos
+			for (j = 0; j < (counth-1); j++)
+			{
+				// si la hoja aun existe.
+				if (( j != i) && (Hojasa[j].existe == true))
+				{
+					coptmp	=	Hojasa[i].Coplanaridad(Hojasa[j]);
+
+					// COJO EL MAS COPLANAR , CERCANO A 1.
+					if (coptmp > cop)
+					{
+						cop									=	coptmp;
+						Hojasa[i].hoja_cop	=	j;
+					}
+				}
+			}
+			Hojasa[i].coplanar	=	1 - cop; //  8/6/01 LO INVIERTO
+		}
+	}
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::DosMayores(float *mayores, int	*indices)
+{
+	float	m1;
+	int		i;
+
+	if	(mayores[0] < mayores[1])
+	{
+		m1					=	mayores[0];
+		mayores[0]	=	mayores[1];
+		mayores[1]	=	m1;
+
+		i						=	indices[0];
+		indices[0]	=	indices[1];
+		indices[1]	=	i;
+	}
+
+	if (mayores [2] < mayores [3])
+	{
+		m1					=	mayores[2];
+		mayores[2]	=	mayores[3];
+		mayores [3]	=	m1;
+
+		i						=	indices[2];
+		indices[2]	=	indices[3];
+		indices[3]	=	i;
+	}
+
+	if  (mayores[0] < mayores[2])
+	{
+		m1					=	mayores[0];
+		mayores[0]	=	mayores[2];
+		mayores[2]	=	m1;
+
+		i						=	indices[0];
+		indices[0]	=	indices[2];
+		indices[2]	=	i;
+	}
+
+	if (mayores [2] < mayores [3])
+	{
+		m1					=	mayores[2];
+		mayores[2]	=	mayores[3];
+		mayores [3]	=	m1;
+
+		i						=	indices[2];
+		indices[2]	=	indices[3];
+		indices[3]	=	i;
+	}
+
+	if (mayores [1] < mayores [2])
+	{
+		m1					=	mayores[1];
+		mayores[1]	=	mayores[2];
+		mayores [2]	=	m1;
+
+		i						= indices[1];
+		indices[1]	= indices[2];
+		indices[2]	= i;
+	}		
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+//float TreeSimplifier::DiametroEsferaEnvolvente (FILE* fp_simplifica)
+float TreeSimplifier::DiametroEsferaEnvolvente()
+{
+	float xmax, xmin, ymax, ymin, zmax, zmin;
+	float diametro, cx, cy, cz;
+	int j;
+
+	//	2006-02-21.
+	float			percent;
+	long	int	update;
+
+	//inicializo al primero de los vértices de las hojas
+
+	xmax = Vertex[Hojasa[0].Vertices[0]][0];
+	xmin = xmax;
+
+	ymax = Vertex[Hojasa[0].Vertices[0]][1];
+	ymin = ymax;
+
+	zmax = Vertex[Hojasa[0].Vertices[0]][2];
+	zmin = zmax;
+
+	// ahora busco los maximos y los minimos correspondientes
+
+
+	//	2006-02-21
+	update	=	counth / 20;
+	percent	=	0.5;
+	for (int i = 1; i < counth; i++)
+	{
+		//	2006-02-21
+		if (mUPB	&&	((i % update) == 0))
+		{
+			mUPB(percent);
+		}
+		
+		for ( j=0;j<4;j++)
+		{
+			
+		if ( xmax < Vertex[Hojasa[i].Vertices[j]][0]) xmax = Vertex[Hojasa[i].Vertices[j]][0];
+		if ( xmin > Vertex[Hojasa[i].Vertices[j]][0]) xmin = Vertex[Hojasa[i].Vertices[j]][0];
+
+		if ( ymax < Vertex[Hojasa[i].Vertices[j]][1]) ymax = Vertex[Hojasa[i].Vertices[j]][1];
+		if ( ymin > Vertex[Hojasa[i].Vertices[j]][1]) ymin = Vertex[Hojasa[i].Vertices[j]][1];
+		
+		if ( zmax < Vertex[Hojasa[i].Vertices[j]][2]) zmax = Vertex[Hojasa[i].Vertices[j]][2];
+		if ( zmin > Vertex[Hojasa[i].Vertices[j]][2]) zmin = Vertex[Hojasa[i].Vertices[j]][2];
+
+		}
+	}
+
+	cx = (xmax + xmin)/2;
+	cy = (ymax + ymin)/2;
+	cz = (zmax + zmin)/2;
+
+
+	diametro = ((xmax-xmin)*(xmax-xmin)) + ((ymax-ymin)*(ymax-ymin)) + ((zmax-zmin)*(zmax-zmin));
+
+return (diametro);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  normaliza las distancia
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::NormalizaDistancia (float diametro)
+{
+	float dtmp;
+	for (int i=0; i<counth;i++)
+	{
+		dtmp = Hojasa[i].dist;
+		Hojasa[i].dist = dtmp / diametro;
+		
+	}
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  establece el criterio como (K1 * dist + K2 * cop)/ K1+K2
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::EstableceCriterio(float diametro)
+{
+	//	Para empezar establezco K1 y K2 con 0,5
+	float coptmp2, coptmp, distmp2, distmp, criteriotmp;
+	int i, j, nhojasi, nhojasj;
+
+	//	2006-02-21
+	float			percent;
+	long	int	update;
+	
+	update	=	counth / 30;
+	percent	=	1;
+	
+	for ( i=0; i<counth;i++)
+	{
+		//	2005-02-21
+		if (mUPB	&&	((i % update) == 0))
+		{
+			mUPB(percent);
+		}
+		
+		if (Hojasa[i].existe == true)
+		{
+			//incializo criterio a un numero elevado
+			Hojasa[i].criterio = 1000;
+			nhojasi = Hojasa[i].Cuantas_hojas;
+			//coplanaridad
+			for ( j =0; j<counth;j++)
+			{
+				if (( j != i) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+				{
+					//17/09/01 ANTES DE CALCULAR NADA, COMPRUEBO QUE ESTAS DOS HOJAS 
+					// SE PODRIAN COLAPSAR, ED, QUE LA DIFERENCIA DE HOJAS QUE COLAPSAN
+					// ES COMO MÁXIMO 1
+
+					nhojasj = Hojasa[j].Cuantas_hojas;
+
+					if ( abs((nhojasi - nhojasj)) < 2)
+					{
+						//coplanaridad y lo invierto
+						coptmp2 = Hojasa[i].Coplanaridad(Hojasa[j]); 
+						coptmp = 1 - coptmp2;
+						//distancia y la normalizo
+						distmp2 = Hausdorff( Hojasa[i], Hojasa[j]); 
+						distmp = distmp2 / diametro;
+						// calculo el criterio para esa hoja
+						criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+						//selecciono el criterio menor
+						if (Hojasa[i].criterio > criteriotmp) 
+						{
+							Hojasa[i].criterio = criteriotmp;
+							Hojasa[i].hoja_crit = j;
+						}
+					}
+				}
+				
+			}
+		}
+	}
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  establece el criterio despues de colapsar
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::EstableceCriterio2 ( float			diametro,
+																					long int	hojanueva)
+{
+	//Para empezar establezco K1 y K2 con 0,5
+	float  coptmp2, coptmp, distmp2, distmp, criteriotmp;
+	int i, j, nhojasi, nhojasj;
+	//ESTAN EN tres PROCEDIMIENTOS: COLAPSA, ESTABLECECRITERIO Y ESTABLECECRITERIO2
+	
+	for (i = 0; i < counth; i++)
+	{
+		if ((Hojasa[i].existe == true) && (i != hojanueva))
+		{	
+			nhojasi = Hojasa[i].Cuantas_hojas;
+			//¿ SE HA DESACTIVADO LA HOJA_CRIT QUE GUARDABA LA HOJA?
+			if ( Hojasa[Hojasa[i].hoja_crit].existe == false)
+			{
+				Hojasa[i].criterio = 1000;
+
+				//coplanaridad
+				for ( j =0; j<counth;j++)
+				{
+					if (( j != i) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+					{
+						//17/09/01 ANTES DE CALCULAR NADA, COMPRUEBO QUE ESTAS DOS HOJAS 
+						// SE PODRIAN COLAPSAR, ED, QUE LA DIFERENCIA DE HOJAS QUE COLAPSAN
+						// ES COMO MÁXIMO 1
+
+						nhojasj = Hojasa[j].Cuantas_hojas;
+
+						if ( abs((nhojasi - nhojasj)) < 2)
+						{
+
+							//coplanaridad y lo invierto
+							coptmp2 = Hojasa[i].Coplanaridad(Hojasa[j]); 
+							coptmp = 1 - coptmp2;	
+							//distancia y la normalizo	
+						//	distmp2 = Hojasa[i].Distancia(Hojasa[j]); 
+							distmp2 = Hausdorff( Hojasa[i],  Hojasa[j]); 
+							distmp = distmp2 / diametro;
+							// calculo el criterio para esa hoja
+							criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+							//selecciono el criterio menor
+							if (Hojasa[i].criterio > criteriotmp) 
+							{
+								Hojasa[i].criterio = criteriotmp;
+								Hojasa[i].hoja_crit = j;
+							}
+						}
+					}
+				}
+			}
+			else
+			{ // CALCULARE SI EL CRITERIO CON ESTA HOJA ES MENOR QUE EL ANTERIOR
+				nhojasj = Hojasa[hojanueva].Cuantas_hojas;//17/09/01
+
+				if ( abs((nhojasi - nhojasj)) < 2)
+				{
+					//coplanaridad y lo invierto
+					coptmp2 = Hojasa[i].Coplanaridad(Hojasa[hojanueva]); 
+					coptmp = 1 - coptmp2;
+					//distancia y la normalizo
+					//distmp2 = Hojasa[i].Distancia(Hojasa[hojanueva]); 
+					distmp2 = Hausdorff( Hojasa[i], Hojasa[hojanueva]); 
+					distmp = distmp2 / diametro;
+					// calculo el criterio para esa hoja
+					criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+					//selecciono el criterio menor
+					if (Hojasa[i].criterio > criteriotmp) 
+					{	
+						Hojasa[i].criterio = criteriotmp;
+						Hojasa[i].hoja_crit = hojanueva;
+					}
+				}
+			}
+		}
+	}
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+// DEVUELVE LA HOJA QUE TIENE EL NUMERO EN EL CAMPO CRITERIO MENOR
+//--------------------------------------------------------------------------------------------------------------------------------
+
+long int TreeSimplifier::MinimoCriterio (void)
+{
+	float mincrit =0;
+	long int cual=-1;
+	int i=0;
+	
+	//inicializo
+	while (Hojasa[i].existe != true) i++;
+	mincrit = Hojasa[i].criterio;
+	cual =i;
+	//busco la minima
+	for ( i=0;i<counth;i++)
+
+	{
+		if (Hojasa[i].existe == true)
+		{
+			if ( mincrit> Hojasa[i].criterio)
+			{
+				mincrit = Hojasa[i].criterio;
+				cual = i;
+			}
+		}
+		
+	}
+	return (cual);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::ElijeVertices(Hoja& Hoja1, Hoja& Hoja2, long int count)
+{
+	// criterio es el de los dos vertices más alejados del centro de la otra hoja
+	
+	float a,b,c;
+	float dist[4];
+	int indices[4];
+	
+	// primero de la primera hoja cojo los dos primeros vertices
+
+
+	a = Vertex[Hoja1.Vertices[0]][0];
+	b = Vertex[Hoja1.Vertices[0]][1];
+	c = Vertex[Hoja1.Vertices[0]][2];
+
+	dist[0] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	
+	a = Vertex[Hoja1.Vertices[1]][0];
+	b = Vertex[Hoja1.Vertices[1]][1];
+	c = Vertex[Hoja1.Vertices[1]][2];
+
+	dist[1] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	a = Vertex[Hoja1.Vertices[2]][0];
+	b = Vertex[Hoja1.Vertices[2]][1];
+	c = Vertex[Hoja1.Vertices[2]][2];
+
+	dist[2] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+
+	a = Vertex[Hoja1.Vertices[3]][0];
+	b = Vertex[Hoja1.Vertices[3]][1];
+	c = Vertex[Hoja1.Vertices[3]][2];
+
+	dist[3] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	for ( int i=0;i<4;i++) indices[i]=i;
+
+	DosMayores(dist, indices);
+	
+	Hojasa[counth].Vertices[0] = Hoja1.Vertices[indices[0]]; 
+	Hojasa[counth].Vertices[1] = Hoja1.Vertices[indices[1]]; 
+	
+	// segunda hoja los dos ultimos vertices
+
+	
+	a = Vertex[Hoja2.Vertices[0]][0];
+	b = Vertex[Hoja2.Vertices[0]][1];
+	c = Vertex[Hoja2.Vertices[0]][2];
+
+	dist[0] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+	
+	a = Vertex[Hoja2.Vertices[1]][0];
+	b = Vertex[Hoja2.Vertices[1]][1];
+	c = Vertex[Hoja2.Vertices[1]][2];
+
+	dist[1] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	a = Vertex[Hoja2.Vertices[2]][0];
+	b = Vertex[Hoja2.Vertices[2]][1];
+	c = Vertex[Hoja2.Vertices[2]][2];
+
+	dist[2] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+
+	a = Vertex[Hoja2.Vertices[3]][0];
+	b = Vertex[Hoja2.Vertices[3]][1];
+	c = Vertex[Hoja2.Vertices[3]][2];
+
+	dist[3] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+	for ( int i=0;i<4;i++) indices[i]=i;
+
+	DosMayores(dist, indices);
+	
+	Hojasa[counth].Vertices[2] = Hoja2.Vertices[indices[0]]; 
+	Hojasa[counth].Vertices[3] = Hoja2.Vertices[indices[1]]; 
+
+
+
+	
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// AÑADE HOJAS 
+//--------------------------------------------------------------------------------------------------------------------------------
+//long int TreeSimplifier::Colapsa (Geometry::TreeSimplificationSequence *tss, float diametro)
+long int TreeSimplifier::Colapsa(float diametro)
+{
+	long int i=0, cual=-1;
+	long int otra = -1;
+	float coptmp, coptmp2, distmp, distmp2, criteriotmp;
+//	char linea[250];
+
+//	cual=MinimaDistancia();
+	cual=MinimoCriterio();
+//	otra = Hojasa[cual].hoja_cerca; //para la distancia
+//	otra = Hojasa[cual].hoja_cop;
+	otra = Hojasa[cual].hoja_crit;
+
+	//desactivo las hojas cercanas
+	Hojasa[cual].existe = false;
+	Hojasa[otra].existe = false;
+	//creo la hoja nueva
+
+	Hojasa[counth].hoja_cerca = -1;
+	Hojasa[counth].dist = 0;
+	Hojasa[counth].hoja_cop = -1;
+	Hojasa[counth].coplanar = 0;
+
+	Hojasa[counth].Cuantas_hojas = Hojasa[cual].Cuantas_hojas + Hojasa[otra].Cuantas_hojas;
+	ElijeVertices(Hojasa[cual], Hojasa[otra], counth);
+	Centroh (Hojasa[counth]);
+	GetNormal ( Hojasa[counth]);
+
+	//18/09/01 
+	if (Hojasa[counth].Cuantas_hojas > 60 )
+	{
+			Hojasa[counth].existe = false;
+			activas--;
+	}
+	else
+	{
+		//establezco el criterio para la hoja nueva
+     	Hojasa[counth].existe = true;
+		Hojasa[counth].criterio = 1000;
+
+ 		//coplanaridad
+		for (int j = 0; j < (counth+1); j++)
+		{
+			if (( j != counth) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+			{
+			//coplanaridad y lo invierto
+			coptmp2 = Hojasa[counth].Coplanaridad(Hojasa[j]); 
+			coptmp = 1 - coptmp2;
+			//distancia y la normalizo
+			//distmp2 = Hojasa[counth].Distancia(Hojasa[j]); 
+			distmp2 = Hausdorff(Hojasa[counth], Hojasa[j]); 
+			distmp = distmp2 / diametro;
+			// calculo el criterio para esa hoja
+			criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+			//selecciono el criterio menor
+			if (Hojasa[counth].criterio > criteriotmp) 
+			{
+				Hojasa[counth].criterio = criteriotmp;
+				Hojasa[counth].hoja_crit = j;}
+			}
+		}
+	}	
+
+	// Crear el paso de simplificación
+	Geometry::TreeSimplificationSequence::Step pasosimp;
+	pasosimp.mV0=Hojasa[cual].id_triangulo[0];
+	pasosimp.mV1=Hojasa[cual].id_triangulo[1];
+	pasosimp.mT0=Hojasa[otra].id_triangulo[0];
+	pasosimp.mT1=Hojasa[otra].id_triangulo[1];
+
+	// Nuevos vértices
+	pasosimp.mNewQuad[0]=Hojasa[counth].Vertices[0];
+	pasosimp.mNewQuad[1]=Hojasa[counth].Vertices[1];
+	pasosimp.mNewQuad[2]=Hojasa[counth].Vertices[2];
+	pasosimp.mNewQuad[3]=Hojasa[counth].Vertices[3];
+
+	// Insertar el paso de simplificación
+	mtreesimpsequence->mSteps.push_back(pasosimp);
+
+	//incremento el numero de hojas
+	counth++;
+	activas--;
+	return (counth-1);//porque lo he incrementado en la linea de antes
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// ESCRIBE EL mIndex EN EL MESH DE SALIDA
+//--------------------------------------------------------------------------------------------------------------------------------
+void TreeSimplifier::EscribeMesh(int idMeshLeaves) 
+{
+	// Calcular el número de indices después de simplificar
+	long int tamIndex	=	activas * 6; // Cada hoja tiene 6 índices
+
+	//	2006-02-21.
+	float			percent;
+	long	int	update;
+	
+	delete [] mesh->mSubMesh[idMeshLeaves].mIndex;
+	mesh->mSubMesh[idMeshLeaves].mIndexCount=tamIndex;
+	mesh->mSubMesh[idMeshLeaves].mIndex=new Geometry::Index[tamIndex];
+
+	// Recorrer las hojas, comprobar las que están activas y copiar los índices al mesh.
+	Geometry::Index indice=0;
+
+	//	2006-02-21.
+	update	=	counth	/ 10;
+	percent	=	1;
+	
+	for (long j=0; j<counth;j++)
+	{
+		//	2006-02-21
+		if (mUPB	&&	((j % update) == 0))
+		{
+			mUPB(percent);
+		}
+		
+		if ( Hojasa[j].existe == true) // si la hoja aun existe
+		{
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice]=Hojasa[j].Vertices[0];
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice+1]=Hojasa[j].Vertices[1];
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice+2]=Hojasa[j].Vertices[2];
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice+3]=Hojasa[j].Vertices[2];
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice+4]=Hojasa[j].Vertices[1];
+			mesh->mSubMesh[idMeshLeaves].mIndex[indice+5]=Hojasa[j].Vertices[3];
+			indice=indice+6;
+		}
+	}
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector2.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector2.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector2.cpp	(revision 774)
@@ -0,0 +1,11 @@
+#include "GeoVector2.h"
+
+namespace Geometry
+{
+    const Vector2 Vector2::ZERO( 0, 0);
+    const Vector2 Vector2::UNIT_X( 1, 0);
+    const Vector2 Vector2::UNIT_Y( 0, 1);
+    const Vector2 Vector2::NEGATIVE_UNIT_X( -1,  0);
+    const Vector2 Vector2::NEGATIVE_UNIT_Y(  0, -1);
+    const Vector2 Vector2::UNIT_SCALE(1, 1);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector3.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector3.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoVector3.cpp	(revision 774)
@@ -0,0 +1,13 @@
+#include "GeoVector3.h"
+
+namespace Geometry
+{
+    const Vector3 Vector3::ZERO( 0, 0, 0 );
+    const Vector3 Vector3::UNIT_X( 1, 0, 0 );
+    const Vector3 Vector3::UNIT_Y( 0, 1, 0 );
+    const Vector3 Vector3::UNIT_Z( 0, 0, 1 );
+    const Vector3 Vector3::NEGATIVE_UNIT_X( -1,  0,  0 );
+    const Vector3 Vector3::NEGATIVE_UNIT_Y(  0, -1,  0 );
+    const Vector3 Vector3::NEGATIVE_UNIT_Z(  0,  0, -1 );
+    const Vector3 Vector3::UNIT_SCALE(1, 1, 1);
+}
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/hoja.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/hoja.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/hoja.cpp	(revision 774)
@@ -0,0 +1,117 @@
+#include <math.h>
+#include "Hoja.h"
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// Void constructor
+// Parameters --> None
+//--------------------------------------------------------------------------------------------------------------------------------
+Hoja::Hoja(void) 
+{
+	
+	Vertices[0] = Vertices[1] = Vertices[2] = Vertices[3] =0; 
+	Centro[0] = Centro[1] = Centro[2] = 0;
+	Normal[0] = Normal[1] = Normal[2] = 0;
+	hoja_cerca=-1;
+	Cuantas_hojas = 1;
+	
+	dist			=	-1;
+	coplanar	=	-1;
+	criterio	=	-1;
+	hoja_cop	=	-1;
+	hoja_crit =	-1;
+	
+	existe = true;
+		
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// Copy constructor
+// Parameters --> const Hoja& aHoja : The Hoja to copy
+//--------------------------------------------------------------------------------------------------------------------------------
+Hoja::Hoja (const Hoja& aHoja)
+{
+
+
+	Cuantas_hojas = aHoja.Cuantas_hojas;;
+	hoja_cerca = aHoja.hoja_cerca;
+	hoja_crit = aHoja.hoja_crit;
+	dist = aHoja.dist;
+	existe = aHoja.existe;
+	coplanar = aHoja.coplanar;
+	hoja_cop = aHoja.hoja_cop;
+	criterio = aHoja.criterio;
+	for ( int i=0;i<3;i++){
+		Centro[i] = aHoja.Centro[i];
+		Normal[i] = aHoja.Normal[i];
+	}
+	for (i = 0L; i < 4; i++)
+		Vertices[i] = aHoja.Vertices[i]; 
+	
+
+}
+
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// Destructor. We must deallocate the memory allocated for pointers to vertices and edges
+//--------------------------------------------------------------------------------------------------------------------------------
+Hoja::~Hoja (void)
+{
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA DISTANCIA ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+float Hoja::Distancia (Hoja& Hoja1)
+{
+	float dist =0;
+	float x1,y1,z1;
+
+	x1 = Hoja1.Centro[0]; y1 = Hoja1.Centro[1] ; z1 = Hoja1.Centro[2];
+
+
+	//DISTANCIA ENTRE CENTROS
+
+	dist = ((Centro[0]-x1)*(Centro[0]-x1)) + ((Centro[1]-y1)*(Centro[1]-y1)) + ((Centro[2]-z1)*(Centro[2]-z1));
+
+	return (dist);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA COPLANARIDAD ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+float Hoja::Coplanaridad (Hoja& Hoja1)
+{
+	float cop =0;
+	float modulo1, modulo2;
+	float x1,y1,z1, nx1, ny1, nz1;
+	float nx, ny, nz;
+
+	//hoja pasada como parametro, normalizo las componentes
+	x1 = Hoja1.Normal[0]; y1 = Hoja1.Normal[1] ; z1 = Hoja1.Normal[2];
+	modulo1 = sqrt ( (x1*x1) + (y1*y1) + (z1*z1));
+	nx1 = x1 / modulo1;
+	ny1 = y1 / modulo1;
+	nz1 = z1 / modulo1;
+
+	// hoja desde la que llamo
+
+	modulo2 = sqrt ( (Normal[0]*Normal[0]) + (Normal[1]*Normal[1]) + (Normal[2]*Normal[2]));
+	nx = Normal[0] / modulo2;
+	ny = Normal[1] / modulo2;
+	nz = Normal[2] / modulo2;
+
+	// producto escalar : si es proximo a 0, perpendiculares, a 1, coplanares
+
+	cop = (nx1*nx) + (ny1*ny) + (nz1*nz);
+
+
+	return (fabs(cop));
+
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/principal.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/principal.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/principal.cpp	(revision 774)
@@ -0,0 +1,1197 @@
+//Headers:
+//#include <Ogre.h>
+#include <iostream>
+#include <fstream>
+
+//#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include "principal.h"
+#include <ctime>
+
+time_t first, second;
+
+using namespace std;
+using namespace Geometry;
+//using namespace principal;
+//--------------------------------------------------------------------------------------------------------------------------------
+//  RELLENA LA ESTRUCTURA DE VERTICES 
+//--------------------------------------------------------------------------------------------------------------------------------
+
+void Mesh2Estructura(Geometry::Mesh *mesh){
+	// Calcular el número de vértices
+	long int countv=0;
+	long int counth=0;
+	long int pos=0;
+	long int v1, v2, v3;
+
+	for (unsigned int i=0; i<mesh->mSubMeshCount; i++){
+		countv+=mesh->mSubMesh[i].mVertexBuffer->mVertexCount;
+	}
+	Vertex  = new float[countv][3];
+	
+	for (unsigned int i=0; i<mesh->mSubMeshCount; i++){
+		for (unsigned int j=0; j<mesh->mSubMesh[i].mVertexBuffer->mVertexCount; j++) {
+			Vertex[pos][0] = mesh->mSubMesh[i].mVertexBuffer->mPosition[j].x; 
+			Vertex[pos][1] = mesh->mSubMesh[i].mVertexBuffer->mPosition[j].y; 
+			Vertex[pos][2] = mesh->mSubMesh[i].mVertexBuffer->mPosition[j].z;
+			pos++;
+		}
+	}
+
+	// Calcular el número de hojas
+	for (unsigned int i=0; i<mesh->mSubMeshCount; i++){
+		counth+=mesh->mSubMesh[i].mIndexCount;
+	}
+	counth=counth/3; // Se supone que cada 3 índices forman una hoja.
+	if ( counth > 0){
+		Hojasa  = new Hoja[counth];
+	}
+	activas = counth;
+
+	// Insertar las hojas en la estructura
+	pos=0;
+	for (unsigned int i=0; i<mesh->mSubMeshCount; i++){
+		for (unsigned int j=0; j<mesh->mSubMesh[i].mIndexCount/3; j++) {
+			v1=mesh->mSubMesh[i].mIndex[j];
+			v2=mesh->mSubMesh[i].mIndex[j];
+			v3=mesh->mSubMesh[i].mIndex[j];
+			Hojasa[pos].Vertices[0]=(v1-1);
+			Hojasa[pos].Vertices[1]=(v2-1);
+			Hojasa[pos].Vertices[2]=(v3-1);
+			Hojasa[pos].Vertices[3]=(v3-1);
+			Centroh( Hojasa[pos]);
+			GetNormal ( Hojasa[pos]);
+			pos++;
+		}
+	}
+}
+
+//long int LeeVertices (char * arbol)
+//
+//{
+//		FILE* fp_origen;
+//		char linea[256], str[20];
+//		float x,y,z;
+//		long int countv=0;
+//		bool fin_vertices = false;
+//		
+//		//cuento todos los vertices, y relleno la estructura
+//		if ((fp_origen = fopen (arbol, "r")) == NULL)
+//			printf ("No he podido abrir el fichero %s\n", arbol);
+//		else
+//		{
+//			while ((fgets (linea, 255, fp_origen) != NULL) && (fin_vertices == false))
+//		
+//				
+//				switch (linea[0])
+//				{
+//					case '#':
+//						switch ( linea[2])
+//						{
+//						case 'v':
+//							sscanf(linea,"# %s %lu",  str, &countv);
+//							if ( countv > 0) 	Vertex  = new float[2*countv][3];
+//							printf ( "hay %lu vertices\n",countv);
+//							countv=0;
+//							break;
+//						
+//						default:
+//							break;
+//
+//						}
+//						break;
+//					case 'v':
+//						switch (linea[1])
+//						{
+//							case ' ':
+//							sscanf (linea, "v %f %f %f ", &x, &y, &z);
+//							Vertex[countv][0] = x; Vertex[countv][1] = y; Vertex[countv][2] = z;
+//								countv++;
+//								break;
+//		
+//							default :
+//								break;
+//
+//						}
+//						break;
+//
+//
+//					default:
+//						break;
+//	
+//				}
+//
+//		fclose (fp_origen);
+//		}
+//		return ( countv);
+//
+//		
+//}
+//--------------------------------------------------------------------------------------------------------------------------------
+// CUENTA LAS HOJAS QUE HAY EN EL FICHERO
+//--------------------------------------------------------------------------------------------------------------------------------
+
+//long int CuentaHojas ( char *hojas)
+//{
+//
+//	FILE* fp_hojas;
+//	char linea[256];
+//	long int counth=0;
+//
+//	if ((fp_hojas = fopen (hojas, "r")) == NULL)
+//			printf ("No he podido abrir el fichero %s\n", hojas);
+//	else
+//		{
+//
+//		while (fgets (linea, 255, fp_hojas) != NULL)
+//	
+//			switch (linea[0])
+//			{
+//				case 'H':
+//					counth++;
+//					break;
+//		
+//				default :
+//					break;
+//			}
+//
+//
+//
+//			fclose (fp_hojas);
+//
+//			if ( counth > 0){
+//				Hojasa  = new Hoja[2*counth];
+//				}
+//	}
+//		activas = counth;
+//		return (counth);
+//}
+//--------------------------------------------------------------------------------------------------------------------------------
+// LEO LAS HOJAS Y RELLENO LA ESTRUCTURA DE DATOS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+//void LeoHojas (char* hojas)
+//{
+//	FILE* fp_hojas;
+//	char linea[256];
+//	long int v1, v2, v3, h=0;
+//		
+//	if ((fp_hojas = fopen (hojas, "r")) == NULL)
+//			printf ("No he podido abrir el fichero %s\n", hojas);
+//		
+//	else
+//	{
+//
+//
+//		while (fgets (linea, 255, fp_hojas) != NULL)
+//		
+//			switch (linea[0])
+//			{
+//				case 'H':
+//				
+//					fgets (linea, 255, fp_hojas);
+//					sscanf(linea, "f %lu %lu %lu", &v1, &v2, &v3);
+//
+//					Hojasa[h].Vertices[0]=(v1-1);
+//					Hojasa[h].Vertices[1]=(v2-1);
+//					Hojasa[h].Vertices[2]=(v3-1);
+//					
+//					fgets (linea, 255, fp_hojas);
+//					sscanf(linea, "f %lu %lu %lu", &v1, &v2, &v3);
+//					Hojasa[h].Vertices[3]=(v3-1);
+//
+//					Centroh( Hojasa[h]);
+//					GetNormal ( Hojasa[h]);
+//					
+//					h++;
+//					break;
+//					
+//				default :
+//					printf( "Hay un error al leer las hojas\n");
+//					break;
+//	
+//			}
+//		
+//			fclose(fp_hojas);
+//	}
+//
+//		
+//}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  FUNCIONES AUXILIARES
+//--------------------------------------------------------------------------------------------------------------------------------
+
+float max ( float a, float b)
+{
+	if (a>b) return (a);
+	else return(b);
+}
+
+float min ( float a, float b)
+{
+	if (a>b) return (b);
+	else return(a);
+}
+
+float distan (float x1, float y1, float z1, float x2, float y2, float z2)
+{
+	float dist = 0;
+
+	dist = ((x2-x1)*(x2-x1)) + ((y2-y1)*(y2-y1)) + ((z2-z1)*(z2-z1));
+
+	return ( dist);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA EL CENTRO DE UNA HOJA
+//--------------------------------------------------------------------------------------------------------------------------------
+
+
+void Centroh ( Hoja& Hoja1)
+{
+
+	float max_x, min_x, max_y, min_y, max_z, min_z;
+
+	
+	//x1
+	max_x = max ( max (Vertex[Hoja1.Vertices[0]][0], Vertex[Hoja1.Vertices[1]][0]),
+				  max (Vertex[Hoja1.Vertices[2]][0], Vertex[Hoja1.Vertices[3]][0]));
+	
+	min_x = min ( min (Vertex[Hoja1.Vertices[0]][0], Vertex[Hoja1.Vertices[1]][0]),
+				  min (Vertex[Hoja1.Vertices[2]][0], Vertex[Hoja1.Vertices[3]][0]));
+
+	Hoja1.Centro[0] = (max_x + min_x)/2;
+
+	//y1
+	max_y = max ( max (Vertex[Hoja1.Vertices[0]][1], Vertex[Hoja1.Vertices[1]][1]),
+				  max (Vertex[Hoja1.Vertices[2]][1], Vertex[Hoja1.Vertices[3]][1]));
+	
+	min_y = min ( min (Vertex[Hoja1.Vertices[0]][1], Vertex[Hoja1.Vertices[1]][1]),
+				  min (Vertex[Hoja1.Vertices[2]][1], Vertex[Hoja1.Vertices[3]][1]));
+
+	Hoja1.Centro[1] = (max_y + min_y)/2;
+	
+	//z1
+	max_z = max ( max (Vertex[Hoja1.Vertices[0]][2], Vertex[Hoja1.Vertices[1]][2]),
+				  max (Vertex[Hoja1.Vertices[2]][2], Vertex[Hoja1.Vertices[3]][2]));
+	
+	min_z = min ( min (Vertex[Hoja1.Vertices[0]][2], Vertex[Hoja1.Vertices[1]][2]),
+				  min (Vertex[Hoja1.Vertices[2]][2], Vertex[Hoja1.Vertices[3]][2]));
+
+	Hoja1.Centro[2] = (max_z + min_z)/2;
+
+
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA NORMAL DE UNA HOJA
+//--------------------------------------------------------------------------------------------------------------------------------
+void GetNormal (Hoja &aHoja)
+{
+
+	float onex, oney, onez;
+	float twox, twoy, twoz;
+	float threex, threey, threez;
+
+	onex=Vertex[aHoja.Vertices[0]][0]; oney= Vertex[aHoja.Vertices[0]][1]; onez = Vertex[aHoja.Vertices[0]][2];
+	twox = Vertex[aHoja.Vertices[1]][0]; twoy = Vertex[aHoja.Vertices[1]][1]; twoz = Vertex[aHoja.Vertices[1]][2];
+	threex = Vertex[aHoja.Vertices[2]][0]; threey = Vertex[aHoja.Vertices[2]][1]; threez = Vertex[aHoja.Vertices[2]][2];
+	
+	aHoja.Normal[0] = ((twoz-onez)*(threey-oney)) - ((twoy-oney)*(threez-onez));
+	aHoja.Normal[1] = ((twox-onex)*(threez-onez)) - ((threex-onex)*(twoz-onez));
+	aHoja.Normal[2] = ((threex-onex)*(twoy-oney)) - ((twox-onex)*(threey-oney));
+
+	
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+//  CALCULA LA distancia de Hausdorff ( distancia entre nubes de puntos)
+//--------------------------------------------------------------------------------------------------------------------------------
+float Hausdorff (Hoja &aHoja, Hoja& h2)
+{
+
+	float onex, oney, onez;
+	float twox, twoy, twoz;
+	float threex, threey, threez;
+	float fourx, foury, fourz;
+	float x1, y1, z1;
+	float x2, y2, z2;
+	float x3, y3, z3;
+	float x4, y4, z4;
+
+	float dist1, dist2, dist3, dist4, distmp, dista, distb, dist;
+
+	onex=Vertex[aHoja.Vertices[0]][0]; oney= Vertex[aHoja.Vertices[0]][1]; onez = Vertex[aHoja.Vertices[0]][2];
+	twox = Vertex[aHoja.Vertices[1]][0]; twoy = Vertex[aHoja.Vertices[1]][1]; twoz = Vertex[aHoja.Vertices[1]][2];
+	threex = Vertex[aHoja.Vertices[2]][0]; threey = Vertex[aHoja.Vertices[2]][1]; threez = Vertex[aHoja.Vertices[2]][2];
+	fourx = Vertex[aHoja.Vertices[3]][0]; foury = Vertex[aHoja.Vertices[3]][1]; fourz = Vertex[aHoja.Vertices[3]][2];
+	
+
+	x1 = Vertex[h2.Vertices[0]][0]; y1 = Vertex[h2.Vertices[0]][1]; z1 = Vertex[h2.Vertices[0]][2];
+	x2 = Vertex[h2.Vertices[1]][0]; y2 = Vertex[h2.Vertices[1]][1]; z2 = Vertex[h2.Vertices[1]][2];
+	x3 = Vertex[h2.Vertices[2]][0]; y3 = Vertex[h2.Vertices[2]][1]; z3 = Vertex[h2.Vertices[2]][2];
+	x4 = Vertex[h2.Vertices[3]][0]; y4 = Vertex[h2.Vertices[3]][1]; z4 = Vertex[h2.Vertices[3]][2];
+
+	// guardo las distancias mínimas de cada vértice a los 4 contrarios.
+	dist1 = distan ( onex, oney,onez,x1,y1,z1);
+	// vertice 1 con los 4 de la otra hoja
+
+	distmp = distan ( onex, oney,onez,x2,y2,z2);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( onex, oney,onez,x3,y3,z3);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( onex, oney,onez,x4,y4,z4);
+	if ( distmp < dist1) dist1 = distmp;
+
+	// vertice 2 con los 4 de la otra hoja
+
+	dist2 = distan ( twox, twoy,twoz,x1,y1,z1);
+	
+	distmp = distan ( twox, twoy,twoz,x2,y2,z2);
+	if ( distmp < dist2) dist2 = distmp;
+	
+	distmp = distan ( twox, twoy,twoz,x3,y3,z3);
+	if ( distmp < dist2) dist2 = distmp;
+	
+	distmp = distan ( twox, twoy,twoz,x4,y4,z4);
+	if ( distmp < dist2) dist2 = distmp;
+
+	// vertice 3 con los 4 de la otra hoja
+
+	dist3 = distan ( threex, threey,threez,x1,y1,z1);
+	
+	distmp = distan ( threex, threey,threez,x2,y2,z2);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( threex, threey,threez,x3,y3,z3);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( threex, threey,threez,x4,y4,z4);
+	if ( distmp < dist3) dist3 = distmp;
+
+
+	// vertice 4 con los 4 de la otra hoja
+
+	dist4 = distan ( fourx, foury,fourz,x1,y1,z1);
+	
+	distmp = distan ( fourx, foury,fourz,x2,y2,z2);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( fourx, foury,fourz,x3,y3,z3);
+	if ( distmp < dist4) dist4 = distmp;
+	
+	distmp = distan ( fourx, foury,fourz,x4,y4,z4);
+	if ( distmp < dist4) dist4 = distmp;
+
+	//de entre estos cojo el máximo
+
+	dista =  max(dist1, max(dist2, max(dist3, dist4)));
+
+	//LO MISMO PERO A LA INVERSA
+
+	dist1 = distan ( x1,y1,z1, onex, oney, onez);
+	// vertice 1 con los 4 de la otra hoja
+
+	distmp = distan ( x1,y1,z1, twox, twoy, twoz);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( x1,y1,z1, threex, threey, threez);
+	if ( distmp < dist1) dist1 = distmp;
+
+	distmp = distan ( x1,y1,z1, fourx, foury, fourz);
+	if ( distmp < dist1) dist1 = distmp;
+
+	//2
+	dist2 = distan ( x2,y2,z2, onex, oney, onez);
+	// vertice 2 con los 4 de la otra hoja
+
+	distmp = distan ( x2,y2,z2, twox, twoy, twoz);
+	if ( distmp < dist2) dist2 = distmp;
+
+	distmp = distan ( x2,y2,z2, threex, threey, threez);
+	if ( distmp < dist2) dist2 = distmp;
+
+	distmp = distan ( x2,y2,z2, fourx, foury, fourz);
+	if ( distmp < dist2) dist2 = distmp;
+
+
+		//3
+	dist3 = distan ( x3,y3,z3, onex, oney, onez);
+	// vertice 3 con los 4 de la otra hoja
+
+	distmp = distan ( x3,y3,z3, twox, twoy, twoz);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( x3,y3,z3, threex, threey, threez);
+	if ( distmp < dist3) dist3 = distmp;
+
+	distmp = distan ( x3,y3,z3, fourx, foury, fourz);
+	if ( distmp < dist3) dist3 = distmp;
+
+		//4
+	dist4 = distan ( x4,y4,z4, onex, oney, onez);
+	// vertice 4 con los 4 de la otra hoja
+
+	distmp = distan ( x4,y4,z4, twox, twoy, twoz);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( x4,y4,z4, threex, threey, threez);
+	if ( distmp < dist4) dist4 = distmp;
+
+	distmp = distan ( x4,y4,z4, fourx, foury, fourz);
+	if ( distmp < dist4) dist4 = distmp;
+
+	//
+	distb =  max(dist1, max(dist2, max(dist3, dist4)));
+
+	dist  = max ( dista, distb);
+	return ( dist);
+	
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// CALCULA LA DISTANCIA ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+void DistanciaEntreHojas(void)
+{
+	float dist, distmp ;
+	int j;
+
+	for ( int i=0;i<counth;i++)
+	{
+		if ( Hojasa[i].existe == true) // si la hoja aun existe
+		{
+			// inicializo para poder comparar
+			if ( i == (counth-1)) j = 0; 
+				else j = i+1;
+			while (Hojasa[j].existe == false) j++;
+			//dist = Hojasa[i].Distancia(Hojasa[j]);
+			dist = Hausdorff( Hojasa[i], Hojasa[j]);
+
+			Hojasa[i].hoja_cerca = j;
+			// empiezo los calculos
+			for ( j =0; j<(counth-1);j++)
+			{
+				if ( j == i) 
+					break;
+				if ( Hojasa[j].existe == true) // si la hoja aun existe
+				{
+					distmp = Hausdorff(Hojasa[i], Hojasa[j]);
+					if ( distmp < dist ) 
+					{
+						dist = distmp;
+						Hojasa[i].hoja_cerca = j;
+					}
+				}
+				
+			}
+			Hojasa[i].dist = dist;
+		}
+	}
+
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// DEVUELVE LA HOJA QUE TIENE UNA DISTANCIA MENOR
+//--------------------------------------------------------------------------------------------------------------------------------
+long int MinimaDistancia ( void)
+{
+	float mindist =0;
+	long int cual=-1;
+	int i=0;
+	
+	//inicializo
+	while (Hojasa[i].existe != true) i++;
+	mindist = Hojasa[i].dist;
+	cual =i;
+	//busco la minima
+	for ( i=0;i<counth;i++)
+	{
+		if (Hojasa[i].existe == true)
+		{
+			if ( mindist> Hojasa[i].dist)
+			{
+				mindist = Hojasa[i].dist;
+				cual = i;
+			}
+		}
+		
+	}
+	return (cual);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// CALCULA LA COPLANARIDAD ENTRE HOJAS
+//--------------------------------------------------------------------------------------------------------------------------------
+
+void CoplanarEntreHojas(FILE* fp_coplanar)
+{
+	float cop, coptmp ;
+	int j, i;
+//	char linea[250];
+
+	for ( i=0;i<counth;i++)
+	{
+		if ( Hojasa[i].existe == true) // si la hoja aun existe
+		{
+			// inicializo para poder comparar
+			if ( i == (counth-1)) j = 0; 
+				else j = i+1;
+			while (Hojasa[j].existe == false) j++;
+			cop = Hojasa[i].Coplanaridad(Hojasa[j]);
+
+		
+
+			Hojasa[i].hoja_cop = j;
+			// empiezo los calculos
+			for ( j =0; j<(counth-1);j++)
+			{
+				if (( j != i) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+				{
+					coptmp = Hojasa[i].Coplanaridad(Hojasa[j]);
+					/*printf ("Hoja %i coplanaridad con hoja %i es %f\n", i, j,cop);
+					sprintf (linea,"%i %f\n",j, coptmp);
+					fputs (linea, fp_coplanar);*/
+
+					if ( coptmp > cop )  // COJO EL MAS COPLANAR , CERCANO A 1
+					{
+						cop = coptmp;
+						Hojasa[i].hoja_cop = j;
+					}
+				}
+				
+			}
+			Hojasa[i].coplanar = 1 - cop; //  8/6/01 LO INVIERTO
+		}
+	}
+	
+
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+// DEVUELVE LA HOJA QUE TIENE MÁS COPLANARIDAD// ya no vale. Ahora la buena será la minima 8/6/01
+//--------------------------------------------------------------------------------------------------------------------------------
+/*long int MaximaCoplanar ( void) 
+{
+	float maxcop =0;
+	long int cual=-1;
+	int i=0;
+	
+	//inicializo
+	while (Hojasa[i].existe != true) i++;
+	maxcop = Hojasa[i].coplanar;
+	cual =i;
+	//busco la minima
+	for ( i=0;i<counth;i++)
+	{
+		if (Hojasa[i].existe == true)
+		{
+			if ( maxcop < Hojasa[i].coplanar)
+			{
+				maxcop = Hojasa[i].coplanar;
+				cual = i;
+			}
+		}
+		
+	}
+	return (cual);
+}
+
+*/
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+void DosMayores(float *mayores, int* indices)
+{
+	
+	float m1;
+	int i;
+
+	if  ( mayores[0] < mayores[1])
+	{
+		m1= mayores[0];
+		mayores[0] = mayores[1];
+		mayores[1] = m1;
+
+		i = indices[0];
+		indices[0] = indices[1];
+		indices[1] = i;
+		
+	}
+
+	if ( mayores [2] < mayores [3])
+	{
+		m1 = mayores[2];
+		mayores[2] = mayores[3];
+		mayores [3] = m1;
+
+		i = indices[2];
+		indices[2] = indices[3];
+		indices[3] = i;
+
+	}
+
+	if  ( mayores[0] < mayores[2])
+	{
+		m1= mayores[0];
+		mayores[0] = mayores[2];
+		mayores[2] = m1;
+
+		i = indices[0];
+		indices[0] = indices[2];
+		indices[2] = i;
+
+	}
+
+
+	if ( mayores [2] < mayores [3])
+	{
+		m1 = mayores[2];
+		mayores[2] = mayores[3];
+		mayores [3] = m1;
+
+		i = indices[2];
+		indices[2] = indices[3];
+		indices[3] = i;
+
+	}
+
+	if ( mayores [1] < mayores [2])
+	{
+		m1 = mayores[1];
+		mayores[1] = mayores[2];
+		mayores [2] = m1;
+
+		i = indices[1];
+		indices[1] = indices[2];
+		indices[2] = i;
+
+	}
+
+			
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+float DiametroEsferaEnvolvente (FILE* fp_simplifica)
+{
+	float xmax, xmin, ymax, ymin, zmax, zmin;
+	float diametro, cx, cy, cz;
+	int j;
+	char linea[250];
+
+	//inicializo al primero de los vértices de las hojas
+
+	xmax = Vertex[Hojasa[0].Vertices[0]][0];
+	xmin = xmax;
+
+	ymax = Vertex[Hojasa[0].Vertices[0]][1];
+	ymin = ymax;
+
+	zmax = Vertex[Hojasa[0].Vertices[0]][2];
+	zmin = zmax;
+
+	// ahora busco los maximos y los minimos correspondientes
+
+
+	for ( int i=1;i<counth;i++)
+	{
+		for ( j=0;j<4;j++)
+		{
+			
+		if ( xmax < Vertex[Hojasa[i].Vertices[j]][0]) xmax = Vertex[Hojasa[i].Vertices[j]][0];
+		if ( xmin > Vertex[Hojasa[i].Vertices[j]][0]) xmin = Vertex[Hojasa[i].Vertices[j]][0];
+
+		if ( ymax < Vertex[Hojasa[i].Vertices[j]][1]) ymax = Vertex[Hojasa[i].Vertices[j]][1];
+		if ( ymin > Vertex[Hojasa[i].Vertices[j]][1]) ymin = Vertex[Hojasa[i].Vertices[j]][1];
+		
+		if ( zmax < Vertex[Hojasa[i].Vertices[j]][2]) zmax = Vertex[Hojasa[i].Vertices[j]][2];
+		if ( zmin > Vertex[Hojasa[i].Vertices[j]][2]) zmin = Vertex[Hojasa[i].Vertices[j]][2];
+
+		}
+	}
+
+	cx = (xmax + xmin)/2;
+	cy = (ymax + ymin)/2;
+	cz = (zmax + zmin)/2;
+
+
+	diametro = ((xmax-xmin)*(xmax-xmin)) + ((ymax-ymin)*(ymax-ymin)) + ((zmax-zmin)*(zmax-zmin));
+	//en la pantalla
+	printf ("Centro %f %f %f\n", cx,cy,cz );
+	//en el fichero
+	sprintf (linea,"Centro %f %f %f \n",cx, cy, cz);
+	fputs (linea, fp_simplifica);
+
+	// x
+	sprintf (linea,"x %f %f\n",xmax, xmin);
+	printf (linea,"x %f %f\n",xmax, xmin);
+	fputs (linea, fp_simplifica);
+	// y
+	sprintf (linea,"y %f %f\n",ymax, ymin);
+	printf (linea,"y %f %f\n",ymax, ymin);
+	fputs (linea, fp_simplifica);
+	// z
+	sprintf (linea,"z %f %f\n",zmax, zmin);
+	printf (linea,"z %f %f\n",zmax, zmin);
+	fputs (linea, fp_simplifica);
+
+
+return (diametro);
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  normaliza las distancia
+//--------------------------------------------------------------------------------------------------------------------------------
+void NormalizaDistancia (float diametro)
+{
+	float dtmp;
+	for (int i=0; i<counth;i++)
+	{
+		dtmp = Hojasa[i].dist;
+		Hojasa[i].dist = dtmp / diametro;
+		
+	}
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+//  establece el criterio como (K1 * dist + K2 * cop)/ K1+K2
+//--------------------------------------------------------------------------------------------------------------------------------
+void EstableceCriterio ( float diametro)
+{
+	//Para empezar establezco K1 y K2 con 0,5
+	float coptmp2, coptmp, distmp2, distmp, criteriotmp;
+	int i, j, nhojasi, nhojasj;
+
+
+	for ( i=0; i<counth;i++)
+
+	{
+		if (Hojasa[i].existe == true)
+		{
+			//incializo criterio a un numero elevado
+			Hojasa[i].criterio = 1000;
+			nhojasi = Hojasa[i].Cuantas_hojas;
+			//coplanaridad
+			for ( j =0; j<counth;j++)
+			{
+				if (( j != i) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+				{
+					//17/09/01 ANTES DE CALCULAR NADA, COMPRUEBO QUE ESTAS DOS HOJAS 
+					// SE PODRIAN COLAPSAR, ED, QUE LA DIFERENCIA DE HOJAS QUE COLAPSAN
+					// ES COMO MÁXIMO 1
+
+					nhojasj = Hojasa[j].Cuantas_hojas;
+
+					if ( abs((nhojasi - nhojasj)) < 2)
+					{
+					//coplanaridad y lo invierto
+					coptmp2 = Hojasa[i].Coplanaridad(Hojasa[j]); 
+					coptmp = 1 - coptmp2;
+					//distancia y la normalizo
+					distmp2 = Hausdorff( Hojasa[i], Hojasa[j]); 
+					distmp = distmp2 / diametro;
+					// calculo el criterio para esa hoja
+					criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+					//selecciono el criterio menor
+					if (Hojasa[i].criterio > criteriotmp) 
+					{Hojasa[i].criterio = criteriotmp;
+					Hojasa[i].hoja_crit = j;}
+
+					}
+				}
+				
+			}
+		//	printf ( "Criterio establecido para hoja %i \n", i);
+		}
+	}
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+//  establece el criterio despues de colapsar
+//--------------------------------------------------------------------------------------------------------------------------------
+void EstableceCriterio2 ( float diametro, long int hojanueva)
+{
+	//Para empezar establezco K1 y K2 con 0,5
+	float  coptmp2, coptmp, distmp2, distmp, criteriotmp;
+	int i, j, nhojasi, nhojasj;
+
+	//ESTAN EN tres PROCEDIMIENTOS: COLAPSA, ESTABLECECRITERIO Y ESTABLECECRITERIO2
+	
+
+	for ( i=0; i<counth;i++)
+	{
+		if ((Hojasa[i].existe == true) && (i != hojanueva))
+		{	
+			nhojasi = Hojasa[i].Cuantas_hojas;
+			//¿ SE HA DESACTIVADO LA HOJA_CRIT QUE GUARDABA LA HOJA?
+			if ( Hojasa[Hojasa[i].hoja_crit].existe == false)
+			{
+				Hojasa[i].criterio = 1000;
+
+				//coplanaridad
+				for ( j =0; j<counth;j++)
+				{
+					if (( j != i) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+					{
+
+				
+					//17/09/01 ANTES DE CALCULAR NADA, COMPRUEBO QUE ESTAS DOS HOJAS 
+					// SE PODRIAN COLAPSAR, ED, QUE LA DIFERENCIA DE HOJAS QUE COLAPSAN
+					// ES COMO MÁXIMO 1
+
+					nhojasj = Hojasa[j].Cuantas_hojas;
+
+					if ( abs((nhojasi - nhojasj)) < 2)
+					{
+
+						//coplanaridad y lo invierto
+						coptmp2 = Hojasa[i].Coplanaridad(Hojasa[j]); 
+						coptmp = 1 - coptmp2;	
+						//distancia y la normalizo	
+					//	distmp2 = Hojasa[i].Distancia(Hojasa[j]); 
+						distmp2 = Hausdorff( Hojasa[i],  Hojasa[j]); 
+						distmp = distmp2 / diametro;
+						// calculo el criterio para esa hoja
+						criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+						//selecciono el criterio menor
+						if (Hojasa[i].criterio > criteriotmp) 
+							{Hojasa[i].criterio = criteriotmp;
+							Hojasa[i].hoja_crit = j;}
+					}
+					}
+				}
+			}
+			else
+			{ // CALCULARE SI EL CRITERIO CON ESTA HOJA ES MENOR QUE EL ANTERIOR
+
+					nhojasj = Hojasa[hojanueva].Cuantas_hojas;//17/09/01
+
+						if ( abs((nhojasi - nhojasj)) < 2)
+						{
+
+
+						//coplanaridad y lo invierto
+						coptmp2 = Hojasa[i].Coplanaridad(Hojasa[hojanueva]); 
+						coptmp = 1 - coptmp2;
+						//distancia y la normalizo
+						//distmp2 = Hojasa[i].Distancia(Hojasa[hojanueva]); 
+						distmp2 = Hausdorff( Hojasa[i], Hojasa[hojanueva]); 
+						distmp = distmp2 / diametro;
+						// calculo el criterio para esa hoja
+						criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+						//selecciono el criterio menor
+						if (Hojasa[i].criterio > criteriotmp) 
+							{Hojasa[i].criterio = criteriotmp;
+							Hojasa[i].hoja_crit = hojanueva;
+							//printf ( "Cambio el criterio  para hoja %i \n", i);
+							}
+					}
+					}
+			}
+									
+			
+	}
+}
+//--------------------------------------------------------------------------------------------------------------------------------
+// DEVUELVE LA HOJA QUE TIENE EL NUMERO EN EL CAMPO CRITERIO MENOR
+//--------------------------------------------------------------------------------------------------------------------------------
+
+long int MinimoCriterio ( void)
+{
+	float mincrit =0;
+	long int cual=-1;
+	int i=0;
+	
+	//inicializo
+	while (Hojasa[i].existe != true) i++;
+	mincrit = Hojasa[i].criterio;
+	cual =i;
+	//busco la minima
+	for ( i=0;i<counth;i++)
+	{
+		if (Hojasa[i].existe == true)
+		{
+			if ( mincrit> Hojasa[i].criterio)
+			{
+				mincrit = Hojasa[i].criterio;
+				cual = i;
+			}
+		}
+		
+	}
+	return (cual);
+}
+
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// 
+//--------------------------------------------------------------------------------------------------------------------------------
+void ElijeVertices(Hoja& Hoja1, Hoja& Hoja2, long int count)
+{
+	// criterio es el de los dos vertices más alejados del centro de la otra hoja
+	
+	float a,b,c;
+	float dist[4];
+	int indices[4];
+	
+	// primero de la primera hoja cojo los dos primeros vertices
+
+
+	a = Vertex[Hoja1.Vertices[0]][0];
+	b = Vertex[Hoja1.Vertices[0]][1];
+	c = Vertex[Hoja1.Vertices[0]][2];
+
+	dist[0] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	
+	a = Vertex[Hoja1.Vertices[1]][0];
+	b = Vertex[Hoja1.Vertices[1]][1];
+	c = Vertex[Hoja1.Vertices[1]][2];
+
+	dist[1] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	a = Vertex[Hoja1.Vertices[2]][0];
+	b = Vertex[Hoja1.Vertices[2]][1];
+	c = Vertex[Hoja1.Vertices[2]][2];
+
+	dist[2] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+
+	a = Vertex[Hoja1.Vertices[3]][0];
+	b = Vertex[Hoja1.Vertices[3]][1];
+	c = Vertex[Hoja1.Vertices[3]][2];
+
+	dist[3] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja2.Centro[1]-b)*(Hoja2.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	for ( int i=0;i<4;i++) indices[i]=i;
+
+	DosMayores(dist, indices);
+	
+	Hojasa[counth].Vertices[0] = Hoja1.Vertices[indices[0]]; 
+	Hojasa[counth].Vertices[1] = Hoja1.Vertices[indices[1]]; 
+	
+	// segunda hoja los dos ultimos vertices
+
+	
+	a = Vertex[Hoja2.Vertices[0]][0];
+	b = Vertex[Hoja2.Vertices[0]][1];
+	c = Vertex[Hoja2.Vertices[0]][2];
+
+	dist[0] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+	
+	a = Vertex[Hoja2.Vertices[1]][0];
+	b = Vertex[Hoja2.Vertices[1]][1];
+	c = Vertex[Hoja2.Vertices[1]][2];
+
+	dist[1] = ((Hoja2.Centro[0]-a)*(Hoja2.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja2.Centro[2]-c)*(Hoja2.Centro[2]-c));
+
+	a = Vertex[Hoja2.Vertices[2]][0];
+	b = Vertex[Hoja2.Vertices[2]][1];
+	c = Vertex[Hoja2.Vertices[2]][2];
+
+	dist[2] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+
+	a = Vertex[Hoja2.Vertices[3]][0];
+	b = Vertex[Hoja2.Vertices[3]][1];
+	c = Vertex[Hoja2.Vertices[3]][2];
+
+	dist[3] = ((Hoja1.Centro[0]-a)*(Hoja1.Centro[0]-a)) + ((Hoja1.Centro[1]-b)*(Hoja1.Centro[1]-b)) +
+		   ((Hoja1.Centro[2]-c)*(Hoja1.Centro[2]-c));
+
+	for ( int i=0;i<4;i++) indices[i]=i;
+
+	DosMayores(dist, indices);
+	
+	Hojasa[counth].Vertices[2] = Hoja2.Vertices[indices[0]]; 
+	Hojasa[counth].Vertices[3] = Hoja2.Vertices[indices[1]]; 
+
+
+
+	
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// AÑADE HOJAS 
+//--------------------------------------------------------------------------------------------------------------------------------
+long int Colapsa (FILE *fp_simplifica, float diametro)
+{
+	long int i=0, cual=-1;
+	long int otra = -1;
+	float coptmp, coptmp2, distmp, distmp2, criteriotmp;
+	char linea[250];
+
+
+//	cual=MinimaDistancia();
+	cual=MinimoCriterio();
+//	otra = Hojasa[cual].hoja_cerca; //para la distancia
+//	otra = Hojasa[cual].hoja_cop;
+	otra = Hojasa[cual].hoja_crit;
+
+
+	//desactivo las hojas cercanas
+	Hojasa[cual].existe = false;
+	Hojasa[otra].existe = false;
+	//creo la hoja nueva
+
+	Hojasa[counth].hoja_cerca = -1;
+	Hojasa[counth].dist = 0;
+	Hojasa[counth].hoja_cop = -1;
+	Hojasa[counth].coplanar = 0;
+
+	Hojasa[counth].Cuantas_hojas = Hojasa[cual].Cuantas_hojas + Hojasa[otra].Cuantas_hojas;
+	ElijeVertices(Hojasa[cual], Hojasa[otra], counth);
+	Centroh (Hojasa[counth]);
+	GetNormal ( Hojasa[counth]);
+
+	//18/09/01 
+	if (	Hojasa[counth].Cuantas_hojas > 60 )
+	{
+			Hojasa[counth].existe = false;
+			activas--;
+	}
+	else
+	{
+
+
+	 //establezco el criterio para la hoja nueva
+     	 Hojasa[counth].existe = true;
+		Hojasa[counth].criterio = 1000; 
+ 		//coplanaridad
+		for ( int j =0; j<(counth+1);j++)
+		{
+			if (( j != counth) && ( Hojasa[j].existe == true)) // si la hoja aun existe
+			{
+			//coplanaridad y lo invierto
+			coptmp2 = Hojasa[counth].Coplanaridad(Hojasa[j]); 
+			coptmp = 1 - coptmp2;
+			//distancia y la normalizo
+			//distmp2 = Hojasa[counth].Distancia(Hojasa[j]); 
+			distmp2 = Hausdorff( Hojasa[counth], Hojasa[j]); 
+			distmp = distmp2 / diametro;
+			// calculo el criterio para esa hoja
+			criteriotmp = (( K1 * distmp * distmp ) + (K2 * coptmp * distmp))/ (K1 + K2);
+			//selecciono el criterio menor
+			if (Hojasa[counth].criterio > criteriotmp) 
+				{Hojasa[counth].criterio = criteriotmp;
+				Hojasa[counth].hoja_crit = j;}
+
+			}
+		}
+
+	}	
+	//en la pantalla
+//	printf ("Nuevo %i Ver %lu %lu %lu %lu  Tviej %lu %lu Engloba %i\n",
+//		      counth, Hojasa[counth].Vertices[0], Hojasa[counth].Vertices[1], Hojasa[counth].Vertices[2],
+//			  Hojasa[counth].Vertices[3], cual, otra, Hojasa[counth].Cuantas_hojas);
+
+	//en el fichero
+	sprintf (linea,"Nuevo %i Ver %lu %lu %lu %lu  T_viej %lu %lu Engloba %i\n",
+		      counth, Hojasa[counth].Vertices[0], Hojasa[counth].Vertices[1], Hojasa[counth].Vertices[2],
+			  Hojasa[counth].Vertices[3], cual, otra, Hojasa[counth].Cuantas_hojas);
+	fputs (linea, fp_simplifica);
+
+
+	//incremento el numero de hojas
+	counth++;
+	activas--;
+
+	return (counth-1);//porque lo he incrementado en la linea de antes
+
+}
+
+void simplifica(void){
+	long int totalv=0, hnueva;
+	float diam;
+
+	FILE* fp_simplifica;
+	diam = DiametroEsferaEnvolvente(fp_simplifica );
+	EstableceCriterio (diam);
+	
+	while ( activas > 20) {
+		hnueva=Colapsa(fp_simplifica, diam);
+		EstableceCriterio2 (diam, hnueva);
+	}
+}
+
+//--------------------------------------------------------------------------------------------------------------------------------
+// MAIN DEL PROGRAMA
+//--------------------------------------------------------------------------------------------------------------------------------
+
+//int main (int argc, char ** argv)
+//{
+//
+//	long int totalv=0, hnueva;
+//	float diam;
+//	FILE* fp_simplifica;
+////	FILE* fp_criterio;
+//
+//	first = time(NULL);
+//
+//	char fvertices[100],fhojas[100],fsalida[100];
+//	strcpy(fvertices,"H:\\GTGeometry\\tests\\bin\\vertices.obj\0");
+//	strcpy(fhojas,"H:\\GTGeometry\\tests\\bin\\hojas.obj\0");
+//	strcpy(fsalida,"H:\\GTGeometry\\tests\\bin\\salida.kk\0");
+//
+//	argc=4;
+//	if (argc != 4) {// el 0 es el nombre del programa
+//		puts ("Sintaxis: fichero_arbol fichero_hojas fichero_simplif");
+//		getchar();
+//		return -1;
+//	}
+//	
+//	//cuento todos los vertices, y relleno la estructura
+//	totalv = LeeVertices(fvertices);
+//
+//	//cuento las hojas
+//	counth= CuentaHojas (fhojas);
+//	printf ("Hay %lu hojas\n", counth);
+//
+//	// lleno la estructura de datos de las hojas ( inicial y activas)
+//	printf ("Ahora las leo\n");
+//	LeoHojas(fhojas);
+////	DistanciaEntreHojas();
+////	CoplanarEntreHojas(fp_coplanar);
+//	if ((fp_simplifica = fopen (fsalida, "w")) == NULL)
+//		printf ("No puedo abrir el fichero %s\n", argv[3]);
+//	else
+//	{	
+//	
+//		diam = DiametroEsferaEnvolvente(fp_simplifica );
+//		EstableceCriterio (diam);
+//	//
+//		/*if ((fp_criterio = fopen ("criterio.obj", "w")) == NULL)
+//		printf ("No puedo abrir el fichero distancias\n");
+//		else 
+//		EscribeCriterio(fp_criterio);
+//
+//		*/while ( activas > 20)
+//		{
+//			hnueva=Colapsa(fp_simplifica, diam);
+//			EstableceCriterio2 (diam, hnueva);
+//		//	EscribeCriterio(fp_criterio);
+//
+//
+//		}
+//	
+//		fclose ( fp_simplifica);
+//	//	fclose ( fp_criterio);
+//	}
+//
+//	second = time(NULL);
+//	printf("Diferencia: %f segundos\n", difftime(second, first));
+//	getchar();	
+//	return 0;
+//}//main
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsConstructor.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsConstructor.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoLodStripsConstructor.cpp	(revision 774)
@@ -0,0 +1,1124 @@
+#include <iostream>
+#include <fstream>
+
+#include "GeoLodStripsConstructor.h"
+
+using namespace Geometry;
+
+//--------------------------------------------------------------------------
+//Call GenerarModeloV and CopiarVectorsArraysNUEVAED to make changes
+//---------------------------------------------------------------------------
+//	Se utiliza en el constructor sobrecargado.
+void LodStripsConstructor::GenerarModeloCompleto(TIPOFUNC	upb)
+{	
+	float	percent;
+
+	percent	=	10;
+
+	this->GenerarModeloV(upb);
+	this->CopiarVectors2ArraysNUEVAED();
+
+	//	Last updtate of the progress bar.
+	upb(percent);
+}
+
+//-----------------------------------------------------------------------------------
+//It makes Lods changes and count them
+//-----------------------------------------------------------------------------------
+void LodStripsConstructor::CalcularCambiosLODsVNuevaED(TIPOFUNC upb)
+{
+//	LODPosition						pos;
+//	vector	<LODPosition>	listaPos;
+	long 		int							k;
+	long 		int							i;
+	long 		int							t;
+	long 		int							r;
+	long 		int							v;
+	long 		int							p0;
+	long 		int							lod	=	0;
+	long 		int							sigue;
+	long 		int							ac[3]	=	{0,0,0};
+	long 		int							totalRegs	=	0;
+	long 		int							RegsCambios;
+	vector	<VECTORINT>			TiraOriginal;
+	LODData 						regLOD;
+	LODChanges						listaCambios;
+	uint32								CreaTira;
+	float	percent;
+	long	int	update;
+
+	//	Guardamos copia original.
+	TiraOriginal	=	this->cStrips;
+
+	this->MARCAVACIO	=	10 * this->cVerts.size();
+	
+	listaCambios.clear();
+
+	update	=	0;
+	
+	for	(lod = 0; ((this->cVerts[lod].Next) != -1); lod++)
+	{
+		update++;
+	}
+
+	update	=	update	/ 20;
+	percent	=	0.5;
+	
+	this->LodsDisp	=	this->TOTALCAMBIOS	=	lod;
+	pCambios				=	new uint32[this->TOTALCAMBIOS];
+	pCambios[0]			=	0;
+	
+	//	5 min.
+	for	(lod = 0; ((this->cVerts[lod].Next) != -1); lod++)
+	{
+		if ((lod % update) == 0)
+		{
+			upb(percent);
+		}
+		
+		RegsCambios				=	0;
+		regLOD.obligatory	=	this->Ordenacion[lod].obligatorio;
+		
+		for(t = 0; t < this->cStrips.size(); t++)
+		{
+			//Inicializar
+			regLOD.strip	=	this->MARCAVACIO;
+
+			//PRIMERO: los cambios de los vertices
+			totalRegs		=	0;
+			
+			for (v = 0; v < this->cStrips[t].size(); v++)
+			{
+				//	RESOLUCION VARIABLE MAL.
+				if (this->cStrips[t][v] == lod)	
+				{ 
+					//Gestion de Tiras.
+					if (regLOD.strip == this->MARCAVACIO)
+					{
+						regLOD.strip	=	t;
+					}
+					
+					++totalRegs;
+
+					cDatos.push_back(v);
+
+					this->cStrips[t][v]	=	this->cVerts[lod].Next;
+				}
+			}
+			
+			regLOD.nP	=	totalRegs;
+
+			//SEGUNDO: Simplificaciones de Longitud 1
+			// Cambio para simplifaciones de nivel 1 mayores de 2
+			totalRegs	=	0;
+			i					=	0;
+			r					=	0;
+			sigue			=	0;
+			k					=	this->cStrips[t].size()-3;
+			
+			while (i < k)
+			{
+				if (	(this->cStrips[t][i] == this->cStrips[t][i+1])
+							&&
+							(this->cStrips[t][i+1] == this->cStrips[t][i+2])
+						)
+				{ 
+					//	Salvar el inicio de la repeticion.
+					if (!r)
+					{
+						p0	=	i;
+					}
+					
+					this->cStrips[t].erase(this->cStrips[t].begin()+i);
+					i--;
+					r++;
+					
+					if ((i+1) != this->cStrips[t].size()-1)
+					{
+						sigue	=	1;
+					}
+					else
+					{
+						sigue	=	0;
+					}
+					
+				}
+				else
+				{
+					sigue	=	0;
+				}
+
+				if (!sigue && r)
+				{
+					if (regLOD.strip == this->MARCAVACIO)
+					{
+						regLOD.strip	=	t;
+					}
+					
+					++totalRegs;
+
+					cDatos.push_back(p0);
+					cDatos.push_back(r);
+
+					r	=	0;
+					k	=	this->cStrips[t].size()-r-3;
+				}
+
+				i++;
+			}
+			
+			regLOD.nL1	=	totalRegs;
+
+			//TERCERO: Simplificaciones de Longitud 2 tipo V1 V2 V1 V2 -> V1 V2
+			totalRegs	=	0;
+			i					=	0;
+			r					=	0;
+			sigue			=	0;
+			k					=	this->cStrips[t].size() - 4;
+			
+			while	(i < k)
+			{
+				if (	(this->cStrips[t][i] == this->cStrips[t][i+2])
+							&&
+							(this->cStrips[t][i+1] == this->cStrips[t][i+3])
+						)
+				{
+					if (!r)
+					{
+						p0	=	i;
+					}
+					
+					this->cStrips[t].erase(this->cStrips[t].begin()+i);
+					this->cStrips[t].erase(this->cStrips[t].begin()+i);
+					r++;
+					
+					i	-=	2;
+					
+					if ((i+1) != this->cStrips[t].size()-3)
+					{
+						sigue	=	1;
+					}
+					else
+					{
+						sigue	=	0;
+					}
+					
+				}
+				else
+				{
+					sigue	=	0;
+				}
+
+				if (!sigue && r)
+				{
+					if (regLOD.strip == this->MARCAVACIO)
+					{
+						regLOD.strip	=	t;
+					}
+					
+					++totalRegs;
+
+					cDatos.push_back(p0);
+					cDatos.push_back(r);
+					
+					r	=	0;
+					k	=	this->cStrips[t].size()-4-2*r;
+				}
+
+				i++;
+			}
+			
+			regLOD.nL2	=	totalRegs;
+			
+			if (regLOD.strip != this->MARCAVACIO)
+			{
+				RegsCambios++;
+				listaCambios.push_back(regLOD);
+			}
+		}//	End for t.
+		
+		pCambios[lod]	=	RegsCambios;
+	}//	End for lod.
+
+	this->cCambios	=	listaCambios;
+
+	//	Guardar el numero de LODS disponibles.
+	this->TOTALCAMBIOS	=	this->LodsDisp=lod;
+
+	//Retornar a la lista original
+	this->cStrips	=	TiraOriginal;
+}
+
+//-----------------------------------------------------------------------
+//Put in order vertex of Mesh from simplification sequence
+//-----------------------------------------------------------------------
+void LodStripsConstructor::OrdenarModeloVQSLIM(TIPOFUNC	upb)
+{
+	long int i;
+	long int j;
+	long int t;
+	long int v;
+	long int vSig;
+	long int k;
+	VECTORVERTEX				Vertices;
+	VECTORVERTEX				NuevosVerts;
+	vector	<VECTORINT>	NuevasTiras;
+	VECTORINT						tira;
+	vector	<Index>			mV1Aux;
+	tipoOrden						Orden;
+	tipoOrden						*Ord;
+	bool								bEncontrado;
+	long	int						c1;
+	long	int						c2;
+	//	Progress bar
+	float	percent;
+	long	int	update;
+
+	bEncontrado = false;
+
+	c1	=	0;
+	c2	=	0;
+	
+	update	=	geoMeshSQ->mSteps.size() / 20;
+	percent	=	0.5;
+	
+	for	(i = 0; i < this->geoMeshSQ->mSteps.size(); i++)
+	{
+		if ((i % update) == 0)
+		{
+			upb(percent);
+		}
+		
+		mV1Aux.push_back(this->geoMeshSQ->mSteps[i].mV1);
+
+		Orden.vQslimNext	=	this->geoMeshSQ->mSteps[i].mV0;
+		Orden.vQslim			=	this->geoMeshSQ->mSteps[i].mV1;
+		Orden.obligatorio	=	this->geoMeshSQ->mSteps[i].obligatorio;
+		Orden.vLS					=	i;
+
+		Orden.x						=	this->geoMeshSQ->mSteps[i].x;
+		Orden.vLSNext			=	-1;
+		Orden.cambio			=	"n";
+
+		Ordenacion.push_back(Orden);
+	}
+
+	this->NumVertsRepetidos = c2;
+
+	update	=	Ordenacion.size() / 20;
+	percent	=	0.5;
+
+	//	1 min.
+	//	Change all vertices that have x != 0.
+	for(i=0;i<Ordenacion.size();i++)
+	{
+		if ((i % update) == 0)
+		{
+			upb(percent);
+		}
+
+		Ord	=	&(Ordenacion[i]);
+
+		if (Ord->x!=0)
+		{
+			//	Change the simplification order.
+			v								=	Ord->vQslim;
+			Ord->vQslim			=	Ord->vQslimNext;
+			Ord->vQslimNext	=	v;
+
+			for (j = i+1; j < Ordenacion.size(); j++)
+			{
+				if (Ordenacion[j].vQslim == Ord->vQslim)
+				{
+					Ordenacion[j].vQslim	=	Ord->vQslimNext;
+					Ordenacion[j].cambio	=	"y";
+				}
+				else if (Ordenacion[j].vQslimNext == Ord->vQslim)
+				{
+					Ordenacion[j].vQslimNext	=	Ord->vQslimNext;	
+					Ordenacion[j].cambio			=	"y";
+				}
+			}
+		}
+	}
+
+	update	=	Ordenacion.size() / 20;
+	percent	=	0.5;
+
+	//	3 seg.
+	//Ordenacion de los vertices
+	for(i = 0; i < Ordenacion.size(); i++)
+	{
+		if ((i % update) == 0)
+		{
+			upb(percent);
+		}
+
+		c1++;
+		NuevosVerts.push_back(this->cVerts[Ordenacion[i].vQslim]);
+
+		cVerts[Ordenacion[i].vQslim].Next	=	-1;
+
+	}
+
+	//	Añadir aquellos vertices que no estaban en NuevosVerts 
+	//	y no se simplificaban.
+	int cont				=	0;
+	int contestaban	=	0;
+
+	for(i = 0; i < this->cVerts.size(); i++)
+	{
+		if (this->cVerts[i].Next != -1)
+		{
+			cont++;
+			NuevosVerts.push_back(this->cVerts[i]);
+			Orden.vLS					=	Ordenacion.size();
+			Orden.obligatorio	= 0;
+			Orden.vLSNext			=	-1;
+			Orden.vQslim			=	i;
+			Orden.vQslimNext	=	-1;
+
+			Ordenacion.push_back(Orden);
+		}
+		else
+		{
+			contestaban++;
+		}
+	}
+
+	update	=	Ordenacion.size() / 20;
+	percent	=	0.5;
+	
+	//	2 min.
+	//	Calcular los siguiente teniendo en cuenta el QSLIM.
+	for (i = 0; i < Ordenacion.size(); i++)
+	{
+		if ((i % update) == 0)
+		{
+			upb(percent);
+		}
+
+		v	=	Ordenacion[i].vQslimNext;
+
+		//Buscar ese vertice v cual es ahora
+		vSig	=	0;
+
+		for (t = 0; t < Ordenacion.size() && !vSig;t++)
+		{
+			if (Ordenacion[t].vQslim==v)
+			{
+				vSig=Ordenacion[t].vLS;
+			}
+		}
+
+		if (vSig!=0)
+		{
+			Ordenacion[i].vLSNext	=	vSig;
+		}
+	}
+
+	//Creacion de nuevas tiras con las mismas dimensiones
+	for(t = 0; t < this->cStrips.size(); t++)
+	{
+		tira.clear();
+
+		for(i = 0; i < this->cStrips[t].size(); i++)
+		{
+			tira.push_back(0);
+		}
+
+		NuevasTiras.push_back(tira);
+	}
+
+	update	=	NuevosVerts.size() / 40;
+	percent	=	0.5;
+
+	k	=	0;
+
+	//	2 min.
+	//Cambiar los vertices de las tiras
+	for(v = 0; v < NuevosVerts.size(); v++)
+	{
+		if ((v % update) == 0)
+		{
+			upb(percent);
+		}
+
+		for(t = 0; t < this->cStrips.size(); t++)
+		{
+			for(i = 0; i < this->cStrips[t].size(); i++)
+			{
+				if (this->cStrips[t][i] == Ordenacion[v].vQslim)
+				{
+					k++;
+					NuevasTiras[t][i]	=	v;
+				}
+			}
+		}
+	}
+
+	//Cambiar a Tiras Nuevas
+	this->cStrips	=	NuevasTiras;
+
+	//NuevosVerts y Ordenacion = tamaño.
+	for(i = 0; i < NuevosVerts.size(); i++)
+	{
+		NuevosVerts[i].Next	=	Ordenacion[i].vLSNext;
+	}
+
+	//Cambiar cVerts por nuevosVerts.
+	this->cVerts	=	NuevosVerts;
+
+	percent	=	10;
+	upb(percent);
+}		
+
+//-----------------------------------------------------------------------------
+//	Constructor of LodStripsConstructor object from
+//	a Mesh and MeshSimplificationSequence
+//	Constructor del objeto LodStripsConstructor.
+//	Tomamos el Mesh y la secuencia de simplificacion que se pasan
+//	como parametros y llamamos a la funcion GenerarModeloCompleto para
+//	que se realicen las modificaciones a efectuar
+//-----------------------------------------------------------------------------
+LodStripsConstructor::LodStripsConstructor(const Mesh						*m,
+										   				const MeshSimplificationSequence	*ms,
+															TIPOFUNC													upb)
+{
+	MARCA	=	TOTALTIRAS	=	TOTALVERTS	=	TOTALCAMBIOS	=	0;
+	
+	meshoriginal		=	m;
+	this->geoMesh		=	new Geometry::Mesh();
+	*this->geoMesh	=	*m;
+	this->geoMeshSQ = ms;
+
+	this->GenerarModeloCompleto(upb);
+}
+
+//---------------------------------------------
+//	Destructor LodStripsConstructor object
+//	Destructor de la clase LodStripsConstructor
+//---------------------------------------------
+LodStripsConstructor::~LodStripsConstructor()
+{
+	uint32 i,j;
+
+	delete [] vDatos;
+	delete [] vCambios;
+	vector <LODData> cCambiosTemp;
+	cCambios.swap(cCambiosTemp);
+
+	VECTORUNINT cDatosTemp;
+	cDatos.swap(cDatosTemp);
+
+	delete [] vStrips;
+
+	delete [] vVerts;
+
+	vector <VECTORINT> cStripsTemp;
+	cStrips.swap(cStripsTemp);;
+
+	VECTORVERTEX cVertsTemp;
+	cVerts.swap(cVertsTemp);
+
+	delete [] pCambios;
+
+	delete this->geoMesh;
+}
+
+//------------------------------------------------------------------------------
+//	build lod file with necessary information and save all changes at
+//	lodStripConstructor object
+//	Construimos el archivo Lod donde se guarda la informacion sobre los
+//	cambios realizados en el mesh
+//	y copiamos todos los cambios realizados sobre las estructuras que
+//	contienen los vertices y los indices 
+//	modificados sobre el objeto Mesh de la clase
+//------------------------------------------------------------------------------
+void LodStripsConstructor::Save(Serializer &oSerializer)
+{
+	int		i,j,k=0,s;
+	char	simp[256];
+
+	Geometry::Index	pos;
+	float						fx,	fy,	fz;
+
+	//******************  1º CONSTRUCCION DEL FICHERO.LOD *********************
+
+	//	VERTICES.
+	for(i = 0; i < this->cVerts.size(); i++)
+	{
+		sprintf(simp,"v %d\n",cVerts[i].Next);
+		oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+	}
+
+	//	CSTRIPS.
+	this->TOTALINDICES	=	0;
+	
+	for(i = 0; i < this->cStrips.size(); i++)
+	{
+		this->TOTALINDICES += this->cStrips[i].size();
+	}
+
+	//	lines starting with a d.
+	//	Changes
+	for(i = 0; i < this->cCambios.size(); i++)
+	{
+		sprintf(simp,"c\n");
+		oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+		
+		sprintf(simp,
+						"d %u %u %u %u %u\n",
+						cCambios[i].strip,
+						cCambios[i].nP,
+						cCambios[i].nL1,
+						cCambios[i].nL2,
+						cCambios[i].obligatory);
+		
+		oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+	}
+
+	//	Lines starting with a b.
+	//	Data.
+	sprintf(simp,"a\n");
+	oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+	
+	for(i = 0; i < this->cDatos.size(); i++)
+	{
+		sprintf(simp,"b %d\n",cDatos[i]);
+
+		oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+	}
+
+	//	lines starting with a p.
+	//	Chages made in a LOD.
+	for(i = 0; i < this->TOTALCAMBIOS; i++)
+	{
+		sprintf(simp,"p %d\n",this->pCambios[i]);
+
+		oSerializer.WriteData(simp,sizeof(char),strlen(simp));
+	}
+
+	oSerializer.WriteData("\n",sizeof(char),1);
+
+	//*******************  2º DEVOLVER EL MESH CON LAS MODIFICACIONES EFECTUADAS  *********************
+	int num_no	=	0;
+
+	if(this->geoMesh->mSubMesh[0].mSharedVertexBuffer == true)
+	{
+		//mPosition
+		delete[] this->geoMesh->mVertexBuffer->mPosition;
+		this->geoMesh->mVertexBuffer->mPosition = new Vector3[this->cVerts.size()];
+
+		//mNormal
+		if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+		{
+			delete[] this->geoMesh->mVertexBuffer->mNormal;
+			this->geoMesh->mVertexBuffer->mNormal = new Vector3[this->cVerts.size()];
+		}
+
+		//mTexCoords
+		if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+		{
+			delete[] this->geoMesh->mVertexBuffer->mTexCoords;
+			this->geoMesh->mVertexBuffer->mTexCoords = new Vector2[this->cVerts.size()];
+		}
+
+		this->geoMesh->mVertexBuffer->mVertexCount	=	this->cVerts.size();
+		this->geoMesh->mVertexBuffer->mVertexInfo		=	this->meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo;
+
+		for(i = 0; i < this->geoMesh->mSubMeshCount; i++)
+		{
+			this->geoMesh->mSubMesh[i].mVertexBuffer				=	this->geoMesh->mVertexBuffer;
+			this->geoMesh->mSubMesh[i].mSharedVertexBuffer	=	true;
+		}
+
+		int	indice	=	0;
+
+		for (j = 0; j < this->cVerts.size(); j++)
+		{
+			//Copiamos las coordeandas de posicion 
+			this->geoMesh->mVertexBuffer->mPosition[indice].x	=	this->cVerts[j].Vertex[0];
+			this->geoMesh->mVertexBuffer->mPosition[indice].y	=	this->cVerts[j].Vertex[1];
+			this->geoMesh->mVertexBuffer->mPosition[indice].z	=	this->cVerts[j].Vertex[2];
+
+			//Copiamos las normales
+			if (meshoriginal->mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+			{
+				this->geoMesh->mVertexBuffer->mNormal[indice].x	=	this->cVerts[j].Normal[0];
+				this->geoMesh->mVertexBuffer->mNormal[indice].y	=	this->cVerts[j].Normal[1];
+				this->geoMesh->mVertexBuffer->mNormal[indice].z	=	this->cVerts[j].Normal[2];
+			}
+
+			//Copiamos las coordenadas de textura
+			if (meshoriginal->mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+			{
+				this->geoMesh->mVertexBuffer->mTexCoords[indice].x	=	this->cVerts[j].TexCoords[0];
+				this->geoMesh->mVertexBuffer->mTexCoords[indice].y	=	this->cVerts[j].TexCoords[1];
+			}
+
+			indice++;
+
+		}
+
+		this->geoMesh->mVertexBuffer->mVertexCount	=	indice;
+	}
+	else	//OSCAR
+	{
+		//Supondre que solo tengo un submesh con vertices no compartidos
+		//mPosition
+		delete[]	this->geoMesh->mSubMesh[0].mVertexBuffer->mPosition;
+		
+		this->geoMesh->mSubMesh[0].mVertexBuffer->mPosition	=	new Vector3[this->cVerts.size()];
+
+		//mNormal
+		if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+		{
+			delete[] this->geoMesh->mSubMesh[0].mVertexBuffer->mNormal;
+			this->geoMesh->mSubMesh[0].mVertexBuffer->mNormal = new Vector3[this->cVerts.size()];
+		}
+
+		//mTexCoords
+		if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+		{
+			delete[] this->geoMesh->mSubMesh[0].mVertexBuffer->mTexCoords;
+			this->geoMesh->mSubMesh[0].mVertexBuffer->mTexCoords = new Vector2[this->cVerts.size()];
+		}
+
+		this->geoMesh->mSubMesh[0].mVertexBuffer->mVertexCount =this->cVerts.size();
+		this->geoMesh->mSubMesh[0].mVertexBuffer->mVertexInfo = this->meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo;
+
+		this->geoMesh->mSubMesh[0].mSharedVertexBuffer=false;
+
+		int indice=0;
+		for (j=0; j<this->cVerts.size(); j++)
+		{
+			//Copiamos las coordeandas de posicion 
+			this->geoMesh->mSubMesh[0].mVertexBuffer->mPosition[indice].x=this->cVerts[j].Vertex[0];
+			this->geoMesh->mSubMesh[0].mVertexBuffer->mPosition[indice].y=this->cVerts[j].Vertex[1];
+			this->geoMesh->mSubMesh[0].mVertexBuffer->mPosition[indice].z=this->cVerts[j].Vertex[2];
+
+			//Copiamos las normales
+			if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+			{
+				this->geoMesh->mSubMesh[0].mVertexBuffer->mNormal[indice].x=this->cVerts[j].Normal[0];
+				this->geoMesh->mSubMesh[0].mVertexBuffer->mNormal[indice].y=this->cVerts[j].Normal[1];
+				this->geoMesh->mSubMesh[0].mVertexBuffer->mNormal[indice].z=this->cVerts[j].Normal[2];
+			}
+
+			//Copiamos las coordenadas de textura
+			if (meshoriginal->mSubMesh[0].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+			{
+				this->geoMesh->mSubMesh[0].mVertexBuffer->mTexCoords[indice].x=this->cVerts[j].TexCoords[0];
+				this->geoMesh->mSubMesh[0].mVertexBuffer->mTexCoords[indice].y=this->cVerts[j].TexCoords[1];
+			}
+			indice++;
+		}
+		this->geoMesh->mSubMesh[0].mVertexBuffer->mVertexCount =indice;
+	}
+	
+	int indice_acum = 0;
+	for(i=0;i<this->geoMesh->mSubMeshCount;i++)
+	{
+		for (size_t ind=0; ind < meshoriginal->mSubMesh[i].mIndexCount; ind++) 
+		{
+			if (meshoriginal->mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+			{
+				//Hay coordenadas de textura y normales
+				if(meshoriginal->mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+				{
+					for (size_t indvo=0; indvo<this->geoMesh->mSubMesh[i].mVertexBuffer->mVertexCount; indvo++)
+					{
+						if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mPosition[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mPosition[indvo]))
+						{
+							if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mNormal[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mNormal[indvo]))
+							{
+								if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mTexCoords[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mTexCoords[indvo]))
+								{
+									this->geoMesh->mSubMesh[i].mIndex[ind]=indvo;//+indice_acum;
+								}
+							}
+						}
+					}
+				}
+				else		//Hay coordenadas de textura pero no hay normales
+				{
+					for (size_t indvo=0; indvo<this->geoMesh->mSubMesh[i].mVertexBuffer->mVertexCount; indvo++)
+					{
+						if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mPosition[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mPosition[indvo]))
+						{
+							if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mTexCoords[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mTexCoords[indvo]))
+							{
+								this->geoMesh->mSubMesh[i].mIndex[ind]=indvo;//+indice_acum;
+							}
+						}
+					}
+				}
+			}
+			else
+			{
+				// No hay coordenadas de textura pero si normales
+				if(meshoriginal->mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+				{
+					for (size_t indvo=0; indvo<this->geoMesh->mSubMesh[i].mVertexBuffer->mVertexCount; indvo++)
+					{
+						if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mPosition[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mPosition[indvo]))
+						{
+							if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mNormal[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mNormal[indvo]))
+							{
+								this->geoMesh->mSubMesh[i].mIndex[ind]=indvo;//+indice_acum;
+							}
+						}
+					}
+				}
+				else		//No hay coordenadas de texturas ni normales
+				{
+					for (size_t indvo=0; indvo<this->geoMesh->mSubMesh[i].mVertexBuffer->mVertexCount; indvo++)
+					{
+						if (igual(meshoriginal->mSubMesh[i].mVertexBuffer->mPosition[meshoriginal->mSubMesh[i].mIndex[ind]],this->geoMesh->mSubMesh[i].mVertexBuffer->mPosition[indvo]))
+						{
+							this->geoMesh->mSubMesh[i].mIndex[ind]=indvo;//+indice_acum;
+						}
+					}
+				}
+			}
+		}
+
+	}
+
+}
+
+int LodStripsConstructor::igual(Geometry::Vector3 vo,Geometry::Vector3 vc)
+{
+	if (vo.x==vc.x && vo.y==vc.y && vo.z==vc.z)
+		return 1;
+	else
+		return 0;
+}
+
+int LodStripsConstructor::igual(Geometry::Vector2 vo,Geometry::Vector2 vc)
+{
+	if (vo.x==vc.x && vo.y==vc.y)
+		return 1;
+	else
+		return 0;
+}
+
+void LodStripsConstructor::Load(Serializer &oSerializer)
+{
+}
+
+//-----------------------------------------------------------------------------------------------
+//Call leeVerticesyTirasDeMesh, OrdenarModeloVQSLIM and CalcularCambiosLODsVNuevaED to make changes 
+//at vertex and index strutures
+//Llama a los metodos que realizan los cambios sobre las estructuras que contienen la informacion 
+//de los vertices y los indices
+//-----------------------------------------------------------------------------------------------
+void LodStripsConstructor::GenerarModeloV(TIPOFUNC	upb)
+{
+	long int	max;
+	long int	t;
+	long int	i;
+	float			percent;
+
+	percent	=	10;
+
+	this->leeVerticesyTirasDeMesh();
+
+	upb(percent);
+
+	//	6 min.
+	this->OrdenarModeloVQSLIM(upb);
+
+	//Calcular el tamaño maximo de tira
+	max	=	0;
+
+	for(i = 0; i < this->TOTALTIRAS; i++)
+	{
+		t	=	this->cStrips[i].size();
+		
+		if (t > max)
+		{
+			max	=	t;
+		}
+	}
+
+	this->MARCA	=	max + 1;
+
+	//	5 min.
+	this->CalcularCambiosLODsVNuevaED(upb);
+
+}
+
+//-----------------------------------------------------------------------------------------
+//It fills structs with vertex and index information
+//Rellena estructuras de datos que contienen la informacion de vertices y tiras modificadas
+//-----------------------------------------------------------------------------------------
+void LodStripsConstructor::CopiarVectors2ArraysNUEVAED()
+{
+	int32				i;
+	int32				j;
+	int32				*vertex;
+	int32				tActual;
+	uint32			max;
+	uint32			t;
+	uint32			CreaTira;
+	VECTORINT		tira;
+	LODData			RegLOD;
+	LODChanges	listaCambios;
+
+	//	ALLOCATE----------------
+	this->TOTALVERTS	=	this->cVerts.size();
+	this->TOTALTIRAS	=	this->cStrips.size();
+	this->vVerts			=	new tipoVertice[this->TOTALVERTS];
+	this->lStripsV		=	new VECTORINT[this->TOTALTIRAS];
+	this->vDatos			=	new uint32[cDatos.size()];
+	
+	//	Calcular el tamaño maximo de tira y el numero de caras total.
+	max								=	0;
+	this->TOTALCARAS	=	0;
+
+	for	(i = 0; i < this->cStrips.size(); i++)
+	{
+		t	=	this->cStrips[i].size();
+		
+		if (t > max)
+		{
+			max	=	t;
+		}
+
+		this->TOTALCARAS	+=	(t-2);
+	}
+	
+	this->vStrips	=	Allocate2DArrayINT(this->TOTALTIRAS,max+1);
+	this->MARCA		=	this->cVerts.size();
+	vCambios			=	new LODData[this->cCambios.size()];
+	
+	//	Rellenar vChanges.
+	for	(i = 0; i < this->cCambios.size();++i)
+	{
+		vCambios[i]	=	cCambios[i];
+	}
+	
+	for (i = 0; i < this->cStrips.size(); i++)
+	{
+		for (j = 0; j < this->cStrips[i].size(); j++)
+		{
+			//	Rellenar el array vStrips.
+			this->vStrips[i][j]	= this->cStrips[i][j];
+			
+			//	Rellenar el vVector.
+			this->lStripsV[i].push_back(this->cStrips[i][j]);
+		}
+		
+		this->vStrips[i][j]	=	this->MARCA;
+	}
+
+	for (i = 0; i < cDatos.size(); i++)
+	{
+		vDatos[i]	=	cDatos[i];
+	}
+	
+	pCurrentData	=	vDatos;
+
+	//	Meter los vertices en vVerts.
+	for	(i = 0; i < this->cVerts.size(); i++)
+	{
+		this->vVerts[i]	=	this->cVerts[i];
+	}
+
+}
+
+//---------------------------------------------------------------------------------------------------
+//It fills cVerts and cStrips with original Mesh vertex and strips information 
+//Rellena las estructuras cVerts Y cStrips a partir de de los vertices y las tiras del mesh original
+//---------------------------------------------------------------------------------------------------
+void LodStripsConstructor::leeVerticesyTirasDeMesh()
+{
+	tipoVertice	vAux;
+	VECTORINT		tira;
+	size_t			i;
+	size_t			j;
+	bool				error;
+
+	error	=	false;
+	
+	if(this->geoMesh->mSubMeshCount == 1)
+	{
+		error	=	false;
+	}
+	else
+	{
+		for	(i = 0; i < this->geoMesh->mSubMeshCount;i++)
+		{
+			if	(this->geoMesh->mSubMesh[i].mSharedVertexBuffer == true)
+			{
+				error	=	false;
+			}
+			else
+			{
+				error	=	true;
+				break;
+			}
+		}
+	}
+	
+	if(!error)
+	{
+		if	(	(this->geoMesh->mSubMesh[0].mSharedVertexBuffer == true)
+					&&
+					(this->geoMesh->mSubMeshCount > 1)
+				)
+		{
+			for	(j = 0; j < this->geoMesh->mVertexBuffer->mVertexCount; j++)
+			{
+				//	Si hay mas de un submesh ListaIndices no se rellena correctamente
+				vAux.Vertex[0] = this->geoMesh->mVertexBuffer->mPosition[j].x;
+				vAux.Vertex[1] = this->geoMesh->mVertexBuffer->mPosition[j].y;
+				vAux.Vertex[2] = this->geoMesh->mVertexBuffer->mPosition[j].z;
+
+				//	Añadimos las normales en cVerts.
+				if	(	this->geoMesh->mVertexBuffer->mVertexInfo
+							&
+							Geometry::VERTEX_NORMAL
+						)
+				{
+					vAux.Normal[0] = this->geoMesh->mVertexBuffer->mNormal[j].x;
+					vAux.Normal[1] = this->geoMesh->mVertexBuffer->mNormal[j].y;
+					vAux.Normal[2] = this->geoMesh->mVertexBuffer->mNormal[j].z;
+				}
+
+				//	Añadimos las coordenadas de textura a cVerts.
+				if	(	this->geoMesh->mVertexBuffer->mVertexInfo
+							&
+							Geometry::VERTEX_TEXCOORDS
+						)
+				{
+					vAux.TexCoords[0] = this->geoMesh->mVertexBuffer->mTexCoords[j].x;
+					vAux.TexCoords[1] = this->geoMesh->mVertexBuffer->mTexCoords[j].y;
+				}
+
+				vAux.Next			=	-10;
+				vAux.numMesh	=	0;
+			
+				vAux.obligatorio	=	0;
+				
+				this->cVerts.push_back(vAux);
+			}
+		}
+		else
+		{
+			for	(i = 0; i < this->geoMesh->mSubMeshCount; i++)
+			{
+				for	(	j = 0;
+							j < this->geoMesh->mSubMesh[i].mVertexBuffer->mVertexCount;
+							j++)
+				{
+					//	Si hay mas de un submesh ListaIndices 
+					//	no se rellena correctamente.
+					vAux.Vertex[0] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mPosition[j].x;
+					vAux.Vertex[1] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mPosition[j].y;
+					vAux.Vertex[2] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mPosition[j].z;
+					//	Añadimos las normales en cVerts.
+					vAux.Normal[0] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mNormal[j].x;
+					vAux.Normal[1] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mNormal[j].y;
+					vAux.Normal[2] = this->geoMesh->mSubMesh[i].
+																					mVertexBuffer->mNormal[j].z;
+
+					//	Añadimos las coordenadas de textura a cVerts.
+					vAux.TexCoords[0]	=	this->geoMesh->mSubMesh[i].
+																							mVertexBuffer->mTexCoords[j].x;
+					vAux.TexCoords[1] = this->geoMesh->mSubMesh[i].
+																							mVertexBuffer->mTexCoords[j].y;
+
+					vAux.Next			=	-10;
+					vAux.numMesh	=	i;
+					
+					this->cVerts.push_back(vAux);
+				}
+			}
+		}	
+
+		Index	indice_acum;
+		Index	num_vert;
+
+		num_vert	=	0;
+		
+		for	(i = 0; i < this->geoMesh->mSubMeshCount; i++)
+		{
+			indice_acum	=	0;
+			
+			for	(j = 0; j < this->geoMesh->mSubMesh[i].mStripCount; j++)
+			{
+				Index	*aux	=	this->geoMesh->mSubMesh[i].mStrip[j];
+				
+				if (j != 0)
+				{
+					// La primera tira no empieza por índices repetidos.
+					aux	=	aux+1;
+					
+					indice_acum++;
+				}
+				
+				if (j+1 < this->geoMesh->mSubMesh[i].mStripCount)
+				{
+					Index	*siguiente	=	this->geoMesh->mSubMesh[i].mStrip[j+1];
+					
+					tira.clear();
+					
+					while (aux != siguiente)
+					{
+						tira.push_back(*aux);
+						indice_acum++;
+						
+						aux	=	aux + 1;
+					}
+					
+					tira.pop_back();
+					this->cStrips.push_back(tira);
+				}
+				else
+				{
+					// Insertar los indices de la última tira en el cStrips
+					tira.clear();
+					
+					for	(	unsigned int k = indice_acum;
+								k < this->geoMesh->mSubMesh[i].mIndexCount;
+								k++)
+					{
+						tira.push_back(this->geoMesh->mSubMesh[i].mIndex[k]);
+					}
+					
+					this->cStrips.push_back(tira);
+				}
+			}
+			
+			num_vert	+=	this->geoMesh->mSubMesh[i].
+																		mVertexBuffer->mVertexCount;
+		}
+
+		this->TOTALVERTS	=	cVerts.size();
+		this->TOTALTIRAS	=	cStrips.size();
+	}
+	else
+	{
+		//	Error.
+	}
+}
+
+///	GetMesh: Return de current Mesh.
+Mesh	*	LodStripsConstructor::GetMesh()
+{
+	Mesh		*mesh_built;
+
+	mesh_built		=	new Mesh();
+	*mesh_built		=	*geoMesh;
+
+	return	mesh_built;
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/tri_stripper.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/tri_stripper.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/tri_stripper.cpp	(revision 774)
@@ -0,0 +1,589 @@
+//
+// Copyright (C) 2004 Tanguy Fautré.
+// For conditions of distribution and use,
+// see copyright notice in tri_stripper.h
+//
+//////////////////////////////////////////////////////////////////////
+// SVN: $Id: tri_stripper.cpp 86 2005-06-08 17:47:27Z gpsnoopy $
+//////////////////////////////////////////////////////////////////////
+
+#include "tri_stripper.h"
+
+#include "detail/connectivity_graph.h"
+#include "detail/policy.h"
+
+#include <cassert>
+
+
+
+
+namespace triangle_stripper {
+
+	using namespace detail;
+
+
+
+
+tri_stripper::tri_stripper(const indices & TriIndices)
+	: m_Triangles(TriIndices.size() / 3), // Silently ignore extra indices if (Indices.size() % 3 != 0)
+	  m_StripID(0),
+	  m_FirstRun(true)
+{
+	SetCacheSize();
+	SetMinStripSize();
+	SetBackwardSearch();
+	SetPushCacheHits();
+
+	make_connectivity_graph(m_Triangles, TriIndices);
+
+	//	Initialize	Progress bar function.
+	mUPB	=	NULL;
+}
+
+
+
+void tri_stripper::Strip(primitive_vector * out_pPrimitivesVector)
+{
+	assert(out_pPrimitivesVector);
+
+	if (! m_FirstRun) {
+		unmark_nodes(m_Triangles);
+		ResetStripIDs();
+		m_Cache.reset();
+		m_TriHeap.clear();
+		m_Candidates.clear();
+		m_StripID = 0;
+
+		m_FirstRun = false;
+	}
+
+	out_pPrimitivesVector->clear();
+
+	InitTriHeap();
+
+	Stripify();
+	AddLeftTriangles();
+	
+	std::swap(m_PrimitivesVector, (* out_pPrimitivesVector));
+}
+
+
+
+void tri_stripper::InitTriHeap()
+{
+	m_TriHeap.reserve(m_Triangles.size());
+
+	// Set up the triangles priority queue
+	// The lower the number of available neighbour triangles, the higher the priority.
+	for (size_t i = 0; i < m_Triangles.size(); ++i)
+		m_TriHeap.push(m_Triangles[i].out_size());
+
+	// We're not going to add new elements anymore
+	m_TriHeap.lock();
+
+	// Remove useless triangles
+	// Note: we had to put all of them into the heap before to ensure coherency of the heap_array object
+	while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
+		m_TriHeap.pop();
+}
+
+
+
+void tri_stripper::ResetStripIDs()
+{
+	for (triangle_graph::node_iterator it = m_Triangles.begin(); it != m_Triangles.end(); ++it)
+		(**it).ResetStripID();
+}
+
+
+void tri_stripper::Stripify()
+{
+	float		percent;
+	size_t	triangle_count;
+	size_t	current_triangles;
+	
+	//	Gets the triangle count.
+	triangle_count	=	m_TriHeap.size();
+	
+	while (! m_TriHeap.empty())
+	{
+		//	If progres bar is activated.
+		if (mUPB)
+		{
+			current_triangles	=	m_TriHeap.size();
+		
+			percent	=	(mUPBInc	*	(triangle_count - current_triangles)) / triangle_count;
+
+			triangle_count	=	current_triangles;
+
+			//	Update progress bar.
+			mUPB(percent);
+		}
+		
+		// There is no triangle in the candidates list, 
+		// refill it with the loneliest triangle
+		const size_t HeapTop = m_TriHeap.position(0);
+		m_Candidates.push_back(HeapTop);
+
+		while (! m_Candidates.empty())
+		{
+			// Note: FindBestStrip empties the candidate list, 
+			// while BuildStrip refills it
+			const strip TriStrip = FindBestStrip();
+
+			if (TriStrip.Size() >= m_MinStripSize)
+			{
+				BuildStrip(TriStrip);
+			}
+		}
+
+		if (! m_TriHeap.removed(HeapTop))
+		{
+			m_TriHeap.erase(HeapTop);
+		}
+
+		// Eliminate all the triangles that have now become useless
+		while ((! m_TriHeap.empty()) && (m_TriHeap.top() == 0))
+		{
+			m_TriHeap.pop();
+		}
+	}
+}
+
+//	Sets the progress bar function and the increment to update.
+void	tri_stripper::SetProgressFunc(Geometry::TIPOFUNC upb,float	increment)
+{
+	mUPB		=	upb;
+	mUPBInc	=	increment;
+}
+
+inline strip tri_stripper::FindBestStrip()
+{
+	// Allow to restore the cache (modified by ExtendTriToStrip) and implicitly reset the cache hit count
+	const cache_simulator CacheBackup = m_Cache;
+
+	policy Policy(m_MinStripSize, Cache());
+
+	while (! m_Candidates.empty()) {
+
+		const size_t Candidate = m_Candidates.back();
+		m_Candidates.pop_back();
+
+		// Discard useless triangles from the candidate list
+		if ((m_Triangles[Candidate].marked()) || (m_TriHeap[Candidate] == 0))
+			continue;		
+
+		// Try to extend the triangle in the 3 possible forward directions
+		for (size_t i = 0; i < 3; ++i) {
+
+			const strip Strip = ExtendToStrip(Candidate, triangle_order(i));
+			Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
+			
+			m_Cache = CacheBackup;
+		}
+
+		// Try to extend the triangle in the 6 possible backward directions
+		if (m_BackwardSearch) {
+
+			for (size_t i = 0; i < 3; ++i) {
+
+				const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), false);
+				Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
+			
+				m_Cache = CacheBackup;
+			}
+
+			for (size_t i = 0; i < 3; ++i) {
+
+				const strip Strip = BackExtendToStrip(Candidate, triangle_order(i), true);
+				Policy.Challenge(Strip, m_TriHeap[Strip.Start()], m_Cache.hitcount());
+			
+				m_Cache = CacheBackup;
+			}
+		}
+
+	}
+
+	return Policy.BestStrip();
+}
+
+
+
+strip tri_stripper::ExtendToStrip(const size_t Start, triangle_order Order)
+{
+	const triangle_order StartOrder = Order;
+	
+	// Begin a new strip
+	m_Triangles[Start]->SetStripID(++m_StripID);
+	AddTriangle(* m_Triangles[Start], Order, false);
+
+	size_t Size = 1;
+	bool ClockWise = false;
+
+	// Loop while we can further extend the strip
+	for (tri_iterator Node = (m_Triangles.begin() + Start); 
+		(Node != m_Triangles.end()) && (!Cache() || ((Size + 2) < CacheSize()));
+		++Size) {
+
+		const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, false);
+
+		// Is it the end of the strip?
+		if (Link == Node->out_end()) {
+
+			Node = m_Triangles.end();
+			--Size;
+
+		} else {
+
+			Node = Link->terminal();
+			(* Node)->SetStripID(m_StripID);
+			ClockWise = ! ClockWise;
+
+		}
+	}
+
+	return strip(Start, StartOrder, Size);
+}
+
+
+
+strip tri_stripper::BackExtendToStrip(size_t Start, triangle_order Order, bool ClockWise)
+{
+	// Begin a new strip
+	m_Triangles[Start]->SetStripID(++m_StripID);
+	BackAddIndex(LastEdge(* m_Triangles[Start], Order).B());
+	size_t Size = 1;
+
+	tri_iterator Node;
+
+	// Loop while we can further extend the strip
+	for (Node = (m_Triangles.begin() + Start); 
+		!Cache() || ((Size + 2) < CacheSize());
+		++Size) {
+
+		const const_link_iterator Link = BackLinkToNeighbour(Node, ClockWise, Order);
+
+		// Is it the end of the strip?
+		if (Link == Node->out_end())
+			break;
+
+		else {
+			Node = Link->terminal();
+			(* Node)->SetStripID(m_StripID);
+			ClockWise = ! ClockWise;
+		}
+	}
+
+	// We have to start from a counterclockwise triangle.
+	// Simply return an empty strip in the case where the first triangle is clockwise.
+	// Even though we could discard the first triangle and start from the next counterclockwise triangle,
+	// this often leads to more lonely triangles afterward.
+	if (ClockWise)
+		return strip();
+
+	if (Cache()) {
+		m_Cache.merge(m_BackCache, Size);
+		m_BackCache.reset();
+	}
+
+	return strip(Node - m_Triangles.begin(), Order, Size);
+}
+
+
+
+void tri_stripper::BuildStrip(const strip Strip)
+{
+	const size_t Start = Strip.Start();
+
+	bool ClockWise = false;
+	triangle_order Order = Strip.Order();
+
+	// Create a new strip
+	m_PrimitivesVector.push_back(primitive_group());
+	m_PrimitivesVector.back().Type = TRIANGLE_STRIP;
+	AddTriangle(* m_Triangles[Start], Order, true);
+	MarkTriAsTaken(Start);
+
+	// Loop while we can further extend the strip
+	tri_iterator Node = (m_Triangles.begin() + Start);
+
+	for (size_t Size = 1; Size < Strip.Size(); ++Size) {
+
+		const const_link_iterator Link = LinkToNeighbour(Node, ClockWise, Order, true);
+
+		assert(Link != Node->out_end());
+
+		// Go to the next triangle
+		Node = Link->terminal();
+		MarkTriAsTaken(Node - m_Triangles.begin());
+		ClockWise = ! ClockWise;
+	}
+}
+
+
+
+inline tri_stripper::const_link_iterator tri_stripper::LinkToNeighbour(const const_tri_iterator Node, const bool ClockWise, triangle_order & Order, const bool NotSimulation)
+{
+	const triangle_edge Edge = LastEdge(** Node, Order);
+
+	for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
+
+		// Get the reference to the possible next triangle
+		const triangle & Tri = ** Link->terminal();
+
+		// Check whether it's already been used
+		if (NotSimulation || (Tri.StripID() != m_StripID)) {
+
+			if (! Link->terminal()->marked()) {
+
+				// Does the current candidate triangle match the required position for the strip?
+
+				if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
+					Order = (ClockWise) ? ABC : BCA;
+					AddIndex(Tri.C(), NotSimulation);
+					return Link;
+				}
+
+				else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
+					Order = (ClockWise) ? BCA : CAB;
+					AddIndex(Tri.A(), NotSimulation);
+					return Link;
+				}
+
+				else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
+					Order = (ClockWise) ? CAB : ABC;
+					AddIndex(Tri.B(), NotSimulation);
+					return Link;
+				}
+			}
+		}
+
+	}
+
+	return Node->out_end();
+}
+
+
+
+inline tri_stripper::const_link_iterator tri_stripper::BackLinkToNeighbour(const_tri_iterator Node, bool ClockWise, triangle_order & Order)
+{
+	const triangle_edge Edge = FirstEdge(** Node, Order);
+
+	for (const_link_iterator Link = Node->out_begin(); Link != Node->out_end(); ++Link) {
+
+		// Get the reference to the possible previous triangle
+		const triangle & Tri = ** Link->terminal();
+
+		// Check whether it's already been used
+		if ((Tri.StripID() != m_StripID) && ! Link->terminal()->marked()) {
+
+			// Does the current candidate triangle match the required position for the strip?
+
+			if ((Edge.B() == Tri.A()) && (Edge.A() == Tri.B())) {
+				Order = (ClockWise) ? CAB : BCA;
+				BackAddIndex(Tri.C());
+				return Link;
+			}
+
+			else if ((Edge.B() == Tri.B()) && (Edge.A() == Tri.C())) {
+				Order = (ClockWise) ? ABC : CAB;
+				BackAddIndex(Tri.A());
+				return Link;
+			}
+
+			else if ((Edge.B() == Tri.C()) && (Edge.A() == Tri.A())) {
+				Order = (ClockWise) ? BCA : ABC;
+				BackAddIndex(Tri.B());
+				return Link;
+			}
+		}
+
+	}
+
+	return Node->out_end();
+}
+
+
+
+void tri_stripper::MarkTriAsTaken(const size_t i)
+{
+	typedef triangle_graph::node_iterator tri_node_iter;
+	typedef triangle_graph::out_arc_iterator tri_link_iter;
+
+	// Mark the triangle node
+	m_Triangles[i].mark();
+
+	// Remove triangle from priority queue if it isn't yet
+	if (! m_TriHeap.removed(i))
+		m_TriHeap.erase(i);
+
+	// Adjust the degree of available neighbour triangles
+	for (tri_link_iter Link = m_Triangles[i].out_begin(); Link != m_Triangles[i].out_end(); ++Link) {
+
+		const size_t j = Link->terminal() - m_Triangles.begin();
+
+		if ((! m_Triangles[j].marked()) && (! m_TriHeap.removed(j))) {
+			size_t NewDegree = m_TriHeap.peek(j);
+			NewDegree = NewDegree - 1;
+			m_TriHeap.update(j, NewDegree);
+
+			// Update the candidate list if cache is enabled
+			if (Cache() && (NewDegree > 0))
+				m_Candidates.push_back(j);
+		}
+	}
+}
+
+
+
+inline triangle_edge tri_stripper::FirstEdge(const triangle & Triangle, const triangle_order Order)
+{
+	switch (Order)
+	{
+	case ABC:
+		return triangle_edge(Triangle.A(), Triangle.B());
+
+	case BCA:
+		return triangle_edge(Triangle.B(), Triangle.C());
+
+	case CAB:
+		return triangle_edge(Triangle.C(), Triangle.A());
+
+	default:
+		assert(false);
+		return triangle_edge(0, 0);
+	}
+}
+
+
+
+inline triangle_edge tri_stripper::LastEdge(const triangle & Triangle, const triangle_order Order)
+{
+	switch (Order)
+	{
+	case ABC:
+		return triangle_edge(Triangle.B(), Triangle.C());
+
+	case BCA:
+		return triangle_edge(Triangle.C(), Triangle.A());
+
+	case CAB:
+		return triangle_edge(Triangle.A(), Triangle.B());
+
+	default:
+		assert(false);
+		return triangle_edge(0, 0);
+	}
+}
+
+
+
+inline void tri_stripper::AddIndex(const index i, const bool NotSimulation)
+{
+	if (Cache())
+		m_Cache.push(i, ! NotSimulation);
+
+	if (NotSimulation)
+		m_PrimitivesVector.back().Indices.push_back(i);
+}
+
+
+
+inline void tri_stripper::BackAddIndex(const index i)
+{
+	if (Cache())
+		m_BackCache.push(i, true);
+}
+
+
+
+inline void tri_stripper::AddTriangle(const triangle & Tri, const triangle_order Order, const bool NotSimulation)
+{
+	switch (Order)
+	{
+	case ABC:
+		AddIndex(Tri.A(), NotSimulation);
+		AddIndex(Tri.B(), NotSimulation);
+		AddIndex(Tri.C(), NotSimulation);
+		break;
+
+	case BCA:
+		AddIndex(Tri.B(), NotSimulation);
+		AddIndex(Tri.C(), NotSimulation);
+		AddIndex(Tri.A(), NotSimulation);
+		break;
+
+	case CAB:
+		AddIndex(Tri.C(), NotSimulation);
+		AddIndex(Tri.A(), NotSimulation);
+		AddIndex(Tri.B(), NotSimulation);
+		break;
+	}
+}
+
+
+
+inline void tri_stripper::BackAddTriangle(const triangle & Tri, const triangle_order Order)
+{
+	switch (Order)
+	{
+	case ABC:
+		BackAddIndex(Tri.C());
+		BackAddIndex(Tri.B());
+		BackAddIndex(Tri.A());
+		break;
+
+	case BCA:
+		BackAddIndex(Tri.A());
+		BackAddIndex(Tri.C());
+		BackAddIndex(Tri.B());
+		break;
+
+	case CAB:
+		BackAddIndex(Tri.B());
+		BackAddIndex(Tri.A());
+		BackAddIndex(Tri.C());
+		break;
+	}
+}
+
+
+
+void tri_stripper::AddLeftTriangles()
+{
+	// Create the last indices array and fill it with all the triangles that couldn't be stripped
+	primitive_group Primitives;
+	Primitives.Type = TRIANGLES;
+	m_PrimitivesVector.push_back(Primitives);
+	indices & Indices = m_PrimitivesVector.back().Indices;
+
+	for (size_t i = 0; i < m_Triangles.size(); ++i)
+		if (! m_Triangles[i].marked()) {
+			Indices.push_back(m_Triangles[i]->A());
+			Indices.push_back(m_Triangles[i]->B());
+			Indices.push_back(m_Triangles[i]->C());
+		}
+
+	// Undo if useless
+	if (Indices.size() == 0)
+		m_PrimitivesVector.pop_back();
+}
+
+
+
+inline bool tri_stripper::Cache() const
+{
+	return (m_Cache.size() != 0);
+}
+
+
+
+inline size_t tri_stripper::CacheSize() const
+{
+	return m_Cache.size();
+}
+
+
+
+
+} // namespace triangle_stripper
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMesh.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMesh.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMesh.cpp	(revision 774)
@@ -0,0 +1,391 @@
+#include "GeoMesh.h"
+
+using namespace Geometry;
+using namespace std;
+
+//----------------------------------------------------------------------------
+Mesh::Mesh():
+	mVertexBuffer(0), mSubMeshCount(0), mSubMesh(0), mType(GEO_TRIANGLE_LIST)
+{
+}
+
+Mesh::~Mesh()
+{
+	delete[] mSubMesh;
+	delete mVertexBuffer;
+}
+
+
+Mesh::Mesh(const Mesh &objmesh) 
+{
+	// constructor copia
+	mVertexBuffer=new VertexBuffer();
+	mType=objmesh.mType;
+	mSubMeshCount=objmesh.mSubMeshCount;
+	mSubMesh = new Geometry::SubMesh[objmesh.mSubMeshCount];
+	for(size_t i=0;i<objmesh.mSubMeshCount;i++)
+	{
+		mSubMesh[i].mSharedVertexBuffer=false;
+		mSubMesh[i].mVertexBuffer = new Geometry::VertexBuffer();
+		mSubMesh[i].mVertexBuffer->mPosition = new Geometry::Vector3[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mNormal = new Geometry::Vector3[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mTexCoords = new Geometry::Vector2[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mVertexCount = objmesh.mSubMesh[i].mVertexBuffer->mVertexCount;
+		mSubMesh[i].mVertexBuffer->mVertexInfo = objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo;
+		
+		// De momento con esto se parte de un geomesh con vértices compartidos y se obtiene un geomesh sin vértices
+		// compartidos. Los vértices se replican en cada uno de los submeshes.
+		// HAY QUE CAMBIARLO.
+		if(objmesh.mSubMesh[i].mSharedVertexBuffer == true) 
+		{
+			for(size_t s=0;s<objmesh.mSubMesh[i].mVertexBuffer->mVertexCount;s++)
+			{
+				//Copiamos mPosition
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_POSITION)
+				{
+					mSubMesh[i].mVertexBuffer->mPosition[s].x = objmesh.mVertexBuffer->mPosition[s].x;
+					mSubMesh[i].mVertexBuffer->mPosition[s].y = objmesh.mVertexBuffer->mPosition[s].y;
+					mSubMesh[i].mVertexBuffer->mPosition[s].z = objmesh.mVertexBuffer->mPosition[s].z;
+				}
+				//Copiamos mNormal
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+				{
+					mSubMesh[i].mVertexBuffer->mNormal[s].x = objmesh.mVertexBuffer->mNormal[s].x;
+					mSubMesh[i].mVertexBuffer->mNormal[s].y = objmesh.mVertexBuffer->mNormal[s].y;
+					mSubMesh[i].mVertexBuffer->mNormal[s].z = objmesh.mVertexBuffer->mNormal[s].z;
+				}
+
+				//Copiamos mTexCoords
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+				{
+					mSubMesh[i].mVertexBuffer->mTexCoords[s].x = objmesh.mVertexBuffer->mTexCoords[s].x;
+					mSubMesh[i].mVertexBuffer->mTexCoords[s].y = objmesh.mVertexBuffer->mTexCoords[s].y;
+				}
+			}
+			objmesh.mSubMesh[i].mSharedVertexBuffer = false;
+		}
+		else
+		{
+			for(size_t s=0;s<objmesh.mSubMesh[i].mVertexBuffer->mVertexCount;s++)
+			{
+				//Copiamos mPosition
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_POSITION)
+				{
+					mSubMesh[i].mVertexBuffer->mPosition[s].x = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].x;
+					mSubMesh[i].mVertexBuffer->mPosition[s].y = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].y;
+					mSubMesh[i].mVertexBuffer->mPosition[s].z = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].z;
+				}
+				//Copiamos mNormal
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+				{
+					mSubMesh[i].mVertexBuffer->mNormal[s].x = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].x;
+					mSubMesh[i].mVertexBuffer->mNormal[s].y = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].y;
+					mSubMesh[i].mVertexBuffer->mNormal[s].z = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].z;
+				}
+
+				//Copiamos mTexCoords
+				if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+				{
+					mSubMesh[i].mVertexBuffer->mTexCoords[s].x = objmesh.mSubMesh[i].mVertexBuffer->mTexCoords[s].x;
+					mSubMesh[i].mVertexBuffer->mTexCoords[s].y = objmesh.mSubMesh[i].mVertexBuffer->mTexCoords[s].y;
+				}
+			}
+
+		}
+		// Copiar los indices
+		mSubMesh[i].mIndexCount=objmesh.mSubMesh[i].mIndexCount;
+		mSubMesh[i].mIndex = new Index[mSubMesh[i].mIndexCount];
+		memcpy(mSubMesh[i].mIndex,objmesh.mSubMesh[i].mIndex,objmesh.mSubMesh[i].mIndexCount*sizeof(Geometry::Index));
+
+		// Copiar las tiras
+		// TENER EN CUENTA SI ES UN MESH DE TIRAS O LISTA DE TRIANGULOS
+		__w64 int Desp=0; // desplazamiento entre posiciones de memoria.
+		mSubMesh[i].mStripCount=objmesh.mSubMesh[i].mStripCount;
+		if (objmesh.mSubMesh[i].mStripCount>0) 
+		{
+			mSubMesh[i].mStrip = new Index*[objmesh.mSubMesh[i].mStripCount];
+
+			Desp= &(mSubMesh[i].mIndex[0]) - &(objmesh.mSubMesh[i].mIndex[0]);
+			for (size_t j=0;j<objmesh.mSubMesh[i].mStripCount;j++) 
+			{
+				mSubMesh[i].mStrip[j]=objmesh.mSubMesh[i].mStrip[j] + Desp;
+			}
+		}
+	}
+}
+
+Mesh &Mesh::operator =(const Geometry::Mesh &objmesh)
+{
+	// Operador de asignación
+	bool copiados	=	false; // indica si los vértices compartidos han sido copiados
+	mVertexBuffer	=	new VertexBuffer();
+	mType					=	objmesh.mType;
+	mSubMeshCount	=	objmesh.mSubMeshCount;
+	mSubMesh			=	new Geometry::SubMesh[objmesh.mSubMeshCount];
+
+	for(size_t i = 0; i < objmesh.mSubMeshCount; i++)
+	{
+		//	Debug.
+		/*
+		cout	<<	"VertexCount["
+					<<	i
+					<<	"]: "
+					<<	objmesh.mSubMesh[i].mVertexBuffer->mVertexCount
+					<<	endl;
+		*/
+		//--------------------------------------------------------------------------------------------
+
+		mSubMesh[i].mSharedVertexBuffer					=	objmesh.mSubMesh[i].mSharedVertexBuffer; //.false;
+		mSubMesh[i].mVertexBuffer								=	new Geometry::VertexBuffer();
+		mSubMesh[i].mVertexBuffer->mPosition		=	new Geometry::Vector3[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mNormal			=	new Geometry::Vector3[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mTexCoords		=	new Geometry::Vector2[objmesh.mSubMesh[i].mVertexBuffer->mVertexCount];
+		mSubMesh[i].mVertexBuffer->mVertexCount	=	objmesh.mSubMesh[i].mVertexBuffer->mVertexCount;
+		mSubMesh[i].mVertexBuffer->mVertexInfo	=	objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo;
+
+		if (objmesh.mSubMesh[i].mSharedVertexBuffer && !copiados)
+		{
+			mVertexBuffer	=	mSubMesh[i].mVertexBuffer;
+			copiados			=	true;
+		}
+
+		for(size_t s = 0; s < objmesh.mSubMesh[i].mVertexBuffer->mVertexCount; s++)
+		{
+			//Copiamos mPosition
+			//if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_POSITION)
+			//{
+				mSubMesh[i].mVertexBuffer->mPosition[s].x = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].x;
+				mSubMesh[i].mVertexBuffer->mPosition[s].y = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].y;
+				mSubMesh[i].mVertexBuffer->mPosition[s].z = objmesh.mSubMesh[i].mVertexBuffer->mPosition[s].z;
+			//}
+			//Copiamos mNormal
+			if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+			{
+				mSubMesh[i].mVertexBuffer->mNormal[s].x = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].x;
+				mSubMesh[i].mVertexBuffer->mNormal[s].y = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].y;
+				mSubMesh[i].mVertexBuffer->mNormal[s].z = objmesh.mSubMesh[i].mVertexBuffer->mNormal[s].z;
+			}
+
+			//Copiamos mTexCoords
+			if (objmesh.mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+			{
+				mSubMesh[i].mVertexBuffer->mTexCoords[s].x = objmesh.mSubMesh[i].mVertexBuffer->mTexCoords[s].x;
+				mSubMesh[i].mVertexBuffer->mTexCoords[s].y = objmesh.mSubMesh[i].mVertexBuffer->mTexCoords[s].y;
+			}
+		}
+
+		// Copiar los indices
+		mSubMesh[i].mIndexCount	=	objmesh.mSubMesh[i].mIndexCount;
+		mSubMesh[i].mIndex			=	new Index[mSubMesh[i].mIndexCount];
+
+		memcpy(mSubMesh[i].mIndex,objmesh.mSubMesh[i].mIndex,objmesh.mSubMesh[i].mIndexCount*sizeof(Geometry::Index));
+
+		// Copiar las tiras
+		__w64 Desp							=	0; // desplazamiento entre posiciones de memoria.
+		mSubMesh[i].mStripCount	=	objmesh.mSubMesh[i].mStripCount;
+
+		if (objmesh.mSubMesh[i].mStripCount>0) 
+		{
+			mSubMesh[i].mStrip	=	new Index*[objmesh.mSubMesh[i].mStripCount];
+			Desp								=	&(mSubMesh[i].mIndex[0]) - &(objmesh.mSubMesh[i].mIndex[0]);
+			
+			for (size_t j = 0; j < objmesh.mSubMesh[i].mStripCount; j++)
+			{
+				mSubMesh[i].mStrip[j]	=	objmesh.mSubMesh[i].mStrip[j] + Desp;
+			}
+		}
+		
+		//OSCAR
+		//Copio los bones
+		if (!objmesh.mSubMesh[i].mBones.empty())
+		{
+			for (int j = 0; j < objmesh.mSubMesh[i].mBones.size(); j++)
+			{
+				mSubMesh[i].mBones.push_back(objmesh.mSubMesh[i].mBones[j]);
+			}
+		}
+	}
+
+	//OSCAR
+	//Copio el nombre del esqueleto
+	if (objmesh.hasSkeleton)
+	{
+		hasSkeleton	=	true;
+		
+		strcpy(mSkeletonName,objmesh.mSkeletonName);
+	}
+
+	//OSCAR
+	//Copio los bones
+	if (!objmesh.mBones.empty())
+	{
+		for (int j = 0; j < objmesh.mBones.size(); j++)
+		{
+			mBones.push_back(objmesh.mBones[j]);
+		}
+	}
+
+	return	*this;
+}
+
+void Mesh::Load(Serializer &s)
+{
+	bool sharedVertexBuffer	= false;
+
+	//Clear Data
+	delete[] mSubMesh;  mSubMesh = 0;
+	delete   mVertexBuffer; mVertexBuffer = 0;
+	mSubMeshCount = 0;
+	
+	s.ReadArray(&sharedVertexBuffer,1);
+	if (sharedVertexBuffer)
+	{
+		mVertexBuffer = new VertexBuffer;
+		mVertexBuffer->Load(s);
+	}
+	s.ReadArray(&mSubMeshCount,1);
+	mSubMesh = new SubMesh[mSubMeshCount];
+	for(size_t i = 0; i < mSubMeshCount; ++i)
+	{
+		mSubMesh[i].Load(s);
+		if (mSubMesh[i].mSharedVertexBuffer && sharedVertexBuffer)
+		{
+			mSubMesh[i].mVertexBuffer = mVertexBuffer;
+		}
+	}
+}
+
+void Mesh::Save(Serializer &s)
+{
+	bool sharedVertexBuffer = (mVertexBuffer != 0);
+	s.WriteArray(&sharedVertexBuffer, 1);
+	if (sharedVertexBuffer)
+	{
+		mVertexBuffer->Save(s);
+	}
+	s.WriteArray(&mSubMeshCount,1);
+	for(size_t i = 0; i < mSubMeshCount; ++i)
+	{
+		mSubMesh[i].Save(s);
+	}
+}
+
+// 26-12-2005
+void Mesh::exportToOBJ(char *nomfich)
+{
+	// Genera un fichero obj con vértices, triángulos
+
+	std::ofstream obj(nomfich);
+	obj << "begin" << std::endl;
+	// Vértices
+	for (size_t i=0; i<this->mSubMeshCount; i++) 
+	{
+		for (size_t j=0; j<this->mSubMesh[i].mVertexBuffer->mVertexCount; j++) 
+		{	
+			obj << "v " <<  this->mSubMesh[i].mVertexBuffer->mPosition[j].x << " " <<
+				this->mSubMesh[i].mVertexBuffer->mPosition[j].y << " " <<
+				this->mSubMesh[i].mVertexBuffer->mPosition[j].z << " " << std::endl;
+		}
+	}
+
+
+	// Caras
+	for (size_t i=0; i<this->mSubMeshCount; i++) 
+	{
+		for (size_t j=0; j<this->mSubMesh[i].mIndexCount; j=j+3) 
+		{	
+			obj << "f " <<  this->mSubMesh[i].mIndex[j]+1 << " " << 
+				this->mSubMesh[i].mIndex[j+1]+1 << " " << 
+				this->mSubMesh[i].mIndex[j+2]+1 << std::endl;
+		}
+	}
+
+	obj << "end" << std::endl;
+	obj.close();
+}
+
+// 26-12-2005
+Geometry::Mesh *Mesh::toSharedVertex() 
+{
+
+	// Move all vertex to the shared vertex buffer.
+	Geometry::Mesh *mesh = new Geometry::Mesh();
+
+	if (this->mSubMesh[0].mSharedVertexBuffer)
+	{
+		*mesh	=	*this;
+		return	mesh;
+	}
+	
+	mesh->mVertexBuffer=new VertexBuffer();
+	mesh->mType=this->mType;
+	mesh->mSubMeshCount = this->mSubMeshCount;
+	// Reserva memoria para los submeshes
+	mesh->mSubMesh = new Geometry::SubMesh[this->mSubMeshCount];
+
+	// construcción de los submeshes
+	long int acumVerts=0;
+	for (size_t i=0; i<mesh->mSubMeshCount; i++) 
+	{
+		mesh->mSubMesh[i].mSharedVertexBuffer=true;
+		mesh->mSubMesh[i].mVertexBuffer=mesh->mVertexBuffer;
+		mesh->mSubMesh[i].mStripCount=0;
+		mesh->mSubMesh[i].mStrip=NULL;
+
+		// copiar los índices
+		mesh->mSubMesh[i].mIndexCount=this->mSubMesh[i].mIndexCount;
+		mesh->mSubMesh[i].mIndex=new Geometry::Index[this->mSubMesh[i].mIndexCount];
+
+		for (size_t j=0; j< this->mSubMesh[i].mIndexCount; j++) 
+		{ 
+			mesh->mSubMesh[i].mIndex[j]	=	this->mSubMesh[i].mIndex[j]+acumVerts;
+		}
+
+		acumVerts	+=	this->mSubMesh[i].mVertexBuffer->mVertexCount;
+
+		// Copiar las tiras
+		int Desp=0; // desplazamiento entre posiciones de memoria.
+		mesh->mSubMesh[i].mStripCount=this->mSubMesh[i].mStripCount;
+		if (this->mSubMesh[i].mStripCount>0) 
+		{
+			mesh->mSubMesh[i].mStrip = new Index*[this->mSubMesh[i].mStripCount];
+
+			Desp= &(mesh->mSubMesh[i].mIndex[0]) - &(this->mSubMesh[i].mIndex[0]);
+			for (size_t j=0;j<this->mSubMesh[i].mStripCount;j++) 
+			{
+				mesh->mSubMesh[i].mStrip[j]=this->mSubMesh[i].mStrip[j] + Desp;
+			}
+		}
+	}
+	
+	mesh->mVertexBuffer->mVertexCount=acumVerts;
+	mesh->mVertexBuffer->mVertexInfo=this->mSubMesh[0].mVertexBuffer->mVertexInfo;
+	mesh->mVertexBuffer->mPosition=new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount];
+	mesh->mVertexBuffer->mNormal=new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount];
+	mesh->mVertexBuffer->mTexCoords=new Geometry::Vector2[mesh->mVertexBuffer->mVertexCount];
+	
+	// copiar los vértices
+	acumVerts=0;
+	size_t newIndex;
+	for (size_t i=0; i<this->mSubMeshCount; i++) 
+	{
+		for(size_t j=0;j<this->mSubMesh[i].mVertexBuffer->mVertexCount;j++)
+		{
+			newIndex=acumVerts+j;
+			mesh->mVertexBuffer->mPosition[newIndex].x=this->mSubMesh[i].mVertexBuffer->mPosition[j].x;
+			mesh->mVertexBuffer->mPosition[newIndex].y=this->mSubMesh[i].mVertexBuffer->mPosition[j].y;
+			mesh->mVertexBuffer->mPosition[newIndex].z=this->mSubMesh[i].mVertexBuffer->mPosition[j].z;
+
+			mesh->mVertexBuffer->mNormal[newIndex].x=this->mSubMesh[i].mVertexBuffer->mNormal[j].x;
+			mesh->mVertexBuffer->mNormal[newIndex].y=this->mSubMesh[i].mVertexBuffer->mNormal[j].y;
+			mesh->mVertexBuffer->mNormal[newIndex].z=this->mSubMesh[i].mVertexBuffer->mNormal[j].z;
+
+			mesh->mVertexBuffer->mTexCoords[newIndex].x=this->mSubMesh[i].mVertexBuffer->mTexCoords[j].x;
+			mesh->mVertexBuffer->mTexCoords[newIndex].y=this->mSubMesh[i].mVertexBuffer->mTexCoords[j].y;
+		}
+		acumVerts+=this->mSubMesh[i].mVertexBuffer->mVertexCount;
+	}
+
+	return mesh;
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshStripifier.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshStripifier.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/src/GeoMeshStripifier.cpp	(revision 774)
@@ -0,0 +1,252 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:	Make triangle strip meshes from triangle list meshes.
+	*
+	*
+	*	@file	GeoMeshStripifier.cpp
+*===========================================================================*/
+
+#include "GeoMeshStripifier.h"
+#include "tri_stripper.h"
+
+using namespace Geometry;
+using	namespace	std;
+using	namespace	triangle_stripper;
+
+//-----------------------------------------------------------------------------
+//	Constructors.
+//-----------------------------------------------------------------------------
+
+MeshStripifier::MeshStripifier()
+{
+}
+
+MeshStripifier::MeshStripifier(	const	Geometry::Mesh	*geoMesh)
+{
+}
+
+CustomStripifier::CustomStripifier()
+{
+}
+
+CustomStripifier::CustomStripifier(	const	Geometry::Mesh	*geoMesh)
+{
+	mGeoMesh	=	new Mesh();
+	*mGeoMesh	=	*geoMesh;
+
+	//	Sets the actual progress bar function.
+	mUPB	=	NULL;
+}
+
+//	Set the progress bar function.
+void	CustomStripifier::SetProgressFunc(TIPOFUNC upb)
+{
+	//	Sets the actual progress bar function.
+	mUPB	=	upb;
+}
+
+//-----------------------------------------------------------------------------
+//	Destroyers.
+//-----------------------------------------------------------------------------
+CustomStripifier::~CustomStripifier()
+{
+	delete	mGeoMesh;
+}
+
+MeshStripifier::~MeshStripifier()
+{
+}
+
+//-----------------------------------------------------------------------------
+//	Public.
+//-----------------------------------------------------------------------------
+
+///	Stripify.
+int CustomStripifier::Stripify()
+{
+	size_t						index_count;
+	size_t						strip_count;
+	SubMesh						*geosubmesh;
+	primitive_vector	PrimitivesVector;
+	indices						Indices;
+	float							increment;
+	float							update;
+	
+	//	For each submesh.
+	for (int	submesh	=	0;	submesh < mGeoMesh->mSubMeshCount;	submesh++)
+	{
+		//	Gets the submesh.
+		geosubmesh	=	&mGeoMesh->mSubMesh[submesh];
+
+		//	Free index vector.
+		Indices.clear();
+
+		//	Progress bar increment.
+		increment	=	20	/	mGeoMesh->mSubMeshCount;
+		increment	=	increment	/	geosubmesh->mIndexCount;
+		update		=	0.0;
+		
+		//	For each index.
+		for (int	index	=	0;	index	<	geosubmesh->mIndexCount;	index++)
+		{
+			//	Update progress bar.
+			if (mUPB)
+			{
+				update	=	update + increment;
+				
+				if (update > 0.9)
+				{
+					mUPB(1.0);
+					
+					update	=	0;
+				}
+			}
+			
+			//	Add an index.
+			Indices.push_back(geosubmesh->mIndex[index]);
+		}
+
+		// we want to time the tri_stripper object destruction as well.
+		tri_stripper TriStripper(Indices);
+
+		//	Sets the progress bar function for stripper algorithm.
+		TriStripper.SetProgressFunc(mUPB,60/mGeoMesh->mSubMeshCount);
+		
+		TriStripper.SetMinStripSize(2);
+		TriStripper.SetCacheSize(32);
+		//TriStripper.SetBackwardSearch(false);
+
+		TriStripper.Strip(&PrimitivesVector);
+
+		//	Free submesh indices.
+		delete	[]	geosubmesh->mIndex;
+
+		//	Initialize index count.
+		geosubmesh->mIndexCount	=	0;
+
+		//	Initialize strip count.
+		strip_count	=	0;
+		
+		//	For each strip or triangle list.
+		for (size_t i = 0; i < PrimitivesVector.size(); ++i)
+		{
+			if (PrimitivesVector[i].Type == TRIANGLE_STRIP)
+			{
+				strip_count++;
+				geosubmesh->mIndexCount	+=	PrimitivesVector[i].Indices.size();
+
+				//	Degenerate triangles.
+				geosubmesh->mIndexCount	+=	2;
+			}
+			else
+			{
+				strip_count += PrimitivesVector[i].Indices.size()/3;
+				
+				geosubmesh->mIndexCount	+=	PrimitivesVector[i].Indices.size();
+
+				//	Degenerate triangles.
+				geosubmesh->mIndexCount	+=	2*(PrimitivesVector[i].Indices.size()/3);
+			}
+		
+		}
+
+		//	Reserve memory for strips list.
+		geosubmesh->mStrip			=	new	Index*[strip_count];
+		geosubmesh->mStripCount	=	strip_count;
+
+		//	Adjust the index count.
+		geosubmesh->mIndexCount	-=	2;
+		
+		//	Reserve memory for indices.
+		geosubmesh->mIndex	=	new	Index[geosubmesh->mIndexCount];
+
+		//	Initialize index count.
+		index_count	=	0;
+
+		//	For each strip.
+		for (size_t	strip	=	0; strip < PrimitivesVector.size();	strip++)
+		{
+			if (PrimitivesVector[strip].Type == TRIANGLE_STRIP)
+			{
+				//	Asigns the beginning of the strip.
+				geosubmesh->mStrip[strip]	=	&geosubmesh->mIndex[index_count];
+
+				//	If is not the first strip.
+				if (strip	!= 0)
+				{
+					geosubmesh->mIndex[index_count++]	= PrimitivesVector[strip].Indices[0];
+				}
+				
+				//	Fill up the index array.
+				for (	size_t	index	=	0;
+							index < PrimitivesVector[strip].Indices.size();
+							index++)
+				{
+					geosubmesh->mIndex[index + index_count]	=	PrimitivesVector[strip].Indices[index];
+				}
+
+				//	Adds the current strip size to index count.
+				index_count	+=	PrimitivesVector[strip].Indices.size();
+
+				if ((strip + 1) != strip_count)
+				{
+					//	Degenerate triangle.
+					geosubmesh->mIndex[index_count++]	=	geosubmesh->mIndex[index_count - 1];
+				}
+			}
+			else
+			{
+				//	For each index.
+				for (	size_t	itri	=	0;
+							itri	<	PrimitivesVector[strip].Indices.size() / 3;
+							itri ++)
+				{
+						//	Asigns the beginning of the strip.
+						geosubmesh->mStrip[strip + itri]	=	&geosubmesh->mIndex[index_count];
+
+						//	Degenerate triangle.
+					  geosubmesh->mIndex[index_count++]	=	PrimitivesVector[strip].Indices[itri*3+0];
+
+						//	Triangle indeces.
+						geosubmesh->mIndex[index_count++]	=	PrimitivesVector[strip].Indices[itri*3+0];
+						geosubmesh->mIndex[index_count++]	=	PrimitivesVector[strip].Indices[itri*3+1];
+						geosubmesh->mIndex[index_count++] =	PrimitivesVector[strip].Indices[itri*3+2];
+
+						//	If is not the last strip.
+						if ((strip + itri + 1) != strip_count)
+						{
+							geosubmesh->mIndex[index_count++]	=	geosubmesh->mIndex[index_count - 1];
+						}
+				}
+				
+			}
+		}
+	}
+
+	//	Update progress bar function.
+	if	(mUPB)
+	{
+		mUPB(100);
+	}
+	
+	//	Sets the mesh type to triangle strips.
+	mGeoMesh->mType	=	GEO_TRIANGLE_STRIPS;
+
+	//	All wright.
+	return	1;
+}
+
+///	GetMesh: Return de current Mesh.
+Mesh*	CustomStripifier::GetMesh()
+{
+	Mesh		*mesh_stripified;
+
+	mesh_stripified		=	new Mesh();
+	*mesh_stripified	=	*mGeoMesh;
+
+	return	mesh_stripified;
+}
+
Index: /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.vcproj
===================================================================
--- /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.vcproj	(revision 774)
+++ /GTP/trunk/Lib/Geom/GTGeometry/GTGeometry.vcproj	(revision 774)
@@ -0,0 +1,384 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="GTGeometry"
+	ProjectGUID="{A1B6E932-F612-4CBC-9260-DF91CD4E748F}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory=".\build\$(ConfigurationName)"
+			IntermediateDirectory=".\build\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".\src\libs;.\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
+				MinimalRebuild="TRUE"
+				ExceptionHandling="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)/GTGeometry_d.lib"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory=".\build\$(ConfigurationName)"
+			IntermediateDirectory=".\build\$(ConfigurationName)"
+			ConfigurationType="4"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".\src\libs;.\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_LIB"
+				MinimalRebuild="TRUE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="4"
+				UsePrecompiledHeader="0"
+				WarningLevel="3"
+				Detect64BitPortabilityProblems="TRUE"
+				DebugInformationFormat="4"
+				CompileAs="2"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLibrarianTool"
+				OutputFile="$(OutDir)/GTGeometry.lib"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath=".\src\auxiliar.cpp">
+			</File>
+			<File
+				RelativePath=".\src\connectivity_graph.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoLodStripsConstructor.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoLodStripsLibrary.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoLodTreeConstructor.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoLodTreeLibrary.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMesh.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshSimplifier.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshSimpSequence.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshStripifier.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoSerializer.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoSubMesh.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoTreeSimplifier.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoTreeSimpSequence.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoVector2.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoVector3.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoVertexBuffer.cpp">
+			</File>
+			<File
+				RelativePath=".\src\hoja.cpp">
+			</File>
+			<File
+				RelativePath=".\src\policy.cpp">
+			</File>
+			<File
+				RelativePath=".\src\SimplificationMethod.cpp">
+			</File>
+			<File
+				RelativePath=".\src\tri_stripper.cpp">
+			</File>
+			<Filter
+				Name="simplif"
+				Filter="">
+				<File
+					RelativePath=".\src\libs\gfx\geom\3D.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\geom\3D.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\Array.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\Array2.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\Array3.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\Buffer.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\cholesky.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\heap.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\tools\Heap.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\jacobi.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat2.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat2.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat3.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat3.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat4.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Mat4.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\geom\ProjectH.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\geom\ProxGrid.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\geom\ProxGrid.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\random.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\Smf\smf.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\Smf\smf.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\Smf\smfstate.cxx">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\Smf\smfstate.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\std.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Vec2.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Vec3.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\gfx\math\Vec4.h">
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath=".\src\libs\AdjModel.cxx">
+			</File>
+			<File
+				RelativePath=".\src\libs\AdjModel.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\AdjPrims.cxx">
+			</File>
+			<File
+				RelativePath=".\src\libs\AdjPrims.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\auxiliar.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\avars.cxx">
+			</File>
+			<File
+				RelativePath=".\src\libs\avars.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoBase.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoLodStripsConstructor.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoLodStripsLibrary.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoLodTreeConstructor.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoLodTreeLibrary.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoMesh.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoMeshSimplifier.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoMeshSimpSequence.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoMeshStripifier.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoSerializable.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoSerializer.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoSubMesh.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoTreeSimplifier.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoTreeSimpSequence.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoVector2.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoVector3.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\GeoVertexBuffer.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\hoja.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\NPrim.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\detail\policy.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\qslim.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\quadrics.cxx">
+			</File>
+			<File
+				RelativePath=".\src\libs\quadrics.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\SimplificationMethod.h">
+			</File>
+			<File
+				RelativePath=".\src\libs\tri_stripper.h">
+			</File>
+			<Filter
+				Name="detail"
+				Filter="">
+				<File
+					RelativePath=".\src\libs\detail\cache_simulator.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\detail\graph_array.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\detail\heap_array.h">
+				</File>
+				<File
+					RelativePath=".\src\libs\detail\types.h">
+				</File>
+			</Filter>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUILayout.xsd
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUILayout.xsd	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUILayout.xsd	(revision 774)
@@ -0,0 +1,42 @@
+<?xml version="1.0"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+
+	<xsd:element name="GUILayout" type="GUILayoutType"/>
+	
+	<xsd:complexType name="GUILayoutType">
+		<xsd:sequence>
+			<xsd:element name="Window" type="WindowType" />
+		</xsd:sequence>
+		<xsd:attribute name="Parent" type="xsd:string" use="optional" default=""/>
+	</xsd:complexType>
+	
+	<xsd:complexType name="WindowType">
+		<xsd:sequence>
+			<xsd:element name="LayoutImport" type="LayoutImportType"  minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="Property" type="PropertyType"  minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="Event" type="EventType"  minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="Window" type="WindowType"  minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="Property" type="PropertyType"  minOccurs="0" maxOccurs="unbounded" />
+		</xsd:sequence>
+		<xsd:attribute name="Type" type="xsd:string" use="required"/>
+		<xsd:attribute name="Name" type="xsd:string" use="required"/>
+	</xsd:complexType>
+
+	<xsd:complexType name="PropertyType">
+		<xsd:attribute name="Name" type="xsd:string" use="required"/>
+		<xsd:attribute name="Value" type="xsd:string" use="required"/>
+	</xsd:complexType>
+
+	<xsd:complexType name="LayoutImportType">
+		<xsd:attribute name="Filename" type="xsd:string" use="required"/>
+		<xsd:attribute name="Prefix" type="xsd:string" use="optional" default="" />
+		<xsd:attribute name="ResourceGroup" type="xsd:string" use="optional"  default="" />
+	</xsd:complexType>
+
+	<xsd:complexType name="EventType">
+		<xsd:attribute name="Name" type="xsd:string" use="required"/>
+		<xsd:attribute name="Function" type="xsd:string" use="required"/>
+	</xsd:complexType>
+
+</xsd:schema>
+
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.imageset
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.imageset	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.imageset	(revision 774)
@@ -0,0 +1,200 @@
+<?xml version="1.0" ?>
+<Imageset Name="TaharezLook" Imagefile="TaharezLook.tga" NativeHorzRes="800" NativeVertRes="600" AutoScaled="true">
+	<Image Name="ClientBrush" XPos="2" YPos="2" Width="64" Height="64" />
+	<Image Name="WindowLeftEdge" XPos="6" YPos="95" Width="1" Height="22" XOffset="4" />
+	<Image Name="WindowRightEdge" XPos="34" YPos="95" Width="1" Height="22" XOffset="-5" />
+	<Image Name="WindowTopEdge" XPos="9" YPos="68" Width="23" Height="1" />
+	<Image Name="WindowBottomEdge" XPos="9" YPos="143" Width="23" Height="1" />
+	<Image Name="WindowTopLeft" XPos="2" YPos="68" Width="5" Height="24" />
+	<Image Name="WindowTopRight" XPos="34" YPos="68" Width="5" Height="24" />
+	<Image Name="WindowBottomLeft" XPos="2" YPos="120" Width="5" Height="24" />
+	<Image Name="WindowBottomRight" XPos="34" YPos="120" Width="5" Height="24" />
+	<Image Name="ButtonLeftNormal" XPos="68" YPos="20" Width="12" Height="16" />
+	<Image Name="ButtonMiddleNormal" XPos="82" YPos="20" Width="12" Height="16" />
+	<Image Name="ButtonRightNormal" XPos="96" YPos="20" Width="12" Height="16" />
+	<Image Name="ButtonLeftPushed" XPos="68" YPos="38" Width="12" Height="16" />
+	<Image Name="ButtonMiddlePushed" XPos="82" YPos="38" Width="12" Height="16" />
+	<Image Name="ButtonRightPushed" XPos="96" YPos="38" Width="12" Height="16" />
+	<Image Name="ButtonLeftHighlight" XPos="68" YPos="56" Width="12" Height="16" />
+	<Image Name="ButtonMiddleHighlight" XPos="82" YPos="56" Width="12" Height="16" />
+	<Image Name="ButtonRightHighlight" XPos="96" YPos="56" Width="12" Height="16" />
+	<Image Name="CheckboxNormal" XPos="110" YPos="2" Width="12" Height="12" />
+	<Image Name="CheckboxHover" XPos="110" YPos="30" Width="12" Height="12" />
+	<Image Name="CheckboxMark" XPos="110" YPos="16" Width="12" Height="12" />
+	<Image Name="RadioButtonNormal" XPos="124" YPos="2" Width="12" Height="12" />
+	<Image Name="RadioButtonHover" XPos="124" YPos="30" Width="12" Height="12" />
+	<Image Name="RadioButtonMark" XPos="124" YPos="16" Width="12" Height="12" />
+	<Image Name="TitlebarLeft" XPos="68" YPos="2" Width="8" Height="16" />
+	<Image Name="TitlebarMiddle" XPos="78" YPos="2" Width="8" Height="16" />
+	<Image Name="TitlebarRight" XPos="88" YPos="2" Width="8" Height="16" />
+	<Image Name="NewTitlebarLeft" XPos="61" YPos="127" Width="13" Height="16" />
+	<Image Name="NewTitlebarMiddle" XPos="77" YPos="127" Width="12" Height="16" />
+	<Image Name="NewTitlebarRight" XPos="92" YPos="127" Width="12" Height="16" />
+	<Image Name="SysAreaMiddle" XPos="107" YPos="127" Width="12" Height="16" />
+	<Image Name="SysAreaRight" XPos="122" YPos="127" Width="13" Height="16" />
+	<Image Name="StaticLeft" XPos="41" YPos="89" Width="6" Height="6" />
+	<Image Name="StaticRight" XPos="63" YPos="89" Width="6" Height="6" />
+	<Image Name="StaticTop" XPos="52" YPos="78" Width="6" Height="6" />
+	<Image Name="StaticBottom" XPos="52" YPos="100" Width="6" Height="6" />
+	<Image Name="StaticTopLeft" XPos="41" YPos="78" Width="6" Height="6" />
+	<Image Name="StaticTopRight" XPos="63" YPos="78" Width="6" Height="6" />
+	<Image Name="StaticBottomLeft" XPos="41" YPos="100" Width="6" Height="6" />
+	<Image Name="StaticBottomRight" XPos="63" YPos="100" Width="6" Height="6" />
+	<Image Name="StaticBackdrop" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="ProgressBarLeft" XPos="71" YPos="74" Width="7" Height="12" />
+	<Image Name="ProgressBarMiddle" XPos="80" YPos="74" Width="6" Height="12" />
+	<Image Name="ProgressBarRight" XPos="88" YPos="74" Width="6" Height="12" />
+	<Image Name="ProgressBarDimSegment" XPos="96" YPos="74" Width="8" Height="12" />
+	<Image Name="ProgressBarLitSegment" XPos="106" YPos="74" Width="8" Height="12" />
+	<Image Name="EditBoxLeft" XPos="41" YPos="108" Width="4" Height="18" />
+	<Image Name="EditBoxMiddle" XPos="47" YPos="108" Width="4" Height="18" />
+	<Image Name="EditBoxRight" XPos="53" YPos="108" Width="4" Height="18" />
+	<Image Name="EditBoxCarat" XPos="60" YPos="108" Width="4" Height="18" />
+	<Image Name="TextSelectionBrush" XPos="8" YPos="70" Width="16" Height="16" />
+	<Image Name="VertScrollTop" XPos="182" YPos="2" Width="20" Height="8" />
+	<Image Name="VertScrollMiddle" XPos="182" YPos="12" Width="20" Height="8" />
+	<Image Name="VertScrollBottom" XPos="182" YPos="22" Width="20" Height="8" />
+	<Image Name="VertScrollBarSegment" XPos="206" YPos="2" Width="4" Height="10" />
+	<Image Name="VertScrollThumbNormal" XPos="214" YPos="2" Width="8" Height="24" />
+	<Image Name="VertScrollThumbHover" XPos="224" YPos="2" Width="8" Height="24" />
+	<Image Name="VertScrollUpNormal" XPos="196" YPos="32" Width="12" Height="12" />
+	<Image Name="VertScrollDownNormal" XPos="182" YPos="32" Width="12" Height="12" />
+	<Image Name="VertScrollUpHover" XPos="196" YPos="46" Width="12" Height="12" />
+	<Image Name="VertScrollDownHover" XPos="182" YPos="46" Width="12" Height="12" />
+	<Image Name="MiniVertScrollBarSegment" XPos="207" YPos="60" Width="4" Height="10" />
+	<Image Name="MiniVertScrollThumbNormal" XPos="214" YPos="59" Width="7" Height="22" />
+	<Image Name="MiniVertScrollThumbTopNormal" XPos="214" YPos="59" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbMiddleNormal" XPos="214" YPos="65" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbBottomNormal" XPos="214" YPos="76" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbTopHover" XPos="223" YPos="59" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbMiddleHover" XPos="223" YPos="65" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbBottomHover" XPos="223" YPos="76" Width="7" Height="5" />
+	<Image Name="MiniVertScrollThumbHover" XPos="223" YPos="59" Width="7" Height="22" />
+	<Image Name="MiniVertScrollUpNormal" XPos="194" YPos="60" Width="10" Height="9" />
+	<Image Name="MiniVertScrollDownNormal" XPos="182" YPos="59" Width="10" Height="9" />
+	<Image Name="MiniVertScrollUpHover" XPos="194" YPos="70" Width="10" Height="9" />
+	<Image Name="MiniVertScrollDownHover" XPos="182" YPos="69" Width="10" Height="9" />
+	<Image Name="VertSliderBody" XPos="234" YPos="2" Width="9" Height="48" />
+	<Image Name="VertSliderThumbNormal" XPos="217" YPos="28" Width="15" Height="6" />
+	<Image Name="VertSliderThumbHover" XPos="217" YPos="36" Width="15" Height="6" />
+	<Image Name="MiniHorzScrollBarSegment" XPos="244" YPos="80" Width="10" Height="4" />
+	<Image Name="MiniHorzScrollThumbNormal" XPos="233" YPos="87" Width="22" Height="7" />
+	<Image Name="MiniHorzScrollThumbLeftNormal" XPos="233" YPos="87" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollThumbMiddleNormal" XPos="239" YPos="87" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollThumbRightNormal" XPos="250" YPos="87" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollThumbHover" XPos="233" YPos="96" Width="22" Height="7" />
+	<Image Name="MiniHorzScrollThumbLeftHover" XPos="233" YPos="96" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollThumbMiddleHover" XPos="239" YPos="96" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollThumbRightHover" XPos="250" YPos="96" Width="5" Height="7" />
+	<Image Name="MiniHorzScrollLeftNormal" XPos="246" YPos="55" Width="9" Height="10" />
+	<Image Name="MiniHorzScrollRightNormal" XPos="245" YPos="67" Width="9" Height="10" />
+	<Image Name="MiniHorzScrollLeftHover" XPos="236" YPos="55" Width="9" Height="10" />
+	<Image Name="MiniHorzScrollRightHover" XPos="235" YPos="67" Width="9" Height="10" />
+	<Image Name="ListboxLeft" XPos="41" YPos="89" Width="7" Height="6" />
+	<Image Name="ListboxRight" XPos="62" YPos="89" Width="7" Height="6" />
+	<Image Name="ListboxTop" XPos="52" YPos="78" Width="6" Height="7" />
+	<Image Name="ListboxBottom" XPos="52" YPos="99" Width="6" Height="7" />
+	<Image Name="ListboxTopLeft" XPos="41" YPos="78" Width="7" Height="7" />
+	<Image Name="ListboxTopRight" XPos="62" YPos="78" Width="7" Height="7" />
+	<Image Name="ListboxBottomLeft" XPos="41" YPos="99" Width="7" Height="7" />
+	<Image Name="ListboxBottomRight" XPos="62" YPos="99" Width="7" Height="7" />
+	<Image Name="ListboxBackdrop" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="ListboxSelectionBrush" XPos="8" YPos="70" Width="16" Height="16" />
+	<Image Name="ComboboxEditLeft" XPos="138" YPos="2" Width="8" Height="16" />
+	<Image Name="ComboboxEditMiddle" XPos="148" YPos="2" Width="8" Height="16" />
+	<Image Name="ComboboxListButtonNormal" XPos="158" YPos="2" Width="16" Height="16" />
+	<Image Name="ComboboxListButtonHover" XPos="158" YPos="20" Width="16" Height="16" />
+	<Image Name="ComboboxListLeft" XPos="138" YPos="48" Width="8" Height="8" />
+	<Image Name="ComboboxListRight" XPos="158" YPos="48" Width="8" Height="8" />
+	<Image Name="ComboboxListTop" XPos="148" YPos="48" Width="8" Height="8" />
+	<Image Name="ComboboxListBottom" XPos="148" YPos="58" Width="8" Height="8" />
+	<Image Name="ComboboxListTopLeft" XPos="138" YPos="38" Width="8" Height="8" />
+	<Image Name="ComboboxListTopRight" XPos="158" YPos="38" Width="8" Height="8" />
+	<Image Name="ComboboxListBottomLeft" XPos="138" YPos="58" Width="8" Height="8" />
+	<Image Name="ComboboxListBottomRight" XPos="158" YPos="58" Width="8" Height="8" />
+	<Image Name="ComboboxListBackdrop" XPos="148" YPos="48" Width="8" Height="8" />
+	<Image Name="ComboboxSelectionBrush" XPos="8" YPos="70" Width="16" Height="16" />
+	<Image Name="ComboboxDividerLeft" XPos="138" YPos="68" Width="14" Height="1" />
+	<Image Name="ComboboxDividerMiddle" XPos="154" YPos="68" Width="8" Height="1" />
+	<Image Name="ComboboxDividerRight" XPos="164" YPos="68" Width="14" Height="1" />
+	<Image Name="HeaderBarBackdropNormal" XPos="230" YPos="163" Width="10" Height="12" />
+	<Image Name="HeaderBarBackdropHover" XPos="230" YPos="163" Width="10" Height="12" />
+	<Image Name="HeaderBarSplitterNormal" XPos="225" YPos="92" Width="3" Height="16" />
+	<Image Name="HeaderBarSplitterHover" XPos="200" YPos="92" Width="3" Height="16" />
+	<Image Name="HeaderBarSortUp" XPos="233" YPos="178" Width="8" Height="8" />
+	<Image Name="HeaderBarSortDown" XPos="244" YPos="178" Width="8" Height="8" />
+	<Image Name="MultiListLeft" XPos="170" YPos="92" Width="7" Height="6" />
+	<Image Name="MultiListRight" XPos="191" YPos="92" Width="7" Height="6" />
+	<Image Name="MultiListTop" XPos="181" YPos="81" Width="6" Height="7" />
+	<Image Name="MultiListBottom" XPos="181" YPos="102" Width="6" Height="7" />
+	<Image Name="MultiListTopLeft" XPos="170" YPos="81" Width="7" Height="7" />
+	<Image Name="MultiListTopRight" XPos="191" YPos="81" Width="7" Height="7" />
+	<Image Name="MultiListBottomLeft" XPos="170" YPos="102" Width="7" Height="7" />
+	<Image Name="MultiListBottomRight" XPos="191" YPos="102" Width="7" Height="7" />
+	<Image Name="MultiListBackdrop" XPos="181" YPos="92" Width="6" Height="6" />
+	<Image Name="MultiListSelectionBrush" XPos="9" YPos="71" Width="14" Height="14" />
+	<Image Name="AltProgressLeft" XPos="71" YPos="88" Width="8" Height="12" />
+	<Image Name="AltProgressMiddle" XPos="81" YPos="88" Width="8" Height="12" />
+	<Image Name="AltProgressRight" XPos="91" YPos="88" Width="8" Height="12" />
+	<Image Name="AltProgressQuarter" XPos="102" YPos="89" Width="3" Height="4" />
+	<Image Name="AltProgressHalf" XPos="109" YPos="89" Width="4" Height="5" />
+	<Image Name="AltProgressLight1" XPos="100" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight2" XPos="106" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight3" XPos="112" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight4" XPos="118" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight5" XPos="124" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight6" XPos="130" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight7" XPos="136" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight8" XPos="142" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight9" XPos="148" YPos="97" Width="4" Height="8" />
+	<Image Name="AltProgressLight10" XPos="154" YPos="97" Width="4" Height="8" />
+	<Image Name="CloseButtonNormal" XPos="41" YPos="128" Width="16" Height="16" />
+	<Image Name="CloseButtonHover" XPos="41" YPos="146" Width="16" Height="16" />
+	<Image Name="CloseButtonPressed" XPos="41" YPos="164" Width="16" Height="16" />
+	<Image Name="NewCloseButtonNormal" XPos="90" YPos="146" Width="10" Height="10" />
+	<Image Name="NewCloseButtonHover" XPos="90" YPos="146" Width="10" Height="10" />
+	<Image Name="NewCloseButtonPressed" XPos="90" YPos="146" Width="10" Height="10" />
+	<Image Name="MultiLineEditboxLeft" XPos="41" YPos="89" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxRight" XPos="63" YPos="89" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxTop" XPos="52" YPos="78" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxBottom" XPos="52" YPos="100" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxTopLeft" XPos="41" YPos="78" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxTopRight" XPos="63" YPos="78" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxBottomLeft" XPos="41" YPos="100" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxBottomRight" XPos="63" YPos="100" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxBackdrop" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="MultiLineEditboxSelectionBrush" XPos="9" YPos="71" Width="14" Height="14" />
+	<Image Name="MouseTarget" XPos="182" YPos="127" Width="17" Height="17" XOffset="-8" YOffset="-8" />
+	<Image Name="MouseArrow" XPos="138" YPos="127" Width="31" Height="25" XOffset="0" YOffset="0" />
+	<Image Name="MouseMoveCursor" XPos="201" YPos="127" Width="18" Height="18" XOffset="-8" YOffset="-8" />
+	<Image Name="MouseNoSoCursor" XPos="221" YPos="127" Width="8" Height="18" XOffset="-3" YOffset="-8" />
+	<Image Name="MouseEsWeCursor" XPos="182" YPos="150" Width="18" Height="8" XOffset="-8" YOffset="-3" />
+	<Image Name="MouseNeSwCursor" XPos="201" YPos="147" Width="14" Height="14" XOffset="-7" YOffset="-7" />
+	<Image Name="MouseNwSeCursor" XPos="230" YPos="126" Width="14" Height="14" XOffset="-7" YOffset="-7" />
+	<Image Name="MouseTextBar" XPos="173" YPos="127" Width="7" Height="18" XOffset="-2" YOffset="-9" />
+	<Image Name="TabControlButtonPaneFiller" XPos="197" YPos="201" Width="7" Height="1" />
+	<Image Name="TabPaneLeft" XPos="41" YPos="89" Width="7" Height="6" />
+	<Image Name="TabPaneRight" XPos="62" YPos="89" Width="7" Height="6" />
+	<Image Name="TabPaneLower" XPos="52" YPos="99" Width="6" Height="7" />
+	<Image Name="TabPaneLowerLeft" XPos="41" YPos="99" Width="7" Height="7" />
+	<Image Name="TabPaneLowerRight" XPos="62" YPos="99" Width="7" Height="7" />
+	<Image Name="TabPaneMiddle" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="TabButtonLeftNormal" XPos="41" YPos="89" Width="7" Height="6" />
+	<Image Name="TabButtonRightNormal" XPos="62" YPos="89" Width="7" Height="6" />
+	<Image Name="TabButtonUpperNormal" XPos="52" YPos="78" Width="6" Height="7" />
+	<Image Name="TabButtonLowerNormal" XPos="52" YPos="99" Width="6" Height="7" />
+	<Image Name="TabButtonUpperLeftNormal" XPos="41" YPos="78" Width="7" Height="7" />
+	<Image Name="TabButtonUpperRightNormal" XPos="62" YPos="78" Width="7" Height="7" />
+	<Image Name="TabButtonLowerLeftNormal" XPos="41" YPos="99" Width="7" Height="7" />
+	<Image Name="TabButtonLowerRightNormal" XPos="187" YPos="195" Width="7" Height="7" />
+	<Image Name="TabButtonMiddleNormal" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="TabButtonLeftSelected" XPos="41" YPos="89" Width="7" Height="6" />
+	<Image Name="TabButtonRightSelected" XPos="62" YPos="89" Width="7" Height="6" />
+	<Image Name="TabButtonUpperSelected" XPos="52" YPos="78" Width="6" Height="7" />
+	<Image Name="TabButtonLowerSelected" XPos="52" YPos="89" Width="6" Height="6" />
+	<Image Name="TabButtonUpperLeftSelected" XPos="41" YPos="78" Width="7" Height="7" />
+	<Image Name="TabButtonUpperRightSelected" XPos="62" YPos="78" Width="7" Height="7" />
+	<Image Name="TabButtonLowerLeftSelected" XPos="41" YPos="99" Width="7" Height="7" />
+	<Image Name="TabButtonLowerRightSelected" XPos="62" YPos="99" Width="7" Height="7" />
+	<Image Name="TabButtonMiddleSelected" XPos="52" YPos="89" Width="6" Height="6" />
+</Imageset>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/cegui8.layout
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/cegui8.layout	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/cegui8.layout	(revision 774)
@@ -0,0 +1,130 @@
+<?xml version="1.0" ?>
+<!-- Layout file from CEGUI Demo8 -->
+<GUILayout>
+<Window Type="DefaultGUISheet" Name="demo_root">
+
+	<Window Type="DefaultGUISheet" Name="Demo8">
+
+		<Property Name="RelativeMaxSize" Value="w:1 h:2" />
+		<Property Name="Size" Value="w:1 h:2" />
+
+		<Window Type="TaharezLook/VerticalScrollbar" Name="Demo8/ViewScroll">
+			<Property Name="Position" Value="x:0.0 y:0.0" />
+			<Property Name="Size" Value="w:0.03 h:0.75" />
+			<Property Name="DocumentSize" Value="2" />
+			<Property Name="PageSize" Value="1" />
+			<Property Name="StepSize" Value="0.01" />
+			<Property Name="OverlapSize" Value="0.5" />
+		</Window>
+
+        <Window Type="TaharezLook/FrameWindow" Name="Demo8/Window1">
+			<Property Name="Position" Value="x:0.05 y:0.1" />
+			<Property Name="RelativeMaxSize" Value="w:0.5 h:1" />
+			<Property Name="AbsoluteMinSize" Value="w:128 h:128" />
+			<Property Name="Size" Value="w:0.4 h:0.35" />
+			<Property Name="Text" Value="Demo 8 - Listbox Demo" />
+
+			<Window Type="TaharezLook/Listbox" Name="Demo8/Window1/Listbox">
+				<Property Name="Position" Value="x:0.05 y:0.1" />
+				<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+				<Property Name="Size" Value="w:0.9 h:0.33" />
+			</Window>
+
+			<Window Type="TaharezLook/StaticText" Name="Demo8/Window1/Controls">
+				<Property Name="Position" Value="x:0.05 y:0.45" />
+				<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+				<Property Name="Size" Value="w:0.9 h:0.5" />
+
+                <Window Type="TaharezLook/HorizontalScrollbar" Name="Demo8/Window1/Controls/Red">
+					<Property Name="Position" Value="x:0.05 y:0.05" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.9 h:0.06" />
+					<Property Name="DocumentSize" Value="255" />
+					<Property Name="PageSize" Value="16" />
+					<Property Name="StepSize" Value="1" />
+					<Property Name="OverlapSize" Value="1" />
+				</Window>
+
+                <Window Type="TaharezLook/HorizontalScrollbar" Name="Demo8/Window1/Controls/Green">
+					<Property Name="Position" Value="x:0.05 y:0.12" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.9 h:0.06" />
+					<Property Name="DocumentSize" Value="256" />
+					<Property Name="PageSize" Value="16" />
+					<Property Name="StepSize" Value="1" />
+					<Property Name="OverlapSize" Value="1" />
+				</Window>
+
+                <Window Type="TaharezLook/HorizontalScrollbar" Name="Demo8/Window1/Controls/Blue">
+					<Property Name="Position" Value="x:0.05 y:0.19" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.9 h:0.06" />
+					<Property Name="DocumentSize" Value="255" />
+					<Property Name="PageSize" Value="16" />
+					<Property Name="StepSize" Value="1" />
+					<Property Name="OverlapSize" Value="1" />
+				</Window>
+
+				<Window Type="TaharezLook/StaticImage" Name="Demo8/Window1/Controls/ColourSample">
+					<Property Name="Position" Value="x:0.05 y:0.26" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.9 h:0.1" />
+					<Property Name="Image" Value="set:TaharezLook image:ListboxSelectionBrush" />
+					<Property Name="ImageColours" Value="tl:0 tr:0 bl:0 br:0" />
+				</Window>
+
+				<Window Type="TaharezLook/Editbox" Name="Demo8/Window1/Controls/Editbox">
+					<Property Name="Position" Value="x:0.05 y:0.38" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.6 h:0.15" />
+				</Window>
+
+                <Window Type="TaharezLook/Button" Name="Demo8/Window1/Controls/Add">
+					<Property Name="Position" Value="x:0.68 y:0.38" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.3 h:0.15" />
+					<Property Name="Text" Value="Add" />
+				</Window>
+
+                <Window Type="TaharezLook/StaticText" Name="Demo8/Window1/Controls/ins1">
+					<Property Name="Position" Value="x:0.05 y:0.55" />
+					<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+					<Property Name="Size" Value="w:0.9 h:0.4" />
+					<Property Name="HorzFormatting" Value="WordWrapCentred" />
+					<Property Name="Text" Value="Use this panel to add items.  The scrollbars change the selection colour." />
+				</Window>
+
+			</Window>
+			
+		</Window>
+
+        <Window Type="TaharezLook/FrameWindow" Name="Demo8/Window2">
+			<Property Name="Position" Value="x:0.55 y:0.1" />
+			<Property Name="RelativeMaxSize" Value="w:0.5 h:1" />
+			<Property Name="AbsoluteMinSize" Value="w:128 h:128" />
+			<Property Name="Size" Value="w:0.4 h:0.3" />
+			<Property Name="Text" Value="Demo 8 - Information Window" />
+
+            <Window Type="TaharezLook/StaticText" Name="Demo8/Window2/Info">
+				<Property Name="Position" Value="x:0.05 y:0.1" />
+				<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+				<Property Name="Size" Value="w:0.9 h:0.3" />
+				<Property Name="HorzFormatting" Value="WordWrapCentred" />
+				<Property Name="Text" Value="The panel below gives some information about the item under the mouse." />
+			</Window>
+	
+            <Window Type="TaharezLook/StaticText" Name="Demo8/Window2/Tips">
+				<Property Name="Position" Value="x:0.05 y:0.5" />
+				<Property Name="RelativeMaxSize" Value="w:1 h:1" />
+				<Property Name="Size" Value="w:0.9 h:0.4" />
+				<Property Name="HorzFormatting" Value="WordWrapCentred" />
+			</Window>
+
+		</Window>
+
+
+	</Window>
+
+</Window>
+
+</GUILayout>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/Font.xsd
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/Font.xsd	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/Font.xsd	(revision 774)
@@ -0,0 +1,49 @@
+<?xml version="1.0" ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+	<xsd:element name="Font" type="FontType" />
+
+	<xsd:complexType name="FontType">
+		<xsd:sequence>
+			<xsd:element name="Mapping" type="MapType" maxOccurs="unbounded" minOccurs="0" />
+			<xsd:element name="GlyphSet" type="GlyphSetType" maxOccurs="unbounded" minOccurs="0" />
+			<xsd:element name="GlyphRange" type="GlyphRangeType" maxOccurs="unbounded" minOccurs="0" />
+			<xsd:element name="Glyph" type="GlyphType" maxOccurs="unbounded" minOccurs="0" />
+		</xsd:sequence>
+		<xsd:attributeGroup ref="FontAttrs" />
+	</xsd:complexType>
+	<xsd:complexType name="MapType">
+		<xsd:attribute name="Codepoint" type="xsd:nonNegativeInteger" use="required" />
+		<xsd:attribute name="Image" type="xsd:string" use="required" />
+		<xsd:attribute name="HorzAdvance" type="xsd:integer" use="optional" default="-1" />
+	</xsd:complexType>
+	<xsd:complexType name="GlyphType">
+		<xsd:attribute name="Codepoint" type="xsd:nonNegativeInteger" use="required" />
+	</xsd:complexType>
+	<xsd:complexType name="GlyphRangeType">
+		<xsd:attribute name="StartCodepoint" type="xsd:nonNegativeInteger" use="required" />
+		<xsd:attribute name="EndCodepoint" type="xsd:nonNegativeInteger" use="required" />
+	</xsd:complexType>
+	<xsd:complexType name="GlyphSetType">
+		<xsd:attribute name="Glyphs" type="xsd:string" use="required" />
+	</xsd:complexType>
+	<xsd:attributeGroup name="FontAttrs">
+		<xsd:attribute name="Name" type="xsd:string" use="required" />
+		<xsd:attribute name="Filename" type="xsd:string" use="required" />
+		<xsd:attribute name="ResourceGroup" type="xsd:string" use="optional"  default="" />
+		<xsd:attribute name="Type" use="required">
+			<xsd:simpleType>
+				<xsd:restriction base="xsd:string">
+					<xsd:enumeration value="Dynamic" />
+					<xsd:enumeration value="Static" />
+				</xsd:restriction>
+			</xsd:simpleType>
+		</xsd:attribute>
+		<xsd:attribute name="Size" type="xsd:nonNegativeInteger" use="optional" default="12" />
+		<xsd:attribute name="FirstCodepoint" type="xsd:nonNegativeInteger" use="optional" default="32" />
+		<xsd:attribute name="LastCodepoint" type="xsd:nonNegativeInteger" use="optional" default="127" />
+		<xsd:attribute name="NativeHorzRes" type="xsd:nonNegativeInteger" use="optional" default="640" />
+		<xsd:attribute name="NativeVertRes" type="xsd:nonNegativeInteger" use="optional" default="480" />
+		<xsd:attribute name="AutoScaled" type="xsd:boolean" use="optional" default="false" />
+		<xsd:attribute name="AntiAlias" type="xsd:boolean" use="optional" default="true" />
+	</xsd:attributeGroup>
+</xsd:schema>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUIScheme.xsd
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUIScheme.xsd	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/GUIScheme.xsd	(revision 774)
@@ -0,0 +1,31 @@
+<?xml version="1.0" ?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+	<xsd:element name="GUIScheme" type="SchemeType" />
+	<xsd:complexType name="SchemeType">
+		<xsd:sequence>
+			<xsd:element name="Imageset" type="NamedDataType" minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="Font" type="NamedDataType" minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="WindowSet" type="WindowSetType" minOccurs="0" maxOccurs="unbounded" />
+			<xsd:element name="WindowAlias" type="WindowAliasType" minOccurs="0" maxOccurs="unbounded" />
+		</xsd:sequence>
+		<xsd:attribute name="Name" type="xsd:string" use="required" />
+	</xsd:complexType>
+	<xsd:complexType name="WindowSetType">
+		<xsd:sequence>
+			<xsd:element name="WindowFactory" type="WindowFactoryType" maxOccurs="unbounded" />
+		</xsd:sequence>
+		<xsd:attribute name="Filename" type="xsd:string" use="required" />
+	</xsd:complexType>
+	<xsd:complexType name="NamedDataType">
+		<xsd:attribute name="Name" type="xsd:string" use="required" />
+		<xsd:attribute name="Filename" type="xsd:string" use="required" />
+		<xsd:attribute name="ResourceGroup" type="xsd:string" use="optional"  default="" />
+	</xsd:complexType>
+	<xsd:complexType name="WindowFactoryType">
+		<xsd:attribute name="Name" type="xsd:string" use="required" />
+	</xsd:complexType>
+	<xsd:complexType name="WindowAliasType">
+		<xsd:attribute name="Alias" type="xsd:string" use="required" />
+		<xsd:attribute name="Target" type="xsd:string" use="required" />
+	</xsd:complexType>
+</xsd:schema>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.scheme
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.scheme	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/TaharezLook.scheme	(revision 774)
@@ -0,0 +1,38 @@
+<?xml version="1.0" ?>
+<GUIScheme Name="TaharezLook">
+	<Imageset Name="TaharezLook" Filename="TaharezLook.imageset" />
+	<Font Name="Tahoma-12" Filename="tahoma-12.font" />
+	<WindowSet Filename="CEGUITaharezLook">
+		<WindowFactory Name="TaharezLook/AlternateProgressBar" />
+		<WindowFactory Name="TaharezLook/Button" />
+		<WindowFactory Name="TaharezLook/Checkbox" />
+		<WindowFactory Name="TaharezLook/CloseButton" />
+		<WindowFactory Name="TaharezLook/Combobox" />
+		<WindowFactory Name="TaharezLook/ComboDropList" />
+		<WindowFactory Name="TaharezLook/ComboEditbox" />
+		<WindowFactory Name="TaharezLook/Editbox" />
+		<WindowFactory Name="TaharezLook/FrameWindow" />
+		<WindowFactory Name="TaharezLook/LargeVerticalScrollbar" />
+		<WindowFactory Name="TaharezLook/LargeVerticalScrollbarThumb" />
+		<WindowFactory Name="TaharezLook/Listbox" />
+		<WindowFactory Name="TaharezLook/ListHeader" />
+		<WindowFactory Name="TaharezLook/ListHeaderSegment" />
+		<WindowFactory Name="TaharezLook/HorizontalScrollbar" />
+		<WindowFactory Name="TaharezLook/HorizontalScrollbarThumb" />
+		<WindowFactory Name="TaharezLook/MultiColumnList" />
+		<WindowFactory Name="TaharezLook/MultiLineEditbox" />
+		<WindowFactory Name="TaharezLook/ProgressBar" />
+		<WindowFactory Name="TaharezLook/RadioButton" />
+		<WindowFactory Name="TaharezLook/Slider" />
+		<WindowFactory Name="TaharezLook/SliderThumb" />
+		<WindowFactory Name="TaharezLook/StaticImage" />
+		<WindowFactory Name="TaharezLook/StaticText" />
+		<WindowFactory Name="TaharezLook/TabButton" />
+		<WindowFactory Name="TaharezLook/TabControl" />
+		<WindowFactory Name="TaharezLook/TabPane" />
+		<WindowFactory Name="TaharezLook/Titlebar" />
+		<WindowFactory Name="TaharezLook/VerticalScrollbar" />
+		<WindowFactory Name="TaharezLook/VerticalScrollbarThumb" />
+		<WindowFactory Name="TaharezLook/VUMeter" />
+	</WindowSet>
+</GUIScheme>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/Imageset.xsd
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/Imageset.xsd	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/Imageset.xsd	(revision 774)
@@ -0,0 +1,28 @@
+<?xml version="1.0"?>
+<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
+
+	<xsd:element name="Imageset" type="ImagesetType"/>
+	
+	<xsd:complexType name="ImagesetType">
+		<xsd:sequence>
+			<xsd:element name="Image" type="ImageType" maxOccurs="unbounded"/>
+		</xsd:sequence>
+		<xsd:attribute name="Imagefile" type="xsd:string" use="required"/>
+		<xsd:attribute name="ResourceGroup" type="xsd:string" use="optional"  default="" />
+		<xsd:attribute name="Name" type="xsd:string" use="required"/>
+		<xsd:attribute name="NativeHorzRes" type="xsd:nonNegativeInteger" use="optional" default="640" />
+		<xsd:attribute name="NativeVertRes" type="xsd:nonNegativeInteger" use="optional" default="480" />
+		<xsd:attribute name="AutoScaled" type="xsd:boolean" use="optional" default="false" />
+	</xsd:complexType>
+	
+	<xsd:complexType name="ImageType">
+		<xsd:attribute name="Name" type="xsd:string" use="required"/>
+		<xsd:attribute name="XPos" type="xsd:nonNegativeInteger" use="required"/>
+		<xsd:attribute name="YPos" type="xsd:nonNegativeInteger" use="required"/>
+		<xsd:attribute name="Width" type="xsd:nonNegativeInteger" use="required"/>
+		<xsd:attribute name="Height" type="xsd:nonNegativeInteger" use="required"/>
+		<xsd:attribute name="XOffset" type="xsd:integer" use="optional" default="0"/>
+		<xsd:attribute name="YOffset" type="xsd:integer" use="optional" default="0"/>						
+	</xsd:complexType>
+
+</xsd:schema>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/ogregui.layout
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/ogregui.layout	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/ogregui.layout	(revision 774)
@@ -0,0 +1,79 @@
+<?xml version="1.0" ?>
+<GUILayout>
+<Window Type="DefaultGUISheet" Name="root">
+    <Window Type="DefaultGUISheet" Name="OgreGuiDemo">
+		<Property Name="Size" Value="w:0.25 h:1" />
+
+        <Window Type="TaharezLook/TabControl" Name="OgreGuiDemo/TabCtrl">
+            <Property Name="Position" Value="x:0.0 y:0.0" />
+            <Property Name="Size" Value="w:1 h:0.5" />
+
+            <Window Type="DefaultGUISheet" Name="OgreGuiDemo/TabCtrl/Page1">
+                <Property Name="Text" Value="File" />
+                <Window Type="TaharezLook/Button" Name="OgreGuiDemo/TabCtrl/Page1/NewButton">
+                    <Property Name="Position" Value="x:0.1 y:0.1" />
+                    <Property Name="Size" Value="w:0.8 h:0.07" />
+                    <Property Name="Text" Value="New" />
+                </Window>
+                <Window Type="TaharezLook/Button" Name="OgreGuiDemo/TabCtrl/Page1/LoadButton">
+                    <Property Name="Position" Value="x:0.1 y:0.2" />
+                    <Property Name="Size" Value="w:0.8 h:0.07" />
+                    <Property Name="Text" Value="Load Test Layout" />
+                </Window>
+                <Window Type="TaharezLook/Button" Name="OgreGuiDemo/TabCtrl/Page1/QuitButton">
+                    <Property Name="Position" Value="x:0.1 y:0.3" />
+                    <Property Name="Size" Value="w:0.8 h:0.07" />
+                    <Property Name="Text" Value="Quit" />
+                </Window>
+            </Window>
+            <Window Type="DefaultGUISheet" Name="OgreGuiDemo/TabCtrl/Page2">
+                <Property Name="Text" Value="Objects" />
+                <Window Type="TaharezLook/Combobox" Name="OgreGuiDemo/TabCtrl/Page2/ObjectTypeList">
+                    <Property Name="Position" Value="x:0.1 y:0.1" />
+                    <Property Name="Size" Value="w:0.8 h:0.5" />
+                    <Property Name="Text" Value="Select Type" />
+                    <Property Name="ClippedByParent" Value="false" />
+                    <Property Name="ReadOnly" Value="true" />
+                </Window>
+            </Window>
+        </Window>
+        <!--<Window Type="TaharezLook/FrameWindow" Name="OgreGuiDemo/WindowPropertiesWindow">
+            <Property Name="Size" Value="w:1 h:0.3" />
+            <Property Name="Position" Value="x:0 y:0.52" />
+            <Property Name="TitlebarEnabled" Value="false" />
+            <Property Name="CloseButtonEnabled" Value="false" />
+            <Property Name="Visible" Value="false" />
+            <Property Name="Text" Value="Editor Window" />
+            <Window Type="TaharezLook/StaticText" Name="OgreGuiDemo/WindowProperties/NameText">
+                <Property Name="Position" Value="x:0.05 y:0.2" />
+                <Property Name="Size" Value="w:0.9 h:0.4" />
+                <Property Name="Text" Value="Name:" />
+            </Window>
+
+            <Window Type="TaharezLook/Button" Name="OgreGuiDemo/WindowPropertiesWindow/OKButton">
+                <Property Name="Position" Value="x:0.15 y:0.8" />
+                <Property Name="Size" Value="w:0.3 h:0.1" />
+                <Property Name="Text" Value="OK" />
+            </Window>
+            <Window Type="TaharezLook/Button" Name="OgreGuiDemo/WindowPropertiesWindow/CancelButton">
+                <Property Name="Position" Value="x:0.55 y:0.8" />
+                <Property Name="Size" Value="w:0.3 h:0.1" />
+                <Property Name="Text" Value="Cancel" />
+            </Window>
+        </Window>-->
+	</Window>
+    <Window Type="DefaultGUISheet" Name="OgreGuiDemo2">
+		<Property Name="Size" Value="w:0.75 h:1" />
+		<Property Name="Position" Value="x:0.25 y:0" />
+        <Window Type="TaharezLook/FrameWindow" Name="OgreGuiDemo2/MainWindow">
+            <Property Name="Size" Value="w:1 h:1" />
+            <Property Name="Position" Value="x:0 y:0" />
+            <Property Name="DragMovingEnabled" Value="false" />
+            <Property Name="RollUpEnabled" Value="false" />
+            <Property Name="CloseButtonEnabled" Value="false" />
+            <Property Name="Text" Value="Editor Window" />
+        </Window>
+    </Window>
+</Window>
+
+</GUILayout>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/gui/tahoma-12.font
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/gui/tahoma-12.font	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/gui/tahoma-12.font	(revision 774)
@@ -0,0 +1,2 @@
+<?xml version="1.0" ?>
+<Font Name="Tahoma-12" Filename="tahoma.ttf" Type="Dynamic" Size="12" NativeHorzRes="800" NativeVertRes="600" AutoScaled="true"/>
Index: /GTP/trunk/Lib/Geom/GeoTool/media/fonts/sample.fontdef
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/media/fonts/sample.fontdef	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/media/fonts/sample.fontdef	(revision 774)
@@ -0,0 +1,121 @@
+IronMaiden
+{
+	// Blame cearny for this one!
+	type 		truetype
+	source 		maiden.ttf
+	size 		48
+	resolution 	96
+}
+
+StarWars
+{
+	// Now this one I agree with ;)
+	// A Star Wars font :)
+	type 		truetype
+	source 		solo5.ttf
+	size 		16
+	resolution 	96
+}
+
+Ogre
+{
+	type	image
+	source 	font_matisse_itc.png
+
+glyph	!	0.0898438	0.125	0.0976563	0.1875
+glyph	 	0.152344	0.125	0.160156	0.1875
+glyph	#	0.205078	0.125	0.232422	0.1875
+glyph	$	0.273438	0.125	0.289063	0.1875
+glyph	%	0.330078	0.125	0.357422	0.1875
+glyph	&	0.396484	0.125	0.416016	0.1875
+glyph	'	0.464844	0.125	0.472656	0.1875
+glyph	(	0.523438	0.125	0.539063	0.1875
+glyph	)	0.585938	0.125	0.601563	0.1875
+glyph	*	0.650391	0.125	0.662109	0.1875
+glyph	+	0.705078	0.125	0.732422	0.1875
+glyph	,	0.777344	0.125	0.785156	0.1875
+glyph	-	0.835938	0.125	0.851563	0.1875
+glyph	.	0.902344	0.125	0.910156	0.1875
+glyph	/	0.957031	0.125	0.980469	0.1875
+glyph	0	0.0195313	0.1875	0.0429688	0.25
+glyph	1	0.0859375	0.1875	0.101563	0.25
+glyph	2	0.146484	0.1875	0.166016	0.25
+glyph	3	0.210938	0.1875	0.226563	0.25
+glyph	4	0.271484	0.1875	0.291016	0.25
+glyph	5	0.333984	0.1875	0.353516	0.25
+glyph	6	0.396484	0.1875	0.416016	0.25
+glyph	7	0.458984	0.1875	0.478516	0.25
+glyph	8	0.521484	0.1875	0.541016	0.25
+glyph	9	0.583984	0.1875	0.603516	0.25
+glyph	:	0.652344	0.1875	0.660156	0.25
+glyph	;	0.714844	0.1875	0.722656	0.25
+glyph	<	0.771484	0.1875	0.791016	0.25
+glyph	=	0.832031	0.1875	0.855469	0.25
+glyph	>	0.896484	0.1875	0.916016	0.25
+glyph	?	0.960938	0.1875	0.976563	0.25
+glyph	@	0.0195313	0.25	0.0429688	0.3125
+glyph	A	0.0839844	0.25	0.103516	0.3125
+glyph	B	0.146484	0.25	0.166016	0.3125
+glyph	C	0.210938	0.25	0.226563	0.3125
+glyph	D	0.271484	0.25	0.291016	0.3125
+glyph	E	0.335938	0.25	0.351563	0.3125
+glyph	F	0.396484	0.25	0.416016	0.3125
+glyph	G	0.458984	0.25	0.478516	0.3125
+glyph	H	0.521484	0.25	0.541016	0.3125
+glyph	I	0.589844	0.25	0.597656	0.3125
+glyph	J	0.646484	0.25	0.666016	0.3125
+glyph	K	0.705078	0.25	0.732422	0.3125
+glyph	L	0.771484	0.25	0.791016	0.3125
+glyph	M	0.824219	0.25	0.863281	0.3125
+glyph	N	0.892578	0.25	0.919922	0.3125
+glyph	O	0.958984	0.25	0.978516	0.3125
+glyph	P	0.0195313	0.3125	0.0429688	0.375
+glyph	Q	0.0820313	0.3125	0.105469	0.375
+glyph	R	0.144531	0.3125	0.167969	0.375
+glyph	S	0.210938	0.3125	0.226563	0.375
+glyph	T	0.269531	0.3125	0.292969	0.375
+glyph	U	0.333984	0.3125	0.353516	0.375
+glyph	V	0.396484	0.3125	0.416016	0.375
+glyph	W	0.453125	0.3125	0.484375	0.375
+glyph	X	0.517578	0.3125	0.544922	0.375
+glyph	Y	0.576172	0.3125	0.611328	0.375
+glyph	Z	0.646484	0.3125	0.666016	0.375
+glyph	[	0.708984	0.3125	0.728516	0.375
+glyph	\	0.767578	0.3125	0.794922	0.375
+glyph	]	0.833984	0.3125	0.853516	0.375
+glyph	^	0.896484	0.3125	0.916016	0.375
+glyph	_	0.957031	0.3125	0.980469	0.375
+glyph	`	0.0195313	0.375	0.0429688	0.4375
+glyph	a	0.0839844	0.375	0.103516	0.4375
+glyph	b	0.146484	0.375	0.166016	0.4375
+glyph	c	0.207031	0.375	0.230469	0.4375
+glyph	d	0.273438	0.375	0.289063	0.4375
+glyph	e	0.333984	0.375	0.353516	0.4375
+glyph	f	0.396484	0.375	0.416016	0.4375
+glyph	g	0.458984	0.375	0.478516	0.4375
+glyph	h	0.521484	0.375	0.541016	0.4375
+glyph	i	0.587891	0.375	0.599609	0.4375
+glyph	j	0.646484	0.375	0.666016	0.4375
+glyph	k	0.705078	0.375	0.732422	0.4375
+glyph	l	0.771484	0.375	0.791016	0.4375
+glyph	m	0.816406	0.375	0.871094	0.4375
+glyph	n	0.888672	0.375	0.923828	0.4375
+glyph	o	0.958984	0.375	0.978516	0.4375
+glyph	p	0.0195313	0.4375	0.0429688	0.5
+glyph	q	0.0839844	0.4375	0.103516	0.5
+glyph	r	0.146484	0.4375	0.166016	0.5
+glyph	s	0.208984	0.4375	0.228516	0.5
+glyph	t	0.271484	0.4375	0.291016	0.5
+glyph	u	0.332031	0.4375	0.355469	0.5
+glyph	v	0.386719	0.4375	0.425781	0.5
+glyph	w	0.445313	0.4375	0.492188	0.5
+glyph	x	0.521484	0.4375	0.541016	0.5
+glyph	y	0.583984	0.4375	0.603516	0.5
+glyph	z	0.646484	0.4375	0.666016	0.5
+glyph	{	0.710938	0.4375	0.726563	0.5
+glyph	|	0.773438	0.4375	0.789063	0.5
+glyph	}	0.835938	0.4375	0.851563	0.5
+glyph	~	0.884766	0.4375	0.927734	0.5
+
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/GeoTool.sln
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/GeoTool.sln	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/GeoTool.sln	(revision 774)
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GeoTool", "GeoTool.vcproj", "{31522E11-420C-4DD6-8922-AF96B93E2207}"
+	ProjectSection(ProjectDependencies) = postProject
+	EndProjectSection
+EndProject
+Global
+	GlobalSection(SolutionConfiguration) = preSolution
+		Debug = Debug
+		Release = Release
+	EndGlobalSection
+	GlobalSection(ProjectConfiguration) = postSolution
+		{31522E11-420C-4DD6-8922-AF96B93E2207}.Debug.ActiveCfg = Debug|Win32
+		{31522E11-420C-4DD6-8922-AF96B93E2207}.Debug.Build.0 = Debug|Win32
+		{31522E11-420C-4DD6-8922-AF96B93E2207}.Release.ActiveCfg = Release|Win32
+		{31522E11-420C-4DD6-8922-AF96B93E2207}.Release.Build.0 = Release|Win32
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+	EndGlobalSection
+	GlobalSection(ExtensibilityAddIns) = postSolution
+	EndGlobalSection
+EndGlobal
Index: /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshLoader.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshLoader.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshLoader.h	(revision 774)
@@ -0,0 +1,186 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	=========================================================================*/
+/**	CONTENT:	
+	*
+	*
+	*	@file	GeoMeshLoader.h
+/*===========================================================================*/
+#ifndef __GEO_MESH_LOADER__
+#define __GEO_MESH_LOADER__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string>
+#include <vector>
+#include <memory.h>
+#include <time.h>
+#include <iostream>
+#include <iomanip>
+#include "GeoBase.h"
+#include "GeoMesh.h"
+
+namespace Geometry 
+{
+	const	unsigned	short	CHUNK_OVERHEAD_SIZE	= sizeof(unsigned short)
+																							+
+																							sizeof(unsigned long);
+
+	const unsigned	short M_HEADER											= 0x1000;
+	const unsigned	short M_MESH												= 0x3000;
+	const unsigned	short M_SUBMESH											= 0x4000; 
+	const unsigned	short M_SUBMESH_OPERATION						= 0x4010;
+	const unsigned	short M_SUBMESH_BONE_ASSIGNMENT			= 0x4100;
+	const unsigned	short M_GEOMETRY										= 0x5000;
+	const unsigned	short M_GEOMETRY_VERTEX_DECLARATION = 0x5100;
+	const unsigned	short M_GEOMETRY_VERTEX_ELEMENT			= 0x5110;
+	const unsigned	short M_GEOMETRY_VERTEX_BUFFER			= 0x5200;
+	const unsigned	short M_GEOMETRY_VERTEX_BUFFER_DATA = 0x5210;
+	const unsigned	short M_MESH_SKELETON_LINK					= 0x6000;
+	const unsigned	short M_MESH_BONE_ASSIGNMENT				= 0x7000;
+	const unsigned	short M_MESH_LOD										=	0x8000;
+	const unsigned	short M_MESH_LOD_USAGE							=	0x8100;
+	const unsigned	short M_MESH_LOD_MANUAL							=	0x8110;
+	const unsigned	short M_MESH_LOD_GENERATED					=	0x8120;
+	const unsigned	short M_MESH_BOUNDS									=	0x9000;
+	const unsigned	short M_SUBMESH_NAME_TABLE					=	0xA000;
+	const unsigned	short	M_SUBMESH_NAME_TABLE_ELEMENT	=	0xA100;
+	const unsigned	short M_EDGE_LISTS									=	0xB000;
+	const unsigned	short M_EDGE_LIST_LOD								=	0xB100;
+	const unsigned	short M_EDGE_GROUP									= 0xB110;
+	const	unsigned	short	SUBMESH_COUNT									=	0;
+	const	unsigned	short	GEOMESH_BUILD									=	1;
+	
+	enum VertexElementType
+	{
+		VET_FLOAT1,
+		VET_FLOAT2,
+		VET_FLOAT3,
+		VET_FLOAT4,
+		VET_COLOUR,
+		VET_SHORT1,
+		VET_SHORT2,
+		VET_SHORT3,
+		VET_SHORT4, 
+		VET_UBYTE4
+	};
+
+	enum VertexElementSemantic
+	{
+		/// Position, 3 reals per vertex
+		VES_POSITION = 1,
+		/// Blending weights
+		VES_BLEND_WEIGHTS = 2,
+		/// Blending indices
+		VES_BLEND_INDICES = 3,
+		/// Normal, 3 reals per vertex
+		VES_NORMAL = 4,
+		/// Diffuse colours
+		VES_DIFFUSE = 5,
+		/// Specular colours
+		VES_SPECULAR = 6,
+		/// Texture coordinates
+		VES_TEXTURE_COORDINATES = 7,
+		/// Binormal (Y axis if normal is Z)
+		VES_BINORMAL = 8,
+		/// Tangent (X axis if normal is Z)
+		VES_TANGENT = 9
+	};
+
+	//	Bounding Box data.
+	struct	GeometryBounds
+	{
+		float	minx;
+		float	miny;
+		float	minz;
+		float	maxx;
+		float	maxy;
+		float	maxz;
+		float	radius;
+	};
+	
+	/// Mesh class interface
+	class GeoMeshLoader
+	{
+		private:
+			
+			Mesh						*geoMesh;
+			size_t					mFileSize;
+			unsigned	int		numVertices;
+			unsigned	long	long_actual;
+			char						*nom_salida;
+			size_t					currentSubMesh;
+
+			struct GeometryElement
+			{
+				unsigned short offset;
+				unsigned short semantic;
+				unsigned short type;
+				unsigned short index;
+			};
+
+			struct GT
+			{
+				unsigned short source; //bindIndex
+				std::vector <GeometryElement> list;
+			};
+
+			std::vector <GT> list;
+
+			//	Jump a chunk.
+			void jumpChunk(FILE	*f);
+
+			//	Read a chunk.
+			unsigned short readChunk(FILE	*f);
+
+			//	Read geometry vertex element.
+			void readGeometryVertexElement(FILE	*f, Mesh	*geoMesh);
+
+			//	Read geometry vertex declaration.
+			void readGeometryVertexDeclaration(FILE	*f, Mesh	*geoMesh);
+
+			//	Read geometry vertex buffer.
+			void readGeometryVertexBuffer(FILE		*f,
+																		Mesh		*geoMesh,
+																		int 		option);
+
+			//	Read geometry.
+			void readGeometry(FILE	*f, Mesh	*geoMesh, int option);
+
+			//	Read a submesh operation.
+			void readSubMeshOperation(FILE	*f, Mesh	*geoMesh, int option);
+
+			//	Read a submesh.
+			void readSubMesh(FILE	*f, Mesh	*geoMesh, int option);
+
+			//	Read a mesh lod information.
+			void readMeshLodInfo(FILE	*f, Mesh	*geoMesh);
+
+			//	Read a submesh name table.
+			void readSubMeshNameTable(FILE	*f, Mesh	*geoMesh);
+
+			//	Read a mesh file.
+			void readMesh(FILE	*f, Mesh	*geoMesh, int option);
+
+			//	Writes the strips list.
+			Mesh* GeoMeshLoader::BuildStripsGeoSubMesh(Mesh* geoMesh);
+			
+		public:
+
+			//	Constructor.
+			GeoMeshLoader();
+
+			//	Destroyer.
+			~GeoMeshLoader();
+
+			//	Loads a Mesh file.
+			Mesh* load(char	*fileNameMesh);
+
+			//	Get the size in bytes of the file.
+			size_t	getFileSize();
+	};
+}
+#endif
+
Index: /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshViewUI.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshViewUI.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshViewUI.h	(revision 774)
@@ -0,0 +1,350 @@
+// generated by Fast Light User Interface Designer (fluid) version 2.0100
+#ifndef GeoMeshViewUI_h
+#define GeoMeshViewUI_h
+#include	<stdio.h>
+#include	<stdlib.h>
+#include	<string.h>
+#include	<fltk/run.h>
+#include	<fltk/Group.h>
+#include	<fltk/Window.h>
+#include	<fltk/ask.h>
+#include	<fltk/file_chooser.h>
+#include	<fltk/FileChooser.h>
+#include	<fltk/MenuBar.h>
+#include	<fltk/Input.h>
+#include	<fltk/Button.h>
+#include	<fltk/ReturnButton.h>
+#include	<fltk/TextBuffer.h>
+#include	<fltk/TextEditor.h>
+#include	<fltk/Input.h>
+#include	<fltk/events.h>
+#include	<fltk/InvisibleBox.h>
+#include	<fltk/ItemGroup.h>
+#include	<fltk/Item.h>
+#include	<fltk/Divider.h>
+#include	<fltk/Output.h>
+#include	<fltk/Button.h>
+#include	<fltk/ProgressBar.h>
+#include	<fltk/CheckButton.h>
+#include	<fltk/RadioButton.h>
+#include	<fltk/FloatInput.h>
+#include	<fltk/Browser.h>
+#include	<fltk/Image.h>
+#include	<fltk/SharedImage.h>
+#include	<fltk/Slider.h>
+#include	<GeoMesh.h>
+#include	<GeoLodStripsLibrary.h>
+#include	<GeoMeshView.h>
+#include	<GeoMeshSaver.h>
+#include	<GeoMeshStripifier.h>
+#include	<GeoMeshSimplifier.h>
+#include	<GeoTreeSimplifier.h>
+#include	"GeoTreeSimpSequence.h"
+#include	"GeoLodStripsConstructor.h"
+
+//	About Dialog.
+#include "GTAboutDialog.h"
+#include	"../resource.h"
+
+//	State of the button process.
+enum	ProcessState
+{
+	NONE,
+	STRIPIFY,
+	EDGE_COLLAPSE,
+	LEAVES_COLLAPSE,
+	LODSTRIPS,
+	LODSTRIPS_AUTO,
+	LODTREES,
+	SELECT_LEAVES,
+	VISUALIZE_LODSTRIPS
+};
+
+// Simplification types
+enum	SimplificationType
+{
+	QSLIM,
+	HOJAS
+};
+
+enum	ProgressBarType
+{
+	PROCESS,
+	BUILD
+};
+
+using	namespace	Geometry;
+
+class GeoMeshViewUI
+{
+	friend	class	GeoMeshView;
+
+	private:
+
+	//	File name Selected.
+	char	*mFileName;
+
+	//	The state of the application menus.
+	ProcessState	mApplicationState;
+
+	//	Mesh object(Model).
+	Mesh	*mGeoMesh;
+
+	//	Mesh for undo operation.
+	Mesh	*mUndoMesh;
+
+	//	Lod strips object.
+	LodStripsLibrary	*lodStripsLib;
+	
+	//	Mesh Bounds.
+	GeometryBounds			mMeshBounds;
+
+	MeshSimplifier 			*ms;
+	TreeSimplifier			*mts;
+	char								*nombremesh;
+	SimplificationType	simplificacionState;
+	ProgressBarType			progressBarType;
+
+	MeshSimplificationSequence	*oMeshSimpSequence;
+	LodStripsConstructor				*oLodStrip;
+	GeoMeshLoader								*geoMeshLoader;
+
+	inline void cb_menuFileOpen_i(fltk::Item*, void*);
+	static void cb_menuFileOpen(fltk::Item*, void*);
+	inline void cb_menuFileSave_i(fltk::Item*, void*);
+	static void cb_menuFileSave(fltk::Item*, void*);
+	inline void cb_menuOpenSaveAs_i(fltk::Item*, void*);
+	static void cb_menuOpenSaveAs(fltk::Item*, void*);
+
+	inline void cb_menuMeshInfo_i(fltk::Item*, void*);
+	static void cb_menuMeshInfo(fltk::Item*, void*);
+	inline void cb_menuMeshExportOBJ_i(fltk::Item*, void*);
+	static void cb_menuMeshExportOBJ(fltk::Item*, void*);
+	inline void cb_menuTransformSharedVertex_i(fltk::Item*, void*);
+	static void	cb_menuFileTransformSharedVertex(fltk::Item* o, void* v);
+
+	inline void cb_menuOpenQuit_i(fltk::Item*, void*);
+	static void cb_menuOpenQuit(fltk::Item*, void*);
+	inline void cb_menuEditUndo_i(fltk::Item*, void*);
+	static void cb_menuEditUndo(fltk::Item*, void*);
+	inline void cb_menuEditFit_i(fltk::Item*, void*);
+	static void cb_menuEditFit(fltk::Item*, void*);
+	inline void cb_menuEditRotate_i(fltk::Item*, void*);
+	static void cb_menuEditRotate(fltk::Item*, void*);
+	inline void cb_menuEditPan_i(fltk::Item*, void*);
+	static void cb_menuEditPan(fltk::Item*, void*);
+	inline void cb_menuEditZoom_i(fltk::Item*, void*);
+	static void cb_menuEditZoom(fltk::Item*, void*);
+	inline void cb_menuRenderWire_i(fltk::Item*, void*);
+	static void cb_menuRenderWire(fltk::Item*, void*);
+	inline void cb_menuRenderSolid_i(fltk::Item*, void*);
+	static void cb_menuRenderSolid(fltk::Item*, void*);
+	inline void cb_menuRenderCW_i(fltk::Item*, void*);
+	static void cb_menuRenderCW(fltk::Item*, void*);
+	inline void cb_menuRenderCCW_i(fltk::Item*, void*);
+	static void cb_menuRenderCCW(fltk::Item*, void*);
+	inline void cb_menuRenderFlat_i(fltk::Item*, void*);
+	static void cb_menuRenderFlat(fltk::Item*, void*);
+	inline void cb_menuRenderSmooth_i(fltk::Item*, void*);
+	static void cb_menuRenderSmooth(fltk::Item*, void*);
+	inline void cb_menuRenderTextures_i(fltk::Item*, void*);
+	static void cb_menuRenderTextures(fltk::Item*, void*);
+	inline void cb_menuStripify_i(fltk::Item*, void*);
+	static void cb_menuStripify(fltk::Item*, void*);
+	inline void cb_menuSimplify_i(fltk::ItemGroup*, void*);
+	static void cb_menuSimplify(fltk::ItemGroup*, void*);
+	inline void cb_menuSimplifyEdgeCollapse_i(fltk::Item*, void*);
+	static void cb_menuSimplifyEdgeCollapse(fltk::Item*, void*);
+	inline void cb_menuSimplifyLeavesCollapse_i(fltk::Item*, void*);
+	static void cb_menuSimplifyLeavesCollapse(fltk::Item*, void*);
+
+	inline void cb_menuLodStripsGenerate_i(fltk::Item*, void*);
+	static void cb_menuLodStripsGenerate(fltk::Item*, void*);
+	inline void cb_menuLodStripsVisualize_i(fltk::Item*, void*);
+	static void cb_menuLodStripsVisualize(fltk::Item*, void*);
+
+	inline void cb_menuSelectLeaves_i(fltk::Item*, void*);
+	static void cb_menuSelectLeaves(fltk::Item*, void*);
+	inline void cb_menuLodTreesOpenLodStripTrunk_i(fltk::Item*, void*);
+	static void cb_menuLodTreesOpenLodStripTrunk(fltk::Item*, void*);
+	inline void cb_menuLodTreesOpenLeavesSimplification_i(fltk::Item*, void*);
+	static void cb_menuLodTreesOpenLeavesSimplification(fltk::Item*, void*);
+	inline void cb_menuHelpAbout_i(fltk::Item*, void*);
+	static void cb_menuHelpAbout(fltk::Item*, void*);
+
+	inline void cb_mButtonProcess_i(fltk::Button*, void*);
+	static void cb_mButtonProcess(fltk::Button*, void*);
+	inline void cb_mButtonSort_i(fltk::Button*, void*);
+	static void cb_mButtonSort(fltk::Button*, void*);
+	inline void cb_mButtonBuild_i(fltk::Button*, void*);
+	static void cb_mButtonBuild(fltk::Button*, void*);
+	inline void cb_mMeshInfo_i(fltk::Browser*, void*);
+	static void cb_mMeshInfo(fltk::Browser*, void*);
+	inline void cb_mLodSlider_i(fltk::Slider*, void*);
+	static void cb_mLodSlider(fltk::Slider*, void*);
+
+	//	Logo's callback.
+	inline void cb_mLogo_i(fltk::InvisibleBox*, void*);
+	static void cb_mLogo(fltk::InvisibleBox*, void*);
+
+	//	Shows the stripify panel.
+	void	showStripify();
+
+	//	Shows the simplify panels.
+	void	showEdgeCollapse();
+	void	showLeavesCollapse();
+
+	//	Shows the LodStrips panels.
+	void	showOpenMeshSimplification();
+	void	showAutoGenerateLodStrips();
+
+	//	Shows the LodTrees panel.
+	void	showOpenLeavesSimplification();
+
+	//	Show the mesh info browser.
+	void	showMeshInfo();
+	
+	//	Show the LodStrips visulization panel.
+	void	showVisualizeLodStrips();
+
+	void	hideStripify();
+	void	hideEdgeCollapse();
+	void	hideLeavesCollapse();
+	void	hideOpenMeshSimplification();
+	void	hideOpenLeavesSimplification();
+	void	hideRightPanel();
+	//	Hide the mesh info browser.
+	void	hideMeshInfo();
+
+	//	Hide the LodStrips visualization panel.
+	void	hideVisualizeLodStrips();
+	
+	//	Get the number of vertices.
+	size_t	getVertexCount(Mesh	*geoMesh);
+
+	//	Get the number of triangles.
+	size_t	getTriangleCount(Mesh	*geoMesh);
+
+	//	Get the number of strips.
+	size_t	getStripCount(Mesh	*geoMesh);
+
+	int		paintMesh();
+
+	//	Simplify the mesh object.
+	void	simplifyEdgeCollapse();
+
+	//	Simplify the mesh object.
+	void	simplifyLeavesCollapse();
+
+	//	Create a siplification sequence of the QSLIM sequence.
+	void	createQslimSequence();
+
+	//	Stripify the mesh object.
+	void	stripify();
+
+	//	Method that undo then mesh changes.
+	void	undo();
+
+	//	Refresh number of vertices, triangles, strips, ...
+	void	refreshApplicationBar();
+
+	//	Open a mesh file.
+	void	openMeshFile();
+
+	public:
+
+	GeoMeshView					*geoMeshView;
+	fltk::Window				*mMainWindow;
+	fltk::Group					*MainView;
+	fltk::InvisibleBox	*cframe;
+	fltk::MenuBar				*menuBar;
+	fltk::ItemGroup			*menuFile;
+	fltk::Item					*menuFileOpen;
+	fltk::Item					*menuFileSave;
+	fltk::Item					*menuOpenSaveAs;
+	fltk::Item					*menuMeshInfo;
+	fltk::Item					*menuMeshExportOBJ;
+	fltk::Item					*menuFileTransformSharedVertex;
+
+	fltk::Item					*menuOpenQuit;
+	fltk::ItemGroup			*menuEdit;
+	fltk::Item					*menuEditUndo;
+	fltk::Item					*menuEditFit;
+	fltk::Item					*menuEditRotate;
+	fltk::Item					*menuEditPan;
+	fltk::Item					*menuEditZoom;
+	fltk::ItemGroup			*menuRender;
+	fltk::Item					*menuRenderWire;
+	fltk::Item					*menuRenderSolid;
+	fltk::Item					*menuRenderCW;
+	fltk::Item					*menuRenderCCW;
+	fltk::Item					*menuRenderFlat;
+	fltk::Item					*menuRenderSmooth;
+	fltk::Item					*menuRenderTextures;
+	fltk::Item					*menuStripify;
+	fltk::ItemGroup			*menuSimplify;
+	fltk::Item					*menuSimplifyEdgeCollapse;
+	fltk::Item					*menuSimplifyLeavesCollapse;
+	fltk::Item					*menuSimplifySaveSequence;
+
+	fltk::ItemGroup			*menuLodStrips;
+	fltk::Item					*menuLodStripsGenerate;
+	fltk::Item					*menuLodStripsVisualize;
+	fltk::ItemGroup			*menuLodTrees;
+
+	fltk::Item					*menuSelectLeaves;
+	fltk::Item					*menuLodTreesOpenLodStripTrunk;
+	fltk::Item					*menuLodTreesOpenLeavesSimplification;
+	fltk::Item					*menuHelpAbout;
+	fltk::InvisibleBox	*mLogo;
+	fltk::Group					*ApplicationBar;
+	fltk::Widget				*mFPS;
+	fltk::Widget				*mVertices;
+	fltk::Widget				*mTriangles;
+	fltk::Widget				*mStrips;
+	fltk::Widget				*mQuads;
+	fltk::Widget				*mMB;
+	fltk::Button				*mButtonProcess;
+	fltk::ProgressBar		*mProcessBar;
+	fltk::Button				*mButtonSort;
+	fltk::ProgressBar		*mSortBar;
+	fltk::Button				*mButtonBuild;
+	fltk::ProgressBar		*mBuildBar;
+	fltk::Slider				*mLodSlider;
+	fltk::CheckButton		*mGeometryBased;
+	fltk::CheckButton		*mImageBased;
+	fltk::CheckButton		*mChangeVertices;
+	fltk::CheckButton		*mChangeTexture;
+	fltk::CheckButton		*mPercent;
+	fltk::CheckButton		*mVerticesNumber;
+	fltk::CheckButton		*mOneCacheStrip;
+	fltk::CheckButton		*mQualityStrips;
+	fltk::FloatInput		*mMeshReduction;
+	fltk::Widget				*mProcessTitle;
+	fltk::Output				*mMetricLabel;
+	fltk::Output				*mTypeLabel;
+	fltk::Output				*mMeshReductionLabel;
+	fltk::Browser				*mMeshInfo;
+	fltk::ItemGroup			*ogeometry;
+
+	//	Repaint the FPS label.
+	void	refreshFPS(int fps);
+
+	//	Initialize the lodstripslibrary for visualization.
+	void	setLodStripsLibrary(std::string lodfile, Mesh	*geomesh);
+
+	// 26-12-2005
+	// Indentify the mesh of leaves.
+	unsigned	short			idMeshLeaves;
+
+	GeoMeshViewUI(TIPOFUNC fun=NULL);
+	~GeoMeshViewUI();
+	void show();
+
+	TIPOFUNC progress_function;
+	float updateProgressBar(float);
+
+};
+
+#endif
+
Index: /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshView.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshView.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshView.h	(revision 774)
@@ -0,0 +1,245 @@
+// generated by Fast Light User Interface Designer (fluid) version 2.0100
+#ifndef GeoMeshView_h
+#define GeoMeshView_h
+
+#include	<fltk/events.h>
+#include	<stdlib.h>
+#include	<time.h>
+#include	<iostream>
+#include	<GL/glut.h>
+#include	<fltk/GlWindow.h>
+#include	<GeoVertexBuffer.h>
+#include	<GeoMesh.h>
+//#ifndef	GeoMeshViewUI_h
+#include	<GeoMeshSaver.h>
+#include	<GeoMeshViewUI.h>
+//#include	<GeoLodStripsLibrary.h>
+//#endif
+
+class GeoMeshView : public fltk::GlWindow
+{
+	friend	class	GeoMeshViewUI;
+
+	public:
+
+	// this value determines the scaling factor used to draw the cube.
+	double	size;
+	double	mScaleFactor;
+	bool		mWire;
+	bool		mSolid;
+	bool		mCW;
+	bool		mCCW;
+	bool		mPan;
+	bool		mRotate;
+	bool		mLodStrip;
+
+	GeoMeshView(int 					x,
+			int						y,
+			int						w,
+			int						h,
+			const	char		*l							=	0,
+			GeoMeshViewUI	*geoMeshViewUI	=	0);
+
+	/*	This function is callalled by the zoom slider
+	 *	
+	 */
+	void scale(double factor){size	=	factor;};
+
+	/* Set the rotation about the vertical (y ) axis.
+	 *
+	 * This function is called by the horizontal roller in GeoMeshViewUI
+	 * and the initialize button in GeoMeshViewUI.
+	 */
+	void v_angle(float angle){vAng=angle;};
+	
+	// Return the rotation about the vertical (y ) axis.
+	float v_angle(){return vAng;};
+	
+	/* Set the rotation about the horizontal (x ) axis.
+	 *
+	 * This function is called by the vertical roller in GeoMeshViewUI
+	 and the
+	 * initialize button in GeoMeshViewUI.
+	 */
+	void h_angle(float angle){hAng=angle;};
+	
+	// the rotation about the horizontal (x ) axis.
+	float h_angle(){return hAng;};
+	
+	/* Sets the x shift of the cube view camera.
+	 *
+	 * This function is called by the slider in GeoMeshViewUI and the
+	 * initialize button in GeoMeshViewUI.
+	 */
+	void panx(float x){xshift=x;};
+	
+	/* Sets the y shift of the cube view camera.
+	 *
+	 * This function is called by the slider in GeoMeshViewUI and the
+	 * initialize button in GeoMeshViewUI.
+	 */
+	void pany(float y){yshift=y;};
+
+	//	Wire model.
+	void	activeWire(){mWire	=	true;};
+	void	deactiveWire(){mWire	=	false;};
+
+	//	Solid model.
+	void	activeSolid(){mSolid	=	true;};
+	void	deactiveSolid(){mSolid	=	false;};
+
+	//	Clockwise mode.
+	void	activeCW(){mCW	=	true;};
+	void	deactiveCW(){mCW	=	false;};
+
+	//	Counter Clockwise mode.
+	void	activeCCW(){mCCW	=	true;};
+	void	deactiveCCW(){mCCW	=	false;};
+
+	//	Pan mode.
+	void	activePan(){mPan	=	true;};
+	void	deactivePan(){mPan	=	false;};
+
+	//	Rotate mode.
+	void	activeRotate(){mRotate	=	true;};
+	void	deactiveRotate(){mRotate	=	false;};
+
+	//	LodStrip mode.
+	void	activeLodStrip(){mLodStrip	=	true;};
+	void	deactiveLodStrip(){mLodStrip	=	false;};
+
+	//	Ilumination modes.
+	void	flat(){glShadeModel(GL_FLAT);};
+	void	smooth(){glShadeModel(GL_SMOOTH);};
+
+	//	Fits the object in the window view.
+	void	fit()
+	{
+		vAng		= 0.0;
+		hAng		=	0.0;
+		size		=	0.0;
+		xshift	=	0.0;
+		yshift	=	0.0;
+	};
+
+	/* Sets the Mesh to display.
+	*/
+	void	setMesh(Geometry::Mesh	*geomesh);
+
+	/* The widget class draw() override.
+	 * The draw() function initialize Gl for another round of
+	 * drawing then calls specialized functions for drawing each
+	 * of the entities displayed in the cube view.
+	 */
+	void draw();
+
+	//	Gets the bounding box.
+	Geometry::GeometryBounds	getBoundingBox();
+
+	//	Store one random color to each strip.
+	void	setStripColors();
+
+	//	Get the number of frames per second.
+	size_t	getFPS();
+
+	//	JGA
+	//	Sets the colorsubmeshi variable
+	void	setColorSubmeshi(int submeshIndex);
+
+	//	Sets the leaves submesh index.
+	void	setLeavesSubmesh(int submeshIndex);
+
+	//	Gets the leaves submesh index.
+	int	getLeavesSubmesh();
+
+	//	Gets the triangle count of the current lod.
+	size_t	getLodStripsTriangleCount();
+	
+	//	Sets the lodstripslibrary object.
+	void	setLodStripsLibrary(Geometry::LodStripsLibrary *lodstrips);
+
+	//	Change de Level of detail of the object.
+	void	GoToLod(unsigned int lod);
+
+	private:
+	/* Draw the cube boundaries
+	 * Draw the faces of the cube using the boxv[] vertices, using
+	 * GL_LINE_LOOP for the faces. The color is #defined by
+	 * CUBECOLOR.
+	 */
+
+	//	GeoMeshViewUI.
+	GeoMeshViewUI	*mGeoMeshViewUI;
+
+	//	LodStrips library object.
+	Geometry::LodStripsLibrary	*lodStripsLib;
+	
+	//	Flag tha activate / deactivate the color strips.
+	bool	colorStripsFlag;
+
+	// Stores the index of the mesh to paint of red color.
+	int		colorsubmeshi;
+
+	//	Frames per second.
+	size_t	mFPS;
+
+	//	StartTime for FPS.
+	clock_t	mStartTime;
+
+	float		xMed;
+	float		yMed;
+	float		zMed;
+
+	int			leavesSubmesh;
+	
+	//	Submesh count.
+	int			mSubMeshCount;
+
+	//	Mesh to show.
+	Geometry::Mesh	*geoMesh;
+
+	virtual	int	handle(int event);
+
+	//	Paint the mesh object.
+	void	drawGeoMesh(int selectedMesh);
+	void	drawTriangleList(int selectedMesh);
+	void	drawTriangleStrip();
+	void	drawLodStrip();
+	void	enableColorStrips();
+	void	disableColorStrips();
+	bool	getColorStrips();
+
+	//	Calculate the number of frames per second.
+	void	calcFPS();
+
+	//	Copy the mesh vertices to the vertex array.
+	void	refreshVertices(Geometry::Mesh	*geomesh);
+
+	float 	vAng;
+	float 	hAng;
+	float 	xshift;
+	float 	yshift;
+	int			mMouseX;
+	int			mMouseY;
+	int			mSizeY;
+	GLfloat	**mPosArray;
+	GLfloat	**mNorArray;
+	GLfloat	*mSharedPosArray;
+	GLfloat	*mSharedNorArray;
+	GLuint	**mIndexArray;
+
+	struct	ColorElement
+	{
+		float	r;
+		float	g;
+		float	b;
+	};
+
+	ColorElement	*mStripColors;
+
+	//	Idetifier of Visualization List.
+	GLuint	mIdVisualList;
+};
+
+#endif
+
Index: /GTP/trunk/Lib/Geom/GeoTool/include/GTAboutDialog.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/include/GTAboutDialog.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/include/GTAboutDialog.h	(revision 774)
@@ -0,0 +1,25 @@
+// generated by Fast Light User Interface Designer (fluid) version 2.0100
+
+#ifndef AboutDialog_h
+#define AboutDialog_h
+#include	<string.h>
+#include <fltk/Window.h>
+#include <fltk/Group.h>
+#include <fltk/MultiLineOutput.h>
+#include <fltk/InvisibleBox.h>
+#include <fltk/Button.h>
+#include	<fltk/Image.h>
+#include	<fltk/SharedImage.h>
+
+class GTAboutDialog  {
+public:
+  GTAboutDialog();
+  fltk::Window *mMainWindow;
+      fltk::MultiLineOutput *mText;
+      fltk::InvisibleBox *mLogo;
+      fltk::Button *mOK;
+private:
+      inline void cb_mOK_i(fltk::Button*, void*);
+      static void cb_mOK(fltk::Button*, void*);
+};
+#endif
Index: /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshSaver.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshSaver.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/include/GeoMeshSaver.h	(revision 774)
@@ -0,0 +1,111 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	=========================================================================*/
+/**	CONTENT:	
+	*
+	*
+	*	@file	GeoMeshSaver.h
+/*===========================================================================*/
+#ifndef	__GEO_MESH_SAVER__
+#define	__GEO_MESH_SAVER__
+
+#include	<GeoMeshLoader.h>
+
+namespace Geometry 
+{
+	//	Saves a Mesh.
+	class	GeoMeshSaver
+	{
+		private:
+			//	The mesh to write.
+			Mesh	*mGeoMesh;
+			
+			//	Mesh Bounds.
+			GeometryBounds	mMeshBounds;
+			
+			//	Write in the file.
+			Serializer	*mSerializer;
+
+			//	Flag that indicate if the mesh 
+			//	is skeletally animated or not.
+			bool	mSkeletallyAnimated;
+			
+			//	Material of the mesh.
+			String	mMaterialName;
+			
+			//	Write the main mesh.
+			void	writeMesh(Mesh	*geoMesh);
+
+			//	Write a submesh.
+			void	writeSubMesh(SubMesh	*geoSubMesh);
+
+			// Operation type
+			void	writeSubMeshOperation(const	SubMesh	*geoSubMesh);
+			
+			//	Write geometry.
+			void	writeGeometry(VertexBuffer	*vertexBuffer);
+
+			//	TODO: Write Mesh Bounds.
+			void	writeMeshBounds(GeometryBounds bounds);
+			
+			//	Calc the mesh size in bytes.
+			size_t	calcMeshSize(const Mesh	*geoMesh);
+
+			//	Calc the size in bytes for the submesh.
+			size_t	calcSubMeshSize(const SubMesh	*geoSubMesh);
+
+			//	Calc the geometry size in bytes.
+			size_t	calcGeometrySize(const VertexBuffer* vertexBuffer);
+
+			//	Write the file header.
+			void	writeFileHeader(void);
+
+			//	Write a header chunk given.
+			void	writeChunkHeader(	unsigned short	id,
+															unsigned long		count);
+
+			//	Write integers into the file.
+			void	writeInts(unsigned long	id,
+											unsigned long	size);
+
+			//	Write shorts into the file
+			void	writeShorts(unsigned short	id,
+												unsigned long		count);
+
+			//	Write float into the file.
+			void	writeFloats(float						id,
+												unsigned long		count);
+
+			//	Write a string into the file.
+			void	writeString(const	String	&string);
+
+			//	Write booleans into the file.
+			void	writeBools(	const bool id,
+												unsigned	long		count);
+		public:
+
+			//	Constructors.
+			GeoMeshSaver();
+
+			GeoMeshSaver(GeometryBounds bounds);
+
+			//	Destroyer.
+			~GeoMeshSaver();
+
+			//	Sets the material of the mesh.
+			void	setMaterialName(String	materialName);
+
+			//	Gets the material of the mesh.
+			String	getMaterialName();
+
+			//	Set Mesh Bounds.
+			void	setMeshBounds(GeometryBounds	bounds);
+
+			//	Saves a Mesh into a file.
+			int	save(Mesh	*geoMesh,	const	char	*fileNameMesh);
+	};
+}
+#endif
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshLoader.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshLoader.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshLoader.cpp	(revision 774)
@@ -0,0 +1,1001 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:	
+	*
+	*
+	*	@file	GeoMeshLoader.cpp
+/*===========================================================================*/
+#include	"GeoMeshLoader.h"
+
+using namespace Geometry;
+using	namespace	std;
+
+//	Jump a chunk.
+void GeoMeshLoader::jumpChunk(FILE	*f)
+{
+	fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+
+	//	Return to the begin of the chunk.
+	fseek(f,long_actual,SEEK_CUR);
+}
+
+//	Read a chunk.
+unsigned short GeoMeshLoader::readChunk(FILE	*f)
+{
+	unsigned	short	id;
+
+	fread(&id,sizeof(unsigned short),1,f);
+	fread(&long_actual,sizeof(unsigned long),1,f);
+									
+	return id;
+}
+
+//	Read geometry vertex element.
+void GeoMeshLoader::readGeometryVertexElement(FILE	*f, Mesh	*geoMesh)
+{
+	unsigned	short		source;
+	GeometryElement		aux;
+	int								i;
+	bool							encontrado;
+	VertexElementType	vType;
+
+	i						=	0;
+	encontrado	=	false;
+
+	//		VertexElementSemantic vSemantic;
+	// unsigned short source;  	// buffer bind source
+	fread(&source,sizeof(unsigned short),1,f);
+
+	// unsigned short type;    	// VertexElementType
+	fread(&aux.type,sizeof(unsigned short),1,f);
+
+	vType	=	static_cast<VertexElementType>(aux.type);
+
+	if (vType == VET_FLOAT3)
+	{
+		printf("%u es float3 ",aux.type);
+	}
+
+	if (vType == VET_FLOAT4)
+	{
+		printf("%u es float4 ",aux.type);
+	}
+
+	if (vType == VET_FLOAT2)
+	{
+		printf("%u es float2 ",aux.type);
+	}
+
+	// unsigned short semantic; // VertexElementSemantic
+	fread(&aux.semantic,sizeof(unsigned short),1,f);
+
+	//	vSemantic = static_cast<VertexElementSemantic>(tmp);
+	//	unsigned short offset;	// start offset in buffer in bytes
+	fread(&aux.offset,sizeof(unsigned short),1,f);
+
+	// unsigned short index;	// index of the semantic
+	/*
+	VES_POSITION  Position, 3 reals per vertex.  
+	VES_BLEND_WEIGHTS  Blending weights.  
+	VES_BLEND_INDICES  Blending indices.  
+	VES_NORMAL  Normal, 3 reals per vertex.  
+	VES_DIFFUSE  Diffuse colours.  
+	VES_SPECULAR  Specular colours.  
+	VES_TEXTURE_COORDINATES  Texture coordinates.  
+	VES_BINORMAL  Binormal (Y axis if normal is Z).  
+	VES_TANGENT  Tangent (X axis if normal is Z).  
+	*/
+	fread(&aux.index,sizeof(unsigned short),1,f);
+
+	while ((i < list.size()) && (!encontrado))
+	{
+		if (list[i].source==source)
+		{
+			encontrado	=	true;
+		}
+		else
+		{
+			i++;
+		}
+	}
+
+	if (encontrado)
+	{
+		list[i].list.push_back(aux);
+	}
+	else
+	{
+		GT	aux2;
+		
+		aux2.source	=	source;
+		aux2.list.push_back(aux);
+		list.push_back(aux2);
+	}
+	
+	//	Debug.
+	cout	<<	"Finish Vertex Element"	<<	endl;
+}
+
+//	Read geometry vertex declaration.
+void GeoMeshLoader::readGeometryVertexDeclaration(FILE	*f, Mesh	*geoMesh)
+{
+	unsigned short chunkID;
+  // Find optional geometry chunks
+  if (!feof(f))
+  {
+    chunkID	=	readChunk(f);
+
+    while(!feof(f) && (chunkID == M_GEOMETRY_VERTEX_ELEMENT ))
+    {
+      switch (chunkID)
+      {
+				case M_GEOMETRY_VERTEX_ELEMENT:
+					cout	<<	"M_GEOMETRY_VERTEX_ELEMENT"	<<	endl;
+          readGeometryVertexElement(f, geoMesh);
+          break;
+      }
+
+      // Get next chunk
+      if (!feof(f))
+      {
+				chunkID = readChunk(f);
+      }
+    }//	End while.
+
+    if (!feof(f))
+    {
+			// Backpedal back to start of non-submesh chunk
+			fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+    }
+
+  }//	End if (!feof(f))
+}
+
+//	Read geometry vertex buffer.
+void GeoMeshLoader::readGeometryVertexBuffer(FILE	*f, Mesh	*geoMesh, int option)
+{
+	unsigned	short	bindIndex;
+	unsigned	short	vertexSize;
+	unsigned	short	headerID;
+	int							i;
+	float						aux;
+	int							k;
+	bool						encontrado;
+	float						x,y,z;
+	SubMesh					*geoSubMesh;
+	VertexBuffer		*vertex_buffer;
+
+	i						=	0;
+	k						=	0;
+	encontrado	=	false;
+
+	
+	if (option == GEOMESH_BUILD)
+	{
+		//	If is the main mesh.
+		if (currentSubMesh == -1)
+		{
+			vertex_buffer	=	geoMesh->mVertexBuffer;
+		}
+		//	If is a submesh.
+		else
+		{
+			//	Gets the current submesh
+			geoSubMesh		=	&geoMesh->mSubMesh[currentSubMesh];
+			vertex_buffer	=	geoSubMesh->mVertexBuffer;
+		}
+	}
+	
+	// Index to bind this buffer to
+	fread(&bindIndex,sizeof(unsigned short),1,f);
+
+	// Per-vertex size, must agree with declaration at this index
+	fread(&vertexSize,sizeof(unsigned short),1,f);
+
+	//	Debug.
+	cout	<<	"Per-vertex size: "
+				<<	vertexSize
+				<<	endl;
+	
+	// Check for vertex data header
+	headerID	=	readChunk(f);
+
+	if (headerID != M_GEOMETRY_VERTEX_BUFFER_DATA)
+	{
+		cout	<<	"Can't find vertex buffer data area"
+					<<	endl;
+	}
+	else
+	{
+		cout	<<	"M_GEOMETRY_VERTEX_BUFFER_DATA"	<<	endl;
+	}
+
+	while ((i<list.size())&&(!encontrado))
+	{
+		if (list[i].source	==	bindIndex)
+		{
+			encontrado	=	true;
+		}
+		else
+		{
+			i++;
+		}
+	}
+
+	//	Considero q los van por grupitos de vertices+normales+...
+	//	para cada uno de los vertices
+	if (encontrado)
+	{
+		FILE * salida;
+		salida=fopen(nom_salida,"a");
+		cout	<<	"----->Leo los vertices"
+					<<	endl;
+
+		for (k=0;k<numVertices;k++)
+		{
+			//Para cada uno de los elementos de ese source.
+			for(int j=0;j<list[i].list.size();j++)
+			{
+				//	Son posiciones, vertices
+				if (list[i].list[j].semantic==1)
+				{
+					fread(&x,sizeof(float),1,f);
+					fread(&y,sizeof(float),1,f);
+					fread(&z,sizeof(float),1,f);
+
+					if (option == GEOMESH_BUILD)
+					{
+						vertex_buffer->mVertexInfo		|=	VERTEX_POSITION;
+						vertex_buffer->mPosition[k].x	=		x;
+						vertex_buffer->mPosition[k].y	=		y;
+						vertex_buffer->mPosition[k].z	=		z;
+					}
+				}
+				//	si no son vertices no lo quiero
+				else 
+				{
+					//Se tendría que hacer con un fseek
+					if (list[i].list[j].type==2) //Son 3 floats
+					{
+						fread(&x,sizeof(float),1,f);
+						fread(&y,sizeof(float),1,f);
+						fread(&z,sizeof(float),1,f);
+
+						if (option == GEOMESH_BUILD)
+						{
+							vertex_buffer->mVertexInfo	|=	VERTEX_NORMAL;
+							vertex_buffer->mNormal[k].x	=		x;
+							vertex_buffer->mNormal[k].y	=		y;
+							vertex_buffer->mNormal[k].z	=		z;
+						}
+					}
+					if (list[i].list[j].type==1) //Son 2 floats
+					{
+						fread(&x,sizeof(float),1,f);
+						fread(&y,sizeof(float),1,f);
+						
+						if (option == GEOMESH_BUILD)
+						{
+							vertex_buffer->mVertexInfo			|=	VERTEX_TEXCOORDS;
+							vertex_buffer->mTexCoords[k].x	=		x;
+							vertex_buffer->mTexCoords[k].y	=		y;
+						}
+					}
+				}
+			}
+		}
+		fclose(salida);
+	}
+	else
+	{
+		cout	<<	"Error"
+					<<	endl;
+	}
+
+}
+
+//	Read geometry.
+void GeoMeshLoader::readGeometry(FILE	*f, Mesh	*geoMesh, int option)
+{
+	SubMesh				*geoSubMesh;
+	VertexBuffer	*vertex_buffer;
+	
+	fread(&numVertices,sizeof(unsigned int),1,f);
+
+	if (option == GEOMESH_BUILD)
+	{
+		if (currentSubMesh == -1)
+		{
+			//	Get the current vertex buffer.
+			vertex_buffer	=	geoMesh->mVertexBuffer;
+		}
+		else
+		{
+			//	Get the current submesh.
+			geoSubMesh		=	&geoMesh->mSubMesh[currentSubMesh];
+
+			//	Create the VertexBuffer of the submesh.
+			geoSubMesh->mVertexBuffer	=	new VertexBuffer();
+
+			//	Get the current vertex buffer.
+			vertex_buffer	=	geoSubMesh->mVertexBuffer;
+		}
+
+		//	Initialize the VertexBuffer of the current submesh.
+		vertex_buffer->mVertexCount	=	numVertices;
+
+		//	Initialize the position array.
+		vertex_buffer->mPosition	=	new Vector3[numVertices];
+
+		//	Initialize the normal array.
+		vertex_buffer->mNormal		=	new Vector3[numVertices];
+
+		//	Initialize the texture coords array.
+		vertex_buffer->mTexCoords	=	new Vector2[numVertices];
+	}
+
+	// Find optional geometry chunks
+	if (!feof(f))
+	{
+		unsigned short chunkID = readChunk(f);
+	
+		while(!feof(f) && 
+					(chunkID == M_GEOMETRY_VERTEX_DECLARATION || 
+					chunkID == M_GEOMETRY_VERTEX_BUFFER ))
+		{
+			switch (chunkID)
+			{
+				case M_GEOMETRY_VERTEX_DECLARATION:
+					cout<<"M_GEOMETRY_VERTEX_DECLARATION\n";
+					readGeometryVertexDeclaration(f, geoMesh);
+					break;
+				case M_GEOMETRY_VERTEX_BUFFER:
+					cout<<"M_GEOMETRY_VERTEX_BUFFER\n";
+					readGeometryVertexBuffer(f, geoMesh,option);
+					break;
+			}
+		
+			// Get next chunk.
+			if (!feof(f))
+			{
+				chunkID = readChunk(f);
+			}
+		}
+		if (!feof(f))
+		{
+			// Backpedal back to start of non-submesh chunk.
+			fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+		}
+	}
+}
+
+//	Read a submesh operation.
+void GeoMeshLoader::readSubMeshOperation(FILE	*f, Mesh	*geoMesh, int option)
+{
+	unsigned	short	opType;
+	fread(&opType,sizeof(unsigned short),1,f);
+	printf("\tLa render operation es %d\n",opType);
+
+	if (option == GEOMESH_BUILD)
+	{
+		if (opType == 5)
+		{
+			geoMesh->mType	=	GEO_TRIANGLE_STRIPS;
+		}
+		else
+		{
+			geoMesh->mType	=	GEO_TRIANGLE_LIST;
+		}
+	}
+}
+
+//	Read a submesh.
+void GeoMeshLoader::readSubMesh(FILE	*f, Mesh	*geoMesh, int option)
+{
+	SubMesh					*geoSubMesh;
+	unsigned	short	chunkID;
+	char						materialName[255];
+	bool						useSharedVertices;
+	unsigned	int		numIndices;
+	bool						idx32bit;
+	FILE						*salida;
+
+	switch	(option)
+	{
+		case	SUBMESH_COUNT:
+			geoMesh->mSubMeshCount++;
+			break;
+		case	GEOMESH_BUILD:
+
+			//	Debug.
+			cout	<<	"Build GEOMESH"	<<	endl;
+
+			//	Initialize the new subMesh.
+			geoSubMesh	=	&geoMesh->mSubMesh[currentSubMesh];
+
+			cout	<<	"Current SubMesh: "
+						<<	currentSubMesh
+						<<	endl;
+	}
+	
+	//La vacio antes de leer el mesh
+	list.clear(); 
+
+	fgets(materialName,255,f);
+	printf("\tmaterialName: %s",materialName);
+
+	fread(&useSharedVertices,sizeof(bool),1,f);
+	
+	if (option	==	GEOMESH_BUILD)
+	{
+		//	Obtain the flag of vertex shared.
+		geoSubMesh->mSharedVertexBuffer	=	useSharedVertices;
+		
+		if (useSharedVertices)
+		{
+			//	The VB of the submesh points to the VB of the mesh.
+			geoSubMesh->mVertexBuffer	=	geoMesh->mVertexBuffer;
+			
+			cout	<<	"\tUse Shared Vertices"
+						<<	endl;
+
+		}
+	}
+
+	fread(&numIndices,sizeof(unsigned int),1,f);
+	printf("\tnumIndices: %u\n",numIndices);
+	printf("\tnumTriangles: %u\n",numIndices/3);
+	fread(&idx32bit,sizeof(bool),1,f);
+	
+	if (option == GEOMESH_BUILD)
+	{
+			//	Sets the index count of the submesh.
+			geoSubMesh->mIndexCount	=	numIndices;
+	
+			//	Create the index arrar for this submesh.
+			geoSubMesh->mIndex	=	new Index[numIndices];
+	}
+	
+	if (idx32bit)
+	{
+		printf("\tSon 32 bits por indice\n");
+	}
+	else
+	{
+		printf("\tSon 16 bits por indice\n");
+	}
+
+	salida	=	fopen(nom_salida,"a");
+
+	fprintf(salida,"\n#----->Leo un subMesh:");
+	
+	if (useSharedVertices)
+	{
+		fprintf(salida," shared vertices");
+	}
+	else
+	{
+		fprintf(salida,
+						" no shared vertices %d triangles",
+						numIndices/3);
+	}
+
+	fprintf(salida,"\n# Indexes:");
+	
+	//Sumo uno a los vertices porque en el obj no puede hacer un vertice 0
+	if (idx32bit)
+	{
+		unsigned int aux;
+
+		for (int i = 0; i < numIndices; i++)
+		{
+			fread(&aux,sizeof(unsigned int),1,f);
+
+			if (option == GEOMESH_BUILD)
+			{
+					geoSubMesh->mIndex[i]	=	aux;
+			}
+		}
+	}
+	else
+	{
+		unsigned short aux;
+
+		for (int i = 0; i < numIndices; i++)
+		{
+			fread(&aux,sizeof(unsigned short),1,f);
+			
+			if (option == GEOMESH_BUILD)
+			{
+				geoSubMesh->mIndex[i]	=	aux;
+			}
+		}
+	}
+
+	fclose(salida);
+
+  // M_GEOMETRY chunk 
+	// (Optional: present only if useSharedVertices = false)
+  if (!useSharedVertices)
+	{
+		chunkID = readChunk(f);
+		
+		if (chunkID != M_GEOMETRY)
+		{
+			printf("Missing geometry data in mesh file\n"); //Error
+		}
+		
+		readGeometry(f, geoMesh, option);
+	}
+
+	// Find all bone assignments (if present) 
+	if (!feof(f))
+	{
+		chunkID = readChunk(f);
+		while(!feof(f) &&
+					(chunkID == M_SUBMESH_BONE_ASSIGNMENT ||
+					chunkID == M_SUBMESH_OPERATION))
+		{
+			switch(chunkID)
+			{
+				case M_SUBMESH_OPERATION:
+								
+					cout<<"M_SUBMESH_OPERATION\n";
+					readSubMeshOperation(f, geoMesh, option);
+					break;
+				case M_SUBMESH_BONE_ASSIGNMENT:
+					jumpChunk(f);
+					break;
+			}
+
+			if (!feof(f))
+			{
+				chunkID	=	readChunk(f);
+			}
+
+		}
+		if (!feof(f))
+		{
+			// Backpedal back to start of chunk
+			fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+		}
+	}
+
+}
+
+//	Read a mesh lod information.
+void GeoMeshLoader::readMeshLodInfo(FILE	*f, Mesh	*geoMesh)
+{
+	unsigned	short	chunkID;
+	unsigned	short	i;
+	unsigned	short	aux;
+	bool						aux2;
+
+  // unsigned short numLevels;
+	fread(&aux,sizeof(unsigned short),1,f);
+	// bool manual;
+	// (true for manual alternate meshes, false for generated)
+	fread(&aux2,sizeof(bool),1,f);
+
+	// Loop from 1 rather than 0 (full detail index is not in file)
+	for (i = 1; i < aux; ++i)
+	{
+		chunkID = readChunk(f);
+		if (chunkID != M_MESH_LOD_USAGE)
+		{
+			printf("Missing M_MESH_LOD_USAGE chunk\n"); //Error
+		}
+		else printf("\tM_MESH_LOD_USAGE (%d bytes) ",long_actual);
+		jumpChunk(f);
+
+	}
+}
+
+//	Read a submesh name table.
+void GeoMeshLoader::readSubMeshNameTable(FILE	*f, Mesh	*geoMesh)
+{
+		unsigned	short	chunkID;
+		unsigned	short	subMeshIndex;
+		char						string[255];
+
+		if (!feof(f))
+		{
+			chunkID	=	readChunk(f);
+			
+			while	(!feof(f) && (chunkID == M_SUBMESH_NAME_TABLE_ELEMENT ))
+			{
+				printf("M_SUBMESH_NAME_TABLE_ELEMENT %d bytes\n",long_actual);
+				
+				// Read in the index of the submesh.
+				fread(&subMeshIndex,sizeof(unsigned short),1,f);
+				
+				// Read in the String and map it to its index.
+				fgets(string,255,f);
+				printf("index %u name %s\n",subMeshIndex,string);
+
+				// If we're not end of file get the next chunk ID
+				if (!feof(f))
+				{
+					chunkID = readChunk(f);
+				}
+			}
+			if (!feof(f))
+			{
+				// Backpedal back to start of chunk
+				fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+			}
+		}
+}
+
+//	Read a mesh file.
+void GeoMeshLoader::readMesh(FILE	*f, Mesh	*geoMesh, int option)
+{
+	unsigned	short	chunkID;
+	bool						nada;
+
+	//	Debug.
+	cout	<<	"Read Mesh"
+				<<	endl;
+	
+	//	Create the VertexBuffer of the mesh.
+	geoMesh->mVertexBuffer	=	new	VertexBuffer();
+	geoMesh->mVertexBuffer->mVertexCount	=	0;
+
+	//La vacio antes de leer el mesh
+	list.clear();
+
+	// bool skeletallyAnimated
+	fread(&nada,sizeof(bool),1,f);
+
+  // Find all subchunks 
+	if (!feof(f))
+	{
+		chunkID	=	readChunk(f);
+
+		while(!feof(f) &&
+				(chunkID == M_GEOMETRY ||
+				 chunkID == M_SUBMESH ||
+				 chunkID == M_MESH_SKELETON_LINK ||
+				 chunkID == M_MESH_BONE_ASSIGNMENT ||
+				 chunkID == M_MESH_LOD ||
+				 chunkID == M_MESH_BOUNDS ||
+				 chunkID == M_SUBMESH_NAME_TABLE ||
+				 chunkID == M_EDGE_LISTS))
+		{
+			switch(chunkID)
+			{
+				case M_GEOMETRY:
+
+					//	Debug.
+					cout	<<	"Geometry"	<<	endl;
+
+					readGeometry(f, geoMesh, option);
+					break;
+
+				case M_SUBMESH:
+
+					cout	<<	"SubMesh"	<<	endl;
+
+					if (option == GEOMESH_BUILD)
+					{
+						//	Increments the current submesh.
+						currentSubMesh++;
+					}
+
+					readSubMesh(f, geoMesh, option);
+
+					break;
+
+				case M_MESH_SKELETON_LINK:
+
+					cout	<<	"M_MESH_SKELETON_LINK  "
+						<<	long_actual
+						<<	" bytes\n";
+
+					jumpChunk(f);
+					break;
+
+				case M_MESH_BONE_ASSIGNMENT:
+
+					cout	<<	"M_MESH_BONE_ASSIGNMENT  "
+						<<	long_actual
+						<<	" bytes\n";
+
+					break;
+
+				case M_MESH_LOD:
+
+					cout	<<	"M_MESH_LOD\n";
+					readMeshLodInfo(f, geoMesh);
+					break;
+
+				case M_MESH_BOUNDS:
+
+					cout	<<	"M_MESH_BOUNDS "
+						<<	long_actual
+						<<	" bytes\n";
+
+					jumpChunk(f);
+					break;
+
+				case M_SUBMESH_NAME_TABLE:
+
+					cout	<<	"M_SUBMESH_NAME_TABLE "
+						<<	long_actual
+						<<	" bytes\n";
+
+					readSubMeshNameTable(f,	geoMesh);
+					break;
+
+				case M_EDGE_LISTS:
+
+					cout	<<	"M_EDGE_LISTS "
+						<<	long_actual
+						<<	" bytes\n";
+
+					jumpChunk(f);
+					break;
+			}
+
+			if (!feof(f))
+			{
+				chunkID	=	readChunk(f);
+			}
+
+		}
+
+		if (!feof(f))
+		{
+			// Backpedal back to start of chunk
+			fseek(f,-(long)CHUNK_OVERHEAD_SIZE,1);
+			printf("Malo\n");
+		}
+	}
+
+}
+
+/*
+		Allocate memory to the array of strips
+*/
+Mesh* GeoMeshLoader::BuildStripsGeoSubMesh(Mesh* geoMesh)
+{
+	bool		head_found;
+	bool		tail_found;
+	int			strip_count;
+	int			tailIndex;
+	size_t	tail;
+	SubMesh	*geoSubMesh;
+
+	//	For each submesh.
+	for (int submesh	=	0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geoSubMesh	=	&geoMesh->mSubMesh[submesh];
+		
+		head_found							=	false;
+		tail_found							=	false;
+		geoSubMesh->mStripCount	=	1;
+	
+		//	Foreachone of the indices.
+		//	Obtains the number of triangle strips.
+		for (int i = 0; i < (geoSubMesh->mIndexCount - 1); i++)
+		{
+			if (geoSubMesh->mIndex[i] == geoSubMesh->mIndex[i+1])
+			{
+				if (head_found)
+				  {
+					tail_found	=	true;
+				}
+				else
+				{
+					head_found	=	true;
+				}
+
+				//	Jump one index.
+				i++;
+			}
+			else
+			{
+				//	Increments the number of triangle strips.
+				if (tail_found)
+				{
+					geoSubMesh->mStripCount++;
+				}
+
+				head_found	=	false;
+				tail_found	=	false;
+			}
+		}
+
+		geoSubMesh->mStrip		=	(Index**) malloc(	sizeof(Index*)
+																							*
+																							geoSubMesh->mStripCount);
+
+		//	Number of strips. Initially there is one triangle strip.
+		strip_count	=	1;
+
+		head_found						=	false;
+		tail_found						=	false;
+
+		//	Initialize the fist triangle strip.
+		geoSubMesh->mStrip[0]	=	&geoSubMesh->mIndex[0];
+
+		//	Foreachone of the indices.
+		//	Assigns the beginning of the triangle strips.
+		for(int i = 0;i < (geoSubMesh->mIndexCount - 1); i++)
+		{
+			if(geoSubMesh->mIndex[i] == geoSubMesh->mIndex[i+1])
+			{
+				if(head_found)
+				{
+					if (!tail_found)
+					{
+						tailIndex		=	i;
+					}
+
+					tail_found	=	true;
+				}
+				else
+				{
+					head_found	=	true;
+				}
+
+				//	Jump one index.
+				i++;
+			}
+			else
+			{
+				//	Increments the number of triangle strips.
+				if(tail_found)
+				{
+					geoSubMesh->mStrip[strip_count++]	=	&geoSubMesh->mIndex[tailIndex];
+				}
+
+				head_found	=	false;
+				tail_found	=	false;
+			}
+		}
+	}
+
+	return	geoMesh;
+}
+
+//	Loads a mesh.
+Mesh* GeoMeshLoader::load(char	*nameFileMesh) 
+{
+	unsigned	short	uno;
+  unsigned	short	chunkID;
+	char						version[255];
+	char						kk;
+	FILE						*salida;
+	FILE						*pFile;
+
+	//	Initialize the current submesh;
+	currentSubMesh	=	-1;
+	
+	std::cout	<<	"Load a new Mesh"
+						<<	std::endl;
+
+	//	Initialize the return value.
+	geoMesh	=	new	Mesh();
+
+	//	Open the mesh file.
+	pFile	=	fopen( nameFileMesh, "rb" );
+
+  if (!pFile)
+  {
+		printf("No he encontrado el fichero\n");
+		exit(0);
+  }
+
+	//	Count the submeshes
+	//	and next build the geomesh.
+	for (int option = 0; option < 2;option++)
+	{
+		fread(&uno,sizeof(unsigned short),1,pFile);
+
+		if (uno != M_HEADER)
+		{
+			cout	<<	"no se ha encontrado el header"
+						<<	endl;
+		}
+
+		// Read version.
+		fgets(version,255,pFile);
+
+		cout	<<	version	<<	endl;
+
+		if (strcmp(version,"[MeshSerializer_v1.30]\n"))
+		{
+			cout	<<
+						"No se puede trabajar con versiones de"
+						<<
+						" .mesh diferentes de la 1.3"
+						<<
+						endl;
+		}
+
+		salida	=	fopen(nom_salida,"w");
+
+		fprintf(salida,"# Empiezo el fichero:");
+
+		fclose(salida);
+
+		while(!feof(pFile))
+		{
+			chunkID = readChunk(pFile);
+
+			switch (chunkID)
+			{
+				case M_MESH:
+					readMesh(pFile, geoMesh, option);
+					break;
+			}
+		}
+
+		//	Create the submesh array
+		if (option == SUBMESH_COUNT)
+		{		
+			cout	<<	"---------------"
+						<<	endl;
+
+			cout	<<	"SubMesh Count: "
+						<<	geoMesh->mSubMeshCount
+						<<	endl;
+
+			geoMesh->mSubMesh	= new SubMesh[geoMesh->mSubMeshCount];
+		}
+							
+		if (feof(pFile))
+		{
+			cout	<<	"------->Hemos llegado al final del fichero"
+						<<	endl;
+		}
+
+		//cout	<<	"Press enter to exit\n";
+
+		//	Move the curso to the begining of the file.
+		fseek(pFile,0,SEEK_SET);
+	}
+
+	//	Goes to the end of the file.
+	fseek(pFile,0,SEEK_END);
+
+	//	Gets the size of the file.
+	mFileSize	=	ftell(pFile);
+	
+	// Close the mesh file.
+	fclose(pFile);
+	
+	if (geoMesh->mType == Geometry::GEO_TRIANGLE_STRIPS)
+	{
+		//	Fill the strips list.
+		geoMesh	=	BuildStripsGeoSubMesh(geoMesh);
+	}
+	
+	return	geoMesh;
+}
+
+//	Get the size in bytes of the file.
+size_t	GeoMeshLoader::getFileSize()
+{
+	return	mFileSize;
+}
+
+//	Constructor
+GeoMeshLoader::GeoMeshLoader()
+{
+	nom_salida	=	"salida22.obj";
+	geoMesh			=	NULL;
+	mFileSize		=	0;
+}
+
+//	Destroyer.
+GeoMeshLoader::~GeoMeshLoader()
+{
+	delete	geoMesh;
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshViewUI.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshViewUI.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshViewUI.cpp	(revision 774)
@@ -0,0 +1,2577 @@
+// generated by Fast Light User Interface Designer (fluid) version 2.0100
+
+#include "GeoMeshViewUI.h"
+#include "resource.h"
+
+using	namespace	Geometry;
+using	namespace	std;
+
+//---------------------------------------------------------------------------
+//	Menu File Open Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuFileOpen_i(fltk::Item*, void*)
+{
+	//	Sets menus application state to NONE.
+	mApplicationState	=	NONE;
+
+	//	Loads a mesh file.
+	openMeshFile();
+	
+	//	Debug.
+	cout	<<	"Vertex Count SubMesh 0:	"
+				<<	mGeoMesh->mSubMesh[0].mVertexBuffer->mVertexCount
+				<<	endl;
+	//----------------------------------------------------------
+	
+	//	Deactive Lod strip visualization.
+	geoMeshView->deactiveLodStrip();
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+//---------------------------------------------------------------------------
+//	Repaint the FPS label.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::refreshFPS(int fps)
+{
+	static char	char_value[10];
+	
+	//	Translate the FPS count to a char value.
+	sprintf(char_value,"FPS %d",fps);
+
+	mFPS->label(char_value);
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuFileOpen(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuFileOpen_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Save callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuFileSave_i(fltk::Item*, void*)
+{
+	GeoMeshSaver	*mesh_saver;
+
+	//	If there is a mesh object created.
+	if (mGeoMesh	!= NULL)
+	{
+		//	Create a mesh saver with mesh bounds.
+		mesh_saver	=	new	GeoMeshSaver(mMeshBounds);
+
+		//	Save the file mesh.
+		mesh_saver->save(	mGeoMesh,
+				mFileName);
+
+		//	Free memory.
+		delete	mesh_saver;
+	}
+}
+
+void GeoMeshViewUI::cb_menuFileSave(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuFileSave_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Save As Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuOpenSaveAs_i(fltk::Item*, void*)
+{
+	fltk::FileChooser *fcho;
+	GeoMeshSaver			*mesh_saver;
+	
+	if (mGeoMesh != NULL)
+	{
+		fcho	=	new fltk::FileChooser("",
+				"*.mesh",
+				fltk::FileChooser::CREATE,
+				"Save Mesh as");
+
+		fcho->exec();
+
+		if (fcho->value())
+		{
+			mesh_saver	=	new	GeoMeshSaver(mMeshBounds);
+
+			mesh_saver->save(	mGeoMesh,
+					filename_name(fcho->value()));
+
+			delete	mesh_saver;
+		}
+
+		//	Repaint the window.
+		mMainWindow->redraw();
+
+		delete	fcho;
+	}
+}
+
+void GeoMeshViewUI::cb_menuOpenSaveAs(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuOpenSaveAs_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Mesh info callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuMeshInfo_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Mesh Info");
+
+	showMeshInfo();
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuMeshInfo(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuMeshInfo_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Mesh Export to OBJ callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuMeshExportOBJ_i(fltk::Item*, void*)
+{
+	char *p;
+  	
+	//	Sets menus application state to NONE.
+	mApplicationState	=	NONE;
+  
+	//	Open file chooser dialog.
+	p	=	fltk::file_chooser(	"Export to OBJ",
+													"*.obj",
+													"");
+	if (p && mGeoMesh)
+	{
+		mGeoMesh->exportToOBJ(p);
+	}
+}
+
+void GeoMeshViewUI::cb_menuMeshExportOBJ(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuMeshExportOBJ_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Transform to Shared Vertex callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuTransformSharedVertex_i(fltk::Item*, void*)
+{
+	Mesh	*mesh_aux;
+	
+	//	if the undo mesh is not initialized.
+	if	(mGeoMesh != NULL)
+	{
+		//	Deletes the actual mesh.
+		delete	mUndoMesh;
+
+		mUndoMesh	=	new Mesh();
+
+		//	Restore the previous mesh.
+		*mUndoMesh	=	*mGeoMesh;
+
+		//	Transform NoSV Mesh to a SV Mesh.
+		mesh_aux	=	mGeoMesh->toSharedVertex();
+
+		//	Deletes the mesh No Shared Vertex.
+		delete	mGeoMesh;
+
+		//	Gets the mesh Shared Vertex.
+		mGeoMesh	=	mesh_aux;
+
+		//	Visualize the mesh stripified.
+		geoMeshView->setMesh(mGeoMesh);
+
+		//	Refresh mesh information.
+		showMeshInfo();
+		
+		//	Repaint the window.
+		mMainWindow->redraw();
+	}
+}
+
+void GeoMeshViewUI::cb_menuFileTransformSharedVertex(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuTransformSharedVertex_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Quit Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuOpenQuit_i(fltk::Item*, void*)
+{
+	delete	this;
+}
+
+void GeoMeshViewUI::cb_menuOpenQuit(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuOpenQuit_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Undo Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuEditUndo_i(fltk::Item*, void*)
+{
+	//	Undo the mesh changes.
+	undo();
+}
+
+void GeoMeshViewUI::cb_menuEditUndo(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuEditUndo_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Fit Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuEditFit_i(fltk::Item*, void*)
+{
+	geoMeshView->fit();
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuEditFit(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuEditFit_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Rotate Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuEditRotate_i(fltk::Item	*item, void*)
+{	
+	//	If the item is activated.
+	if (item->value())
+	{
+		menuEditPan->clear_value();
+		geoMeshView->deactivePan();
+		
+		geoMeshView->activeRotate();
+	}
+	else
+	{
+		menuEditPan->set_value();
+		geoMeshView->activePan();
+
+		geoMeshView->deactiveRotate();
+	}
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuEditRotate(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuEditRotate_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Pan Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuEditPan_i(fltk::Item	*item, void*)
+{	
+	//	If the item is activated.
+	if (item->value())
+	{
+		geoMeshView->activePan();
+		
+		menuEditRotate->clear_value();
+		geoMeshView->deactiveRotate();
+	}
+	else
+	{
+		geoMeshView->deactivePan();
+		
+		menuEditRotate->set_value();
+		geoMeshView->activeRotate();
+	}
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuEditPan(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuEditPan_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Zoom Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuEditZoom_i(fltk::Item*, void*)
+{
+}
+
+void GeoMeshViewUI::cb_menuEditZoom(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuEditZoom_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Wire Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderWire_i(fltk::Item *item, void*)
+{
+	if (item->value())
+	{
+		geoMeshView->activeWire();
+	}
+	else
+	{
+		geoMeshView->deactiveWire();
+	}
+
+	//	Repaint the canvas.
+	//geoMeshView->redraw();
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderWire(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderWire_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Solid Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderSolid_i(fltk::Item	*item, void*)
+{
+	if (item->value())
+	{
+		geoMeshView->activeSolid();
+	}
+	else
+	{
+		geoMeshView->deactiveSolid();
+	}
+									
+	//	Repaint the canvas.
+	//geoMeshView->redraw();
+	
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderSolid(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderSolid_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	CW callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderCW_i(fltk::Item	*item, void*)
+{
+	//	Clear the CCW state.
+	menuRenderCCW->clear_value();
+	geoMeshView->deactiveCCW();
+	
+	//	If the item is activated.
+	if (item->value())
+	{
+		geoMeshView->activeCW();
+	}
+	else
+	{
+		geoMeshView->deactiveCW();
+	}
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderCW(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderCW_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	CCW callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderCCW_i(fltk::Item	*item, void*)
+{
+	//	Clear the CW state.
+	menuRenderCW->clear_value();
+	geoMeshView->deactiveCW();
+	
+	//	If the item is activated.
+	if (item->value())
+	{
+		geoMeshView->activeCCW();
+	}
+	else
+	{
+		geoMeshView->deactiveCCW();
+	}
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderCCW(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderCCW_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Flat callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderFlat_i(fltk::Item*, void*)
+{
+	//	Deactive smooth flag.
+	menuRenderSmooth->clear_value();
+	
+	//	Sets flat lighting.
+	geoMeshView->flat();
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderFlat(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderFlat_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Smooth Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderSmooth_i(fltk::Item*, void*)
+{
+	//	Deactive flat flag.
+	menuRenderFlat->clear_value();
+
+	//	Sets smooth lighting.
+	geoMeshView->smooth();
+
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderSmooth(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderSmooth_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Textures callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuRenderTextures_i(fltk::Item*, void*)
+{
+	//	Repaint the main window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuRenderTextures(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuRenderTextures_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Stripify Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuStripify_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Stripify");
+	mProcessBar->position(0);
+
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the stripify panel.
+	showStripify();
+	
+	//	Sets menus application state to STRIPIFY.
+	mApplicationState	=	STRIPIFY;
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuStripify(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->user_data()))
+										->
+										cb_menuStripify_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Simplify Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuSimplify_i(fltk::ItemGroup*, void*)
+{
+}
+
+void GeoMeshViewUI::cb_menuSimplify(fltk::ItemGroup* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->user_data()))
+										->
+										cb_menuSimplify_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Edge collapse Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuSimplifyEdgeCollapse_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Mesh Simplification");
+	mProcessBar->position(0);
+
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the edge collapse panel.
+	showEdgeCollapse();
+	
+	//	Sets menus application state to EDGE_COLLAPSE.
+	mApplicationState	=	EDGE_COLLAPSE;
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+
+}
+
+void GeoMeshViewUI::cb_menuSimplifyEdgeCollapse(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuSimplifyEdgeCollapse_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Leaves collapse Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuSimplifyLeavesCollapse_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Leaves Simplification");
+	mProcessBar->position(0);
+
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the leaves collapse panel.
+	showLeavesCollapse();
+	
+	//	Sets menus application state to LEAVES_COLLAPSE.
+	mApplicationState	=	LEAVES_COLLAPSE;
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuSimplifyLeavesCollapse(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuSimplifyLeavesCollapse_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Tree select leaves simplification Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuSelectLeaves_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Select Leaves");
+
+	showMeshInfo();
+	mButtonProcess->show();
+	mButtonProcess->activate();
+	mApplicationState	=	SELECT_LEAVES;
+}
+
+void GeoMeshViewUI::cb_menuSelectLeaves(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuSelectLeaves_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Auto Generate LodStrips Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuLodStripsGenerate_i(fltk::Item*, void*)
+{
+	//	Show title.
+	mProcessTitle->label("Generate LodStrips");
+	mProcessBar->position(0);
+	mBuildBar->position(0);
+
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the LodStrips panel.
+	showAutoGenerateLodStrips();
+	
+	//	Sets menus application state to LODSTRIPS_AUTO.
+	mApplicationState	=	LODSTRIPS_AUTO;
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuLodStripsGenerate(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuLodStripsGenerate_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Visualize LodStrips Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuLodStripsVisualize_i(fltk::Item*, void*)
+{
+	fltk::FileChooser *fcho;
+	const	char				*lod_file;
+	
+	//	Sets menus application state to NONE.
+	mApplicationState	=	NONE;
+
+	//	Deactive Lod strip visualization.
+	geoMeshView->deactiveLodStrip();
+
+	//	Loads a mesh file.
+	openMeshFile();
+	
+	//	Show title.
+	mProcessTitle->label("Visualize LodStrips");
+
+	//	If an object is loaded.
+	if (mGeoMesh != NULL)
+	{
+		fcho	=	new fltk::FileChooser("",
+				"*.lod",
+				fltk::FileChooser::CREATE,
+				"Open Lod file");
+
+		fcho->exec();
+
+		//	If a file was selected.
+		if (fcho->value())
+		{
+			//	Build lod strips library.
+			setLodStripsLibrary(string(fcho->value()), mGeoMesh);
+
+			//	Sets the aplication mode.
+			mApplicationState	=	VISUALIZE_LODSTRIPS;
+		}
+
+		//	Free memory.
+		delete	fcho;
+	}
+
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the Visulize LodStrips panel.
+	showVisualizeLodStrips();
+	
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuLodStripsVisualize(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuLodStripsVisualize_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Open LodStrip trunk Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuLodTreesOpenLodStripTrunk_i(fltk::Item*, void*)
+{
+}
+
+void GeoMeshViewUI::cb_menuLodTreesOpenLodStripTrunk(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuLodTreesOpenLodStripTrunk_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Open leaves simplification Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuLodTreesOpenLeavesSimplification_i(fltk::Item*, void*)
+{
+	//	Hide the right panel.
+	hideRightPanel();
+
+	//	Show the LodTrees panel.
+	showOpenLeavesSimplification();
+
+	//	Sets menus application state to LODTREES.
+	mApplicationState	=	LODTREES;
+
+	//	Repaint the window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_menuLodTreesOpenLeavesSimplification(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuLodTreesOpenLeavesSimplification_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	About Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_menuHelpAbout_i(fltk::Item*, void*)
+{
+	new	GTAboutDialog();
+}
+
+void GeoMeshViewUI::cb_menuHelpAbout(fltk::Item* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_menuHelpAbout_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Button Process Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mButtonProcess_i(fltk::Button*, void*)
+{
+	Mesh	*mesh_aux;
+	
+	//	Sets the progress bar to process bar.
+	progressBarType	=	PROCESS;
+	mProcessBar->position(0);
+
+	//	If there is a mesh object.
+	if (mGeoMesh != NULL)
+	{
+		//	Choose between aplication state.
+		switch(mApplicationState)
+		{
+			//	Stripify state.
+			case	STRIPIFY:
+
+				//	Stripify the mesh object.
+				stripify();
+
+				break;
+
+				//	Simplify edge collapse state.
+			case	EDGE_COLLAPSE:
+
+				//	if the mesh is stripified.
+				if (mGeoMesh->mType == GEO_TRIANGLE_STRIPS)
+				{
+					fltk::alert("Can't simplify a mesh in triagle strips.");
+				}
+				else
+				{
+
+					//	Simplify the mesh object.
+					simplifyEdgeCollapse();
+				}
+				break;
+
+				// Simplify leaves
+			case	LEAVES_COLLAPSE:
+
+				//	Simplify the mesh object.
+				simplifyLeavesCollapse();
+
+				break;
+
+				//	Simplify and generate simplification sequence.
+			case	LODSTRIPS_AUTO:
+
+				//	if the mesh is stripified.
+				if (mGeoMesh->mType == GEO_TRIANGLE_STRIPS)
+				{
+					fltk::alert("Can't simplify a mesh in triagle strips.");
+				}
+				else
+				{
+
+					//	Transform NoSV Mesh to a SV Mesh.
+					mesh_aux	=	mGeoMesh->toSharedVertex();
+
+					//	Deletes the mesh No Shared Vertex.
+					delete	mGeoMesh;
+
+					//	Gets the mesh Shared Vertex.
+					mGeoMesh	=	mesh_aux;
+
+					//	Simplify the mesh object.
+					simplifyEdgeCollapse();
+
+					//	Create the qslim simplification sequence.
+					createQslimSequence();
+				}
+
+				break;
+
+				// Añadido 23-12-2005
+			case	SELECT_LEAVES:
+
+				idMeshLeaves	=	paintMesh();
+
+				//	Set the leaves submesh.
+				geoMeshView->setLeavesSubmesh(idMeshLeaves);
+
+				//	Refresh mesh info.
+				showMeshInfo();
+
+				break;
+		}
+
+		//	Refresh geometry attributes.
+		refreshApplicationBar();
+	}
+	
+	//	Repaint the GL Window.
+	mMainWindow->redraw();
+}
+
+void GeoMeshViewUI::cb_mButtonProcess(fltk::Button* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_mButtonProcess_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Button Sort Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mButtonSort_i(fltk::Button*, void*)
+{
+}
+
+void GeoMeshViewUI::cb_mButtonSort(fltk::Button* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_mButtonSort_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Button Build Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mButtonBuild_i(fltk::Button*, void*)
+{
+	char					*file_name;
+	GeoMeshSaver	*mesh_saver;
+	Serializer		*oSerializer;
+	
+	//	Sets the progress bar to process bar.
+	progressBarType	=	BUILD;
+
+	//	Reset the build bar.
+	mBuildBar->position(0);
+
+	//	If there is a mesh object.
+	if (mGeoMesh != NULL)
+	{
+		//	Choose between aplication state.
+		switch(mApplicationState)
+		{
+			//	Build the LOD file.
+			case	LODSTRIPS_AUTO:
+
+				// Builder
+
+				//	Open file chooser dialog.
+				file_name	=	fltk::file_chooser(	"Build LOD",
+						"*",
+						"");
+
+				//	If a file was selected.
+				if (file_name)
+				{
+					//	Undo the simplification changes.
+					undo();
+
+					//	Stripify the mesh object.
+					stripify();
+
+					//	Reset the build bar.
+					mBuildBar->position(0);
+
+					//	Simplification sequence.
+					oMeshSimpSequence = new MeshSimplificationSequence();
+
+					//	Loads a simplification sequence file.
+					oMeshSimpSequence->Load(Serializer(	"mqslimSequence.txt",
+								Serializer::READ));
+
+					//	If the simplification sequence and the mesh exist.
+					if (oMeshSimpSequence && mGeoMesh)
+					{
+						oLodStrip		=	new LodStripsConstructor(	mGeoMesh,
+								oMeshSimpSequence,
+								progress_function);
+
+						oSerializer	=	new Serializer(	strcat(file_name,".lod"),
+								Serializer::Mode::WRITE);
+
+						oLodStrip->LodStripsConstructor::Save(*oSerializer);
+
+						//	Close file.
+						delete	oSerializer;
+
+						//	Deletes the previous mesh.
+						delete mUndoMesh;
+
+						mUndoMesh	=	new Mesh();
+
+						//	Sets the undo mesh.
+						*mUndoMesh	=	*mGeoMesh;
+
+						delete	mGeoMesh;
+
+						mGeoMesh	=	oLodStrip->GetMesh();
+
+						geoMeshView->setMesh(mGeoMesh);
+
+						mesh_saver	=	new	GeoMeshSaver(mMeshBounds);
+						file_name[strlen(file_name) - 4]	=	'\0';
+						mesh_saver->save(	mGeoMesh,
+								strcat(file_name,".mesh"));
+						delete	mesh_saver;
+
+					}
+					else
+					{
+						//	Error message.
+						fltk::alert("There is no simplification sequence.");
+					}
+
+					//	Deletes the siplification sequence object.
+					delete	oMeshSimpSequence;
+				}
+				break;
+		}
+		//	Refresh data aplication.
+		refreshApplicationBar();
+	}	
+}
+
+void GeoMeshViewUI::cb_mButtonBuild(fltk::Button	*o, void	*v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_mButtonBuild_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Lod Slider Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mLodSlider_i(fltk::Slider	*o, void	*)
+{
+	//	Change the lod.
+	geoMeshView->GoToLod((unsigned int)o->value());
+
+	//	Refresh data aplication.
+	refreshApplicationBar();
+		
+	mMainWindow->flush();
+}
+
+void GeoMeshViewUI::cb_mLodSlider(fltk::Slider	*o, void	*v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_mLodSlider_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Mesh Info Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mMeshInfo_i(fltk::Browser	*, void	*)
+{	
+	paintMesh();
+}
+
+void GeoMeshViewUI::cb_mMeshInfo(fltk::Browser* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->parent()->user_data()))
+										->
+										cb_mMeshInfo_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Logo Callback
+//---------------------------------------------------------------------------
+inline void GeoMeshViewUI::cb_mLogo_i(fltk::InvisibleBox*, void*)
+{
+}
+
+void GeoMeshViewUI::cb_mLogo(fltk::InvisibleBox* o, void* v)
+{
+  ((GeoMeshViewUI*)	(o->parent()->parent()->user_data()))
+										->
+										cb_mLogo_i(o,v);
+}
+
+//---------------------------------------------------------------------------
+//	Show the stripify panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showStripify()
+{
+	/*
+	mTypeLabel->set_visible();
+	mTypeLabel->activate();
+
+	mOneCacheStrip->set_visible();
+	mOneCacheStrip->activate();
+
+	mQualityStrips->set_visible();
+	mQualityStrips->activate();
+	*/
+
+	mButtonProcess->set_visible();
+	mButtonProcess->activate();
+
+	mProcessBar->set_visible();
+	mProcessBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the stripify panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideStripify()
+{
+	/*
+	mTypeLabel->hide();
+	mTypeLabel->deactivate();
+	*/
+	
+	mOneCacheStrip->hide();
+	mOneCacheStrip->deactivate();
+
+	mQualityStrips->hide();
+	mQualityStrips->deactivate();
+
+	mButtonProcess->hide();
+	mButtonProcess->deactivate();
+
+	mProcessBar->hide();
+	mProcessBar->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the Simplify Edge Collapse panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showEdgeCollapse()
+{
+	mMetricLabel->set_visible();
+	mMetricLabel->activate();
+
+	mGeometryBased->set_visible();
+	mGeometryBased->activate();
+	mGeometryBased->set();
+
+	mImageBased->set_visible();
+	mImageBased->activate();
+
+	/*
+	mTypeLabel->set_visible();
+	mTypeLabel->activate();
+
+	mChangeVertices->set_visible();
+	mChangeVertices->activate();
+	*/
+	
+	mMeshReductionLabel->set_visible();
+	mMeshReductionLabel->activate();
+
+	mPercent->set_visible();
+	mPercent->activate();
+	mPercent->set();
+
+	mVerticesNumber->set_visible();
+	mVerticesNumber->activate();
+
+	mMeshReduction->set_visible();
+
+	// JGA
+	// Allows floating point.
+	mMeshReduction->type(fltk::FloatInput::FLOAT);
+
+	mMeshReduction->activate();
+
+	mButtonProcess->set_visible();
+	mButtonProcess->activate();
+
+	mProcessBar->set_visible();
+	mProcessBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the Simplify Edge Collapse
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideEdgeCollapse()
+{
+	mMetricLabel->hide();
+	mMetricLabel->deactivate();
+
+	mGeometryBased->hide();
+	mGeometryBased->deactivate();
+
+	mImageBased->hide();
+	mImageBased->deactivate();
+
+	/*
+	mTypeLabel->hide();
+	mTypeLabel->deactivate();
+
+	mChangeVertices->hide();
+	mChangeVertices->deactivate();
+	*/
+	
+	mMeshReductionLabel->hide();
+	mMeshReductionLabel->deactivate();
+
+	mPercent->hide();
+	mPercent->deactivate();
+
+	mVerticesNumber->hide();
+	mVerticesNumber->deactivate();
+
+	mMeshReduction->hide();
+	mMeshReduction->deactivate();
+	
+	mButtonProcess->hide();
+	mButtonProcess->deactivate();
+
+	mProcessBar->hide();
+	mProcessBar->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the Simlify Leaves Collapse
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showLeavesCollapse()
+{
+	mMetricLabel->set_visible();
+	mMetricLabel->activate();
+
+	mGeometryBased->set_visible();
+	mGeometryBased->activate();
+	mGeometryBased->set();
+
+	mImageBased->set_visible();
+	mImageBased->activate();
+
+	/*
+	mTypeLabel->set_visible();
+	mTypeLabel->activate();
+
+	mChangeTexture->set_visible();
+	mChangeTexture->activate();
+	*/
+
+	mMeshReductionLabel->set_visible();
+	mMeshReductionLabel->activate();
+
+	mPercent->set_visible();
+	mPercent->activate();
+	mPercent->set();
+
+	mVerticesNumber->set_visible();
+	mVerticesNumber->activate();
+
+	mMeshReduction->set_visible();
+	mMeshReduction->type(fltk::FloatInput::FLOAT);
+	mMeshReduction->activate();
+
+	mButtonProcess->set_visible();
+	mButtonProcess->activate();
+
+	mProcessBar->set_visible();
+	mProcessBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the Simplify Leaves Collapse
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideLeavesCollapse()
+{
+	mMetricLabel->hide();
+	mMetricLabel->deactivate();
+
+	mGeometryBased->hide();
+	mGeometryBased->deactivate();
+
+	mImageBased->hide();
+	mImageBased->deactivate();
+
+	/*
+	mTypeLabel->hide();
+	mTypeLabel->deactivate();
+
+	mChangeTexture->hide();
+	mChangeTexture->deactivate();
+	*/
+	
+	mMeshReductionLabel->hide();
+	mMeshReductionLabel->deactivate();
+
+	mPercent->hide();
+	mPercent->deactivate();
+
+	mVerticesNumber->hide();
+	mVerticesNumber->deactivate();
+
+	mMeshReduction->hide();
+	mMeshReduction->deactivate();
+
+	mButtonProcess->hide();
+	mButtonProcess->deactivate();
+
+	mProcessBar->hide();
+	mProcessBar->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the LodStrips Panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showOpenMeshSimplification()
+{
+	mButtonProcess->set_visible();
+	mButtonProcess->activate();
+
+	mProcessBar->set_visible();
+	mProcessBar->activate();
+
+	mButtonBuild->set_visible();
+	mButtonBuild->activate();
+
+	mBuildBar->set_visible();
+	mBuildBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the LodStrips Panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideOpenMeshSimplification()
+{
+	mButtonProcess->hide();
+	mButtonProcess->deactivate();
+
+	mProcessBar->hide();
+	mProcessBar->deactivate();
+
+	mButtonBuild->hide();
+	mButtonBuild->deactivate();
+
+	mBuildBar->hide();
+	mBuildBar->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Shows the auto generate LodStrips panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showAutoGenerateLodStrips()
+{
+	//	Shows the simplify panel.
+	showEdgeCollapse();
+
+	mButtonBuild->set_visible();
+	mButtonBuild->activate();
+
+	mBuildBar->set_visible();
+	mBuildBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the LodStrips visulization panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showVisualizeLodStrips()
+{
+	mLodSlider->set_visible();
+	mLodSlider->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the LodStrips visualization panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideVisualizeLodStrips()
+{
+	mLodSlider->hide();
+	mLodSlider->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the LodTrees Panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showOpenLeavesSimplification()
+{
+	mButtonBuild->set_visible();
+	mButtonBuild->activate();
+
+	mBuildBar->set_visible();
+	mBuildBar->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the LodTrees Panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideOpenLeavesSimplification()
+{
+	mButtonBuild->hide();
+	mButtonBuild->deactivate();
+
+	mBuildBar->hide();
+	mBuildBar->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Show the mesh info browser
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::showMeshInfo()
+{
+	char	type[10];
+	
+	if (mGeoMesh)
+	{
+		// Remove previous mesh information
+		this->mMeshInfo->remove_all();
+		ogeometry = new fltk::ItemGroup("Geometry");
+		ogeometry->begin();
+
+		fltk::ItemGroup **oprueba;
+		oprueba=new fltk::ItemGroup*[mGeoMesh->mSubMeshCount];
+		for(int i=0; i<mGeoMesh->mSubMeshCount;i++)
+		{
+			char *cadena=new char[12];
+
+			if (geoMeshView->getLeavesSubmesh() >= 0)
+			{
+				if (geoMeshView->getLeavesSubmesh() == i)
+				{
+					strcpy(type,"(Leaves)");
+				}
+				else
+				{
+					strcpy(type,"(Trunc)");
+				}
+			}
+			else
+			{
+				strcpy(type,"");
+			}
+
+			//	Submesh identifier.
+			sprintf(cadena,"SubMesh %d %s",i,type);
+			
+			oprueba[i] = new fltk::ItemGroup(cadena);
+			oprueba[i]->begin();
+			fltk::Item *sharedGeometry;
+			if (mGeoMesh->mSubMesh[i].mSharedVertexBuffer)
+			{
+				sharedGeometry = new fltk::Item("Shared Geometry: Yes");
+			}
+			else
+			{
+				sharedGeometry = new fltk::Item("Shared Geometry: No");
+			}
+
+			char *cadena2=new char[30];
+			sprintf(cadena2, "Number of indexes: %d",mGeoMesh->mSubMesh[i].mIndexCount);
+			fltk::Item *numberIndex = new fltk::Item(cadena2);
+			if (mGeoMesh->mType==Geometry::GEO_TRIANGLE_LIST)
+			{
+				fltk::Item *type = new fltk::Item("Triangle list");
+			}
+			else
+			{
+				fltk::Item *type = new fltk::Item("Triangle strips");
+			}
+
+			char *cadenavertex=new char[30];
+			sprintf(cadenavertex, "Number of vertices: %d",mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexCount);
+			fltk::Item *numberVertex = new fltk::Item(cadenavertex);
+
+			if (mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_NORMAL)
+			{
+				fltk::Item *normals = new fltk::Item("Normals: Yes");
+			}
+			else
+			{
+				fltk::Item *normals = new fltk::Item("Normals: No");
+			}
+
+			if (mGeoMesh->mSubMesh[i].mVertexBuffer->mVertexInfo & Geometry::VERTEX_TEXCOORDS)
+			{
+				fltk::Item *textures = new fltk::Item("Textures: Yes");
+			}
+			else
+			{
+				fltk::Item *textures = new fltk::Item("Textures: No");
+			}
+
+
+			oprueba[i]->end();
+		}
+		ogeometry->end();
+		this->mMeshInfo->add(ogeometry);
+	}
+
+	//	Hide the right panel.
+	hideRightPanel();
+	
+	mMeshInfo->set_visible();
+	mMeshInfo->activate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the mesh info browser
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideMeshInfo()
+{
+	mMeshInfo->hide();
+	mMeshInfo->deactivate();
+}
+
+//---------------------------------------------------------------------------
+//	Hide the right panel
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::hideRightPanel()
+{
+	hideStripify();
+	hideEdgeCollapse();
+	hideLeavesCollapse();
+	hideOpenMeshSimplification();
+	hideOpenLeavesSimplification();
+	hideVisualizeLodStrips();
+	hideMeshInfo();
+}
+
+//---------------------------------------------------------------------------
+//	Get the number of vertices
+//---------------------------------------------------------------------------
+size_t	GeoMeshViewUI::getVertexCount(Mesh	*geoMesh)
+{
+	size_t	vertex_count;
+	SubMesh	*geoSubMesh;
+
+	vertex_count	=	geoMesh->mVertexBuffer->mVertexCount;
+
+	//	For each submesh.
+	for (int submesh	=	0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geoSubMesh	=	&geoMesh->mSubMesh[submesh];
+
+		//	If the mesh does not have shared vertex.
+		if (!geoSubMesh->mSharedVertexBuffer)
+		{			
+			//	Adds the vertex of the submesh to the total count.
+			vertex_count	+=	geoSubMesh->mVertexBuffer->mVertexCount;
+		}
+	}
+
+	return	vertex_count;
+}
+
+//---------------------------------------------------------------------------
+//	Get the number of triangles
+//---------------------------------------------------------------------------
+size_t	GeoMeshViewUI::getTriangleCount(Geometry::Mesh	*geoMesh)
+{
+	size_t	triangle_count;
+	SubMesh	*geoSubMesh;
+
+	//	Initialize the triangle count.
+	triangle_count	=	0;
+	
+	//	If the application is in visualize lodstrips mode.
+	if (mApplicationState == VISUALIZE_LODSTRIPS)
+	{
+		triangle_count	=	geoMeshView->getLodStripsTriangleCount();
+	}
+	else
+	{
+		//	For each submesh.
+		for (int submesh	=	0; submesh < geoMesh->mSubMeshCount; submesh++)
+		{
+			//	Gets the actual submesh.
+			geoSubMesh	=	&geoMesh->mSubMesh[submesh];
+
+			switch (geoMesh->mType)
+			{
+				case	GEO_TRIANGLE_LIST:
+					triangle_count	+=	geoSubMesh->mIndexCount / 3;
+					break;
+				case	GEO_TRIANGLE_STRIPS:
+					triangle_count	+=	geoSubMesh->mIndexCount - 2;
+					break;
+			}
+		}
+	}
+
+	return	triangle_count;
+}
+
+//---------------------------------------------------------------------------
+//	Get the number of strips
+//---------------------------------------------------------------------------
+size_t	GeoMeshViewUI::getStripCount(Geometry::Mesh	*geoMesh)
+{
+	size_t	strip_count;
+	SubMesh	*geoSubMesh;
+
+	//	Initialize the triangle count.
+	strip_count	=	0;
+	
+	if (geoMesh->mType == GEO_TRIANGLE_STRIPS)
+	{
+		//	For each submesh.
+		for (int submesh	=	0; submesh < geoMesh->mSubMeshCount; submesh++)
+		{
+			//	Gets the actual submesh.
+			geoSubMesh	=	&geoMesh->mSubMesh[submesh];
+
+			strip_count	+=	geoSubMesh->mStripCount;
+		}	
+	}
+	return	strip_count;
+}
+
+//---------------------------------------------------------------------------
+//	It paints the submesh selected by the mMeshInfo tree
+//	Trate the mMeshInfo event	
+//---------------------------------------------------------------------------
+int GeoMeshViewUI::paintMesh(void)
+{
+	char selectedTag[100];
+	char *pch;
+	char *p;
+	int meshNumber;
+
+	//	Initializa mesh to not selected.
+	meshNumber	=	-1;
+
+	// Shows the selected object label
+	strcpy(selectedTag,mMeshInfo->goto_focus()->label());
+	
+	p=strstr(selectedTag,"SubMesh ");
+
+	// If the item begins with string "SubMesh"
+	if (p!=NULL)
+	{
+		pch = strtok (selectedTag," ");
+		pch = strtok (NULL, " ");
+		sscanf(pch,"%d",&meshNumber);
+	}
+	
+	geoMeshView->setColorSubmeshi(meshNumber);
+	geoMeshView->redraw();
+	
+	return meshNumber;
+}
+
+//---------------------------------------------------------------------------
+//	Simplify the mesh object.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::simplifyEdgeCollapse()
+{
+	Real	percent;
+
+	simplificacionState	=	QSLIM;
+
+	ms = new ImageBasedSimplifier(mGeoMesh,	progress_function);
+
+	ms->setMeshLeaves(idMeshLeaves);
+
+	if (mPercent->value() == true)
+	{
+		// Simplificación por porcentaje
+		if (mMeshReduction->fvalue() <= 100.0 && mMeshReduction->fvalue()>0.0)
+		{
+			percent	= mMeshReduction->fvalue();
+			percent	=	percent	/ 100.0;
+
+			// Simplifica el geomesh -> Parámetro es un factor LOD [0,1].
+			ms->Simplify(percent);
+
+			//	Deletes the previous mesh.
+			delete mUndoMesh;
+
+			mUndoMesh	=	new Mesh();
+
+			//	Sets the undo mesh.
+			*mUndoMesh	=	*mGeoMesh;
+
+			delete	mGeoMesh;
+
+			mGeoMesh	=	ms->GetMesh();
+
+			//	Visualize mesh.
+			geoMeshView->setMesh(mGeoMesh);
+		}
+		else
+		{
+			fltk::alert("Wrong value for simplification.\n"
+					"Valid values [0..100]");
+		}
+	}
+	else
+	{
+		// Simplificar hasta un número de vértices.
+		uint32 v	=	(uint32)mMeshReduction->fvalue();
+
+		// Simplifica el geomesh -> Parámetro es un factor LOD [0,1].
+		ms->Simplify(v);
+
+		//	Deletes the previous mesh.
+		delete mUndoMesh;
+
+		mUndoMesh	=	new Mesh();
+
+		//	Sets the undo mesh.
+		*mUndoMesh	=	*mGeoMesh;
+
+		delete	mGeoMesh;
+
+		mGeoMesh	=	ms->GetMesh();
+
+		//	Visualize the mesh.
+		geoMeshView->setMesh(mGeoMesh);
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Simplify the mesh object.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::simplifyLeavesCollapse()
+{
+	uint32						vi;
+
+	//	if the mesh is stripified.
+	if (mGeoMesh->mType == GEO_TRIANGLE_STRIPS)
+	{
+		fltk::alert("Can't simplify a tree in triagle strips.");
+	}
+	//	if the mesh is in triangle list.
+	else
+	{			
+		simplificacionState	=	HOJAS;
+		
+		mts	=	new TreeSimplifier(mGeoMesh, progress_function);
+		vi	=	(uint32)mMeshReduction->fvalue();
+
+		// Simplify
+		if(idMeshLeaves	!=	(unsigned short)-1)
+		{
+			// Simplify
+			mts->Simplify(vi, idMeshLeaves);
+
+			//	Deletes the previous mesh.
+			delete mUndoMesh;
+
+			mUndoMesh	=	new Mesh();
+			
+			//	Sets the undo mesh.
+			*mUndoMesh	=	*mGeoMesh;
+
+			delete	mGeoMesh;
+
+			mGeoMesh	=	mts->GetMesh();
+			
+			geoMeshView->setMesh(mGeoMesh);
+		}
+		else
+		{
+			fltk::alert("You must select the mesh that contains the leaves.");
+		}
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Create a simplification sequence of the QSLIM method.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::createQslimSequence()
+{
+	MeshSimplificationSequence	*secsimpl;
+	
+	secsimpl	=	ms->GetSimplificationSequence();
+	
+	secsimpl->putMeshName(nombremesh); // Nombre del mesh para guardar la secuencia de simplificación
+	secsimpl->Save(Geometry::Serializer("mqslimSequence.txt",Serializer::WRITE));
+
+	delete	secsimpl;
+}
+
+//---------------------------------------------------------------------------
+//	Stripify the mesh object.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::stripify()
+{	
+	char							char_value[10];
+	CustomStripifier	*geoStripifier;
+
+	//	if the mesh is stripified.
+	if (mGeoMesh->mType == GEO_TRIANGLE_STRIPS)
+	{
+		fltk::alert("The mesh is already in strips.");
+	}
+	//	if the mesh is in triangle list.
+	else
+	{
+		//Stripify.
+		geoStripifier	=	new CustomStripifier(mGeoMesh);
+
+		//	Set the progress bar function.	
+		geoStripifier->SetProgressFunc(progress_function);
+		
+		if (geoStripifier->Stripify())
+		{
+			//	Deletes the mesh object.
+			delete	mUndoMesh;
+
+			mUndoMesh	=	new Mesh();
+
+			*mUndoMesh	=	*mGeoMesh;
+
+			delete	mGeoMesh;
+
+			//	Gets the mesh stripified.
+			mGeoMesh	=	geoStripifier->GetMesh();
+
+			//	Visualize the mesh stripified.
+			geoMeshView->setMesh(mGeoMesh);
+
+			//	Store the color of the strips.
+			geoMeshView->setStripColors();
+		}
+		else
+		{
+			//	Error message.
+			fltk::alert("Impossible to stripify. The mesh is not manifold");
+		}
+
+		//	Deletes the stripifier object.
+		delete	geoStripifier;
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Method that undo then mesh changes.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::undo()
+{
+	//	if the undo mesh is not initialized.
+	if	(mUndoMesh != NULL)
+	{
+		//	Deletes the actual mesh.
+		delete	mGeoMesh;
+
+		mGeoMesh	=	new Mesh();
+
+		//	Restore the previous mesh.
+		*mGeoMesh	=	*mUndoMesh;
+
+		//	Visualize the mesh.
+		geoMeshView->setMesh(mGeoMesh);
+
+		//	Refresh geometry attributes.
+		refreshApplicationBar();
+
+		//	Repaint the window.
+		mMainWindow->redraw();
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Refresh number of vertices, triangles, strips, ...
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::refreshApplicationBar()
+{
+	static char	vertices_value[50];
+	static char	triangles_value[50];
+	static char	strips_value[50];
+	
+	//	Translate the vertex count to a char value.
+	sprintf(vertices_value,"Vertices %d",getVertexCount(mGeoMesh));
+
+	mVertices->label(vertices_value);
+
+	//	Translate the triangle count to a char value.
+	sprintf(triangles_value,"Triangles %d",getTriangleCount(mGeoMesh));
+
+	mTriangles->label(triangles_value);
+
+	//	Translate the triangle count to a char value.
+	sprintf(strips_value,"Strips %d",getStripCount(mGeoMesh));
+
+	mStrips->label(strips_value);
+}
+
+//	Method that updates the porgress bar.
+float GeoMeshViewUI::updateProgressBar(float v)
+{
+	fltk::ProgressBar		*progressBar;
+	
+	//	Choose progress bar to update.
+	switch(progressBarType)
+	{
+		case	PROCESS:
+			progressBar	=	mProcessBar;
+			break;
+		case	BUILD:
+			progressBar	=	mBuildBar;
+			break;
+	}
+	
+	//	Update progress bar.
+	progressBar->step(v);
+	progressBar->step();
+	mMainWindow->flush();
+	//mMainWindow->redraw();
+	
+	return 0;
+}
+
+//---------------------------------------------------------------------------
+//	Initialize the lodstripslibrary for visualization.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::setLodStripsLibrary(std::string lodfile, Mesh	*geomesh)
+{
+	//	If there is no lod strips object.
+	if (lodStripsLib)
+	{
+		delete	lodStripsLib;
+	}
+
+	//	New lod strips object.
+	lodStripsLib	=	new	LodStripsLibrary(lodfile, geomesh);
+
+	//	Sets the slider range.
+	mLodSlider->range(lodStripsLib->MaxLod(),
+										lodStripsLib->MinLod());
+
+	//	Pass to geomeshview the lod strips object.
+	geoMeshView->setLodStripsLibrary(lodStripsLib);
+	
+	//	Puts the slider in the max position.
+	mLodSlider->value(lodStripsLib->MinLod());
+}
+
+//---------------------------------------------------------------------------
+//	Open a mesh file.
+//---------------------------------------------------------------------------
+void	GeoMeshViewUI::openMeshFile()
+{
+	fltk::FileChooser	*fcho;
+	static	char			char_value[10];
+	static	char			title[256];
+
+	fcho	=	new fltk::FileChooser("",
+																"*.mesh",
+																fltk::FileChooser::CREATE,
+																"Open mesh file");
+
+	fcho->exec();
+
+	//	File name.
+	mFileName	=	(char *)fcho->value();
+
+	if (mFileName)
+	{
+		//	Set Window Title.
+		strcpy(title,mFileName);
+		mMainWindow->label(strcat(title," - GeoTool"));
+
+		//	Identify the mesh that stores the leaves
+		idMeshLeaves	=	-1;
+
+		//	Stores the name of the mesh.
+		nombremesh	=	new char[255];
+		strcpy(nombremesh,mFileName);
+
+		//	Delete	the current mesh.
+		delete	mGeoMesh;
+		delete	mUndoMesh;
+
+		//	Loads a new mesh.
+		mGeoMesh		=	geoMeshLoader->load(mFileName);
+
+		//	Reset the undo mesh.
+		mUndoMesh		=	new Mesh();
+		*mUndoMesh	=	*mGeoMesh;
+
+		//	Translate the MB count to a char value.
+		sprintf(char_value,
+				"MB %.3f",
+				(float)geoMeshLoader->getFileSize()/1024/1024);
+
+		mMB->label(char_value);
+
+		//	Visualize mesh.
+		geoMeshView->setMesh(mGeoMesh);
+
+		//	Get the mesh bounds.
+		mMeshBounds	=	geoMeshView->getBoundingBox();
+
+		//	Hide right panel.
+		hideRightPanel();
+
+		//	Quit culling.
+		menuRenderCW->clear_value();
+		menuRenderCCW->clear_value();
+		geoMeshView->deactiveCW();
+		geoMeshView->deactiveCCW();
+
+		//	Deactive solid mode and wire.
+		menuRenderSolid->clear_value();
+		menuRenderWire->clear_value();
+		geoMeshView->deactiveSolid();
+		geoMeshView->deactiveWire();
+
+		//	Fit model in midle.
+		geoMeshView->fit();
+
+		//	Lighting smooth.
+		menuRenderFlat->clear_value();
+		menuRenderSmooth->set_value();
+		geoMeshView->smooth();
+
+		//	Show title.
+		mProcessTitle->label("Mesh Info");
+
+		//	Shows the mesh info.
+		showMeshInfo();
+
+		//	if the mesh is stripified.
+		if (mGeoMesh->mType == GEO_TRIANGLE_STRIPS)
+		{
+			geoMeshView->setStripColors();
+		}
+
+		//	Refresh geometry attributes.
+		refreshApplicationBar();
+	}
+	
+	//	Free memory.
+	delete	fcho;
+}
+
+/******************/
+/*	Constructor		*/
+/******************/
+GeoMeshViewUI::GeoMeshViewUI(TIPOFUNC fun)
+{
+	progress_function	=	fun;
+	fltk::gifImage	*logo;
+	
+	//	Initialize the file name.
+	mFileName	=	NULL;
+
+	//	Initialize the 3D object.
+	mGeoMesh	=	NULL;
+	mUndoMesh	=	NULL;
+
+	//	Initialize the lod strip object.
+	lodStripsLib	=	NULL;
+
+	//	Identify the mesh that stores the leaves
+	idMeshLeaves	=	-1;
+
+	//	Initialize the loader of meshes.
+	geoMeshLoader	=	new	GeoMeshLoader();
+
+	//	Initialize the menus application state.
+	mApplicationState	=	NONE;
+	
+	{
+		fltk::Window*	o	=	new fltk::Window(800, 600,"GeoTool");
+
+		mMainWindow	=	o;
+
+		//	Program Icon for Win32.
+		mMainWindow->icon((char *)LoadIcon(	GetModuleHandle(0),
+					MAKEINTRESOURCE(GEOICON)));
+
+		//	Double buffer.
+		mMainWindow->set_double_buffer();
+
+		o->user_data((void*)(this));
+		o->begin();
+
+		{
+			fltk::Group* o = new fltk::Group(0, 27, 806, 559);
+			o->begin();
+
+			{
+				fltk::Group* o;
+				o = MainView = new fltk::Group(0, 0, 600, 500);
+				o->begin();
+
+				{
+					fltk::InvisibleBox* o;
+					o = cframe = new fltk::InvisibleBox(0, 0, 600, 500);
+					o->box(fltk::FLAT_BOX);
+					o->color((fltk::Color)0xffffff00);
+					//fltk::Group::current()->resizable(o);
+				}
+
+				{
+					GeoMeshView* o;
+					o = geoMeshView = new GeoMeshView(	0,0,600,500,0,this);
+				}
+
+				o->end();
+
+				fltk::Group::current()->resizable(o);
+
+			}
+
+			{
+				fltk::Group* o;
+				o = MainView = new fltk::Group(600, 0, 200, 500);
+				o->begin();
+
+				{
+					fltk::Button* o;
+					//o = mButtonProcess = new fltk::Button(665, 410, 73, 25, "Process");
+					o = mButtonProcess = new fltk::Button(65, 410, 73, 25, "Process");
+					o->callback((fltk::Callback*)cb_mButtonProcess);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::ProgressBar* o;
+					//o = mProcessBar = new fltk::ProgressBar(616, 435, 175, 18);
+					o = mProcessBar = new fltk::ProgressBar(16, 435, 175, 18);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::Button* o;
+					o = mButtonSort = new fltk::Button(65, 375, 73, 25, "Sort");
+					o->callback((fltk::Callback*)cb_mButtonSort);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::ProgressBar* o;
+					o = mSortBar = new fltk::ProgressBar(16, 390, 175, 18);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::Button* o;
+					o = mButtonBuild = new fltk::Button(65, 455, 73, 25, "Build");
+					o->callback((fltk::Callback*)cb_mButtonBuild);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::ProgressBar* o;
+					o = mBuildBar = new fltk::ProgressBar(16, 480, 175, 18);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					fltk::Slider* o;
+					o = mLodSlider = new fltk::Slider(16, 50, 30, 450);
+					o->type(fltk::Slider::TICK_BELOW);
+					o->set_vertical();
+					o->callback((fltk::Callback*)cb_mLodSlider);
+					o->hide();
+					o->deactivate();
+				}
+
+				{
+					mMetricLabel	= new fltk::Output(26, 28, 5, 25, "Metric");
+					fltk::Output* o	=	mMetricLabel;
+					o->set_vertical();
+					o->box(fltk::NO_BOX);
+					o->labelfont(fltk::HELVETICA_BOLD);
+					o->color((fltk::Color)0xe0dfe300);
+					o->align(fltk::ALIGN_RIGHT);
+				}
+
+				{
+					fltk::Group* o;
+					o = MainView = new fltk::Group(30, 40, 30, 60);
+					o->begin();
+					{
+						mGeometryBased = new fltk::RadioButton(0, 8, 25, 25, "Geometry based");
+						mImageBased = new fltk::RadioButton(0, 23, 25, 25, "Image based");
+					}
+					o->end();
+				}
+
+				//mChangeVertices = new fltk::CheckButton(30, 104, 25, 25, "Change vertices");
+
+				{
+					mProcessTitle		= new fltk::Widget(0, 0, 200, 25, "");
+					fltk::Widget* o	=	mProcessTitle;
+					o->set_vertical();
+					o->box(fltk::NO_BOX);
+					o->labelfont(fltk::HELVETICA_BOLD);
+					o->labelsize(15.0);
+					o->color((fltk::Color)0xe0dfe300);
+					o->align(fltk::ALIGN_CENTER);
+				}
+
+				/*
+					 {
+					 mTypeLabel			= new fltk::Output(26, 82, 5, 25, "Type");
+					 fltk::Output* o	=	mTypeLabel;
+					 o->set_vertical();
+					 o->box(fltk::NO_BOX);
+					 o->labelfont(fltk::HELVETICA_BOLD);
+					 o->color((fltk::Color)0xe0dfe300);
+					 o->align(fltk::ALIGN_RIGHT);
+					 }
+					 */
+
+				{
+					mMeshReductionLabel	= new fltk::Output(26, 124, 5, 25, "Mesh Reduction");
+					fltk::Output* o	=	mMeshReductionLabel;
+					o->set_vertical();
+					o->box(fltk::NO_BOX);
+					o->labelfont(fltk::HELVETICA_BOLD);
+					o->color((fltk::Color)0xe0dfe300);
+					o->align(fltk::ALIGN_RIGHT);
+				}
+
+				//mChangeTexture = new fltk::CheckButton(30, 104, 25, 25, "Change texture");
+
+				{
+					fltk::Group* o;
+					o = MainView = new fltk::Group(30, 140, 30, 60);
+					o->begin();
+
+					{
+						mPercent = new fltk::RadioButton(0, 5, 25, 25, "%");
+						mVerticesNumber = new fltk::RadioButton(0, 20, 25, 25, "Vertices number");
+					}
+					o->end();
+				}
+
+				{
+					mMeshReduction = new fltk::FloatInput(75, 181, 75, 21, "Value:");
+					fltk::FloatInput* o = mMeshReduction;
+					o->type(1);
+				}
+
+				{
+					fltk::Group* o;
+					o = MainView = new fltk::Group(30, 100, 30, 60);
+					o->begin();
+
+					{
+						mOneCacheStrip = new fltk::RadioButton(0, 4, 25, 25, "One cache strip");
+						mQualityStrips = new fltk::RadioButton(0, 23, 25, 25, "Quality strips");
+					}
+					o->end();
+				}
+
+				{
+					fltk::Browser* o = mMeshInfo = new fltk::Browser(0, 20, 200, 380);
+					o->set_vertical();
+					o->callback((fltk::Callback*)cb_mMeshInfo);
+				}
+				o->end();
+			}	
+
+			o->end();
+
+			fltk::Group::current()->resizable(o);
+		}
+
+		{
+			fltk::MenuBar* o = menuBar = new fltk::MenuBar(1, 2, 801, 21);
+			o->begin();
+
+			//	Menu File.
+			{
+				fltk::ItemGroup* o = menuFile = new fltk::ItemGroup("File");
+				o->begin();
+
+				{
+					fltk::Item* o = menuFileOpen = new fltk::Item("Open");
+					o->callback((fltk::Callback*)cb_menuFileOpen);
+				}
+
+				{
+					fltk::Item* o = menuFileSave = new fltk::Item("Save");
+					o->callback((fltk::Callback*)cb_menuFileSave);
+				}
+
+				{
+					fltk::Item* o = menuOpenSaveAs = new fltk::Item("Save As");
+					o->callback((fltk::Callback*)cb_menuOpenSaveAs);
+				}
+
+				//{
+				//	fltk::Item* o = menuMeshExportOBJ = new fltk::Item("Export to OBJ");
+				//	o->callback((fltk::Callback*)cb_menuMeshExportOBJ);
+				//}
+
+				//{
+				//	fltk::Item* o = menuFileTransformSharedVertex = new fltk::Item("Transform to Shared Vertex");
+				//	o->callback((fltk::Callback*)cb_menuFileTransformSharedVertex);
+				//}
+
+				{
+					fltk::Item* o = menuOpenQuit = new fltk::Item("Quit");
+					o->callback((fltk::Callback*)cb_menuOpenQuit);
+				}
+
+				o->end();
+			}
+
+			//	Menu Edit.
+			{
+				fltk::ItemGroup* o = menuEdit = new fltk::ItemGroup("Edit");
+				o->begin();
+
+				{
+					fltk::Item* o = menuEditUndo = new fltk::Item("Undo");
+					o->callback((fltk::Callback*)cb_menuEditUndo);
+				}
+
+				{
+					fltk::Item* o = menuEditFit = new fltk::Item("Fit");
+					o->callback((fltk::Callback*)cb_menuEditFit);
+
+				}
+
+				{
+					fltk::Item* o = menuEditRotate = new fltk::Item("Rotate");
+					o->type(fltk::Item::RADIO);
+					o->set_value();
+					o->callback((fltk::Callback*)cb_menuEditRotate);
+				}
+
+				{
+					fltk::Item* o = menuEditPan = new fltk::Item("Pan");
+					o->type(fltk::Item::RADIO);
+					o->callback((fltk::Callback*)cb_menuEditPan);
+				}
+
+				//{
+				//	fltk::Item* o = menuEditZoom = new fltk::Item("Zoom");
+				//	o->callback((fltk::Callback*)cb_menuEditZoom);
+				//}
+
+				new fltk::Divider();
+
+				{
+					fltk::Item* o = menuMeshInfo = new fltk::Item("Mesh info");
+					o->callback((fltk::Callback*)cb_menuMeshInfo);
+				}
+
+				//{
+				//	fltk::Item* o;
+				//	o = menuSelectLeaves = new fltk::Item("Select leaves");
+				//	o->callback((fltk::Callback*)cb_menuSelectLeaves);
+				//}
+
+				o->end();
+			}
+
+			//	Menu Render.
+			{
+				fltk::ItemGroup* o = menuRender = new fltk::ItemGroup("Render");
+				o->begin();
+
+				{
+					fltk::Item* o = menuRenderWire = new fltk::Item("Wire");
+					o->type(fltk::Item::RADIO);
+					o->callback((fltk::Callback*)cb_menuRenderWire);
+				}
+
+				{
+					fltk::Item* o = menuRenderSolid = new fltk::Item("Solid");
+					o->type(fltk::Item::RADIO);
+					o->callback((fltk::Callback*)cb_menuRenderSolid);
+				}
+
+				//new fltk::Divider();
+
+				{
+					fltk::Item* o = menuRenderCW = new fltk::Item("CW");
+					o->type(fltk::Item::RADIO);
+					o->callback((fltk::Callback*)cb_menuRenderCW);
+
+					o->hide();
+				}
+
+				{
+					fltk::Item* o = menuRenderCCW = new fltk::Item("CCW");
+					o->type(fltk::Item::RADIO);
+					o->set_value();
+					o->callback((fltk::Callback*)cb_menuRenderCCW);
+
+					o->hide();
+				}
+
+				new fltk::Divider();
+
+				{
+					fltk::Item* o = menuRenderFlat = new fltk::Item("Flat");
+					o->type(fltk::Item::RADIO);
+					o->clear_value();
+					o->callback((fltk::Callback*)cb_menuRenderFlat);
+				}
+
+				{
+					fltk::Item* o = menuRenderSmooth = new fltk::Item("Smooth");
+					o->type(fltk::Item::RADIO);
+					o->set_value();
+					o->callback((fltk::Callback*)cb_menuRenderSmooth);
+				}
+
+				//new fltk::Divider();
+
+				//{
+				//	fltk::Item* o = menuRenderTextures = new fltk::Item("Textures");
+				//	o->callback((fltk::Callback*)cb_menuRenderTextures);
+				//}
+
+				o->end();
+			}
+
+			//	Menu Stripify.
+			{
+				fltk::Item* o = menuStripify = new fltk::Item("Stripify");
+				o->callback((fltk::Callback*)cb_menuStripify);
+			}
+
+			//	Menu Simplify.
+			{
+				fltk::ItemGroup* o = menuSimplify = new fltk::ItemGroup("Simplify");
+				o->callback((fltk::Callback*)cb_menuSimplify);
+				o->begin();
+
+				{
+					fltk::Item* o;
+					o = menuSimplifyEdgeCollapse = new fltk::Item("Mesh Simplification");
+					o->callback((fltk::Callback*)cb_menuSimplifyEdgeCollapse);
+				}
+
+				//{
+				//	fltk::Item* o;
+				//	o = menuSimplifyLeavesCollapse = new fltk::Item("Leaves Simplification");
+				//	o->callback((fltk::Callback*)cb_menuSimplifyLeavesCollapse);
+				//}
+
+				o->end();
+			}
+
+			//	Menu LodStrips.
+			{
+				fltk::ItemGroup* o;
+				o = menuLodStrips = new fltk::ItemGroup("LodStrips");
+				o->begin();
+
+				{
+					fltk::Item* o;
+					o = menuLodStripsGenerate	= new fltk::Item("Generate");
+					o->callback((fltk::Callback*)cb_menuLodStripsGenerate);
+				}
+
+				{
+					fltk::Item* o;
+					o = menuLodStripsVisualize	= new fltk::Item("Visualize");
+					o->callback((fltk::Callback*)cb_menuLodStripsVisualize);
+				}
+
+				o->end();
+			}
+
+			//	Menu LodTrees.
+			/*
+			{
+				fltk::ItemGroup* o;
+				o = menuLodTrees = new fltk::ItemGroup("LodTrees");
+				o->begin();
+
+				{
+					fltk::Item* o;
+					o = menuLodTreesOpenLodStripTrunk = new fltk::Item("Open LodStrip trunk");
+					o->callback((fltk::Callback*)cb_menuLodTreesOpenLodStripTrunk);
+				}
+
+				{
+					fltk::Item* o;
+					o = menuLodTreesOpenLeavesSimplification = new fltk::Item("Open leaves simplification");
+					o->callback((fltk::Callback*)cb_menuLodTreesOpenLeavesSimplification);
+				}
+				o->end();
+			}
+			*/
+			
+			{
+				fltk::ItemGroup* o = new fltk::ItemGroup("?");
+				o->begin();
+
+				{
+					fltk::Item* o = menuHelpAbout = new fltk::Item("About");
+					o->callback((fltk::Callback*)cb_menuHelpAbout);
+				}	
+
+				o->end();
+			}
+
+			{
+				fltk::SharedImage *gifLogo = logo->get("media\\logos\\logo.gif");
+				
+				//o->callback((fltk::Callback*)cb_mLogo);
+				
+				mLogo	=	new fltk::InvisibleBox(406, 1, 43, 13);				
+				mLogo->image(gifLogo);
+			}
+
+			o->end();
+		}
+
+		{
+			fltk::Group* o;
+			o = ApplicationBar = new fltk::Group(0, 570, 807, 28);
+			o->box(fltk::BORDER_BOX);
+			o->begin();
+
+			{
+				fltk::Widget* o;
+				o = mFPS = new fltk::Widget(10, 4, 30, 15, "FPS ");
+				o->box(fltk::NO_BOX);
+				o->labelfont(fltk::HELVETICA_BOLD);
+				o->color((fltk::Color)0xe0dfe300);
+			}
+
+			{
+				fltk::Widget* o;
+				o = mVertices = new fltk::Widget(154, 4, 40, 15, "Vertices");
+				o->box(fltk::NO_BOX);
+				o->labelfont(fltk::HELVETICA_BOLD);
+				o->color((fltk::Color)0xe0dfe300);
+			}
+
+			{
+				fltk::Widget* o;
+				o = mTriangles = new fltk::Widget(254, 3, 40, 15, "Triangles");
+				o->box(fltk::NO_BOX);
+				o->labelfont(fltk::HELVETICA_BOLD);
+				o->color((fltk::Color)0xe0dfe300);
+
+				//	Hide triangle count.
+				o->hide();
+			}
+
+			{
+				fltk::Widget* o;
+				o = mStrips = new fltk::Widget(354, 3, 30, 15, "Strips");
+				o->box(fltk::NO_BOX);
+				o->labelfont(fltk::HELVETICA_BOLD);
+				o->color((fltk::Color)0xe0dfe300);
+			}
+
+			//{
+			//	fltk::Widget* o;
+			//	o = mQuads = new fltk::Widget(454, 4, 40, 15, "Quads");
+			//	o->box(fltk::NO_BOX);
+			//	o->labelfont(fltk::HELVETICA_BOLD);
+			//	o->color((fltk::Color)0xe0dfe300);
+			//}
+
+			{
+				fltk::Widget* o;
+				o = mMB = new fltk::Widget(740, 3, 30, 15, "MB");
+				o->box(fltk::NO_BOX);
+				o->labelfont(fltk::HELVETICA_BOLD);
+				o->color((fltk::Color)0xe0dfe300);
+			}
+			o->end();
+		}
+
+
+		o->end();
+	}
+	
+	fltk::focus(geoMeshView);
+	
+
+	/*Hide Right Panel*/
+	hideRightPanel();
+	
+	mMainWindow->show();
+}
+
+/****************/
+/*	Destroyer		*/
+/****************/
+GeoMeshViewUI::~GeoMeshViewUI()
+{
+	delete	geoMeshLoader;
+	mMainWindow->destroy();
+}
+
+//	Shows the main window.
+void GeoMeshViewUI::show()
+{
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshView.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshView.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshView.cpp	(revision 774)
@@ -0,0 +1,982 @@
+#include "GeoMeshView.h"
+
+using	namespace	Geometry;
+using	namespace	std;
+
+//---------------------------------------------------------------------------
+//	Hanle events.
+//---------------------------------------------------------------------------
+int	GeoMeshView::handle(int event)
+{
+	int key;
+	int	button;
+	int	x;
+	int	y;
+	
+	if (geoMesh != NULL)
+	{
+		draw();
+	}
+
+	switch(event)
+	{
+		case	fltk::KEY:
+		case	fltk::PUSH:
+			
+			button	=	fltk::event_key();
+			mMouseX	=	fltk::event_x();
+			mMouseY	=	fltk::event_y();
+			
+			return	1;
+
+		case	fltk::DRAG:
+			
+			button	=	fltk::event_state();
+			x				=	fltk::event_x();
+			y				=	fltk::event_y();
+			
+			switch (button)
+			{
+				//	Button 1 Pushed.
+				case	0x01100000:
+			
+					if (x > mMouseX)
+					{
+						if (mPan)
+						{
+							xshift	=	xshift	+	(x	-	mMouseX);
+						}
+						else
+						{
+							hAng	=	hAng	+	(x - mMouseX);
+						}
+					}
+					else
+					{
+						if (x < mMouseX)
+						{
+							if (mPan)
+							{
+								xshift	=	xshift	-	(mMouseX	-	x);
+							}
+							else
+							{
+								hAng	=	hAng	- (mMouseX - x);
+							}
+						}
+					}
+
+					if (y > mMouseY)
+					{
+						if (mPan)
+						{
+							yshift	=	yshift	-	(y - mMouseY);
+						}
+						else
+						{
+							vAng	=	vAng	+	(y - mMouseY);
+						}
+					}
+					else
+					{
+						if (y < mMouseY)
+						{
+							if (mPan)
+							{
+								yshift	=	yshift	+	(mMouseY	-	y);
+							}
+							else
+							{
+								vAng	=	vAng	-	(mMouseY	-	y);
+							}
+						}
+					}
+
+					hAng	=	float(int(hAng)	%	360);
+					vAng	=	float(int(vAng)	%	360);
+					
+					mMouseX	=	x;
+					mMouseY	=	y;
+					
+					draw();
+					
+					return	1;
+				
+				case	0x04100000:
+
+					if (y	> mSizeY)
+					{
+						size++;
+					}
+					else
+					{
+						if (y < mSizeY)
+						{
+							size--;
+						}
+					}
+					
+					mSizeY	=	y;
+					
+					draw();
+
+					return 1;
+
+			}			
+			
+		case	fltk::MOUSEWHEEL:
+
+			size	=	size + fltk::event_dy();
+			draw();
+			return	1;
+	}
+	
+	return	fltk::GlWindow::handle(event);
+}
+
+//---------------------------------------------------------------------------
+//	Get the number of frames per second.
+//---------------------------------------------------------------------------
+size_t	GeoMeshView::getFPS()
+{
+	return	mFPS;
+}
+
+//---------------------------------------------------------------------------
+//	Calculate the number of frames per second.
+//---------------------------------------------------------------------------
+void	GeoMeshView::calcFPS()
+{
+	double	duration;
+	clock_t	finish_time;
+
+	//	Gets the time.
+	finish_time	=	clock();
+
+	//	Calc the duration respect the start time.
+	duration	=	(double)((finish_time - mStartTime) / CLOCKS_PER_SEC);
+	
+	//	Increments the number of frames per second.
+	mFPS++;
+	
+	//	If a second have passed.
+	if (duration >= 1.0)
+	{
+		//	Repaint the FPS.
+		mGeoMeshViewUI->refreshFPS(mFPS);
+		
+		mFPS				=	0;
+		mStartTime	=	clock();
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Enable color strips.
+//---------------------------------------------------------------------------
+void	GeoMeshView::enableColorStrips()
+{
+	colorStripsFlag	=	true;
+}
+
+//---------------------------------------------------------------------------
+//	Disable color strips.
+//---------------------------------------------------------------------------
+void	GeoMeshView::disableColorStrips()
+{
+	colorStripsFlag	=	false;
+}
+
+//---------------------------------------------------------------------------
+//	Gets the color strips state.
+//---------------------------------------------------------------------------
+bool	GeoMeshView::getColorStrips()
+{
+	return	colorStripsFlag;
+}
+
+//---------------------------------------------------------------------------
+// JGA
+//	Set the color to the submesh sumbmeshIndex
+//---------------------------------------------------------------------------
+void	GeoMeshView::setColorSubmeshi(int submeshIndex)
+{
+	colorsubmeshi	=	submeshIndex;
+}
+
+//---------------------------------------------------------------------------
+//	Sets the leaves submesh index.
+//---------------------------------------------------------------------------
+void	GeoMeshView::setLeavesSubmesh(int submeshIndex)
+{
+	leavesSubmesh	=	submeshIndex;
+}
+
+//---------------------------------------------------------------------------
+//	Gets the leaves submesh index.
+//---------------------------------------------------------------------------
+int	GeoMeshView::getLeavesSubmesh()
+{
+	return	leavesSubmesh;
+}
+
+//---------------------------------------------------------------------------
+//	Set the list of strip colors.
+//---------------------------------------------------------------------------
+void	GeoMeshView::setStripColors()
+{
+	int	total_strips;
+
+	total_strips	=	0;
+	
+	//	Delete previous color strips.
+	delete	[]mStripColors;
+
+	//	Count the total number of strips y the submeshes.
+	for (int i = 0; i < geoMesh->mSubMeshCount; i++)
+	{
+		total_strips	=	total_strips + geoMesh->mSubMesh[i].mStripCount;
+	}
+
+	//	Initialize the Colors array.
+	mStripColors	=	new	ColorElement[total_strips];
+	
+	//	Sets random colors to each strip.
+	for (int i	= 0; i < total_strips; i++)
+	{
+		mStripColors[i].r	=	rand()/((float)RAND_MAX);
+		mStripColors[i].g	=	rand()/((float)RAND_MAX);
+		mStripColors[i].b	=	rand()/((float)RAND_MAX);
+	}
+}
+
+//---------------------------------------------------------------------------
+//	Get the bounding box of the object.
+//---------------------------------------------------------------------------
+GeometryBounds	GeoMeshView::getBoundingBox()
+{
+	SubMesh					*geosubmesh;
+	Index						position;
+	Vector3					vector3;
+	GeometryBounds	bounds;
+	float						x,y,z;
+	float						xMin,yMin,zMin;
+	float						xMax,yMax,zMax;
+		
+	//	For each submesh.
+	for (int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geosubmesh	=	&geoMesh->mSubMesh[submesh];
+
+		//	For each index of the strip.
+		for (int index = 0; index < geosubmesh->mIndexCount; index++)
+		{
+			position	=	geosubmesh->mIndex[index];
+
+			//	Gets the vertex coordinates.
+			vector3	=	geosubmesh->mVertexBuffer->mPosition[position];
+				
+			x					=	vector3[0];
+			y					=	vector3[1];
+			z					=	vector3[2];
+				
+			//	If is the first iteation.
+			if ((submesh	== 0)	&&	(index	==	0))
+			{
+				xMin	=	xMax	=	x;
+				yMin	=	yMax	=	y;
+				zMin	=	zMax	=	z;
+			}
+			else
+			{
+				if (x < xMin)
+				{
+					xMin	=	x;
+				}
+				else if (x > xMax)
+				{
+					xMax	=	x;
+				}
+
+				if (y < yMin)
+				{
+					yMin	=	y;
+				}
+				else if (y > yMax)
+				{
+					yMax	=	y;
+				}
+
+				if (z < zMin)
+				{
+					zMin	=	z;
+				}
+				else if (z > zMax)
+				{
+					zMax	=	z;
+				}
+			}
+		}
+	}
+
+	xMed	=	(xMax + xMin)	/	2;
+	yMed	=	(yMax + yMin)	/	2;
+	zMed	=	(zMax + zMin)	/	2;
+
+
+	if ((xMax - xMin) > (yMax - yMin))
+	{
+		if ((xMax - xMin) > (zMax - zMin))
+		{
+			mScaleFactor	=	xMax - xMin;
+		}
+		else
+		{
+			mScaleFactor	=	zMax - zMin;
+		}
+	}
+	else
+	{
+		if ((yMax - yMin) > (zMax - zMin))
+		{
+			mScaleFactor	=	yMax - yMin;
+		}
+		else
+		{
+			mScaleFactor	=	zMax - zMin;
+		}
+	}
+
+	//	Set the bounds.
+	bounds.minx		=	xMin;
+	bounds.miny		=	yMin;
+	bounds.minz		=	zMin;
+	bounds.maxx		=	xMax;
+	bounds.maxy		=	yMax;
+	bounds.maxz		=	zMax;
+	bounds.radius	=	mScaleFactor;
+
+	return	bounds;
+}
+
+//---------------------------------------------------------------------------
+//	Constructor.
+//---------------------------------------------------------------------------
+GeoMeshView::GeoMeshView(	int						x,
+													int						y,
+													int						w,
+													int						h,
+													const char		*l,
+													GeoMeshViewUI	*geoMeshViewUI)
+            : fltk::GlWindow(x,y,w,h,l)
+{
+		mStripColors		=	NULL;
+		mSharedPosArray	=	NULL;
+		mSharedNorArray	=	NULL;
+		mPosArray				=	NULL;
+		mNorArray				=	NULL;
+		mIndexArray			=	NULL;
+    vAng						= 0.0;
+		hAng						=	0.0;
+		size						=	0.0;
+		mSizeY					=	0;
+		xshift					=	0.0;
+		yshift					=	0.0;
+		geoMesh					=	0;
+		mRotate					=	true;
+		mPan						=	false;
+		mLodStrip				=	false;
+		mIdVisualList		=	0;
+		mSubMeshCount		=	0;
+		
+		//	Initialize the model view.
+		deactiveWire();
+		deactiveSolid();
+		activeRotate();
+		deactiveCW();
+		activeCCW();
+		
+		//	Init start time for FPS.
+		mStartTime	=	clock();
+
+		//	Cross Reference.
+		mGeoMeshViewUI	=	geoMeshViewUI;
+}
+
+// The color used for the edges of the bounding cube.
+#define CUBECOLOR 255,255,255,255
+
+/* Draw a colored cube */
+#define ALPHA 0.5
+
+//---------------------------------------------------------------------------
+//	Sets the Mesh to display.
+//---------------------------------------------------------------------------
+void GeoMeshView::setMesh(Mesh	*geomesh)
+{
+	GLfloat color_blanco[]	=	{1.0f,1.0f,1.0f,1.0f};
+
+	this->geoMesh	=	geomesh;
+	colorsubmeshi	=	-1;
+	leavesSubmesh	=	-1;
+	
+	//	Refresh vertices to the vertex array.
+	refreshVertices(geomesh);
+	
+	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_blanco);
+}
+
+//---------------------------------------------------------------------------
+//	 Refresh vertices to the vertex array.
+//---------------------------------------------------------------------------
+void	GeoMeshView::refreshVertices(Mesh	*geomesh)
+{
+	SubMesh				*geosubmesh;
+	VertexBuffer	*vertex_buffer;
+
+	//	If the vertex array exists.
+	if (mSubMeshCount > 0)
+	{
+		for (int submesh = 0; submesh < mSubMeshCount; submesh++)
+		{
+			delete	[]	mPosArray[submesh];
+			delete	[]	mNorArray[submesh];
+			delete	[]	mIndexArray[submesh];
+		}
+		
+		delete	[]	mSharedPosArray;
+		delete	[]	mSharedNorArray;
+		delete	[]	mPosArray;
+		delete	[]	mNorArray;
+		delete	[]	mIndexArray;
+	}
+
+	//	If there is shared vertex.
+	if (geomesh->mVertexBuffer != NULL)
+	{
+		vertex_buffer	=	geomesh->mVertexBuffer;
+
+		//	Allocate memory.
+		mSharedPosArray	=	new GLfloat[vertex_buffer->mVertexCount * 3];
+		mSharedNorArray	=	new GLfloat[vertex_buffer->mVertexCount * 3];
+
+		for (int vertex = 0; vertex < vertex_buffer->mVertexCount; vertex++)
+		{
+			mSharedPosArray[3 * vertex]				=	vertex_buffer->mPosition[vertex].x;
+			mSharedPosArray[(3 * vertex) + 1]	=	vertex_buffer->mPosition[vertex].y;
+			mSharedPosArray[(3 * vertex) + 2]	=	vertex_buffer->mPosition[vertex].z;
+
+			mSharedNorArray[3 * vertex]				=	vertex_buffer->mNormal[vertex].x;
+			mSharedNorArray[(3 * vertex) + 1]	=	vertex_buffer->mNormal[vertex].y;
+			mSharedNorArray[(3 * vertex) + 2]	=	vertex_buffer->mNormal[vertex].z;
+		}
+	}
+	
+	//	Build the arrays of vertices and indices.
+	mPosArray		=	new GLfloat*[geomesh->mSubMeshCount];
+	mNorArray		=	new GLfloat*[geomesh->mSubMeshCount];
+	mIndexArray	=	new GLuint*[geomesh->mSubMeshCount];
+
+	//	For each submesh.
+	for (int submesh = 0; submesh < geomesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geosubmesh	=	&geomesh->mSubMesh[submesh];
+		
+		//	Allocate memory for index array of the actual submesh.
+		mIndexArray[submesh]	=	new GLuint[geosubmesh->mIndexCount];
+
+		//	Gets the indices of the actual submesh.
+		for (int index = 0; index < geosubmesh->mIndexCount; index++)
+		{
+			mIndexArray[submesh][index]	=	geosubmesh->mIndex[index];
+		}
+		
+		//	If the submesh is NOT shared vertex.
+		if (!geosubmesh->mSharedVertexBuffer)
+		{
+			vertex_buffer	=	geosubmesh->mVertexBuffer;
+
+			//	Allocate memory for vertices of the actual submesh.
+			mPosArray[submesh]	=	new GLfloat[vertex_buffer->mVertexCount * 3];
+			mNorArray[submesh]	=	new GLfloat[vertex_buffer->mVertexCount * 3];
+
+			//	For each one of the vertex.
+			for (int vertex = 0; vertex < vertex_buffer->mVertexCount; vertex++)
+			{
+				mPosArray[submesh][3 * vertex]				=	vertex_buffer->mPosition[vertex].x;
+				mPosArray[submesh][(3 * vertex) + 1]	=	vertex_buffer->mPosition[vertex].y;
+				mPosArray[submesh][(3 * vertex) + 2]	=	vertex_buffer->mPosition[vertex].z;
+
+				mNorArray[submesh][3 * vertex]				=	vertex_buffer->mNormal[vertex].x;
+				mNorArray[submesh][(3 * vertex) + 1]	=	vertex_buffer->mNormal[vertex].y;
+				mNorArray[submesh][(3 * vertex) + 2]	=	vertex_buffer->mNormal[vertex].z;
+			}//	End for each vertex.
+		}
+		//	If the submesh is shared vertex.
+		else
+		{
+			mPosArray[submesh]	=	NULL;
+			mNorArray[submesh]	=	NULL;
+		}
+
+	}//	End for each submesh.
+	
+}
+
+//---------------------------------------------------------------------------
+//	Gets the triangle count of the current lod.
+//---------------------------------------------------------------------------
+size_t	GeoMeshView::getLodStripsTriangleCount()
+{
+	size_t	triangle_count;
+
+	//	Initialize triangle count.
+	triangle_count	=	0;
+		
+	//	For each strip.
+	for (int strip	=	0; strip < lodStripsLib->GetStripCount(); strip++)
+	{
+		triangle_count	+=	lodStripsLib->mStrips[strip].size() - 2;
+	}
+
+	return	triangle_count;
+}
+
+//---------------------------------------------------------------------------
+//	Repaint the Mesh.
+//---------------------------------------------------------------------------
+void GeoMeshView::drawGeoMesh(int selectedMesh)
+{
+	if (geoMesh)
+	{
+		if (mLodStrip)
+		{
+			drawLodStrip();
+		}
+		//	Choose the render operation.
+		else if (geoMesh->mType == GEO_TRIANGLE_LIST)
+		{
+			//	Paint vertices.
+			drawTriangleList(selectedMesh);
+		}
+		else
+		{
+			//	Paint vertices.
+			drawTriangleStrip();
+		}
+	}
+}//	End drawGeoMesh.
+
+//---------------------------------------------------------------------------
+//	Paint eah strip separately.
+//---------------------------------------------------------------------------
+void GeoMeshView::drawTriangleStrip()
+{
+	SubMesh				*geosubmesh;
+	Index					position;
+	Vector3				vector3;
+	float					x,y,z;
+	float					r,g,b;
+	Index					*index;
+	Index					*indexBegin;
+	Index					*indexEnd;
+	int						color_index;
+
+	color_index	=	0;
+
+	//	For each submesh.
+	for (int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geosubmesh	=	&geoMesh->mSubMesh[submesh];
+
+		//	For each one of the strips.
+		for (int strip = 0; strip < geosubmesh->mStripCount; strip++)
+		{
+			//	Paint the current strip.
+			glBegin(GL_TRIANGLE_STRIP);
+			
+			//	First index of the strip.
+			indexBegin	=	geosubmesh->mStrip[strip];
+
+			//	If the strips is not the first.
+			//if (strip != 0)
+			//{
+			//	indexBegin++;
+			//}
+
+			//	If is the final strip
+			if (strip	== (geosubmesh->mStripCount - 1))
+			{
+				//	The end of the index array.
+				indexEnd	= &geosubmesh->mIndex[geosubmesh->mIndexCount];
+			}
+			else
+			{
+				//	The beginning of the next strip.
+				indexEnd	= geosubmesh->mStrip[strip + 1];
+
+				//	Remove degenerated
+				//indexEnd--;
+			}
+			
+			int i;
+			i	= 0;
+
+			if (getColorStrips())
+			{
+				//	Gets the color of the strip.
+				r	=	mStripColors[color_index].r;
+				g	=	mStripColors[color_index].g;
+				b	=	mStripColors[color_index].b;
+			
+				//	Change to the next color.
+				color_index++;
+			
+				//	Paint a new color.
+				glColor3f(r,g,b);
+			}
+
+			//	For each index of the strip.
+			for (index = indexBegin; index < indexEnd; index++)
+			{
+				position	=	indexBegin[i];
+
+				//	Gets the vertex normal.
+				vector3	=	geosubmesh->mVertexBuffer->mNormal[position];
+
+				x				=	vector3[0];
+				y				=	vector3[1];
+				z				=	vector3[2];
+				
+				//	Sets the vertex normal.
+				glNormal3f(x,y,z);
+				
+				//	Gets the vertex coordinates.
+				vector3	=	geosubmesh->mVertexBuffer->mPosition[position];
+				
+				x				=	vector3[0];
+				y				=	vector3[1];
+				z				=	vector3[2];
+				
+
+				//	Sets the vertex position.
+				glVertex3f(x,y,z);
+				
+				//	Increments i.
+				i++;
+			}
+			
+			glEnd();
+
+		}
+	}
+	
+}//End drawTriangleStrip.
+
+//---------------------------------------------------------------------------
+//	Paint the array of idices.
+//---------------------------------------------------------------------------
+void GeoMeshView::drawTriangleList(int selectedMesh)
+{
+	SubMesh	*geosubmesh;
+	Index		position;
+	Vector3	vector3;
+	float		x,y,z;
+	int			idx_offset;
+	int			vrt_offset;
+
+	//	Index offset.
+	idx_offset	=	0;
+
+	//	Vertex offset.
+	vrt_offset	=	0;
+	
+	//	For each submesh.
+	for (int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geosubmesh	=	&geoMesh->mSubMesh[submesh];
+
+		//	If a mesh is selected.
+		if (selectedMesh >= 0)
+		{
+			//	If is a tree.
+			if (leavesSubmesh >= 0)
+			{
+				glColor3d(1.0, 0.5, 0.5);
+				GLfloat color_blanco[]	=	{1.0f,0.5f,0.5f,1.0f};
+				glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_blanco);
+
+				//	For each index of the strip.
+				if (submesh == leavesSubmesh)
+				{
+					glColor3d(0.0,1.0,0.0);
+					GLfloat color_rojo[]	=	{0.0f,1.0f,0.0f,1.0f};
+					glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_rojo);
+				}
+			}
+			//	If is NOT a tree.
+			else
+			{
+				//	Set white color to the object.
+				glColor3d(1.0, 1.0, 1.0);
+				GLfloat color_blanco[]	=	{1.0f,1.0f,1.0f,1.0f};
+				glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_blanco);
+			}
+
+			//	For each index of the strip.
+			if (submesh == selectedMesh)
+			{
+				glColor3d(1.0,0.0,0.0);
+				GLfloat color_rojo[]	=	{1.0f,0.0f,0.0f,1.0f};
+				glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_rojo);
+			}
+		}
+		else
+		{
+			//	If is a tree.
+			if (leavesSubmesh >= 0)
+			{
+				glColor3d(1.0, 0.5, 0.5);
+				GLfloat color_blanco[]	=	{1.0f,0.5f,0.5f,1.0f};
+				glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_blanco);
+
+				//	For each index of the strip.
+				if (submesh == leavesSubmesh)
+				{
+					glColor3d(0.0,1.0,0.0);
+					GLfloat color_rojo[]	=	{0.0f,1.0f,0.0f,1.0f};
+					glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_rojo);
+				}
+			}
+		}
+		
+		//	Enable arrays.
+		glEnableClientState(GL_VERTEX_ARRAY);
+		glEnableClientState(GL_NORMAL_ARRAY);
+
+		//	If the submesh is shared vertex.
+		if (geosubmesh->mSharedVertexBuffer)
+		{
+			glVertexPointer(3, GL_FLOAT, 0, mSharedPosArray);
+			glNormalPointer(GL_FLOAT, 0, mSharedNorArray);
+		}
+		else
+		{
+			glVertexPointer(3, GL_FLOAT, 0, mPosArray[submesh]);
+			glNormalPointer(GL_FLOAT, 0, mNorArray[submesh]);
+		}
+
+		glDrawElements(	GL_TRIANGLES,
+										geosubmesh->mIndexCount,
+										GL_UNSIGNED_INT,
+										mIndexArray[submesh]);
+	}
+
+}//End drawTriangleList
+
+//---------------------------------------------------------------------------
+//	Paint lodstrip object.
+//---------------------------------------------------------------------------
+void GeoMeshView::drawLodStrip()
+{
+	SubMesh				*geosubmesh;
+	Index					position;
+	Vector3				vector3;
+	float					x,y,z;
+	float					r,g,b;
+	int						color_index;
+	int						current_strip;
+
+	color_index	=	0;
+
+	//	Initialize current strip.
+	current_strip	=	0;
+		
+	//	For each submesh.
+	for (int submesh = 0; submesh < geoMesh->mSubMeshCount; submesh++)
+	{
+		//	Gets the actual submesh.
+		geosubmesh	=	&geoMesh->mSubMesh[submesh];
+
+		//	For each one of the strips.
+		for (int strip = 0; strip < geosubmesh->mStripCount; strip++)
+		{
+			//	Paint the current strip.
+			glBegin(GL_TRIANGLE_STRIP);
+						
+			if (getColorStrips())
+			{
+				//	Gets the color of the strip.
+				r	=	mStripColors[color_index].r;
+				g	=	mStripColors[color_index].g;
+				b	=	mStripColors[color_index].b;
+			
+				//	Change to the next color.
+				color_index++;
+			
+				//	Paint a new color.
+				glColor3f(r,g,b);
+			}
+
+			//	For each index of the strip.
+			for (int index = 0; index < lodStripsLib->mStrips[current_strip].size(); index++)
+			{
+				position	=	lodStripsLib->mStrips[current_strip][index];
+
+				//	Gets the vertex normal.
+				vector3	=	geosubmesh->mVertexBuffer->mNormal[position];
+
+				x				=	vector3[0];
+				y				=	vector3[1];
+				z				=	vector3[2];
+				
+				//	Sets the vertex normal.
+				glNormal3f(x,y,z);
+				
+				//	Gets the vertex coordinates.
+				vector3	=	geosubmesh->mVertexBuffer->mPosition[position];
+				
+				x				=	vector3[0];
+				y				=	vector3[1];
+				z				=	vector3[2];
+
+				//	Sets the vertex position.
+				glVertex3f(x,y,z);
+			}
+			
+			//	Increments current strip.
+			current_strip++;
+
+			//	A strip is generated.
+			glEnd();
+
+		}
+	}
+	
+}//End drawTriangleStrip.
+
+//---------------------------------------------------------------------------
+//	Sets the lodstripslibrary object.
+//---------------------------------------------------------------------------
+void	GeoMeshView::setLodStripsLibrary(LodStripsLibrary *lodstrips)
+{
+	lodStripsLib	=	lodstrips;
+	activeLodStrip();
+}
+
+//---------------------------------------------------------------------------
+//	Change de Level of detail of the object.
+//---------------------------------------------------------------------------
+void	GeoMeshView::GoToLod(unsigned int	lod)
+{
+	lodStripsLib->GoToLod(lod);
+	draw();
+}
+//---------------------------------------------------------------------------
+//	Draw the object in the window.
+//---------------------------------------------------------------------------
+void GeoMeshView::draw()
+{
+	glMatrixMode(GL_PROJECTION);
+	glLoadIdentity();
+
+	glEnable(GL_LIGHTING);
+
+	//	Frustrum.
+	glViewport(0,0,w(),h());
+	gluPerspective(60,1,0.1,1000);
+
+	glMatrixMode(GL_MODELVIEW);
+	glLoadIdentity();
+
+	glEnable(GL_BLEND);
+	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+	GLfloat	light_ambient[]	=	{0.3,0.3,0.3,1.0};
+	GLfloat	luzpos[]				=	{0.0,0.0,1.0,0.0};
+	GLfloat	luzcolor[]			=	{1.0,1.0,1.0,1.0};
+
+	//	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_ambient);
+	glEnable(GL_LIGHT0);
+	glLightfv(GL_LIGHT0, GL_POSITION, luzpos);
+	glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
+	glLightfv(GL_LIGHT0, GL_DIFFUSE, luzcolor);
+	glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1);
+	glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0);
+	glLightf(GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0);
+
+	glEnable (GL_POLYGON_OFFSET_LINE);
+	glPolygonOffset(-1,-1);
+	glEnable(GL_DEPTH_TEST);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+	gluLookAt(0,0,mScaleFactor*2+size, 0,0,0, 0,1,0);
+
+	glTranslatef(xshift,yshift,0);
+	glRotatef(hAng,0,1,0);
+	glRotatef(vAng,1,0,0);
+	glTranslatef(-xMed,-yMed,-zMed);
+
+	//	Set white color to the object.
+	glColor3d(1.0, 1.0, 1.0);
+	GLfloat color_blanco[]	=	{1.0f,1.0f,1.0f,1.0f};
+	glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,color_blanco);
+
+	if (mCW)
+	{
+		glFrontFace(GL_CW);
+		glEnable(GL_CULL_FACE);
+	}
+	else
+	{
+		if (mCCW)
+		{
+			glFrontFace(GL_CCW);
+			glEnable(GL_CULL_FACE);
+		}
+		else
+		{
+			glDisable(GL_CULL_FACE);
+		}
+	}
+
+	if (mSolid)
+	{
+		enableColorStrips();
+		glDisable(GL_LIGHTING);
+		glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
+		drawGeoMesh(colorsubmeshi);
+	}
+	else
+	{
+		glEnable(GL_LIGHTING);
+	}
+
+	if (mWire)
+	{
+		disableColorStrips();
+		glDisable(GL_LIGHTING);
+		glColor3d(0.0, 0.0, 1.0);
+		glPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
+		drawGeoMesh(-1);
+	}
+	else
+	{
+		if (!mSolid)
+		{
+			enableColorStrips();
+			glEnable(GL_LIGHTING);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+			drawGeoMesh(colorsubmeshi);
+		}
+	}
+
+	swap_buffers();
+
+	//	Calculate the FPS.
+	calcFPS();
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GTAboutDialog.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GTAboutDialog.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GTAboutDialog.cpp	(revision 774)
@@ -0,0 +1,62 @@
+// generated by Fast Light User Interface Designer (fluid) version 2.0100
+
+#include "GTAboutDialog.h"
+#include	<fltk/ask.h>
+
+
+/*OK Callback*/
+inline void GTAboutDialog::cb_mOK_i(fltk::Button*, void*)
+{
+	delete	mMainWindow;
+}
+
+void GTAboutDialog::cb_mOK(fltk::Button* o, void* v) {
+  ((GTAboutDialog*)(o->parent()->parent()->user_data()))->cb_mOK_i(o,v);
+}
+
+GTAboutDialog::GTAboutDialog()
+{
+	fltk::gifImage	*logo;
+	fltk::Window		*w;
+	
+	const char	credits[1000]	=	"Benito Córcoles Almela\n"
+						"Jesús Galindo Álvaro\n"
+						"Gustavo Puche Rodríguez";
+	{
+		fltk::Window* o = mMainWindow = new fltk::Window(289, 319, "About");
+		w = o;
+		o->user_data((void*)(this));
+		o->begin();
+		{fltk::Group* o = new fltk::Group(0, 0, 289, 318);
+			o->set_vertical();
+			o->begin();
+			
+			{
+				fltk::MultiLineOutput* o = mText = new fltk::MultiLineOutput(15, 135, 260, 140);
+				mText->value(credits,strlen(credits));
+				o->type(4);
+				o->box(fltk::NO_BOX);
+				o->color((fltk::Color)0xe0dfe300);
+			}
+			
+			{
+				fltk::SharedImage *gifLogo = logo->get("media\\logos\\GameTools.gif");				
+
+				fltk::InvisibleBox* o = mLogo = new fltk::InvisibleBox(100, 25, 95, 100);
+				mLogo->image(gifLogo);
+				o->set_vertical();
+				o->color((fltk::Color)0xe0dfe300);
+			}
+			
+			{
+				fltk::Button* o = mOK = new fltk::Button(105, 285, 89, 25, "OK");
+				o->callback((fltk::Callback*)cb_mOK);
+			}
+			o->end();
+		}
+		o->end();
+	}
+
+	mMainWindow->show();
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshSaver.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshSaver.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoMeshSaver.cpp	(revision 774)
@@ -0,0 +1,698 @@
+/*	==========================================================================
+ *	(C) 2005 Universitat Jaume I
+ *	==========================================================================
+ *	PROYECT:	GAME TOOLS
+ *	==========================================================================*/
+/**	CONTENT:	
+	*
+	*
+	*	@file	GeoMeshSaver.cpp
+/*===========================================================================*/
+#include	<GeoMeshSaver.h>
+
+using	namespace	Geometry;
+using	namespace	std;
+
+//------------------------------------------
+//		Public:
+//------------------------------------------
+
+////////////////////
+//	Constructors.	//
+////////////////////
+GeoMeshSaver::GeoMeshSaver()
+{
+	mMaterialName				=	"";
+	mSkeletallyAnimated	=	false;
+
+	//	Initializa the mesh bounds.
+	mMeshBounds.minx			=	0.0;
+	mMeshBounds.miny			=	0.0;
+	mMeshBounds.minz			=	0.0;
+	mMeshBounds.maxx			=	0.0;
+	mMeshBounds.maxy			=	0.0;
+	mMeshBounds.maxz			=	0.0;
+	mMeshBounds.radius		=	0.0;
+}
+
+GeoMeshSaver::GeoMeshSaver(GeometryBounds bounds)
+{
+	mMaterialName				=	"";
+	mSkeletallyAnimated	=	false;
+
+	//	Initializa the mesh bounds.
+	mMeshBounds.minx			=	bounds.minx;
+	mMeshBounds.miny			=	bounds.miny;
+	mMeshBounds.minz			=	bounds.minz;
+	mMeshBounds.maxx			=	bounds.maxx;
+	mMeshBounds.maxy			=	bounds.maxy;
+	mMeshBounds.maxz			=	bounds.maxz;
+	mMeshBounds.radius		=	bounds.radius;
+}
+
+//////////////////
+//	Destroyer.	//
+//////////////////
+GeoMeshSaver::~GeoMeshSaver()
+{
+}
+
+//	Saves a Mesh into a file.
+int	GeoMeshSaver::save(Mesh	*geoMesh,	const	char	*fileNameMesh)
+{
+	int			size;
+	String	name(fileNameMesh);
+	
+	//	Open the file.
+	mSerializer	=	new	Serializer(	name,
+																Serializer::WRITE);
+
+	//	Set the mesh.
+	mGeoMesh	=	geoMesh;
+
+	//	Write the file header.
+	writeFileHeader();
+
+	//	Write the mesh data.
+	writeMesh(geoMesh);
+
+	//	Debug.
+	cout	<<	"Write mesh finish"
+				<<	endl;
+	
+	size	=	mSerializer->GetSize();
+	
+	//	Close the file.
+	delete	mSerializer;
+	
+	//	Return the number of bytes written.
+	return	size;
+}
+
+//------------------------------------------
+//		Private:
+//------------------------------------------
+
+//	Write the main mesh.
+void	GeoMeshSaver::writeMesh(Mesh	*geoMesh)
+{
+	//	Debug.
+	cout	<<	"Write the chunk header"
+				<<	endl;
+	
+	// Header
+	writeChunkHeader(M_MESH, calcMeshSize(geoMesh));
+
+	//	Write the skeletally animated flag.
+	writeBools(mSkeletallyAnimated,1);
+	
+	cout	<<	"1 - VertexCount: "
+				<<	geoMesh->mVertexBuffer->mVertexCount
+				<<	endl;
+
+	//	Write shared geometry.
+	if (geoMesh->mVertexBuffer->mVertexCount > 0)
+	{
+		//	Debug.
+		cout	<<	"Write the shared vertex buffer"
+					<<	endl;
+		
+		writeGeometry(geoMesh->mVertexBuffer);
+	}
+
+	//	Write submeshes.
+	for (int i = 0;	i < geoMesh->mSubMeshCount;	i++)
+	{
+		//	Debug.
+		cout	<<	"Write the submesh "
+					<<	i
+					<<	endl;
+		
+		writeSubMesh(&geoMesh->mSubMesh[i]);
+	}
+
+	//	Write the mesh bounds.
+	writeMeshBounds(mMeshBounds);
+	
+	/*
+	// Write skeleton info if required
+	if (pMesh->hasSkeleton())
+	{
+	LogManager::getSingleton().logMessage("Exporting skeleton link...");
+	// Write skeleton link
+	writeSkeletonLink(pMesh->getSkeletonName());
+	LogManager::getSingleton().logMessage("Skeleton link exported.");
+
+	// Write bone assignments
+	if (!pMesh->mBoneAssignments.empty())
+	{
+	LogManager::getSingleton().logMessage("Exporting shared geometry bone assignments...");
+
+	Mesh::VertexBoneAssignmentList::const_iterator vi;
+	for (vi = pMesh->mBoneAssignments.begin(); 
+	vi != pMesh->mBoneAssignments.end(); ++vi)
+	{
+	writeMeshBoneAssignment(vi->second);
+	}
+
+	LogManager::getSingleton().logMessage("Shared geometry bone assignments exported.");
+	}
+	}
+
+	// Write LOD data if any
+	if (pMesh->getNumLodLevels() > 1)
+	{
+	LogManager::getSingleton().logMessage("Exporting LOD information....");
+	writeLodInfo(pMesh);
+	LogManager::getSingleton().logMessage("LOD information exported.");
+
+	}
+	// Write bounds information
+	LogManager::getSingleton().logMessage("Exporting bounds information....");
+	writeBoundsInfo(pMesh);
+	LogManager::getSingleton().logMessage("Bounds information exported.");
+
+	// Write submesh name table
+	LogManager::getSingleton().logMessage("Exporting submesh name table...");
+	writeSubMeshNameTable(pMesh);
+	LogManager::getSingleton().logMessage("Submesh name table exported.");
+
+	// Write edge lists
+	if (pMesh->isEdgeListBuilt())
+	{
+	LogManager::getSingleton().logMessage("Exporting edge lists...");
+	writeEdgeList(pMesh);
+	LogManager::getSingleton().logMessage("Edge lists exported");
+	}
+	*/
+}
+
+//	Write a submesh.
+void	GeoMeshSaver::writeSubMesh(SubMesh	*geoSubMesh)
+{
+	bool						idx32bit;
+	unsigned	long	indexCount;
+	String					materialName;
+	
+	//	Debug.
+	cout	<<	"Write the submesh chunk header"
+				<<	endl;
+	
+	// Header.
+	writeChunkHeader(M_SUBMESH, calcSubMeshSize(geoSubMesh));
+
+	//	Debug.
+	cout	<<	"Write the material name"
+				<<	endl;
+
+	// Material Name.
+	materialName	=	getMaterialName();
+	writeString(materialName);
+
+	//	Debug.
+	cout	<<	"Write the shared vertex buffer flag: "
+				<<	endl;
+
+	// bool useSharedVertices
+	writeBools(geoSubMesh->mSharedVertexBuffer, 1);
+
+	indexCount	=	geoSubMesh->mIndexCount;
+
+	writeInts(indexCount, 1);
+
+	// bool indexes32Bit
+	idx32bit	=	true;
+	writeBools(idx32bit, 1);
+
+	//	Debug.
+	cout	<<	"Write the mIndex array"
+				<<	endl;
+
+	//	Write the index array.
+	for (int i = 0; i < geoSubMesh->mIndexCount; i++)
+	{
+		writeInts(geoSubMesh->mIndex[i], 1);
+	}
+
+	// M_GEOMETRY stream (Optional: present only if useSharedVertices = false)
+	if (!geoSubMesh->mSharedVertexBuffer)
+	{
+		//	Debug.
+		cout	<<	"Write the geometry of the submesh"
+					<<	endl;
+
+		writeGeometry(geoSubMesh->mVertexBuffer);
+	}
+
+	//	Debug.
+	cout	<<	"mIndex array written"
+				<<	endl;
+
+	// Operation type
+	writeSubMeshOperation(geoSubMesh);
+
+	//TODO:Bones.
+	/*
+	// Bone assignments
+	if (!s->mBoneAssignments.empty())
+	{
+		LogManager::getSingleton().logMessage("Exporting dedicated geometry bone assignments...");
+
+		SubMesh::VertexBoneAssignmentList::const_iterator vi;
+
+		for (vi = s->mBoneAssignments.begin(); 
+				vi != s->mBoneAssignments.end(); ++vi)
+		{
+			writeSubMeshBoneAssignment(vi->second);
+		}
+
+		LogManager::getSingleton().logMessage("Dedicated geometry bone assignments exported.");
+	}
+	*/
+}
+
+//	Write the submesh operation chunk and data.
+void GeoMeshSaver::writeSubMeshOperation(const	SubMesh	*geoSubMesh)
+{
+	unsigned 	short opType;
+	unsigned	long	size;
+
+	//	Debug.
+	cout	<<	"Write submesh operation"
+				<<	endl;
+	
+	size	=	CHUNK_OVERHEAD_SIZE	+	sizeof(unsigned	short);
+	
+	// Header
+	writeChunkHeader(M_SUBMESH_OPERATION, size);
+
+	//	If the mesh is in triangle strips.
+	if (mGeoMesh->mType	==	GEO_TRIANGLE_STRIPS)
+	{
+		opType	=	5;
+	}
+	//	If the mesh is in triangle list.
+	else
+	{
+		opType	=	4;
+	}
+	
+	writeShorts(opType, 1);
+
+	//	Debug.
+	cout	<<	"Submesh operation Written"
+				<<	endl;
+}
+
+//	Write geometry.
+void	GeoMeshSaver::writeGeometry(VertexBuffer	*vertexBuffer)
+{
+	unsigned	short	element;
+	unsigned	long	size;
+	unsigned	short	buffer_count;
+
+	buffer_count	=	3;
+
+	
+	//	Calc the size in bytes of the geometry chunk.
+	size	=	calcGeometrySize(vertexBuffer);
+		
+	//	Header.
+	//
+	//	Write the M_GEOMETRY header.
+	writeChunkHeader(M_GEOMETRY, size);
+
+	writeInts(vertexBuffer->mVertexCount,1);
+
+	//	Vertex declaration.
+	//	Calculate the size of vertex declaration.
+	size	=	CHUNK_OVERHEAD_SIZE
+					+
+					buffer_count
+					*
+					(CHUNK_OVERHEAD_SIZE	+	(sizeof(unsigned short)	*	5));
+
+	//	Write the vertex declaration header.
+	writeChunkHeader(	M_GEOMETRY_VERTEX_DECLARATION,size);
+
+	//	Obtain the size of the vertex element chunk.
+	size	=	CHUNK_OVERHEAD_SIZE	+	(sizeof(unsigned short)	*	5);
+
+	//	Positions.
+	//	Write the vertex element header for position.
+	writeChunkHeader(	M_GEOMETRY_VERTEX_ELEMENT,size);
+
+	element	=	0;
+	writeShorts(element,1);
+
+	element	=	VET_FLOAT3;
+	writeShorts(element,1);
+	
+	element	=	VES_POSITION;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+
+	//	Normals.
+	//	Write the vertex element header for position.
+	writeChunkHeader(	M_GEOMETRY_VERTEX_ELEMENT,size);
+	
+	element	=	1;
+	writeShorts(element,1);
+	
+	element	=	VET_FLOAT3;
+	writeShorts(element,1);
+	
+	element	=	VES_NORMAL;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+
+	//	Textures.
+	//	Write the vertex element header for position.
+	writeChunkHeader(M_GEOMETRY_VERTEX_ELEMENT,size);
+	
+	element	=	2;
+	writeShorts(element,1);
+	
+	element	=	VET_FLOAT2;
+	writeShorts(element,1);
+	
+	element	=	VES_TEXTURE_COORDINATES;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+	
+	element	=	0;
+	writeShorts(element,1);
+
+	//	Obtain the size for vertex buffer header for positons.
+	size	=	(2	*	CHUNK_OVERHEAD_SIZE)	+	(2	*	sizeof(unsigned short));
+
+	//	Write the vertex buffer header for positions.
+	writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER,	size);
+
+	element	=	0;
+	writeShorts(element,1);
+	
+	element	=	12;
+	writeShorts(element,1);
+
+	//	Obtain the size for the vertex buffer data header for positions.
+	size	=	CHUNK_OVERHEAD_SIZE
+					+
+					((sizeof(float)	*	3)	*	vertexBuffer->mVertexCount);
+
+	//	Write the vertex buffer data header for positions.
+	writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA,	size);
+
+	//	Write all the positions coords.
+	mSerializer->WriteArray(vertexBuffer->mPosition,
+													vertexBuffer->mVertexCount);
+
+	//	Obtain the size for vertex buffer header for normals.
+	size	=	(2	*	CHUNK_OVERHEAD_SIZE)	+	(2	*	sizeof(unsigned short));
+
+	//	Write the vertex buffer header.
+	writeChunkHeader(	M_GEOMETRY_VERTEX_BUFFER,	size);
+
+	element	=	1;
+	writeShorts(element,1);
+	
+	element	=	12;
+	writeShorts(element,1);
+
+	//	Obtain the size for the vertex buffer data header for normals.
+	size	=	CHUNK_OVERHEAD_SIZE
+					+
+					((sizeof(float)	*	3)	*	vertexBuffer->mVertexCount);
+
+	//	Write the vertex buffer data header for normals.
+	writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA,	size);
+
+	//	Write all the normals coords.
+	mSerializer->WriteArray(vertexBuffer->mNormal,
+													vertexBuffer->mVertexCount);
+
+	//	Obtain the size for vertex buffer header for textures.
+	size	=	(2	*	CHUNK_OVERHEAD_SIZE)	+	(2	*	sizeof(unsigned short));
+
+	//	Write the vertex buffer header for textures.
+	writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER,	size);
+
+	element	=	2;
+	writeShorts(element,1);
+	
+	element	=	8;
+	writeShorts(element,1);
+
+	//	Obtain the size for the vertex buffer data header for textures.
+	size	=	CHUNK_OVERHEAD_SIZE
+					+
+					((sizeof(float)	*	2)	*	vertexBuffer->mVertexCount);
+
+	//	Write the vertex buffer data header for textures.
+	writeChunkHeader(M_GEOMETRY_VERTEX_BUFFER_DATA,	size);
+
+	//	Debug.
+	cout	<<	"-7-"	<<	endl;
+
+	//	Write all the texture coords.
+	mSerializer->WriteArray(vertexBuffer->mTexCoords,
+													vertexBuffer->mVertexCount);
+
+	//	Debug.
+	cout	<<	"-8-"	<<	endl;
+
+}
+
+//	TODO: Write Mesh Bounds.
+void	GeoMeshSaver::writeMeshBounds(GeometryBounds bounds)
+{
+	size_t	size;
+
+	size	=	CHUNK_OVERHEAD_SIZE
+					+
+					(sizeof(float)	*	7);
+
+	writeChunkHeader(M_MESH_BOUNDS,	size);
+
+	writeFloats(bounds.minx,1);
+	writeFloats(bounds.miny,1);
+	writeFloats(bounds.minz,1);
+	writeFloats(bounds.maxx,1);
+	writeFloats(bounds.maxy,1);
+	writeFloats(bounds.maxz,1);
+	writeFloats(bounds.radius,1);
+}
+
+//	Calc the mesh size in bytes.
+size_t GeoMeshSaver::calcMeshSize(const Mesh	*geoMesh)
+{
+	size_t size = CHUNK_OVERHEAD_SIZE;
+
+	//	Debug.
+	cout	<<	"Calc the size of the mesh"
+				<<	endl;
+	
+	// Num shared vertices
+	size += sizeof(uint32);
+
+	//	Debug.
+	cout	<<	"VertexCount: "
+				<<	geoMesh->mVertexBuffer->mVertexCount
+				<<	endl;
+
+	// Geometry
+	if (geoMesh->mVertexBuffer->mVertexCount > 0)
+	{
+		//	Debug.
+		cout	<<	"Calc the size of the shared vertex buffer"
+					<<	endl;
+		
+		size += calcGeometrySize(geoMesh->mVertexBuffer);
+	}
+
+	// Submeshes
+	for (unsigned short i = 0; i < geoMesh->mSubMeshCount; ++i)
+	{
+		//	Debug.
+		cout	<<	"Calc the size of the submesh "
+					<<	i
+					<<	endl;
+
+		size += calcSubMeshSize(&geoMesh->mSubMesh[i]);
+	}
+
+	//	Mesh Bounds size added.
+	size	+=	CHUNK_OVERHEAD_SIZE
+						+
+						(sizeof(float)	*	7);
+
+	/*
+	// Skeleton link
+	if (geoMesh->hasSkeleton())
+	{
+		size += calcSkeletonLinkSize(geoMesh->getSkeletonName());
+	}
+	*/
+
+	/*
+	// Submesh name table
+	size += calcSubMeshNameTableSize(geoMesh);
+
+	// Edge list
+	if (geoMesh->isEdgeListBuilt())
+	{
+		size += calcEdgeListSize(geoMesh);
+	}
+	*/
+	
+	return size;
+}
+
+//	Calc the size in bytes for the submesh.
+size_t GeoMeshSaver::calcSubMeshSize(const SubMesh	*geoSubMesh)
+{
+	size_t size = CHUNK_OVERHEAD_SIZE;
+
+	// Material name
+	size += getMaterialName().length() + 1;
+
+	// bool useSharedVertices
+	size += sizeof(bool);
+	// unsigned int indexCount
+	size += sizeof(unsigned int);
+	// bool indexes32bit
+	size += sizeof(bool);
+
+	// unsigned int* faceVertexIndices 
+	size += sizeof(unsigned int) * geoSubMesh->mIndexCount;
+
+	// Geometry
+	if (!geoSubMesh->mSharedVertexBuffer)
+	{
+		size += calcGeometrySize(geoSubMesh->mVertexBuffer);
+	}
+
+	return size;
+}
+
+//	Calc the geometry size in bytes.
+size_t GeoMeshSaver::calcGeometrySize(const VertexBuffer* vertexBuffer)
+{
+	unsigned	long		size;
+	unsigned	long		buffer_count;
+
+	//	and another for normals.
+	buffer_count	=	3;
+
+	//	Calculate the size of the Geometry chunk.
+	size	=	CHUNK_OVERHEAD_SIZE	+	sizeof(unsigned int);
+	size	=	size
+					+
+					CHUNK_OVERHEAD_SIZE
+					+
+					buffer_count
+					*
+					(CHUNK_OVERHEAD_SIZE	+	(sizeof(unsigned short)	*	5));
+	size	=	size
+					+
+					buffer_count
+					*
+					(	(CHUNK_OVERHEAD_SIZE		*	2)
+						+
+						(sizeof(unsigned short)	*	2)
+						+
+						vertexBuffer->mVertexCount
+					);
+
+	return size;
+}
+
+//	Write the file header.
+void GeoMeshSaver::writeFileHeader(void)
+{
+	String	mesh_version("[MeshSerializer_v1.30]");
+	
+	writeShorts(M_HEADER, 1);
+
+	writeString(mesh_version);
+
+}
+
+//	Write a header chunk given.
+void GeoMeshSaver::writeChunkHeader(unsigned short	id,
+																		unsigned long		size)
+{
+	mSerializer->WriteData(&id,sizeof(unsigned short),1);
+	mSerializer->WriteData(&size,sizeof(unsigned long),1);
+}
+
+//	Write integers into the file.
+void	GeoMeshSaver::writeInts(unsigned long	id,
+															unsigned long	count)
+{
+	mSerializer->WriteData(&id,sizeof(id),count);
+}
+
+//	Write shorts into the file
+void	GeoMeshSaver::writeShorts(unsigned short	id,
+																unsigned long		count)
+{
+	mSerializer->WriteData(&id,sizeof(id),count);
+}
+
+//	Write float into the file.
+void	GeoMeshSaver::writeFloats(float						id,
+																unsigned long		count)
+{
+	mSerializer->WriteData(&id,sizeof(id),count);
+}
+
+//	Write a string into the file.
+void GeoMeshSaver::writeString(const	String	&string)
+{
+	mSerializer->WriteData(string);
+}
+
+//	Write booleans into the file.
+void	GeoMeshSaver::writeBools(	const bool id,
+																unsigned	long		count)
+{
+	mSerializer->WriteData(&id,sizeof(bool),count);
+}
+
+//	Sets the material of the mesh.
+void	GeoMeshSaver::setMaterialName(String	materialName)
+{
+	mMaterialName	=	materialName;
+}
+
+//	Gets the material of the mesh.
+String	GeoMeshSaver::getMaterialName()
+{
+	return	mMaterialName;
+}
+
+//	Set Mesh Bounds.
+void	GeoMeshSaver::setMeshBounds(GeometryBounds	bounds)
+{
+	mMeshBounds.minx		=	bounds.minx;
+	mMeshBounds.miny		=	bounds.miny;
+	mMeshBounds.minz		=	bounds.minz;
+	mMeshBounds.maxx		=	bounds.maxx;
+	mMeshBounds.maxy		=	bounds.maxy;
+	mMeshBounds.maxz		=	bounds.maxz;
+	mMeshBounds.radius	=	bounds.radius;
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.cpp	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.cpp	(revision 774)
@@ -0,0 +1,18 @@
+#include "GeoMeshViewUI.h"
+
+using namespace fltk;
+
+GeoMeshViewUI	*interface;
+
+float incrementa(float i) { return interface->updateProgressBar(i);  }
+
+
+int main(int argc, char **argv)
+{
+	interface	=	new GeoMeshViewUI(incrementa);
+	
+	interface->show();
+
+  return run();
+}
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.rc
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.rc	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/GeoTool.rc	(revision 774)
@@ -0,0 +1,72 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Español resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ESN)
+#ifdef _WIN32
+LANGUAGE LANG_SPANISH, SUBLANG_SPANISH_MODERN
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE 
+BEGIN
+    "resource.h\0"
+END
+
+2 TEXTINCLUDE 
+BEGIN
+    "#include ""afxres.h""\r\n"
+    "\0"
+END
+
+3 TEXTINCLUDE 
+BEGIN
+    "\r\n"
+    "\0"
+END
+
+#endif    // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+GEOICON                 ICON                    ".\media\logos\GeoIcon.ico"
+#endif    // Español resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif    // not APSTUDIO_INVOKED
+
Index: /GTP/trunk/Lib/Geom/GeoTool/src/resource.h
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/src/resource.h	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/src/resource.h	(revision 774)
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by test_MainForm2.rc
+//
+#define GEOICON                         101
+
+// Next default values for new objects
+// 
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE        102
+#define _APS_NEXT_COMMAND_VALUE         40001
+#define _APS_NEXT_CONTROL_VALUE         1001
+#define _APS_NEXT_SYMED_VALUE           101
+#endif
+#endif
Index: /GTP/trunk/Lib/Geom/GeoTool/GeoTool.vcproj
===================================================================
--- /GTP/trunk/Lib/Geom/GeoTool/GeoTool.vcproj	(revision 774)
+++ /GTP/trunk/Lib/Geom/GeoTool/GeoTool.vcproj	(revision 774)
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="7.10"
+	Name="GeoTool"
+	ProjectGUID="{31522E11-420C-4DD6-8922-AF96B93E2207}"
+	Keyword="Win32Proj">
+	<Platforms>
+		<Platform
+			Name="Win32"/>
+	</Platforms>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="build\$(ConfigurationName)"
+			IntermediateDirectory="build\Debug"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".\include;..\include;..\..\..\..\..\..\NonGTP\FLTK\include;..\GTGeometry\include"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;WIN32_LEAN_AND_MEAN;VC_EXTRA_LEAN;WIN32_EXTRA_LEAN"
+				MinimalRebuild="FALSE"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="1"
+				BufferSecurityCheck="TRUE"
+				DisableLanguageExtensions="FALSE"
+				UsePrecompiledHeader="0"
+				WarningLevel="1"
+				SuppressStartupBanner="TRUE"
+				Detect64BitPortabilityProblems="FALSE"
+				DebugInformationFormat="4"
+				CompileAs="2"
+				ShowIncludes="FALSE"
+				UndefineAllPreprocessorDefinitions="FALSE"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="fltkd.lib comctl32.lib wsock32.lib GTGeometry_d.lib glu32.lib opengl32.lib glaux.lib fltk_opengl.lib"
+				OutputFile="$(OutDir)/GeoTool.exe"
+				LinkIncremental="1"
+				SuppressStartupBanner="TRUE"
+				AdditionalLibraryDirectories="..\..\..\..\..\..\NonGTP\FLTK\lib;..\GTGeometry\build\$(ConfigurationName)"
+				IgnoreDefaultLibraryNames="LIBCD"
+				GenerateDebugInformation="TRUE"
+				ProgramDatabaseFile="$(OutDir)/GeoTool.pdb"
+				SubSystem="2"
+				OptimizeReferences="0"
+				EnableCOMDATFolding="0"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="build\$(ConfigurationName)"
+			IntermediateDirectory="build\Release"
+			ConfigurationType="1"
+			CharacterSet="2">
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories=".\include;..\include;..\..\..\..\..\..\NonGTP\FLTK\include;..\GTGeometry\include"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;WIN32_LEAN_AND_MEAN;VC_EXTRA_LEAN;WIN32_EXTRA_LEAN"
+				RuntimeLibrary="4"
+				UsePrecompiledHeader="0"
+				WarningLevel="0"
+				Detect64BitPortabilityProblems="FALSE"
+				DebugInformationFormat="0"
+				CompileAs="0"/>
+			<Tool
+				Name="VCCustomBuildTool"/>
+			<Tool
+				Name="VCLinkerTool"
+				AdditionalDependencies="GTGeometry.lib fltk.lib comctl32.lib wsock32.lib glu32.lib opengl32.lib glaux.lib fltk_opengl.lib"
+				OutputFile="$(OutDir)/GeoTool.exe"
+				LinkIncremental="1"
+				SuppressStartupBanner="TRUE"
+				AdditionalLibraryDirectories="..\..\..\..\..\..\NonGTP\FLTK\lib;..\GTGeometry\build\$(ConfigurationName)"
+				IgnoreDefaultLibraryNames="LIBCMT;LIBCMTD"
+				GenerateDebugInformation="FALSE"
+				SubSystem="2"
+				OptimizeReferences="0"
+				EnableCOMDATFolding="0"
+				TargetMachine="1"/>
+			<Tool
+				Name="VCMIDLTool"/>
+			<Tool
+				Name="VCPostBuildEventTool"/>
+			<Tool
+				Name="VCPreBuildEventTool"/>
+			<Tool
+				Name="VCPreLinkEventTool"/>
+			<Tool
+				Name="VCResourceCompilerTool"/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"/>
+			<Tool
+				Name="VCWebDeploymentTool"/>
+			<Tool
+				Name="VCManagedWrapperGeneratorTool"/>
+			<Tool
+				Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}">
+			<File
+				RelativePath=".\src\GeoMeshLoader.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshSaver.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshView.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoMeshViewUI.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GeoTool.cpp">
+			</File>
+			<File
+				RelativePath=".\src\GTAboutDialog.cpp">
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}">
+			<File
+				RelativePath=".\include\GeoMeshLoader.h">
+			</File>
+			<File
+				RelativePath=".\include\GeoMeshSaver.h">
+			</File>
+			<File
+				RelativePath=".\include\GeoMeshView.h">
+			</File>
+			<File
+				RelativePath=".\include\GeoMeshViewUI.h">
+			</File>
+			<File
+				RelativePath=".\include\GTAboutDialog.h">
+			</File>
+			<File
+				RelativePath=".\src\resource.h">
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}">
+			<File
+				RelativePath=".\media\logos\GeoIcon.ico">
+			</File>
+			<File
+				RelativePath=".\src\GeoTool.rc">
+			</File>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>
