2 using System.Collections.Generic;
4 using System.Runtime.InteropServices;
7 namespace BlenderMeshReader
10 [StructLayout(LayoutKind.Explicit, Pack = 4, Size = 8)]
20 [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 12)]
36 [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 20)]
61 [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 104)]
125 public string objectName;
126 public ulong uniqueIdentifier;
127 public Vector3 location;
128 public Quaternion rotation;
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; }
148 StructureList =
new List<Structure>();
150 BlenderVersionNumber = null;
152 FileBockList = readFileBlockList();
157 StructureList = readDNA1Block(f.StartAddess, f.Size);
163 private void readHeader()
165 if (!File.Exists(Filename))
167 throw new FileNotFoundException(
"File not found.");
170 BinaryReader reader =
new BinaryReader(File.Open(Filename, FileMode.Open ));
172 if(System.Text.Encoding.ASCII.GetString(reader.ReadBytes(7)) !=
"BLENDER")
174 throw new FormatException(
"Wrong file format.");
176 PointerSize = Convert.ToChar(reader.ReadByte()) ==
'-' ? 8 : 4;
177 char end = Convert.ToChar(reader.ReadByte());
178 if ((end !=
'v' && end !=
'V') || (end ==
'v' && !BitConverter.IsLittleEndian) || (end ==
'V' && BitConverter.IsLittleEndian))
180 throw new FormatException(
"Endianness of computer does not match with endianness of file. Open the file in Blender and save it to convert.");
182 BlenderVersionNumber =
new string(
new[] { Convert.ToChar(reader.ReadByte()),
'.', Convert.ToChar(reader.ReadByte()), Convert.ToChar(reader.ReadByte()) });
188 private List<FileBlock> readFileBlockList()
190 List<FileBlock> result =
new List<FileBlock>();
191 BinaryReader reader =
new BinaryReader(File.Open(Filename, FileMode.Open));
193 reader.ReadBytes(12);
195 while (reader.BaseStream.Position < reader.BaseStream.Length)
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();
208 reader.BaseStream.Position = reader.BaseStream.Position + size;
219 private List<Structure> readDNA1Block(
long startAddress,
int size)
222 BinaryReader reader =
new BinaryReader(File.Open(Filename, FileMode.Open));
223 reader.BaseStream.Position = startAddress + (PointerSize == 8 ? 24 : 20) + 4;
226 int numberOfNames = reader.ReadInt32();
227 string[] nameArray =
new string[numberOfNames];
228 for(
int i = 0; i<numberOfNames; i++)
232 while((c = reader.ReadChar()) != 0x0)
239 while (reader.BaseStream.Position % 4 != 0)
241 reader.BaseStream.Position++;
246 int numberOfTypes = reader.ReadInt32();
247 Type[] typeArray =
new Type[numberOfTypes];
248 for (
int i = 0; i < numberOfTypes; i++)
252 while ((c = reader.ReadChar()) != 0x0)
256 typeArray[i] =
new Type(name);
259 while (reader.BaseStream.Position % 4 != 0)
261 reader.BaseStream.Position++;
266 for (
int i = 0; i < numberOfTypes; i++)
268 short s = reader.ReadInt16();
269 typeArray[i].Length = s;
272 while (reader.BaseStream.Position % 4 != 0)
274 reader.BaseStream.Position++;
279 List<Structure> sList =
new List<Structure>();
280 int numberOfStructure = reader.ReadInt32();
281 for (
int i = 0; i < numberOfStructure; i++)
283 short nameIndex = reader.ReadInt16();
286 short numberOfFields = reader.ReadInt16();
287 for(
short s = 0; s< numberOfFields; s++)
289 short indexType = reader.ReadInt16();
290 short indexName = reader.ReadInt16();
291 Field f =
new Field(nameArray[indexName], typeArray[indexType]);
407 public List<BlenderObjectBlock> readObject()
409 List<BlenderObjectBlock> result =
new List<BlenderObjectBlock>();
412 int startPositionLoc = 0;
413 int startPositionQuat = 0;
414 int startPositionData = 0;
447 if (s.Name ==
"Object")
451 foreach (
Field f
in s.Fields)
453 if (f.Name ==
"loc[3]")
455 startPositionLoc = countLenght;
457 else if (f.Name ==
"quat[4]")
459 startPositionQuat = countLenght;
461 else if (f.Name ==
"*data")
463 startPositionData = countLenght;
465 countLenght += f.getLength();
471 BinaryReader reader =
new BinaryReader(File.Open(Filename, FileMode.Open));
472 foreach (
FileBlock fileBlock
in FileBockList)
474 if (fileBlock.SDNAIndex == objIndex)
476 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + 32;
478 for (
int i = 0; i < 66; i++)
480 char c = reader.ReadChar();
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();
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();
504 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionData;
505 ulong uniqueIdentifier = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
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]);
520 public List<BlenderMesh> readMesh()
522 List<BlenderMesh> result =
new List<BlenderMesh>();
527 int startPositionMVert = -1;
530 int startPositionMPoly = -1;
533 int startPositionMLoop = -1;
542 foreach(
Field f
in s.Fields)
544 if (f.Name ==
"*mvert")
546 startPositionMVert = countLenght;
548 else if (f.Name ==
"*mpoly")
550 startPositionMPoly = countLenght;
552 else if (f.Name ==
"*mloop")
554 startPositionMLoop = countLenght;
556 countLenght += f.getLength();
577 BinaryReader reader =
new BinaryReader(File.Open(Filename, FileMode.Open));
578 foreach (
FileBlock fileBlock
in FileBockList)
580 if(fileBlock.SDNAIndex == indexMesh)
583 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + 32;
585 for(
int i = 0; i < 66; i++)
587 char c = reader.ReadChar();
596 result.Add(currentMesh);
598 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMVert;
599 ulong mVertAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
601 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMPoly;
602 ulong mPolyAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
604 reader.BaseStream.Position = fileBlock.StartAddess + (PointerSize == 8 ? 24 : 20) + startPositionMLoop;
605 ulong mLoopAddress = PointerSize == 8 ? reader.ReadUInt64() : reader.ReadUInt32();
610 if (f.OldAddess == mVertAddress)
612 currentMesh.VertexList =
new Vector3[f.Count];
613 currentMesh.NormalList =
new Vector3[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);
622 for (
int i = 0; i < readVerts.Length; i++)
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);
629 else if (f.OldAddess == mPolyAddress)
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);
638 for (
int i = 0; i < readPoly.Length; i++)
640 currentMesh.PolygonList.Add(
new PolygonListEntry(readPoly[i].loopstart, readPoly[i].totloop));
644 else if (f.OldAddess == mLoopAddress)
646 currentMesh.LoopList =
new int[f.Count];
648 reader.BaseStream.Position = f.StartAddess + (PointerSize == 8 ? 24 : 20);
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);
655 for(
int i = 0; i< readLoop.Length; i++)
657 currentMesh.LoopList[i] = readLoop[i].v;
661 currentMesh.createTriangleList();
690 public static List<List<UnityMesh>> createSubmeshesForUnity(List<BlenderMesh> blenderMesh)
692 List<List<UnityMesh>> result =
new List<List<UnityMesh>>();
695 foreach (
BlenderMesh completeBlenderMesh
in blenderMesh)
698 UnityMesh completeMesh = completeBlenderMesh.ToUnityMesh();
700 List<UnityMesh> outterListElement =
new List<UnityMesh>();
701 result.Add(outterListElement);
704 int positionTriangleList = 0;
706 while (positionTriangleList < completeMesh.TriangleList.Length)
709 outterListElement.Add(newMesh);
710 List<Vector3> vertList =
new List<Vector3>();
711 List<Vector3> normList =
new List<Vector3>();
712 List<int> triangles =
new List<int>();
714 int[] findVertexIndex =
new int[completeMesh.VertexList.Length];
715 for(
int i = 0; i < findVertexIndex.Length; i++)
717 findVertexIndex[i] = -1;
721 while (vertList.Count < maxVerts - 3 && positionTriangleList < completeMesh.TriangleList.Length)
723 for(
int i = 0; i < 3; i++)
725 int indexCurrentVertex = completeMesh.TriangleList[positionTriangleList];
726 int newIndex = findVertexIndex[indexCurrentVertex];
730 vertList.Add(completeMesh.VertexList[indexCurrentVertex]);
731 normList.Add(completeMesh.NormalList[indexCurrentVertex]);
732 findVertexIndex[indexCurrentVertex] = vertList.Count - 1;
733 triangles.Add(vertList.Count - 1);
737 triangles.Add(newIndex);
739 positionTriangleList++;
742 newMesh.VertexList = vertList.ToArray();
743 newMesh.NormalList = normList.ToArray();
744 newMesh.TriangleList = triangles.ToArray();