Guest User

Untitled

a guest
Oct 20th, 2018
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.30 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.InteropServices;
  5. using System.Text;
  6.  
  7. using OpenTK;
  8. using OpenTK.Graphics.OpenGL;
  9.  
  10. using TopHat.Graphics;
  11.  
  12. namespace TopHat.IO
  13. {
  14. public static class IqmParser
  15. {
  16. private enum IqmAttributeType
  17. {
  18. Position = 0,
  19. TexCoord = 1,
  20. Normal = 2,
  21. Tangent = 3,
  22. BlendIndexes = 4,
  23. BlendWeights = 5,
  24. Color = 6,
  25. Custom = 0x10
  26. }
  27.  
  28. private enum IqmDataFormat
  29. {
  30. Byte = 0,
  31. UnsignedByte = 1,
  32. Short = 2,
  33. UnsignedShort = 3,
  34. Int = 4,
  35. UnsignedInt = 5,
  36. Half = 6,
  37. Float = 7,
  38. Double = 8
  39. }
  40.  
  41. private enum IqmAnimationType
  42. {
  43. Loop = 1 << 0
  44. }
  45.  
  46. /// <summary>
  47. /// The header at the top of every IQM file.
  48. /// </summary>
  49. [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)]
  50. private struct IqmHeader
  51. {
  52. /// <summary>
  53. /// The identifier for an IQM file - "INTERQUAKEMODEL\0".
  54. /// </summary>
  55. [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
  56. public string Magic;
  57.  
  58. /// <summary>
  59. /// The version of the file. Must be at version 2 to work.
  60. /// </summary>
  61. public uint Version;
  62.  
  63. /// <summary>
  64. /// Size of the file.
  65. /// </summary>
  66. public uint FileSize;
  67.  
  68. /// <summary>
  69. /// File flags. There's nothing in the specification about the meaning of this field.
  70. /// </summary>
  71. public uint Flags;
  72.  
  73. public uint TextCount;
  74. public uint TextOffset;
  75.  
  76. public uint MeshesCount;
  77. public uint MeshesOffset;
  78.  
  79. public uint VertexArraysCount;
  80. public uint VertexesCount;
  81. public uint VertexArraysOffset;
  82.  
  83. public uint TrianglesCount;
  84. public uint TrianglesOffset;
  85. public uint AdjacencyOffset;
  86.  
  87. public uint JointsCount;
  88. public uint JointsOffset;
  89.  
  90. public uint PosesCount;
  91. public uint PosesOffset;
  92.  
  93. public uint AnimationsCount;
  94. public uint AnimationsOffset;
  95.  
  96. public uint FramesCount;
  97. public uint FrameChannelsCount;
  98. public uint FramesOffset;
  99. public uint BoundsOffset;
  100.  
  101. public uint CommentCount;
  102. public uint CommentOffset;
  103.  
  104. public uint ExtensionsCount;
  105. public uint ExtensionsOffset;
  106.  
  107. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmHeader)); } }
  108. }
  109.  
  110. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  111. private struct IqmMesh
  112. {
  113. public uint Name;
  114. public uint Material;
  115.  
  116. public uint FirstVertex;
  117. public uint VertexesCount;
  118.  
  119. public uint FirstTriangle;
  120. public uint TrianglesCount;
  121.  
  122. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmMesh)); } }
  123. }
  124.  
  125. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  126. private struct IqmTriangle
  127. {
  128. public uint Vertex0;
  129. public uint Vertex1;
  130. public uint Vertex2;
  131.  
  132. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmTriangle)); } }
  133. }
  134.  
  135. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  136. private struct IqmAdjacency
  137. {
  138. public uint Triangle0;
  139. public uint Triangle1;
  140. public uint Triangle2;
  141.  
  142. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmAdjacency)); } }
  143. }
  144.  
  145. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  146. private struct IqmJoint
  147. {
  148. public uint Name;
  149. public int Parent;
  150.  
  151. public Vector3 Translate;
  152. public Quaternion Rotate;
  153. public Vector3 Scale;
  154.  
  155. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmJoint)); } }
  156. }
  157.  
  158. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  159. private struct IqmPose
  160. {
  161. public int Parent;
  162. public uint Mask;
  163.  
  164. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
  165. public float[] ChannelOffset;
  166.  
  167. [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)]
  168. public float[] ChannelScale;
  169.  
  170. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmPose)); } }
  171. }
  172.  
  173. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  174. private struct IqmAnimation
  175. {
  176. public uint Name;
  177.  
  178. public uint FirstFrame;
  179. public uint FramesCount;
  180.  
  181. public float Framerate;
  182.  
  183. public uint Flags;
  184.  
  185. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmAnimation)); } }
  186. }
  187.  
  188. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  189. private struct IqmVertexArray
  190. {
  191. public IqmAttributeType Type;
  192. public uint Flags;
  193. public IqmDataFormat Format;
  194. public uint Size;
  195. public uint Offset;
  196.  
  197. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmVertexArray)); } }
  198. }
  199.  
  200. [StructLayout(LayoutKind.Sequential, Pack = 1)]
  201. private struct IqmBounds
  202. {
  203. public Vector3 BBMin;
  204. public Vector3 BBMax;
  205.  
  206. public float XYRadius;
  207. public float Radius;
  208.  
  209. public static int SizeInBytes { get { return Marshal.SizeOf(typeof(IqmBounds)); } }
  210. }
  211.  
  212. public static Drawable Parse(string path)
  213. {
  214. if (!File.Exists(path))
  215. throw new ArgumentException("The file \"" + path + "\" does not exist.", "path");
  216.  
  217. List<string> text;
  218. List<IqmMesh> meshes;
  219. List<IqmVertexArray> vertexArrays;
  220. List<IqmTriangle> triangles;
  221. List<IqmAdjacency> adjacency;
  222. List<IqmJoint> joints;
  223. List<IqmPose> poses;
  224. List<IqmAnimation> animations;
  225. //TODO matrix3x4 for frames.
  226. IqmBounds bounds;
  227.  
  228. List<VertexAttribute> attributes = new List<VertexAttribute>();
  229.  
  230. using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read))
  231. {
  232. using (BinaryReader reader = new BinaryReader(fs))
  233. {
  234. //make sure the file is long enough to parse a header before we check the other requirements.
  235. if (fs.Length < IqmHeader.SizeInBytes)
  236. throw new ArgumentException("The file \"" + path + "\" is not an IQM file.", "path");
  237.  
  238. //parse the header and check for magic number match, file size match, and version match.
  239. IqmHeader header = ParseHeader(reader);
  240.  
  241. if (header.Magic != "INTERQUAKEMODEL")
  242. throw new ArgumentException("The file \"" + path + "\" is not an IQM file.", "path");
  243.  
  244. if (header.FileSize != fs.Length)
  245. throw new DataCorruptionException("The file \"" + path + "\" is invalid or corrupted. The file size doesn't match the size reported in the header.");
  246.  
  247. if (header.Version != 2)
  248. throw new OutdatedClientException("The file \"" + path + "\" is using a different version of the IQM specification. Make sure to compile the model as version 2.");
  249.  
  250. //Parse text
  251. if (header.TextOffset != 0)
  252. text = ParseText(reader, (int)header.TextOffset, (int)header.TextCount);
  253. else
  254. text = new List<string>();
  255.  
  256. //Parse meshes
  257. if (header.MeshesOffset != 0)
  258. meshes = ParseMeshes(reader, (int)header.MeshesOffset, (int)header.MeshesCount);
  259. else
  260. meshes = new List<IqmMesh>();
  261.  
  262. //Parse vertexarrays
  263. if (header.VertexArraysOffset != 0)
  264. vertexArrays = ParseVertexArrays(reader, (int)header.VertexArraysOffset, (int)header.VertexArraysCount);
  265. else
  266. vertexArrays = new List<IqmVertexArray>();
  267.  
  268. //Parse triangles
  269. if (header.TrianglesOffset != 0)
  270. triangles = ParseTriangles(reader, (int)header.TrianglesOffset, (int)header.TrianglesCount);
  271. else
  272. triangles = new List<IqmTriangle>();
  273.  
  274. //Parse adjacency
  275. if (header.AdjacencyOffset != 0)
  276. adjacency = ParseAdjacency(reader, (int)header.AdjacencyOffset, (int)header.TrianglesCount);
  277. else
  278. adjacency = new List<IqmAdjacency>();
  279.  
  280. //Parse joints
  281. if (header.JointsOffset != 0)
  282. joints = ParseJoints(reader, (int)header.JointsOffset, (int)header.JointsCount);
  283. else
  284. joints = new List<IqmJoint>();
  285.  
  286. //Parse poses
  287. if (header.PosesOffset != 0)
  288. poses = ParsePoses(reader, (int)header.PosesOffset, (int)header.PosesCount);
  289. else
  290. poses = new List<IqmPose>();
  291.  
  292. //Parse animations
  293. if (header.AnimationsOffset != 0)
  294. animations = ParseAnimations(reader, (int)header.AnimationsOffset, (int)header.AnimationsCount);
  295. else
  296. animations = new List<IqmAnimation>();
  297.  
  298. //Parse frames
  299.  
  300. //Parse bounds
  301. if (header.BoundsOffset != 0)
  302. bounds = ParseBounds(reader, (int)header.BoundsOffset);
  303.  
  304. //Parse vertices
  305. for (int i = 0; i < header.VertexArraysCount; i++)
  306. {
  307. IqmVertexArray va = vertexArrays[i];
  308.  
  309. if ((int)va.Type > 3) //HACK no animation stuff set up yet.
  310. continue;
  311.  
  312. IBuffer buf = Resources.CreateBuffer();
  313.  
  314. reader.BaseStream.Position = va.Offset;
  315. buf.SetData(reader.ReadBytes((int)va.Size * SizeOfIqmFormat(va.Format) * (int)header.VertexesCount), BufferUsageHint.StaticDraw);
  316. attributes.Add(new VertexAttribute(buf, (int)va.Size, 0, 0, ConvertIqmFormat(va.Format), ConvertIqmAttribute(va.Type)));
  317. }
  318.  
  319. Drawable d = new Drawable(attributes);
  320. d.DrawMode = BeginMode.Triangles;
  321.  
  322. //Parse indices
  323. IBuffer indBuf = Resources.CreateBuffer();
  324. indBuf.SetData(triangles.ToArray(), BufferUsageHint.StaticDraw);
  325.  
  326. d.IndexBuffer = indBuf;
  327. d.IndexType = DrawElementsType.UnsignedInt;
  328. d.IndexCount = triangles.Count * 3;
  329.  
  330. return d;
  331. }
  332. }
  333. }
  334.  
  335. private unsafe static IqmHeader ParseHeader(BinaryReader reader)
  336. {
  337. byte[] headerData = reader.ReadBytes(IqmHeader.SizeInBytes);
  338.  
  339. fixed (byte* headerPtr = headerData)
  340. return PtrToStructure<IqmHeader>(headerPtr);
  341. }
  342.  
  343. private static List<string> ParseText(BinaryReader reader, int position, int count)
  344. {
  345. List<string> text = new List<string>();
  346. StringBuilder builder = new StringBuilder();
  347.  
  348. reader.BaseStream.Position = position;
  349.  
  350. for (int i = 0; i < count; i++)
  351. {
  352. byte nextByte = reader.ReadByte();
  353. builder.Append((char)nextByte);
  354.  
  355. if (nextByte == 0)
  356. {
  357. text.Add(builder.ToString());
  358. builder.Clear();
  359. }
  360. }
  361.  
  362. return text;
  363. }
  364.  
  365. private unsafe static List<IqmMesh> ParseMeshes(BinaryReader reader, int position, int count)
  366. {
  367. List<IqmMesh> meshes = new List<IqmMesh>(count);
  368.  
  369. reader.BaseStream.Position = position;
  370.  
  371. for (int i = 0; i < count; i++)
  372. fixed (byte* meshPtr = reader.ReadBytes(IqmMesh.SizeInBytes))
  373. meshes.Add(PtrToStructure<IqmMesh>(meshPtr));
  374.  
  375. return meshes;
  376. }
  377.  
  378. private unsafe static List<IqmVertexArray> ParseVertexArrays(BinaryReader reader, int position, int count)
  379. {
  380. List<IqmVertexArray> vertexArrays = new List<IqmVertexArray>(count);
  381.  
  382. reader.BaseStream.Position = position;
  383.  
  384. for (int i = 0; i < count; i++)
  385. fixed (byte* vertexArrayPtr = reader.ReadBytes(IqmVertexArray.SizeInBytes))
  386. vertexArrays.Add(PtrToStructure<IqmVertexArray>(vertexArrayPtr));
  387.  
  388. return vertexArrays;
  389. }
  390.  
  391. private unsafe static List<IqmTriangle> ParseTriangles(BinaryReader reader, int position, int count)
  392. {
  393. List<IqmTriangle> triangles = new List<IqmTriangle>(count);
  394.  
  395. reader.BaseStream.Position = position;
  396.  
  397. for (int i = 0; i < count; i++)
  398. fixed (byte* trianglePtr = reader.ReadBytes(IqmTriangle.SizeInBytes))
  399. triangles.Add(PtrToStructure<IqmTriangle>(trianglePtr));
  400.  
  401. return triangles;
  402. }
  403.  
  404. private unsafe static List<IqmAdjacency> ParseAdjacency(BinaryReader reader, int position, int count)
  405. {
  406. List<IqmAdjacency> adjacency = new List<IqmAdjacency>(count);
  407.  
  408. reader.BaseStream.Position = position;
  409.  
  410. for (int i = 0; i < count; i++)
  411. fixed (byte* adjacencyPtr = reader.ReadBytes(IqmAdjacency.SizeInBytes))
  412. adjacency.Add(PtrToStructure<IqmAdjacency>(adjacencyPtr));
  413.  
  414. return adjacency;
  415. }
  416.  
  417. private unsafe static List<IqmJoint> ParseJoints(BinaryReader reader, int position, int count)
  418. {
  419. List<IqmJoint> joints = new List<IqmJoint>(count);
  420.  
  421. reader.BaseStream.Position = position;
  422.  
  423. for (int i = 0; i < count; i++)
  424. fixed (byte* jointPtr = reader.ReadBytes(IqmJoint.SizeInBytes))
  425. joints.Add(PtrToStructure<IqmJoint>(jointPtr));
  426.  
  427. return joints;
  428. }
  429.  
  430. private unsafe static List<IqmPose> ParsePoses(BinaryReader reader, int position, int count)
  431. {
  432. List<IqmPose> poses = new List<IqmPose>(count);
  433.  
  434. reader.BaseStream.Position = position;
  435.  
  436. for (int i = 0; i < count; i++)
  437. fixed (byte* posePtr = reader.ReadBytes(IqmPose.SizeInBytes))
  438. poses.Add(PtrToStructure<IqmPose>(posePtr));
  439.  
  440. return poses;
  441. }
  442.  
  443. private unsafe static List<IqmAnimation> ParseAnimations(BinaryReader reader, int position, int count)
  444. {
  445. List<IqmAnimation> animations = new List<IqmAnimation>(count);
  446.  
  447. reader.BaseStream.Position = position;
  448.  
  449. for (int i = 0; i < count; i++)
  450. fixed (byte* animationPtr = reader.ReadBytes(IqmAnimation.SizeInBytes))
  451. animations.Add(PtrToStructure<IqmAnimation>(animationPtr));
  452.  
  453. return animations;
  454. }
  455.  
  456. private unsafe static IqmBounds ParseBounds(BinaryReader reader, int position)
  457. {
  458. reader.BaseStream.Position = position;
  459.  
  460. fixed (byte* boundsPtr = reader.ReadBytes(IqmBounds.SizeInBytes))
  461. return PtrToStructure<IqmBounds>(boundsPtr);
  462. }
  463.  
  464. private unsafe static T PtrToStructure<T>(byte* data)
  465. where T : struct
  466. {
  467. return (T)Marshal.PtrToStructure((IntPtr)data, typeof(T));
  468. }
  469.  
  470. private static AttributeType ConvertIqmAttribute(IqmAttributeType type)
  471. {
  472. switch (type)
  473. {
  474. case IqmAttributeType.Position:
  475. return AttributeType.Position;
  476. case IqmAttributeType.TexCoord:
  477. return AttributeType.TexCoord;
  478. case IqmAttributeType.Normal:
  479. return AttributeType.Normal;
  480. case IqmAttributeType.Tangent:
  481. return AttributeType.Tangent;
  482. default:
  483. return AttributeType.Position; //return 0.
  484. }
  485. }
  486.  
  487. private static VertexAttribPointerType ConvertIqmFormat(IqmDataFormat format)
  488. {
  489. switch (format)
  490. {
  491. case IqmDataFormat.Byte:
  492. return VertexAttribPointerType.Byte;
  493. case IqmDataFormat.Double:
  494. return VertexAttribPointerType.Double;
  495. case IqmDataFormat.Float:
  496. return VertexAttribPointerType.Float;
  497. case IqmDataFormat.Half:
  498. return VertexAttribPointerType.HalfFloat;
  499. case IqmDataFormat.Int:
  500. return VertexAttribPointerType.Int;
  501. case IqmDataFormat.Short:
  502. return VertexAttribPointerType.Short;
  503. case IqmDataFormat.UnsignedByte:
  504. return VertexAttribPointerType.UnsignedByte;
  505. case IqmDataFormat.UnsignedInt:
  506. return VertexAttribPointerType.UnsignedInt;
  507. case IqmDataFormat.UnsignedShort:
  508. return VertexAttribPointerType.UnsignedShort;
  509. default:
  510. return VertexAttribPointerType.Float;
  511. }
  512. }
  513.  
  514. private static int SizeOfIqmFormat(IqmDataFormat format)
  515. {
  516. switch (format)
  517. {
  518. case IqmDataFormat.Byte:
  519. case IqmDataFormat.UnsignedByte:
  520. return 1;
  521. case IqmDataFormat.Half:
  522. case IqmDataFormat.Short:
  523. case IqmDataFormat.UnsignedShort:
  524. return 2;
  525. case IqmDataFormat.Float:
  526. case IqmDataFormat.Int:
  527. case IqmDataFormat.UnsignedInt:
  528. return 4;
  529. case IqmDataFormat.Double:
  530. return 8;
  531. default:
  532. return 0;
  533. }
  534. }
  535. }
  536. }
Add Comment
Please, Sign In to add comment