PageRenderTime 73ms CodeModel.GetById 28ms app.highlight 38ms RepoModel.GetById 1ms app.codeStats 1ms

/src/org/mt4j/util/modelImporter/file3ds/Model3dsFileFactory.java

http://mt4j.googlecode.com/
Java | 685 lines | 451 code | 111 blank | 123 comment | 74 complexity | 708825288d8de6cb9b7a5c8dd38a0f79 MD5 | raw file
  1/***********************************************************************
  2 * mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
  3 *  
  4 *   This program is free software: you can redistribute it and/or modify
  5 *   it under the terms of the GNU General Public License as published by
  6 *   the Free Software Foundation, either version 3 of the License, or
  7 *   (at your option) any later version.
  8 *
  9 *   This program is distributed in the hope that it will be useful,
 10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *   GNU General Public License for more details.
 13 *
 14 *   You should have received a copy of the GNU General Public License
 15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 *
 17 ***********************************************************************/
 18package org.mt4j.util.modelImporter.file3ds;
 19
 20import java.io.File;
 21import java.io.FileNotFoundException;
 22import java.io.InputStream;
 23import java.util.ArrayList;
 24import java.util.HashMap;
 25import java.util.Iterator;
 26import java.util.Map;
 27import java.util.WeakHashMap;
 28
 29import mri.v3ds.Face3ds;
 30import mri.v3ds.FaceMat3ds;
 31import mri.v3ds.Material3ds;
 32import mri.v3ds.Mesh3ds;
 33import mri.v3ds.Scene3ds;
 34import mri.v3ds.TexCoord3ds;
 35import mri.v3ds.TextDecode3ds;
 36import mri.v3ds.Vertex3ds;
 37
 38import org.mt4j.MTApplication;
 39import org.mt4j.components.visibleComponents.shapes.GeometryInfo;
 40import org.mt4j.components.visibleComponents.shapes.mesh.MTTriangleMesh;
 41import org.mt4j.util.MT4jSettings;
 42import org.mt4j.util.TriangleNormalGenerator;
 43import org.mt4j.util.logging.ILogger;
 44import org.mt4j.util.logging.MTLoggerFactory;
 45import org.mt4j.util.math.Tools3D;
 46import org.mt4j.util.math.Vertex;
 47import org.mt4j.util.modelImporter.ModelImporterFactory;
 48import org.mt4j.util.opengl.GLTexture;
 49import org.mt4j.util.opengl.GLTexture.EXPANSION_FILTER;
 50import org.mt4j.util.opengl.GLTexture.SHRINKAGE_FILTER;
 51import org.mt4j.util.opengl.GLTexture.TEXTURE_TARGET;
 52import org.mt4j.util.opengl.GLTexture.WRAP_MODE;
 53import org.mt4j.util.opengl.GLTextureSettings;
 54
 55import processing.core.PApplet;
 56import processing.core.PImage;
 57
 58/**
 59 * A factory for creating Model3dsFile objects.
 60 * @author Christopher Ruff
 61 */
 62public class Model3dsFileFactory extends ModelImporterFactory{
 63	private static final ILogger logger = MTLoggerFactory.getLogger(Model3dsFileFactory.class.getName());
 64	static{
 65		logger.setLevel(ILogger.ERROR);
 66	}
 67	
 68	private PApplet pa;
 69	private Map<String, PImage> textureCache ;
 70	
 71	/**
 72	 * Load model.
 73	 * 
 74	 * @param pa the pa
 75	 * @param pathToModel the path to model
 76	 * @param creaseAngle the crease angle
 77	 * @param flipTextureY flip texture y
 78	 * @param flipTextureX flip texture x
 79	 * 
 80	 * @return the MT triangle meshes[]
 81	 * 
 82	 * @throws FileNotFoundException the file not found exception
 83	 */
 84	public MTTriangleMesh[] loadModelImpl(PApplet pa, String pathToModel, float creaseAngle, boolean flipTextureY, boolean flipTextureX) throws FileNotFoundException{
 85		long timeA = System.currentTimeMillis();
 86		this.pa = pa;
 87		
 88		ArrayList<MTTriangleMesh> returnMeshList = new ArrayList<MTTriangleMesh>();
 89		
 90		TriangleNormalGenerator normalGenerator = new TriangleNormalGenerator();
 91//		normalGenerator.setDebug(debug); 
 92		
 93		HashMap<Integer, Group> materialIdToGroup = new HashMap<Integer, Group>();
 94		
 95		//TODO implement
 96		if (textureCache != null)
 97			textureCache.clear();
 98		textureCache = new WeakHashMap<String, PImage>();
 99		
100		Scene3ds scene = null;
101		
102		try{
103			TextDecode3ds decode = new TextDecode3ds();
104//			int level = Scene3ds.DECODE_USED_PARAMS_AND_CHUNKS; //Scene3ds.DECODE_ALL; DECODE_USED_PARAMS, DECODE_USED_PARAMS_AND_CHUNKS
105			int level = Scene3ds.DECODE_ALL;
106
107			//LOAD all meshes from file into scene object
108			File file = new File(pathToModel);
109			if (file.exists()){
110				scene = new Scene3ds(file, decode, level );
111			}else{
112				InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(pathToModel);
113				if (in == null){
114					in = pa.getClass().getResourceAsStream(pathToModel);
115				}
116				if (in != null){
117					scene = new Scene3ds(in, decode, level );
118				}else{
119					throw new FileNotFoundException("File not found: " + file.getAbsolutePath());
120				}
121			}
122				
123			
124			if (debug)
125				logger.debug("\n-> Loading model: " + file.getName() + " <-");
126			
127
128			if (debug){
129				//Go through all MATERIALS
130				logger.debug("\nNum Scene Materials: " + scene.materials() );
131				for( int m=0; m < scene.materials(); m++ ){
132					Material3ds mat = scene.material( m );
133					logger.debug("  Material " + m + ": \" " + mat.name() + "\"");
134				}
135				logger.debug("");
136			}
137
138
139			///////// Go through all MESHES //////////////////////////
140			for( int i=0; i<scene.meshes(); i++ ) {
141				Mesh3ds m = scene.mesh( i );
142				
143				if (debug){
144					int texMapType = m.texMapType();
145					logger.debug("Texture coordinates provided: " + m.texCoords());
146					logger.debug("Texture mapping type: " + texMapType);
147					logger.debug("Mesh:" + m.name() + " Pivot:" + m.pivot());
148				}
149				
150				/*
151				XYZTrack3ds pos 		= m.positionTrack();
152				RotationTrack3ds rot 	= m.rotationTrack();
153				XYZTrack3ds sc 			= m.scaleTrack();
154				//FIXME .track and key(i) werden nicht zur verfügung gestellt?!? aber in javadoc
155				*/
156				
157				if (debug){
158					logger.debug("->Processing mesh: " 	+ i + " of " + scene.meshes() + " Name: \"" + m.name() + "\"");
159					logger.debug("  Num Faces: " 			+ m.faces());
160					logger.debug("  Num Vertices: " 		+ m.vertices());
161					logger.debug("  Num TextureCoordinates: " + m.texCoords());
162					logger.debug("");
163				}
164				
165				//Create the arrays needed for the cruncher
166				Vertex[] vertices 		= new Vertex[m.vertices()];
167				int[] indices 			= new int[m.faces()*3];
168				
169				int[] texCoordIndices 	= new int[m.faces()*3];
170				float[][] textureCoords = new float[m.texCoords()][2];
171				
172				//Fill Vertices array 
173				for (int j = 0; j < m.vertices(); j++) {
174					Vertex3ds vert = m.vertex(j);
175					
176					if (this.flipY){
177						vertices[j] = new Vertex(vert.X, -vert.Y, vert.Z, -1,-1);
178					}else{
179						vertices[j] = new Vertex(vert.X, vert.Y, vert.Z, -1,-1);
180					}
181					
182					if (m.texCoords()> j)
183						textureCoords[j] = new float[]{m.texCoord(j).U, m.texCoord(j).V };
184				}
185				
186				//Fill texcoords array
187				for (int j = 0; j < m.texCoords(); j++) {
188					TexCoord3ds tex =  m.texCoord(j);
189					
190					float[] texCoord = new float[2];
191					texCoord[0] = tex.U;
192					texCoord[1] = tex.V;
193					
194					textureCoords[j] = texCoord;
195				}
196				
197				//TODO so werden gleiche materials in verschiedenen meshes nicht zu einem mesh gemacht!
198				//also müsste also ohne clear machen und dafür vertices + texcoords in einen grossen
199				//array, dafür müssten indices aber per offset angepasst werden dass die wieder stimmen!
200				materialIdToGroup.clear();
201				
202				if (m.faceMats() > 0){
203					//List face Materials  //TODO USE LOGGERS!!
204					logger.debug("  Num Face-Materials: " + m.faceMats() );
205					for( int n = 0; n < m.faceMats(); n++ ){
206						FaceMat3ds fmat = m.faceMat( n );
207						logger.debug("    FaceMat ID: " 		+ fmat.matIndex() );
208						logger.debug("    FaceMat indices: " 	+ fmat.faceIndexes());
209						
210						int[] faceIndicesForMaterial = fmat.faceIndex();
211						if (faceIndicesForMaterial.length <= 0){
212							continue;
213						}
214
215						//Check if there already is a group with the same material
216						Group group = materialIdToGroup.get(fmat.matIndex());
217
218						//If not, create a new group and save it in map
219						if (group == null){
220							group = new Group(Integer.toString(fmat.matIndex()));
221							materialIdToGroup.put(fmat.matIndex(), group);
222						}
223
224						//Go through all pointers to the faces for this material 
225						//and get the corresponding face
226                        for (int k : faceIndicesForMaterial) {
227                            Face3ds face = m.face(k);
228
229                            AFace aFace = new AFace();
230                            aFace.p0 = face.P0;
231                            aFace.p1 = face.P1;
232                            aFace.p2 = face.P2;
233
234                            aFace.t0 = face.P0;
235                            aFace.t1 = face.P1;
236                            aFace.t2 = face.P2;
237
238                            group.addFace(aFace);
239                        }
240					}
241
242					Iterator<Integer> it = materialIdToGroup.keySet().iterator();
243					logger.debug("Mesh: " + m.name() + " Anzahl Groups:" + materialIdToGroup.keySet().size());
244					while (it.hasNext()) {
245						int currentGroupName =  it.next();
246						Group currentGroup = materialIdToGroup.get(currentGroupName);
247						logger.debug("Current group: " + currentGroupName);
248
249						currentGroup.compileItsOwnLists(vertices, textureCoords);
250
251						//Get the new arrays 
252						Vertex[] newVertices 		= currentGroup.getGroupVertices(); 
253						int[] newIndices 			= currentGroup.getIndexArray(); 
254						float[][] newTextureCoords  = currentGroup.getGroupTexCoords();
255						int[] newTexIndices 		= currentGroup.getTexCoordIndices();
256
257						logger.debug("\nGroup: \"" + currentGroup.name + "\" ->Vertices: " + currentGroup.verticesForGroup.size()+ " ->TextureCoords: " + currentGroup.texCoordsForGroup.size() + " ->Indices: " + currentGroup.indexArray.length + " ->Texcoord Indices: " + currentGroup.texCoordIndexArray.length );
258						logger.debug("");
259
260						if (vertices.length > 2){
261							GeometryInfo geometry  = null;
262							//Load as all vertex normals smoothed if creaseAngle == 180;
263							if (creaseAngle == 180){
264								geometry = normalGenerator.generateSmoothNormals(pa, newVertices , newIndices, newTextureCoords, newTexIndices, creaseAngle, flipTextureY, flipTextureX);
265							}else{
266								geometry = normalGenerator.generateCreaseAngleNormals(pa, newVertices, newIndices, newTextureCoords, newTexIndices, creaseAngle, flipTextureY, flipTextureX);
267							}
268
269							MTTriangleMesh mesh = new MTTriangleMesh(pa, geometry);
270
271							if (mesh != null){
272								mesh.setName(m.name() + " material: " + Integer.toString(currentGroupName));
273								//Assign texture
274								this.assignMaterial(pathToModel, file, scene, m, currentGroupName, mesh);
275
276								if (mesh.getTexture() != null){
277									mesh.setTextureEnabled(true);
278								}else{
279									logger.debug("No texture could be assigned to mesh.");
280								}
281								returnMeshList.add(mesh);
282							}
283						}
284					}
285				}else{
286					//If there are no materials for this mesh dont split mesh into
287					//groups by material
288					//Fill indices array and texcoords array (Here: vertex index = texcoord index)
289					for( int faceIndex = 0; faceIndex < m.faces(); faceIndex++ ){
290						Face3ds f = m.face( faceIndex );
291
292						indices[faceIndex*3] 	= f.P0;
293						indices[faceIndex*3+1] 	= f.P1;
294						indices[faceIndex*3+2] 	= f.P2;
295
296						texCoordIndices[faceIndex*3] 	= f.P0;
297						texCoordIndices[faceIndex*3+1] 	= f.P1;
298						texCoordIndices[faceIndex*3+2] 	= f.P2;
299					}//for faces
300
301					//Create the Mesh and set a texture
302					if (vertices.length > 2){
303						//Create normals for the mesh and duplicate vertices for faces that share the same 
304						//Vertex, but with different texture coordinates or different normals
305						GeometryInfo geometry = null;
306						//Generate normals and denormalize vertices with more than 1 texture coordinate
307						if (creaseAngle == 180){
308							geometry = normalGenerator.generateSmoothNormals(pa, vertices, indices, textureCoords, texCoordIndices, creaseAngle, flipTextureY, flipTextureX);
309						}else{
310							geometry = normalGenerator.generateCreaseAngleNormals(pa, vertices, indices, textureCoords, texCoordIndices, creaseAngle, flipTextureY, flipTextureX);
311						}
312						MTTriangleMesh mesh = new MTTriangleMesh(pa, geometry);
313						mesh.setName(m.name());
314//						this.assignMaterial(file, scene, m, sceneMaterialID, mesh);
315						returnMeshList.add(mesh);
316					}//end if vertices.lentgh > 2
317				}
318			}//for meshes
319			
320//			logger.debug(decode.text()); 
321		}catch (Exception e) {
322			e.printStackTrace();
323		}
324		
325		materialIdToGroup.clear();
326		
327		long timeB = System.currentTimeMillis();
328		long delta = timeB-timeA;
329		logger.debug("Loaded model in: " + delta + " ms");
330		return returnMeshList.toArray(new MTTriangleMesh[returnMeshList.size()]);
331	}
332			
333			
334	/**
335	 * Assigns the texture.
336	 * @param pathToModel 
337	 * @param modelFile
338	 * @param scene
339	 * @param m
340	 * @param sceneMaterialID
341	 * @param mesh
342	 */		
343	private void assignMaterial(String pathToModel, File modelFile, Scene3ds scene, Mesh3ds m, int sceneMaterialID, MTTriangleMesh mesh){
344		if (scene.materials() > 0){
345			if (m.faceMats() > 0){
346				//Just take the first material in the mesh, it could have more but we dont support more than 1 material for a mesh
347				// materialIndexForMesh = m.faceMat(0).matIndex();
348
349				Material3ds mat = scene.material(sceneMaterialID);
350				String materialName = mat.name();
351				if (debug)
352					logger.debug("Material name for mesh \"" + mesh.getName() + ":-> \"" + materialName + "\"");
353				materialName = materialName.trim();
354				materialName = materialName.toLowerCase();
355
356				//Try to load texture
357				try {
358					PImage cachedImage = textureCache.get(materialName);
359					if (cachedImage != null){
360						mesh.setTexture(cachedImage);
361						mesh.setTextureEnabled(true);
362						if (debug)
363							logger.debug("->Loaded texture from CACHE : \"" + materialName + "\"");
364						return;
365					}
366					
367					if (modelFile.exists()){ //If model is loaded from local file system
368						String modelFolder  = modelFile.getParent();// pathToModel.substring(), pathToModel.lastIndexOf(File.pathSeparator)
369						File modelFolderFile = new File (modelFolder);
370						if (modelFolderFile.exists() &&  modelFolderFile.isDirectory())
371							modelFolder = modelFolderFile.getAbsolutePath();
372						else{
373							modelFolder = "";
374						}
375
376						String[] suffix = new String[]{"jpg", "JPG", "tga" , "TGA", "bmp", "BMP", "png", "PNG", "tiff", "TIFF"};
377						for (int j = 0; j < suffix.length; j++) {
378							String suffixString = suffix[j];
379							//Try to load and set texture to mesh
380							String texturePath 	= modelFolder + MTApplication.separator + materialName + "." +  suffixString;
381							File textureFile = new File(texturePath);
382							if (textureFile.exists()){
383								boolean success = textureFile.renameTo(new File(texturePath));
384								if (!success) {
385									// File was not successfully renamed
386									logger.debug("failed to RENAME file: " + textureFile.getAbsolutePath());
387								}
388								PImage texture = null;
389								if (MT4jSettings.getInstance().isOpenGlMode()){ //TODO check if render thread
390									PImage img = pa.loadImage(texturePath);
391									if (Tools3D.isPowerOfTwoDimension(img)){
392										texture = new GLTexture(pa, img, new GLTextureSettings(TEXTURE_TARGET.TEXTURE_2D, SHRINKAGE_FILTER.Trilinear, EXPANSION_FILTER.Bilinear, WRAP_MODE.REPEAT, WRAP_MODE.REPEAT));
393									}else{
394										texture = new GLTexture(pa, img, new GLTextureSettings(TEXTURE_TARGET.RECTANGULAR, SHRINKAGE_FILTER.Trilinear, EXPANSION_FILTER.Bilinear, WRAP_MODE.REPEAT, WRAP_MODE.REPEAT));
395										// ((GLTexture)texture).setFilter(SHRINKAGE_FILTER.BilinearNoMipMaps, EXPANSION_FILTER.Bilinear);
396									}
397								}else{
398									texture 		= pa.loadImage(texturePath);
399								}
400								mesh.setTexture(texture);
401								mesh.setTextureEnabled(true);
402
403								textureCache.put(materialName, texture);
404								if (debug)
405									logger.debug("->Loaded material texture: \"" + materialName + "\"");
406								break;
407							}
408							if (j+1==suffix.length){
409								logger.error("Couldnt load material texture: \"" + materialName + "\"");
410							}
411						}
412					}else{//Probably loading from jar file
413						PImage texture = null;
414						String[] suffix = new String[]{"jpg", "JPG", "tga" , "TGA", "bmp", "BMP", "png", "PNG", "tiff", "TIFF"};
415						for (String suffixString : suffix) {
416							String modelFolder  = pathToModel.substring(0, pathToModel.lastIndexOf(MTApplication.separator));
417							String texturePath 	= modelFolder + MTApplication.separator + materialName + "." +  suffixString;
418							if (MT4jSettings.getInstance().isOpenGlMode()){
419								PImage img = pa.loadImage(texturePath);
420								if (Tools3D.isPowerOfTwoDimension(img)){
421									texture = new GLTexture(pa, img, new GLTextureSettings(TEXTURE_TARGET.TEXTURE_2D, SHRINKAGE_FILTER.Trilinear, EXPANSION_FILTER.Bilinear, WRAP_MODE.REPEAT, WRAP_MODE.REPEAT));
422								}else{
423									texture = new GLTexture(pa, img, new GLTextureSettings(TEXTURE_TARGET.RECTANGULAR, SHRINKAGE_FILTER.Trilinear, EXPANSION_FILTER.Bilinear, WRAP_MODE.REPEAT, WRAP_MODE.REPEAT));
424									// ((GLTexture)texture).setFilter(SHRINKAGE_FILTER.BilinearNoMipMaps, EXPANSION_FILTER.Bilinear);
425								}
426							}else{
427								texture = pa.loadImage(texturePath);
428							}
429							mesh.setTexture(texture);
430							mesh.setTextureEnabled(true);
431
432							textureCache.put(materialName, texture);
433							if (debug)
434								logger.debug("->Loaded material texture: \"" + materialName + "\"");
435							break;
436						}
437					}
438				} catch (Exception e) {
439					logger.error(e.getMessage());
440				}
441			}//if (m.faceMats() > 0)
442		}//if (scene.materials() > 0)
443	}
444	
445	
446	
447	private boolean debug = true;
448	private boolean flipY = true;
449
450
451	public void setDebug(boolean debug) {
452		this.debug = debug;
453		if (debug)
454			logger.setLevel(ILogger.DEBUG);
455		else
456			logger.setLevel(ILogger.ERROR);
457	}
458	
459	public void setFlipY(boolean flipY){
460		this.flipY  = flipY;
461	}
462	
463
464	
465	/**
466	 * A class representing one group in a .3ds file
467	 * @author C.Ruff
468	 *
469	 */
470	private class Group{
471		private String name;
472		private ArrayList<AFace> faces;
473		private ArrayList<Vertex> verticesForGroup;
474		
475		private HashMap<Integer, Integer> oldIndexToNewIndex;
476		
477		private ArrayList<float[]> texCoordsForGroup;
478		private HashMap<Integer, Integer> oldTexIndexToNewTexIndex;
479		
480		private int[] indexArray;
481		
482		private int[] texCoordIndexArray;
483		
484		public Group(String name){
485			this.name = name;
486			
487			faces 						= new ArrayList<AFace>();
488			
489			verticesForGroup 			= new ArrayList<Vertex>();
490			oldIndexToNewIndex 			= new HashMap<Integer, Integer>();
491			
492			texCoordsForGroup 			= new ArrayList<float[]>();
493			oldTexIndexToNewTexIndex 	= new HashMap<Integer, Integer>();
494			
495			indexArray 			= new int[0];
496			texCoordIndexArray 	= new int[0];
497			
498			//name = "default";
499		}
500		
501		public void addFace(AFace face){
502			faces.add(face);
503		}
504
505		//Irgendwann am ende ausführen
506		//=>für jede gruppe eigene liste von vertices on indices speichern
507		//aus hauptlisten rausholen
508		
509		/**
510		 * Uses the faces attached to this group during the parsing process and the lists with
511		 * all vertex and all texture coordinates of the obj file to create arrays for this group
512		 * with vertices and texture coords that only belong to this single group.
513		 * 
514		 * @param allFileVerts
515		 * @param allTexCoords
516		 */
517		public void compileItsOwnLists(Vertex[] allFileVerts, float[][] allTexCoords){
518			indexArray = new int[faces.size()*3];
519			
520			if (allTexCoords.length > 0){
521				texCoordIndexArray = new int[faces.size()*3];
522			}
523			
524			for (int i = 0; i < faces.size(); i++) {
525				AFace currentFace = faces.get(i);
526				
527				Vertex v0 = allFileVerts[currentFace.p0];
528				Vertex v1 = allFileVerts[currentFace.p1];
529				Vertex v2 = allFileVerts[currentFace.p2];
530				
531				if (	allTexCoords.length > currentFace.t0
532					&& 	allTexCoords.length > currentFace.t1
533					&& 	allTexCoords.length > currentFace.t2
534				){
535					float[] texV0 = allTexCoords[currentFace.t0];
536					float[] texV1 = allTexCoords[currentFace.t1];
537					float[] texV2 = allTexCoords[currentFace.t2];
538					
539					//Etwas redundant immer wieder zu machen beim gleichen vertex..whatever
540					v0.setTexCoordU(texV0[0]);
541					v0.setTexCoordV(texV0[1]);
542					
543					v1.setTexCoordU(texV1[0]);
544					v1.setTexCoordV(texV1[1]);
545					
546					v2.setTexCoordU(texV2[0]);
547					v2.setTexCoordV(texV2[1]);
548					
549					//Check if there is a texture index in the hashtable at the faces texture pointer
550					//if not, create a new index = the end of thexcoords list, and put the pointer into the hash
551					//if yes, point the faces texture pointer to the pointer in the hash
552					
553					//This process maps the texture coords and indices of all the groups in the obj
554					//file to only this groups texture coord list and texture indices, the indices 
555					//are created from the index in the thex coord list when they are put in
556					//Only the texture coordinates are added to the list that have not been adressed
557					//in the texture indices pointers in the faces
558					//Same texture pointers will point to the same texcoord in the list
559					Integer oldToNewT0 = oldTexIndexToNewTexIndex.get(currentFace.t0);
560					if (oldToNewT0 != null){
561						currentFace.t0 = oldToNewT0;
562					}else{
563						int newIndex = texCoordsForGroup.size();
564						texCoordsForGroup.add(texV0);
565						oldTexIndexToNewTexIndex.put(currentFace.t0, newIndex);
566						currentFace.t0 = newIndex;
567					}
568					
569					Integer oldToNewT1 = oldTexIndexToNewTexIndex.get(currentFace.t1);
570					if (oldToNewT1 != null){
571						currentFace.t1 = oldToNewT1;
572					}else{
573						int newIndex = texCoordsForGroup.size();
574						texCoordsForGroup.add(texV1);
575						oldTexIndexToNewTexIndex.put(currentFace.t1, newIndex);
576						currentFace.t1 = newIndex;
577					}
578					
579					Integer oldToNewT2 = oldTexIndexToNewTexIndex.get(currentFace.t2);
580					if (oldToNewT2 != null){
581						currentFace.t2 = oldToNewT2;
582					}else{
583						int newIndex = texCoordsForGroup.size();
584						texCoordsForGroup.add(texV2);
585						oldTexIndexToNewTexIndex.put(currentFace.t2, newIndex);
586						currentFace.t2 = newIndex;
587					}
588				}
589				
590				//Do the same for the vertices.
591				//Create a new vertex pointer when adding the vertex to the list
592				Integer oldToNewP0 = oldIndexToNewIndex.get(currentFace.p0);
593				if (oldToNewP0 != null){
594					//index of the old vertex list has already been mapped to a new one here -> use the new index in the face
595					currentFace.p0 = oldToNewP0;
596				}else{
597					int newIndex = verticesForGroup.size();
598					verticesForGroup.add(v0);
599					//mark that the former index (for exmample 323) is now at new index (f.e. 1)
600					oldIndexToNewIndex.put(currentFace.p0, newIndex); 
601					currentFace.p0 = newIndex;
602				}
603				
604				Integer oldToNewP1 = oldIndexToNewIndex.get(currentFace.p1);
605				if (oldToNewP1 != null){
606					currentFace.p1 = oldToNewP1;
607				}else{
608					int newIndex = verticesForGroup.size();
609					verticesForGroup.add(v1);
610					oldIndexToNewIndex.put(currentFace.p1, newIndex);
611					currentFace.p1 = newIndex;
612				}
613				
614				Integer oldToNewP2 = oldIndexToNewIndex.get(currentFace.p2);
615				if (oldToNewP2 != null){
616					currentFace.p2 = oldToNewP2;
617				}else{
618					int newIndex = verticesForGroup.size();
619					verticesForGroup.add(v2);
620					oldIndexToNewIndex.put(currentFace.p2, newIndex);
621					currentFace.p2 = newIndex;
622				}
623				
624				indexArray[i*3]   = currentFace.p0;
625				indexArray[i*3+1] = currentFace.p1;
626				indexArray[i*3+2] = currentFace.p2;
627				
628				if (allTexCoords.length > 0){
629					texCoordIndexArray[i*3]   = currentFace.t0;
630					texCoordIndexArray[i*3+1] = currentFace.t1;
631					texCoordIndexArray[i*3+2] = currentFace.t2;
632				}
633			}
634		}
635
636		public int[] getIndexArray() {
637			return indexArray;
638		}
639
640		public String getName() {
641			return name;
642		}
643
644		public int[] getTexCoordIndices() {
645			return texCoordIndexArray;
646		}
647
648		public float[][] getGroupTexCoords() {
649			return texCoordsForGroup.toArray(new float[this.texCoordsForGroup.size()][]);
650		}
651
652		public Vertex[] getGroupVertices() {
653			return verticesForGroup.toArray(new Vertex[this.verticesForGroup.size()]);
654		}
655	}
656	
657	/**
658	 * A class representing a face in the obj file.
659	 * Has pointers into the vertex and the texture arrays.
660	 * 
661	 * @author C.Ruff
662	 *
663	 */
664	private class AFace{
665		int p0;
666		int p1;
667		int p2;
668		
669		int t0;
670		int t1;
671		int t2;
672		
673		public AFace(){
674			p0 = -1;
675			p1 = -1;
676			p2 = -1;
677			
678			t0 = 0;
679			t1 = 0;
680			t2 = 0;
681		}
682	}
683	
684	
685}