Index: /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshLoader.h
===================================================================
--- /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshLoader.h	(revision 989)
+++ /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshLoader.h	(revision 1050)
@@ -188,4 +188,7 @@
 			void	normalizeModel(Mesh	*geoMesh);
 
+			// Imports an OBJ object
+			void importOBJ(FILE *f, Mesh *geoMesh);
+
 		public:
 
Index: /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshViewUI.h
===================================================================
--- /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshViewUI.h	(revision 1024)
+++ /GTP/trunk/Lib/Geom/shared/GeoTool/include/GeoMeshViewUI.h	(revision 1050)
@@ -279,5 +279,5 @@
 
 	//	Open a mesh file.
-	void	openMeshFile();
+	void	openMeshFile(void);
 
 	//	Check if file exists.
Index: /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshLoader.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshLoader.cpp	(revision 1024)
+++ /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshLoader.cpp	(revision 1050)
@@ -11,4 +11,7 @@
 
 #include	"GeoMeshLoader.h"
+#include	<algorithm>
+#include	<cctype>
+#include	<map>
 
 using namespace Geometry;
@@ -992,9 +995,9 @@
 {
 	unsigned	short	uno;
-  unsigned	short	chunkID;
-	char						version[255];
-	char						kk;
-	FILE						*pFile;
-	SubMesh					*geosubmesh;
+	unsigned	short	chunkID;
+	char		version[255];
+	char		kk;
+	FILE		*pFile;
+	SubMesh		*geosubmesh;
 
 	//	Debug.
@@ -1006,4 +1009,16 @@
 				<<	endl;
 
+	// retrieve the extension of the file
+	std::string fileExt;
+	std::string completeFileName(nameFileMesh);
+	for (std::string::reverse_iterator it = completeFileName.rbegin(); it!=completeFileName.rend(); it++)
+		if (*it=='.')
+			break;
+		else
+			fileExt += *it;
+
+	std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), std::toupper);
+	reverse(fileExt.begin(),fileExt.end());
+	
 	geoMesh	=	NULL;
 
@@ -1011,5 +1026,5 @@
 	pFile	=	fopen(nameFileMesh, "rb");
 
-  if (pFile)
+	if (pFile)
 	{
 		//	Initialize the current submesh;
@@ -1019,67 +1034,75 @@
 		geoMesh	=	new	Mesh();
 
-		//	Count the submeshes
-		//	and next build the geomesh.
-		for (int option = 0; option < 2;option++)
-		{
-			//	Initialize Error.
+		if (fileExt==std::string("OBJ"))
+		{
 			mError	=	false;
-	
-			fread(&uno,sizeof(unsigned short),1,pFile);
-
-			if (uno != M_HEADER)
-			{
-				//	Debug.
-				cout	<<	"Error: Header not found."
-					<<	endl;
-
-				//	Error.
-				mError	=	true;
-			}
-
-			// Read version.
-			fgets(version,255,pFile);
-
-			cout	<<	version	<<	endl;
-
-			if (strcmp(version,"[MeshSerializer_v1.30]\n"))
-			{
-				//	Debug.
-				cout	<<	"Error: Wrong mesh version."
-					<<	endl
-					<<	"Only version 1.3 or older allowed."
-					<<	endl;
-
-				//	Error.
-				mError	=	true;
-			}
-
-			while(!feof(pFile))
-			{
-				chunkID = readChunk(pFile);
-
-				switch (chunkID)
+			importOBJ(pFile,geoMesh);
+		}
+		else
+		{
+			//	Count the submeshes
+			//	and next build the geomesh.
+			for (int option = 0; option < 2;option++)
+			{
+				//	Initialize Error.
+				mError	=	false;
+		
+				fread(&uno,sizeof(unsigned short),1,pFile);
+
+				if (uno != M_HEADER)
 				{
-					case M_MESH:
-						readMesh(pFile, geoMesh, option);
-						break;
+					//	Debug.
+					cout	<<	"Error: Header not found."
+						<<	endl;
+
+					//	Error.
+					mError	=	true;
 				}
-			}
-
-			//	Create the submesh array.
-			if (option == SUBMESH_COUNT)
-			{
-				geoMesh->mSubMesh	= new SubMesh[geoMesh->mSubMeshCount];
-			}
-
-			//	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);
+
+				// Read version.
+				fgets(version,255,pFile);
+
+				cout	<<	version	<<	endl;
+
+				if (strcmp(version,"[MeshSerializer_v1.30]\n"))
+				{
+					//	Debug.
+					cout	<<	"Error: Wrong mesh version."
+						<<	endl
+						<<	"Only version 1.3 or older allowed."
+						<<	endl;
+
+					//	Error.
+					mError	=	true;
+				}
+
+				while(!feof(pFile))
+				{
+					chunkID = readChunk(pFile);
+
+					switch (chunkID)
+					{
+						case M_MESH:
+							readMesh(pFile, geoMesh, option);
+							break;
+					}
+				}
+
+				//	Create the submesh array.
+				if (option == SUBMESH_COUNT)
+				{
+					geoMesh->mSubMesh	= new SubMesh[geoMesh->mSubMeshCount];
+				}
+
+				//	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.
@@ -1351,2 +1374,254 @@
 }
 
+struct face_t
+{
+	int v1,v2,v3;
+	int t1,t2,t3;
+	int n1,n2,n3;
+};
+
+
+class vertex_arranger_node
+{
+public:
+	int v, n, t;
+
+	vertex_arranger_node(void){
+		v=n=t=-1;
+	}
+	vertex_arranger_node(int iv, int in=-1, int it=-1){
+		v=iv;
+		n=in;
+		t=it;
+	}
+
+	bool operator<(const vertex_arranger_node &vu) const {
+		if (v<vu.v) return true;
+		if (v>vu.v) return false;
+		if (n<vu.n) return true;
+		if (n>vu.n) return false;
+		if (t<vu.t) return true;
+		if (t>vu.t) return false;
+		return false;
+	}
+	bool operator==(const vertex_arranger_node &vu) const {
+		return (v==vu.v && v==vu.v && n==vu.n && n==vu.n && t==vu.t && t==vu.t);
+	}
+};
+
+
+void	GeoMeshLoader::importOBJ(FILE *f, Mesh *mesh)
+{
+	mesh->hasSkeleton=false;
+	mesh->mSubMeshCount=0;
+
+	std::vector<Geometry::Vector3> vertices;
+	std::vector<Geometry::Vector3> normals;
+	std::vector<Geometry::Vector2> texcoords;
+	std::vector<std::vector<face_t> > faces;
+	std::vector<face_t> current_faces;
+
+	mesh->mMeshBounds.maxX = -99999999.9f;
+	mesh->mMeshBounds.maxY = -99999999.9f;
+	mesh->mMeshBounds.maxZ = -99999999.9f;
+	mesh->mMeshBounds.minX =  99999999.9f;
+	mesh->mMeshBounds.minY =  99999999.9f;
+	mesh->mMeshBounds.minZ =  99999999.9f;
+	mesh->mMeshBounds.radius = 1.0f;
+	mesh->mMeshBounds.scaleFactor = 1.0f;
+
+	char line[256]="";
+	while(!feof(f))
+	{
+		fgets(line,256,f);
+		if (line[0]=='v' && line[1]==' ')
+		{
+			Geometry::Vector3 v3;
+			sscanf(line+2,"%f %f %f",&v3.x,&v3.y,&v3.z);
+			vertices.push_back(v3);
+		}
+		else if (line[0]=='v' && line[1]=='t')
+		{
+			Geometry::Vector2 v2;
+			sscanf(line+2,"%f %f",&v2.x,&v2.y);
+			texcoords.push_back(v2);
+		}
+		else if (line[0]=='v' && line[1]=='n')
+		{
+			Geometry::Vector3 v3;
+			sscanf(line+2,"%f %f %f",&v3.x,&v3.y,&v3.z);
+			normals.push_back(v3);
+		}
+		else if (line[0]=='f')
+		{
+			face_t auxface;
+			auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0;
+			int n = sscanf(line+2,"%d/%d/%d %d/%d/%d %d/%d/%d", &auxface.v1,&auxface.t1,&auxface.n1, 
+									  						    &auxface.v2,&auxface.t2,&auxface.n2, 
+																&auxface.v3,&auxface.t3,&auxface.n3);
+			if (n<9)
+			{
+				auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0;
+				n = sscanf(line+2,"%d//%d %d//%d %d//%d", &auxface.v1,&auxface.n1, 
+														  &auxface.v2,&auxface.n2, 
+														  &auxface.v3,&auxface.n3);
+				if (n<6)
+				{
+					auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0;
+					n = sscanf(line+2,"%d/%d %d/%d %d/%d", &auxface.v1,&auxface.t1,
+														   &auxface.v2,&auxface.t2, 
+														   &auxface.v3,&auxface.t3);
+					if (n<6)
+					{
+						auxface.n1=auxface.n2=auxface.n3=auxface.t1=auxface.t2=auxface.t3=auxface.v1=auxface.v2=auxface.v3=0;
+						n = sscanf(line+2,"%d %d %d", &auxface.v1,&auxface.v2,&auxface.v3);
+					}
+				}
+			}
+
+			auxface.v1=abs(auxface.v1); auxface.v2=abs(auxface.v2); auxface.v3=abs(auxface.v3);
+			auxface.t1=abs(auxface.t1); auxface.t2=abs(auxface.t2); auxface.t3=abs(auxface.t3);
+			auxface.n1=abs(auxface.n1); auxface.n2=abs(auxface.n2); auxface.n3=abs(auxface.n3);
+			auxface.v1--; auxface.v2--; auxface.v3--;
+			auxface.t1--; auxface.t2--; auxface.t3--;
+			auxface.n1--; auxface.n2--; auxface.n3--;
+			current_faces.push_back(auxface);
+		}
+		else if (line[0]=='g')
+		{
+			if (current_faces.size()>0)
+				faces.push_back(current_faces);
+			current_faces.clear();
+		}
+	}
+
+	if (current_faces.size()>0)
+		faces.push_back(current_faces);
+	current_faces.clear();
+
+	mesh->mSubMeshCount = faces.size();
+	bool found_texcoords=!texcoords.empty();
+
+	if (normals.empty())
+	{
+		// calculate face normals
+		for (int i=0, inormal=0; i<mesh->mSubMeshCount; i++)
+		{
+			Geometry::SubMesh *submesh = mesh->mSubMesh+i;
+			 std::vector<face_t> & vecfaces = faces[i];
+			int j=0;
+			for (std::vector<face_t>::iterator it=vecfaces.begin(); it!=vecfaces.end(); it++,j++,inormal++)
+			{
+				face_t & auxface = *it;
+				auxface.n1 = inormal;
+				auxface.n2 = inormal;
+				auxface.n3 = inormal;
+				Geometry::Vector3 v1,v2,v3,v31,v21,nor;
+				v1 = vertices[auxface.v1];
+				v2 = vertices[auxface.v2];
+				v3 = vertices[auxface.v3];
+				v31 = v3 - v1;
+				v21 = v2 - v1;
+				nor = v21.crossProduct(v31);
+				nor.normalise();
+				normals.push_back(nor);
+			}			
+		}
+	}
+
+	// fill up the mesh structure with the loaded information
+
+	std::map<vertex_arranger_node,int> vertex_map;
+		 
+	mesh->mSubMesh=new Geometry::SubMesh[mesh->mSubMeshCount];
+	for (int i=0; i<mesh->mSubMeshCount; i++)
+	{
+		Geometry::SubMesh *submesh = mesh->mSubMesh+i;
+		int j=0;
+		const std::vector<face_t> & vecfaces = faces[i];
+		std::vector<Geometry::Index> aux_indices;
+		submesh->mSharedVertexBuffer = true;
+		submesh->mIndexCount = vecfaces.size()*3;
+		submesh->mIndex=new Geometry::Index[submesh->mIndexCount];
+		
+		for (std::vector<face_t>::const_iterator it=vecfaces.begin(); it!=vecfaces.end(); it++,j++)
+		{
+			const face_t & auxface = *it;
+
+			vertex_arranger_node v1(auxface.v1,auxface.n1,auxface.t1);
+			vertex_arranger_node v2(auxface.v2,auxface.n2,auxface.t2);
+			vertex_arranger_node v3(auxface.v3,auxface.n3,auxface.t3);
+
+			std::map<vertex_arranger_node,int>::iterator res;
+			res=vertex_map.find(v1);
+			if (res==vertex_map.end())
+			{
+				int val = vertex_map.size();
+				vertex_map[v1] = val;
+				submesh->mIndex[j*3+0] = val;
+			}
+			else
+				submesh->mIndex[j*3+0] = res->second;
+
+			res=vertex_map.find(v2);
+			if (res==vertex_map.end())
+			{
+				int val = vertex_map.size();
+				vertex_map[v2] = val;
+				submesh->mIndex[j*3+1] = val;
+			}
+			else
+				submesh->mIndex[j*3+1] = res->second;
+
+			res=vertex_map.find(v3);
+			if (res==vertex_map.end())
+			{
+				int val = vertex_map.size();
+				vertex_map[v3] = val;
+				submesh->mIndex[j*3+2] = val;
+			}
+			else
+				submesh->mIndex[j*3+2] = res->second;
+		}			
+	}
+
+	mesh->mVertexBuffer=new Geometry::VertexBuffer;
+	mesh->mVertexBuffer->mVertexCount = vertex_map.size();
+	mesh->mVertexBuffer->mPosition = new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount];
+	mesh->mVertexBuffer->mTexCoords = texcoords.empty()?NULL:new Geometry::Vector2[mesh->mVertexBuffer->mVertexCount];
+	mesh->mVertexBuffer->mNormal = normals.empty()?NULL:new Geometry::Vector3[mesh->mVertexBuffer->mVertexCount];
+	mesh->mVertexBuffer->mVertexInfo = Geometry::VERTEX_POSITION | (texcoords.empty()?0:Geometry::VERTEX_TEXCOORDS) | (normals.empty()?0:Geometry::VERTEX_NORMAL);
+
+	// sort the calculated vertices
+	
+	vertex_arranger_node * vertex_list = new vertex_arranger_node[mesh->mVertexBuffer->mVertexCount];
+	for (std::map<vertex_arranger_node,int>::iterator it=vertex_map.begin(); it!=vertex_map.end(); it++)
+		vertex_list[it->second] = it->first;
+
+
+	for (int i=0; i<mesh->mSubMeshCount; i++)
+		mesh->mSubMesh[i].mVertexBuffer=mesh->mVertexBuffer;
+	
+	for (int j=0; j<mesh->mVertexBuffer->mVertexCount; j++)
+	{		
+		int vi = vertex_list[j].v;
+		int ti = vertex_list[j].t;
+		int ni = vertex_list[j].n;
+
+		Geometry::Vector3 auxpos(vertices[vi]);
+		if (auxpos.x < mesh->mMeshBounds.minX) mesh->mMeshBounds.minX = auxpos.x;
+		if (auxpos.y < mesh->mMeshBounds.minY) mesh->mMeshBounds.minY = auxpos.y;
+		if (auxpos.z < mesh->mMeshBounds.minZ) mesh->mMeshBounds.minZ = auxpos.z;
+		if (auxpos.x > mesh->mMeshBounds.maxX) mesh->mMeshBounds.maxX = auxpos.x;
+		if (auxpos.y > mesh->mMeshBounds.maxY) mesh->mMeshBounds.maxY = auxpos.y;
+		if (auxpos.z > mesh->mMeshBounds.maxZ) mesh->mMeshBounds.maxZ = auxpos.z;
+
+		mesh->mVertexBuffer->mPosition[j] = auxpos;
+		mesh->mVertexBuffer->mNormal[j] = normals[ni];
+		if (found_texcoords)
+			mesh->mVertexBuffer->mTexCoords[j] = texcoords[ti];		
+	}
+
+	delete[] vertex_list;
+}
+
Index: /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshViewUI.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshViewUI.cpp	(revision 1026)
+++ /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshViewUI.cpp	(revision 1050)
@@ -51,4 +51,5 @@
 										cb_menuFileLoadTexture_i(o,v);
 }
+
 
 inline void GeoMeshViewUI::cb_menuFileLoadTextureSubMesh_i(fltk::Item *item, void *)
@@ -2444,5 +2445,5 @@
 //	Open a mesh file.
 //---------------------------------------------------------------------------
-void	GeoMeshViewUI::openMeshFile()
+void	GeoMeshViewUI::openMeshFile(void)
 {
 	Mesh							*mesh_loaded;
@@ -2451,8 +2452,5 @@
 	static	char			title[256];
 	
-	fcho	=	new fltk::FileChooser("",
-																"*.mesh",
-																fltk::FileChooser::CREATE,
-																"Open mesh file");
+	fcho	=	new fltk::FileChooser("", "*.{mesh,obj}", fltk::FileChooser::CREATE, "Open a mesh");
 
 	fcho->exec();
Index: /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshView.cpp
===================================================================
--- /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshView.cpp	(revision 1018)
+++ /GTP/trunk/Lib/Geom/shared/GeoTool/src/GeoMeshView.cpp	(revision 1050)
@@ -503,7 +503,10 @@
 
 		//	Allocate memory.
-		mSharedPosArray	=	new GLfloat[vertex_buffer->mVertexCount * 3];
-		mSharedNorArray	=	new GLfloat[vertex_buffer->mVertexCount * 3];
-		mSharedTexCoordArray	=	new GLfloat[vertex_buffer->mVertexCount * 2];
+		mSharedPosArray = new GLfloat[vertex_buffer->mVertexCount * 3];
+		mSharedNorArray = new GLfloat[vertex_buffer->mVertexCount * 3];
+		if (vertex_buffer->mTexCoords)
+			mSharedTexCoordArray = new GLfloat[vertex_buffer->mVertexCount * 2];
+		else
+			mSharedTexCoordArray = NULL;
 
 		for (int vertex = 0; vertex < vertex_buffer->mVertexCount; vertex++)
@@ -517,6 +520,9 @@
 			mSharedNorArray[(3 * vertex) + 2]	=	vertex_buffer->mNormal[vertex].z;
 
-			mSharedTexCoordArray[2 * vertex]		=	vertex_buffer->mTexCoords[vertex].x;
-			mSharedTexCoordArray[(2 * vertex) + 1]	=	vertex_buffer->mTexCoords[vertex].y;
+			if (vertex_buffer->mTexCoords)
+			{
+				mSharedTexCoordArray[2 * vertex]		=	vertex_buffer->mTexCoords[vertex].x;
+				mSharedTexCoordArray[(2 * vertex) + 1]	=	vertex_buffer->mTexCoords[vertex].y;
+			}
 		}
 	}
