IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
BlenderFile.cs
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Runtime.InteropServices;
5 using UnityEngine;
6 
7 namespace BlenderMeshReader
8 {
10  [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 8)]
11  struct MLoop
12  {
13  [FieldOffset(0)]
14  public int v;
15  [FieldOffset(4)]
16  public int e;
17  }
18 
20  [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 12)]
21  struct MPoly
22  {
23  [FieldOffset(0)]
24  public int loopstart;
25  [FieldOffset(4)]
26  public int totloop;
27  [FieldOffset(8)]
28  public short mat_nr;
29  [FieldOffset(10)]
30  public byte flag;
31  [FieldOffset(11)]
32  public byte pad;
33  }
34 
36  [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 20)]
37  struct MVert
38  {
39  [FieldOffset(0)]
40  public float coX;
41  [FieldOffset(4)]
42  public float coY;
43  [FieldOffset(8)]
44  public float coZ;
45 
46  [FieldOffset(12)]
47  public short noX;
48  [FieldOffset(14)]
49  public short noY;
50  [FieldOffset(16)]
51  public short noZ;
52 
53  [FieldOffset(18)]
54  public byte flag;
55 
56  [FieldOffset(19)]
57  public byte bweight;
58  }
59 
61  [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 104)]
62  struct BoundBox
63  {
64  [FieldOffset(0)]
65  public float vec00;
66  [FieldOffset(4)]
67  public float vec10;
68  [FieldOffset(8)]
69  public float vec20;
70  [FieldOffset(12)]
71  public float vec30;
72  [FieldOffset(16)]
73  public float vec40;
74  [FieldOffset(20)]
75  public float vec50;
76  [FieldOffset(24)]
77  public float vec60;
78  [FieldOffset(28)]
79  public float vec70;
80 
81  [FieldOffset(32)]
82  public float vec01;
83  [FieldOffset(36)]
84  public float vec11;
85  [FieldOffset(40)]
86  public float vec21;
87  [FieldOffset(44)]
88  public float vec31;
89  [FieldOffset(48)]
90  public float vec41;
91  [FieldOffset(52)]
92  public float vec51;
93  [FieldOffset(56)]
94  public float vec61;
95  [FieldOffset(60)]
96  public float vec71;
97 
98  [FieldOffset(64)]
99  public float vec02;
100  [FieldOffset(68)]
101  public float vec12;
102  [FieldOffset(72)]
103  public float vec22;
104  [FieldOffset(76)]
105  public float vec32;
106  [FieldOffset(80)]
107  public float vec42;
108  [FieldOffset(84)]
109  public float vec52;
110  [FieldOffset(88)]
111  public float vec62;
112  [FieldOffset(92)]
113  public float vec72;
114 
115  [FieldOffset(96)]
116  public int flag;
117 
118  [FieldOffset(100)]
119  public int pad;
120  }
121 
124  {
125  public string objectName;
126  public ulong uniqueIdentifier;
127  public Vector3 location;
128  public Quaternion rotation;
129  }
130 
136  {
137  public static int PointerSize { get; private set; }
138  public string BlenderVersionNumber { get; private set; }
139  public string Filename { get; private set; }
140  public List<FileBlock> FileBockList { get; private set; }
141  public List<Structure> StructureList { get; private set; }
142 
143 
144  //private BinaryReader reader;
145 
146  public BlenderFile(string path)
147  {
148  StructureList = new List<Structure>();
149  Filename = path;
150  BlenderVersionNumber = null;
151  readHeader();
152  FileBockList = readFileBlockList();
153  foreach(FileBlock f in FileBockList)
154  {
155  if(f.Code == "DNA1")
156  {
157  StructureList = readDNA1Block(f.StartAddess, f.Size);
158  }
159  }
160  //reader = new BinaryReader(File.Open(path, FileMode.Open, FileAccess.Read));
161  }
162 
163  private void readHeader()
164  {
165  if (!File.Exists(Filename))
166  {
167  throw new FileNotFoundException("File not found.");
168  }
169 
170  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open ));
171 
172  if(System.Text.Encoding.ASCII.GetString(reader.ReadBytes(7)) != "BLENDER")
173  {
174  throw new FormatException("Wrong file format.");
175  }
176  PointerSize = Convert.ToChar(reader.ReadByte()) == '-' ? 8 : 4; // '-' = 8, '_' = 4
177  char end = Convert.ToChar(reader.ReadByte()); // 'V' = big endian, 'v' = little endian
178  if ((end != 'v' && end != 'V') || (end == 'v' && !BitConverter.IsLittleEndian) || (end == 'V' && BitConverter.IsLittleEndian))
179  {
180  throw new FormatException("Endianness of computer does not match with endianness of file. Open the file in Blender and save it to convert.");
181  }
182  BlenderVersionNumber = new string(new[] { Convert.ToChar(reader.ReadByte()), '.', Convert.ToChar(reader.ReadByte()), Convert.ToChar(reader.ReadByte()) });
183 
184  reader.Close();
185 
186  }
187 
188  private List<FileBlock> readFileBlockList()
189  {
190  List<FileBlock> result = new List<FileBlock>();
191  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open));
192 
193  reader.ReadBytes(12); //skip file header
194 
195  while (reader.BaseStream.Position < reader.BaseStream.Length)
196  {
197  // read block header
198  long startaddess = reader.BaseStream.Position;
199  string code = new string(reader.ReadChars(4));
200  int size = reader.ReadInt32();
201  ulong oldaddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
202  int sdna = reader.ReadInt32();
203  int count = reader.ReadInt32();
204 
205  FileBlock f = new FileBlock(code, size, sdna, count, startaddess, oldaddress);
206  result.Add(f);
207 
208  reader.BaseStream.Position = reader.BaseStream.Position + size;
209  //reader.ReadBytes(size); //skip data
210 
211  }
212 
213  reader.Close();
214  return result;
215 
216  }
217 
218 
219  private List<Structure> readDNA1Block(long startAddress, int size)
220  {
221  //List<FileBlock> result = new List<FileBlock>();
222  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open));
223  reader.BaseStream.Position = startAddress + (PointerSize == 8 ? 24 : 20) + 4; //set position to data
224 
225  reader.ReadBytes(4); //read NAME
226  int numberOfNames = reader.ReadInt32();
227  string[] nameArray = new string[numberOfNames];
228  for(int i = 0; i<numberOfNames; i++)
229  {
230  string name = "";
231  char c;
232  while((c = reader.ReadChar()) != 0x0)
233  {
234  name += c;
235  }
236  nameArray[i] = name;
237  }
238  //next date is aligned at four bytes
239  while (reader.BaseStream.Position % 4 != 0)
240  {
241  reader.BaseStream.Position++;
242  }
243 
244 
245  reader.ReadBytes(4); //read TYPE
246  int numberOfTypes = reader.ReadInt32();
247  Type[] typeArray = new Type[numberOfTypes];
248  for (int i = 0; i < numberOfTypes; i++)
249  {
250  string name = "";
251  char c;
252  while ((c = reader.ReadChar()) != 0x0)
253  {
254  name += c;
255  }
256  typeArray[i] = new Type(name);
257  }
258  //next date is aligned at four bytes
259  while (reader.BaseStream.Position % 4 != 0)
260  {
261  reader.BaseStream.Position++;
262  }
263 
264 
265  reader.ReadBytes(4); //read TLEN
266  for (int i = 0; i < numberOfTypes; i++)
267  {
268  short s = reader.ReadInt16();
269  typeArray[i].Length = s;
270  }
271  //next date is aligned at four bytes
272  while (reader.BaseStream.Position % 4 != 0)
273  {
274  reader.BaseStream.Position++;
275  }
276 
277 
278  reader.ReadBytes(4); //read STRC
279  List<Structure> sList = new List<Structure>();
280  int numberOfStructure = reader.ReadInt32();
281  for (int i = 0; i < numberOfStructure; i++)
282  {
283  short nameIndex = reader.ReadInt16();
284  Structure st = new Structure(typeArray[nameIndex].Name, i);
285  sList.Add(st);
286  short numberOfFields = reader.ReadInt16();
287  for(short s = 0; s< numberOfFields; s++)
288  {
289  short indexType = reader.ReadInt16();
290  short indexName = reader.ReadInt16();
291  Field f = new Field(nameArray[indexName], typeArray[indexType]);
292  //Field f = new Field(nameArray[indexName], new Type(typeArray[indexType].Name, typeArray[indexType].Length));
293  st.Fields.Add(f);
294  }
295  }
296 
297  reader.Close();
298  return sList;
299  }
300 
301  //Return a list of bounding boxes or an empty list if there are no bounding boxes
302  /*public List<BoundingBox> readBoundingBoxes()
303  {
304  List<BoundingBox> result = new List<BoundingBox>();
305 
306  //get information about the structure of a mesh block
307  int indexMesh = 0;
308 
309  int startPositionBoundBox = -1;
310 
311 
312  foreach (Structure s in StructureList)
313  {
314  if (s.Name == "Mesh") //search index of mesh structure and start position of *bb in mesh structure
315  {
316  indexMesh = s.Index;
317  int countLenght = 0;
318  foreach (Field f in s.Fields)
319  {
320  if (f.Name == "*bb")
321  {
322  startPositionBoundBox = countLenght;
323  }
324  countLenght += f.getLength();
325  }
326  }
327 
328  }
329  //read bound box
330  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open));
331  foreach (FileBlock fileBlock in FileBockList)
332  {
333  if (fileBlock.SDNAIndex == indexMesh)
334  {
335  //read name
336  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + 32;
337  string name = "";
338  for (int i = 0; i < 66; i++)
339  {
340  char c = reader.ReadChar();
341  if (c == 0x0)
342  {
343  break;
344  }
345  name += c;
346  }
347 
348  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionBoundBox;
349  ulong boundBoxAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32(); //pointer to file block with BoundBox structures
350  if(boundBoxAddress == 0)
351  {
352  continue; //continue if there are no bounding box
353  }
354 
355  BoundingBox currentBoundingBox = new BoundingBox();
356  currentBoundingBox.name = name;
357  result.Add(currentBoundingBox);
358 
359  foreach (FileBlock f in FileBockList)
360  {
361  //Read bound box
362  if (f.OldAddess == boundBoxAddress)
363  {
364 
365  BoundBox readBoundBox = new BoundBox();
366  reader.BaseStream.Position = f.StartAddess + (PointerSize == 8 ? 24 : 20);
367  byte[] readBytes = reader.ReadBytes(f.Count * Marshal.SizeOf(typeof(BoundBox)));
368  GCHandle pinnedHandle = GCHandle.Alloc(readBoundBox, GCHandleType.Pinned);
369  Marshal.Copy(readBytes, 0, pinnedHandle.AddrOfPinnedObject(), readBytes.Length);
370  pinnedHandle.Free();
371 
372  currentBoundingBox.vec[0, 0] = readBoundBox.vec00;
373  currentBoundingBox.vec[1, 0] = readBoundBox.vec10;
374  currentBoundingBox.vec[2, 0] = readBoundBox.vec20;
375  currentBoundingBox.vec[3, 0] = readBoundBox.vec30;
376  currentBoundingBox.vec[4, 0] = readBoundBox.vec40;
377  currentBoundingBox.vec[5, 0] = readBoundBox.vec50;
378  currentBoundingBox.vec[6, 0] = readBoundBox.vec60;
379  currentBoundingBox.vec[7, 0] = readBoundBox.vec70;
380  currentBoundingBox.vec[0, 1] = readBoundBox.vec01;
381  currentBoundingBox.vec[1, 1] = readBoundBox.vec11;
382  currentBoundingBox.vec[2, 1] = readBoundBox.vec21;
383  currentBoundingBox.vec[3, 1] = readBoundBox.vec31;
384  currentBoundingBox.vec[4, 1] = readBoundBox.vec41;
385  currentBoundingBox.vec[5, 1] = readBoundBox.vec51;
386  currentBoundingBox.vec[6, 1] = readBoundBox.vec61;
387  currentBoundingBox.vec[7, 1] = readBoundBox.vec71;
388  currentBoundingBox.vec[0, 2] = readBoundBox.vec02;
389  currentBoundingBox.vec[1, 2] = readBoundBox.vec12;
390  currentBoundingBox.vec[2, 2] = readBoundBox.vec22;
391  currentBoundingBox.vec[3, 2] = readBoundBox.vec32;
392  currentBoundingBox.vec[4, 2] = readBoundBox.vec42;
393  currentBoundingBox.vec[5, 2] = readBoundBox.vec52;
394  currentBoundingBox.vec[6, 2] = readBoundBox.vec62;
395  currentBoundingBox.vec[7, 2] = readBoundBox.vec72;
396 
397  }
398 
399  }
400  }
401  }
402 
403  reader.Close();
404  return result;
405  }*/
406 
407  public List<BlenderObjectBlock> readObject()
408  {
409  List<BlenderObjectBlock> result = new List<BlenderObjectBlock>();
410 
411  int objIndex = 0;
412  int startPositionLoc = 0;
413  int startPositionQuat = 0;
414  int startPositionData = 0;
415 
416  //Print name of all Blocks
417  /*foreach (FileBlock fileBlock in FileBockList)
418  {
419  foreach (Structure s in StructureList)
420  {
421  if(fileBlock.SDNAIndex == s.Index)
422  {
423  Debug.LogWarning("File Block: " + s.Name + " SA: " + fileBlock.StartAddess.ToString("X"));
424  }
425  }
426  }
427 
428 
429  foreach (Structure s in StructureList)
430  {
431  if (s.Name == "Base")
432  {
433  foreach (FileBlock fileBlock in FileBockList)
434  {
435  if(fileBlock.SDNAIndex == s.Index)
436  {
437  Debug.LogWarning("Code: " + fileBlock.Code + " Start address: "+ fileBlock.StartAddess.ToString("X"));
438  }
439  }
440  }
441 
442  }*/
443 
444 
445  foreach (Structure s in StructureList)
446  {
447  if (s.Name == "Object") //search index of object structure
448  {
449  objIndex = s.Index;
450  int countLenght = 0;
451  foreach (Field f in s.Fields)
452  {
453  if (f.Name == "loc[3]")
454  {
455  startPositionLoc = countLenght;
456  }
457  else if (f.Name == "quat[4]")
458  {
459  startPositionQuat = countLenght;
460  }
461  else if (f.Name == "*data")
462  {
463  startPositionData = countLenght;
464  }
465  countLenght += f.getLength();
466  }
467  }
468 
469  }
470 
471  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open));
472  foreach (FileBlock fileBlock in FileBockList)
473  {
474  if (fileBlock.SDNAIndex == objIndex)
475  {
476  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + 32;
477  string name = "";
478  for (int i = 0; i < 66; i++)
479  {
480  char c = reader.ReadChar();
481  if (c == 0x0)
482  {
483  break;
484  }
485  name += c;
486  }
487 
488  //Read location
489  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionLoc;
490  float[] loc = new float[3];
491  loc[0] = reader.ReadSingle();
492  loc[1] = reader.ReadSingle();
493  loc[2] = reader.ReadSingle();
494 
495  //Read rotation
496  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionQuat;
497  float[] quat = new float[4];
498  quat[0] = reader.ReadSingle();
499  quat[1] = reader.ReadSingle();
500  quat[2] = reader.ReadSingle();
501  quat[3] = reader.ReadSingle();
502 
503  //Read unique identifier
504  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionData;
505  ulong uniqueIdentifier = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
506 
508  b.objectName = name;
509  b.uniqueIdentifier = uniqueIdentifier;
510  b.location = new Vector3(loc[0], loc[1], loc[2]);
511  b.rotation = new Quaternion(quat[0], quat[1], quat[2], quat[3]);
512  result.Add(b);
513  }
514 
515  }
516  reader.Close();
517  return result;
518  }
519 
520  public List<BlenderMesh> readMesh()
521  {
522  List<BlenderMesh> result = new List<BlenderMesh>();
523 
524  //get information about the structure of a mesh block
525  int indexMesh = 0;
526 
527  int startPositionMVert = -1;
528  //int lengthMVert = 0;
529 
530  int startPositionMPoly = -1;
531  //int lengthMPoly = 0;
532 
533  int startPositionMLoop = -1;
534  //int lengthMLoop = 0;
535 
536  foreach (Structure s in StructureList)
537  {
538  if(s.Name == "Mesh") //search index of mesh structure and start position of *mvert, *mpoly, *mloop in mesh structure
539  {
540  indexMesh = s.Index;
541  int countLenght = 0;
542  foreach(Field f in s.Fields)
543  {
544  if (f.Name == "*mvert")
545  {
546  startPositionMVert = countLenght;
547  }
548  else if (f.Name == "*mpoly")
549  {
550  startPositionMPoly = countLenght;
551  }
552  else if (f.Name == "*mloop")
553  {
554  startPositionMLoop = countLenght;
555  }
556  countLenght += f.getLength();
557  }
558  }
559 
560  /*if(s.Name == "MVert") //search for structure information of MVert
561  {
562  lengthMVert = s.getLength();
563  }
564 
565  if (s.Name == "MPoly") //search for structure information of MPoly
566  {
567  lengthMPoly = s.getLength();
568  }
569 
570  if (s.Name == "MLoop") //search for structure information of MLoop
571  {
572  lengthMLoop = s.getLength();
573  }*/
574 
575  }
576  //read vertices, polys and loops
577  BinaryReader reader = new BinaryReader(File.Open(Filename, FileMode.Open));
578  foreach (FileBlock fileBlock in FileBockList)
579  {
580  if(fileBlock.SDNAIndex == indexMesh) //If the file block contains a mesh
581  {
582  //read name
583  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + 32; //32 because name has an offset of 32 in the ID structure
584  string name = "";
585  for(int i = 0; i < 66; i++)
586  {
587  char c = reader.ReadChar();
588  if(c == 0x0)
589  {
590  break;
591  }
592  name += c;
593  }
594 
595  BlenderMesh currentMesh = new BlenderMesh(name, fileBlock.OldAddess);
596  result.Add(currentMesh);
597 
598  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMVert;
599  ulong mVertAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32(); //pointer to file block with MVert structures
600 
601  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMPoly;
602  ulong mPolyAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32(); //pointer to file block with MEdge structure
603 
604  reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMLoop;
605  ulong mLoopAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32(); //pointer to file block with MEdge structure
606 
607  foreach (FileBlock f in FileBockList)
608  {
609  //Read vertices and normals
610  if (f.OldAddess == mVertAddress)
611  {
612  currentMesh.VertexList = new Vector3[f.Count];
613  currentMesh.NormalList = new Vector3[f.Count];
614 
615  MVert[] readVerts = new MVert[f.Count];
616  reader.BaseStream.Position = f.StartAddess + (PointerSize == 8 ? 24 : 20);
617  byte[] readBytes = reader.ReadBytes(f.Count * Marshal.SizeOf(typeof(MVert)));
618  GCHandle pinnedHandle = GCHandle.Alloc(readVerts, GCHandleType.Pinned);
619  Marshal.Copy(readBytes, 0, pinnedHandle.AddrOfPinnedObject(), readBytes.Length);
620  pinnedHandle.Free();
621 
622  for (int i = 0; i < readVerts.Length; i++)
623  {
624  currentMesh.VertexList[i] = new Vector3(readVerts[i].coX, readVerts[i].coY, readVerts[i].coZ);
625  currentMesh.NormalList[i] = new Vector3(readVerts[i].noX, readVerts[i].noY, readVerts[i].noZ);
626  }
627  }
628  //Read polygon list
629  else if (f.OldAddess == mPolyAddress)
630  {
631  MPoly[] readPoly = new MPoly[f.Count];
632  reader.BaseStream.Position = f.StartAddess + (PointerSize == 8 ? 24 : 20);
633  byte[] readBytes = reader.ReadBytes(f.Count * Marshal.SizeOf(typeof(MPoly)));
634  GCHandle pinnedHandle = GCHandle.Alloc(readPoly, GCHandleType.Pinned);
635  Marshal.Copy(readBytes, 0, pinnedHandle.AddrOfPinnedObject(), readBytes.Length);
636  pinnedHandle.Free();
637 
638  for (int i = 0; i < readPoly.Length; i++)
639  {
640  currentMesh.PolygonList.Add(new PolygonListEntry(readPoly[i].loopstart, readPoly[i].totloop));
641  }
642  }
643  //Read loop list
644  else if (f.OldAddess == mLoopAddress)
645  {
646  currentMesh.LoopList = new int[f.Count];
647 
648  reader.BaseStream.Position = f.StartAddess + (PointerSize == 8 ? 24 : 20);
649  MLoop[] readLoop = new MLoop[f.Count];
650  byte[] readBytes = reader.ReadBytes(f.Count * Marshal.SizeOf(typeof(MLoop)));
651  GCHandle pinnedHandle = GCHandle.Alloc(readLoop, GCHandleType.Pinned);
652  Marshal.Copy(readBytes, 0, pinnedHandle.AddrOfPinnedObject(), readBytes.Length);
653  pinnedHandle.Free();
654 
655  for(int i = 0; i< readLoop.Length; i++)
656  {
657  currentMesh.LoopList[i] = readLoop[i].v;
658  }
659  }
660  }
661  currentMesh.createTriangleList();
662 
663 
664  }
665  }
666 
667  /*foreach(BlenderMesh m in result)
668  {
669  foreach (Vector3 t in m.VertexList)
670  {
671  Debug.Log(t);
672  }
673 
674  foreach (PolygonListEntry t in m.PolygonList)
675  {
676  Debug.Log(t);
677  }
678 
679  foreach (int t in m.LoopList)
680  {
681  Debug.Log(t);
682  }
683  }*/
684 
685  reader.Close();
686  return result;
687  }
688 
689  //Creates a list of lists with BlenderMeshes. The inner list contains multipe BlenderMeshes for one object with max. 2^16 vertices, because of Unitys limitation.
690  public static List<List<UnityMesh>> createSubmeshesForUnity(List<BlenderMesh> blenderMesh)
691  {
692  List<List<UnityMesh>> result = new List<List<UnityMesh>>();
693 
694  //Iterate all complete meshes found in file
695  foreach (BlenderMesh completeBlenderMesh in blenderMesh)
696  {
697 
698  UnityMesh completeMesh = completeBlenderMesh.ToUnityMesh();
699 
700  List<UnityMesh> outterListElement = new List<UnityMesh>();
701  result.Add(outterListElement);
702 
703  int maxVerts = 6000;//65534; //TODO ? magic number, performs well
704  int positionTriangleList = 0;
705  //Go over the complete triangle list of mesh
706  while (positionTriangleList < completeMesh.TriangleList.Length)
707  {
708  UnityMesh newMesh = new UnityMesh(completeMesh.Name, completeMesh.UniqueIdentifier); //Create submesh
709  outterListElement.Add(newMesh);
710  List<Vector3> vertList = new List<Vector3>(); //Create vertices list for submesh
711  List<Vector3> normList = new List<Vector3>(); //Create normal list for submesh
712  List<int> triangles = new List<int>(); //Create triangle list for submesh
713 
714  int[] findVertexIndex = new int[completeMesh.VertexList.Length]; //for optimization, key: vertex index of complete mesh, value: vertex index of new mesh
715  for(int i = 0; i < findVertexIndex.Length; i++) //memset() faster?
716  {
717  findVertexIndex[i] = -1;
718  }
719 
720  //Write vertex, normal and triangle infos in variables until maxVert is reached or end of TriangleList is reached
721  while (vertList.Count < maxVerts - 3 && positionTriangleList < completeMesh.TriangleList.Length)
722  {
723  for(int i = 0; i < 3; i++)
724  {
725  int indexCurrentVertex = completeMesh.TriangleList[positionTriangleList];
726  int newIndex = findVertexIndex[indexCurrentVertex];
727 
728  if (newIndex == -1)
729  {
730  vertList.Add(completeMesh.VertexList[indexCurrentVertex]);
731  normList.Add(completeMesh.NormalList[indexCurrentVertex]);
732  findVertexIndex[indexCurrentVertex] = vertList.Count - 1;
733  triangles.Add(vertList.Count - 1);
734  }
735  else
736  {
737  triangles.Add(newIndex);
738  }
739  positionTriangleList++;
740  }
741  }
742  newMesh.VertexList = vertList.ToArray();
743  newMesh.NormalList = normList.ToArray();
744  newMesh.TriangleList = triangles.ToArray();
745  }
746 
747  }
748  return result;
749  }
750  }
751 }
752