Advertisement
Krythic

Wavefront Model Loader

May 6th, 2016
292
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 11.36 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Runtime.CompilerServices;
  5. using System.Security.Cryptography.X509Certificates;
  6. using System.Threading.Tasks;
  7. using GrimoireTactics.Framework.Maths;
  8. using GrimoireTactics.Framework.OpenGL.Texturing;
  9. using OpenTK;
  10. using OpenTK.Graphics.OpenGL;
  11.  
  12. namespace GrimoireTactics.Framework.OpenGL.Modeling
  13. {
  14.     public class WavefrontModel
  15.     {
  16.         public List<Vector3> Vertices;
  17.         public List<Vector2> TexCoords;
  18.         public List<Vector3> Normals;
  19.         public List<Face> Faces;
  20.         public string ModelSource;
  21.         public string Name;
  22.         public Material Material;
  23.         /// <summary>
  24.         /// A static buffer used by all models when they are loaded.
  25.         /// </summary>
  26.         private static readonly string[] FileBuffer = new string[15];
  27.         /// <summary>
  28.         /// A static buffer used by all models when they are loaded.
  29.         /// </summary>
  30.         private static readonly string[] IndiceBuffer = new string[3];
  31.         /// <summary>
  32.         /// A static buffer used by all models when they are loaded.
  33.         /// </summary>
  34.         private static readonly FaceIndices[] VerticesIndexBuffer = new FaceIndices[3];
  35.         public static readonly WavefrontBufferSettings DefaultBuffer = new WavefrontBufferSettings(300, 300, 300, 300);
  36.  
  37.         /// <summary>
  38.         /// The Triangle Count of this model.
  39.         /// </summary>
  40.         public int TriCount
  41.         {
  42.             get
  43.             {
  44.                 return this.Faces.Count;
  45.             }
  46.         }
  47.  
  48.         public WavefrontModel()
  49.         {
  50.             Initialize(new WavefrontBufferSettings(0, 0, 0, 0));
  51.         }
  52.  
  53.         public WavefrontModel(int buffer)
  54.         {
  55.             Initialize(new WavefrontBufferSettings(buffer,buffer,buffer,buffer));
  56.         }
  57.  
  58.         public WavefrontModel(int verticesBuffer, int texCoordsBuffer, int normalsBuffer, int facesBuffer)
  59.         {
  60.             Initialize(new WavefrontBufferSettings(verticesBuffer,texCoordsBuffer,normalsBuffer,facesBuffer));
  61.         }
  62.  
  63.         public WavefrontModel(string modelPath, Material material)
  64.         {
  65.             this.ModelSource = modelPath;
  66.             this.Material = material;
  67.             Initialize(new WavefrontBufferSettings(0, 0, 0, 0));
  68.         }
  69.  
  70.         public WavefrontModel(string modelPath)
  71.         {
  72.             this.ModelSource = modelPath;
  73.             this.Material = null;
  74.             Initialize(new WavefrontBufferSettings(0,0,0,0));
  75.         }
  76.  
  77.         public WavefrontModel(string modelPath, WavefrontBufferSettings buffers)
  78.         {
  79.             this.ModelSource = modelPath;
  80.             this.Material = null;
  81.             Initialize(buffers);
  82.         }
  83.  
  84.         public WavefrontModel(string modelPath, Material material, WavefrontBufferSettings buffers)
  85.         {
  86.             this.ModelSource = modelPath;
  87.             this.Material = material;
  88.             Initialize(buffers);
  89.         }
  90.  
  91.         private void Initialize(WavefrontBufferSettings buffers)
  92.         {
  93.             this.Vertices = new List<Vector3>(buffers.VerticeBuffer);
  94.             this.TexCoords = new List<Vector2>(buffers.TexCoordBuffer);
  95.             this.Normals = new List<Vector3>(buffers.NormalBuffer);
  96.             this.Faces = new List<Face>(buffers.FacesBuffer);
  97.         }
  98.  
  99.         /// <summary>
  100.         /// Loads a model from the desired Wavefront.obj source given
  101.         /// at constructor initialization.
  102.         /// </summary>
  103.         public void Load()
  104.         {
  105.             Load(this.ModelSource);
  106.         }
  107.  
  108.         /// <summary>
  109.         /// Loads a model from a Wavefront.obj located on disk.
  110.         /// </summary>
  111.         /// <param name="file"></param>
  112.         public void Load(string file)
  113.         {
  114.             Parse(File.ReadAllLines(file));
  115.         }
  116.  
  117.         /// <summary>
  118.         /// Initializes this model with the data provided.
  119.         /// </summary>
  120.         /// <param name="data"></param>
  121.         public void Load(string[] data)
  122.         {
  123.             Parse(data);
  124.         }
  125.  
  126.         /// <summary>
  127.         /// Clears Vertices, TexCoords, Faces, and Normals.
  128.         /// </summary>
  129.         public void ClearData()
  130.         {
  131.             Vertices.Clear();
  132.             TexCoords.Clear();
  133.             Faces.Clear();
  134.             Normals.Clear();
  135.         }
  136.  
  137.         /// <summary>
  138.         /// Current Benchmarked time(Warm boot)
  139.         ///
  140.         /// 244kb Wavefront OBJ (8297 lines)
  141.         /// 00:00:00.0013752
  142.         ///
  143.         /// If you try to optimize this anymore than I already have,
  144.         /// I feel so very, very, very sorry for you. You poor, pathetic soul.
  145.         /// </summary>
  146.         /// <param name="data"></param>
  147.         private void Parse(string[] data)
  148.         {
  149.             int numberOfLinesInFile = data.Length;
  150.             for (int line = 0; line < numberOfLinesInFile; line++)
  151.             {
  152.                 string[] lineTokens = SplitStringFast(data[line], ' ', FileBuffer);
  153.                 switch (lineTokens[0])
  154.                 {
  155.                     case "v": // Vector
  156.                         Vector3 vector = new Vector3
  157.                         {
  158.                             X = ParseFloatFast(lineTokens[1]),
  159.                             Y = ParseFloatFast(lineTokens[2]),
  160.                             Z = ParseFloatFast(lineTokens[3])
  161.                         };
  162.                         Vertices.Add(vector);
  163.                         break;
  164.                     case "vt": // Texture Coordinate
  165.                         Vector2 textureCoordinate = new Vector2
  166.                         {
  167.                             X = ParseFloatFast(lineTokens[1]), // U
  168.                             Y = -ParseFloatFast(lineTokens[2]) // V (Inverted)
  169.                         };
  170.                         TexCoords.Add(textureCoordinate);
  171.                         break;
  172.                     case "vn": // Normal
  173.                         Vector3 normal = new Vector3
  174.                         {
  175.                             X = ParseFloatFast(lineTokens[1]),
  176.                             Y = ParseFloatFast(lineTokens[2]),
  177.                             Z = ParseFloatFast(lineTokens[3])
  178.                         };
  179.                         Normals.Add(normal);
  180.                         break;
  181.                     case "f": // Face (Triangle indices)
  182.                         for (int i = 0; i < 3; i++)
  183.                         {
  184.                             string[] parameters = SplitStringFast(lineTokens[i + 1], '/', IndiceBuffer);
  185.                             FaceIndices indices = new FaceIndices
  186.                             {
  187.                                 Vertex = ParseUInt32Fast(parameters[0]) - 1,
  188.                                 Texture = ParseUInt32Fast(parameters[1]) - 1,
  189.                                 Normal = ParseUInt32Fast(parameters[2]) - 1
  190.                             };
  191.                             VerticesIndexBuffer[i] = indices;
  192.                         }
  193.                         Faces.Add(new Face(VerticesIndexBuffer[0], VerticesIndexBuffer[1], VerticesIndexBuffer[2]));
  194.                         break;
  195.                 }
  196.             }
  197.         }
  198.  
  199.         /// <summary>
  200.         /// A custom implementation of Int32.Parse. This
  201.         /// function is, on average, 5-6x faster than the one
  202.         /// offered by .NET. This function assumes that the string
  203.         /// given will yield a positive integer.
  204.         /// </summary>
  205.         /// <param name="value"></param>
  206.         /// <returns></returns>
  207.         private static int ParseUInt32Fast(string value)
  208.         {
  209.             int result = 0;
  210.             int length = value.Length; // Squeeze out every last drop!
  211.             for (int i = 0; i < length; i++)
  212.             {
  213.                 result = 10 * result + (value[i] - 48);
  214.             }
  215.             return result;
  216.         }
  217.  
  218.         /// <summary>
  219.         /// A custom implementation of String.Split(). Realistically, this
  220.         /// function is not much faster than what .NET offers; it gains speed
  221.         /// more from a preset buffer mechanism.
  222.         /// </summary>
  223.         /// <param name="value"></param>
  224.         /// <param name="delimiter"></param>
  225.         /// <param name="buffer"></param>
  226.         /// <returns></returns>
  227.         private static string[] SplitStringFast(string value, char delimiter, string[] buffer)
  228.         {
  229.             int resultIndex = 0;
  230.             int startIndex = 0;
  231.             int length = value.Length;
  232.             for (int i = 0; i < length; i++)
  233.             {
  234.                 if (value[i] == delimiter)
  235.                 {
  236.                     buffer[resultIndex] = value.Substring(startIndex, i - startIndex);
  237.                     resultIndex++;
  238.                     startIndex = i + 1;
  239.                 }
  240.             }
  241.             buffer[resultIndex] = value.Substring(startIndex, value.Length - startIndex);
  242.             return buffer;
  243.         }
  244.  
  245.         /// <summary>
  246.         /// A custom implementation of Float.Parse. This
  247.         /// function is, on average, 5-6x faster than the one
  248.         /// offered by .NET
  249.         /// </summary>
  250.         /// <param name="inputData">The inputData.</param>
  251.         /// <returns></returns>
  252.         private static float ParseFloatFast(string inputData)
  253.         {
  254.             float result = 0;
  255.             int position = 0;
  256.             int inputLength = inputData.Length;
  257.             char firstCharacter = inputData[0];
  258.             float negativeSign = 1;
  259.             if (firstCharacter == '-')
  260.             {
  261.                 negativeSign = -1;
  262.                 ++position;
  263.             }
  264.             while (true)
  265.             {
  266.                 if (position >= inputLength)
  267.                 {
  268.                     return negativeSign * result;
  269.                 }
  270.                 firstCharacter = inputData[position++];
  271.                 if (firstCharacter < '0' || firstCharacter > '9')
  272.                 {
  273.                     break;
  274.                 }
  275.                 result = (float)((result * 10.0) + (firstCharacter - '0'));
  276.             }
  277.             float exponent = 0.1f;
  278.             while (position < inputLength)
  279.             {
  280.                 firstCharacter = inputData[position++];
  281.                 result += (firstCharacter - '0') * exponent;
  282.                 exponent *= 0.1f;
  283.             }
  284.             return negativeSign * result;
  285.         }
  286.  
  287.         /// <summary>
  288.         /// Renders the Model using deprecated immediate mode. This
  289.         /// function exists only for testing purposes.
  290.         /// </summary>
  291.         public void Render()
  292.         {
  293.             GL.Enable(EnableCap.Texture2D);
  294.             GL.Color3(Material.AmbientColor);
  295.             GL.BindTexture(TextureTarget.Texture2D, Material.Diffuse);
  296.             GL.Begin(PrimitiveType.Triangles);
  297.             for (int i = 0; i < Faces.Count; i++)
  298.             {
  299.                 for (int index = 0; index < Faces[i].Indices.Length; index++)
  300.                 {
  301.                     Vector3 v = Vertices[Faces[i].Indices[index].Vertex];
  302.                     Vector3 n = Normals[Faces[i].Indices[index].Normal];
  303.                     Vector2 tc = TexCoords[Faces[i].Indices[index].Texture];
  304.                     GL.Normal3(n.X, n.Y, n.Z);
  305.                     GL.TexCoord2(tc.X, tc.Y);
  306.                     GL.Vertex3(v.X, v.Y, v.Z);
  307.                 }
  308.             }
  309.             GL.End();
  310.         }
  311.     }
  312. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement