title: Inconsistent Model Texturing In OpenGL/OpenTK
body: <p>I am creating a Model Importer which converts .obj's to my own proprietary format, that will be used for the game I am creating. My model parser appeared to work just fine at first, loading small models from various games like Legend of Zelda, but for whatever reason, fails at correctly texturing advanced models, like Claptrap from Borderlands. Here are some screen grabs to show you what I mean:</p>
  
  <p>The model loader working with a zelda model:
  <a href="https://i.stack.imgur.com/r3BGU.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/r3BGU.png" alt="enter image description here"></a></p>
  
  <p>And then there is Claptrap NOT being textured correctly:
  <a href="https://i.stack.imgur.com/D35pY.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/D35pY.png" alt="enter image description here"></a></p>
  
  <p>Despite the fact that it is textured just fine in Blender:
  <a href="https://i.stack.imgur.com/K3QcO.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/K3QcO.png" alt="enter image description here"></a></p>
  
  <p>I don't understand this, nor do I know where the error is coming from. Here is the code for my WavefrontParser, which may yield some unforeseen bug for larger models that I am not aware of:</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.IO;
  using OpenTK;
  using StardustModeling.Modeling.DataTypes;
  
  namespace StardustModeling.Modeling.Parsers
  {
      /// &lt;summary&gt;
      /// 
      /// Stardust Engine
      /// 
      /// A simple, lightweight WavefrontModel Parser. This
      /// class serves as the basis for the Stardust Model
      /// conversion wizard. All Stardust Models(.sdm) start
      /// out as .obj files; this class is how we load them
      /// before the conversion to .sdm begins.
      /// 
      /// Original Author: Gordon Kyle Wallace, "Krythic"
      /// 
      /// &lt;/summary&gt;
      public static class WavefrontModelParser
      {
          /// &lt;summary&gt;
          /// Parses a Wavefront .obj file. The given
          /// file must be triangulated and have normals
          /// included during exportation from Blender.
          /// &lt;/summary&gt;
          /// &lt;param name="path"&gt;The path of the .obj on disk&lt;/param&gt;
          /// &lt;returns&gt;A WavefrontModel Instance&lt;/returns&gt;
          public static WavefrontModel Parse( string path )
          {
              WavefrontModel model = new WavefrontModel();
              VertexIndex[] verticesIndex;
              string[] wavefrontFileData = File.ReadAllLines( path );
              int loopLength = wavefrontFileData.Length; // Squeeze out every last drop!
              for( int lines = 0; lines &lt; loopLength; lines++ )
              {
                  string[] lineTokens = wavefrontFileData[ lines ].Split( ' ' );
                  switch( lineTokens[ 0 ] )
                  {
                      case "v": // Vector
                          float x = Single.Parse( lineTokens[ 1 ] );
                          float y = Single.Parse( lineTokens[ 2 ] );
                          float z = Single.Parse( lineTokens[ 3 ] );
                          model.Vertices.Add( new Vector3( x , y , z ) );
                          break;
                      case "vt": // Texture Coordinate
                          float u = Single.Parse( lineTokens[ 1 ] );
                          float v = Single.Parse( lineTokens[ 2 ] );
                          model.TexCoords.Add( new Vector2( u , v ) );
                          break;
                      case "vn": // Normal
                          float normalX = Single.Parse( lineTokens[ 1 ] );
                          float normalY = Single.Parse( lineTokens[ 2 ] );
                          float normalZ = Single.Parse( lineTokens[ 3 ] );
                          model.Normals.Add( new Vector3( normalX , normalY , normalZ ) );
                          break;
                      case "f":
                          verticesIndex = new VertexIndex[ 3 ];
                          for( int i = 0; i &lt; 3; i++ )
                          {
                              string[] parameters = lineTokens[ i + 1 ].Split( '/' );
                              int vertice = Int32.Parse( parameters[ 0 ] ) - 1;
                              int texture = Int32.Parse( parameters[ 1 ] ) - 1;
                              int normal = Int32.Parse( parameters[ 2 ] ) - 1;
                              verticesIndex[ i ] = new VertexIndex( vertice , normal , texture );
                          }
                          model.Faces.Add( new Face( verticesIndex ) );
                          break;
                  }
              }
              return model;
          }
      }
  }
  </code></pre>
  
  <p>My WavefrontModel class:</p>
  
  <pre><code>using System.Collections.Generic;
  using OpenTK;
  using StardustModeling.Modeling.Parsers;
  
  namespace StardustModeling.Modeling.DataTypes
  {
      public class WavefrontModel
      {
          public List&lt;Vector3&gt; Vertices;
          public List&lt;Vector2&gt; TexCoords;
          public List&lt;Vector3&gt; Normals;
          public List&lt;Face&gt; Faces;
          public string ModelSource;
  
          public int TotalTriangles
          {
              get
              {
                  return this.Vertices.Count/3;
              }
          }
  
          public WavefrontModel()
          {
              this.Vertices = new List&lt;Vector3&gt;();
              this.TexCoords = new List&lt;Vector2&gt;();
              this.Normals = new List&lt;Vector3&gt;();
              this.Faces = new List&lt;Face&gt;();
          }
  
          public WavefrontModel(int buffer)
          {
              this.Vertices = new List&lt;Vector3&gt;(buffer);
              this.TexCoords = new List&lt;Vector2&gt;(buffer);
              this.Normals = new List&lt;Vector3&gt;(buffer);
              this.Faces = new List&lt;Face&gt;(buffer);
          }
  
          public WavefrontModel(string modelPath, bool loadImmediately)
          {
              this.ModelSource = modelPath;
              if (loadImmediately)
              {
                  Load();
              }
          }
  
          private void Load()
          {
              WavefrontModel model = WavefrontModelParser.Parse(ModelSource);
              this.Vertices = model.Vertices;
              this.TexCoords = model.TexCoords;
              this.Normals = model.Normals;
              this.Faces = model.Faces;
          }
      }
  
  }
  </code></pre>
  
  <p>And my Material class, which may also yield a mistake:</p>
  
  <pre><code>using System.Drawing;
  using System.Drawing.Imaging;
  using OpenTK.Graphics.OpenGL;
  using PixelFormat = OpenTK.Graphics.OpenGL.PixelFormat;
  
  namespace StardustFramework.Framework.OpenGL.Texturing
  {
      public enum MaterialType
      {
          /// &lt;summary&gt;
          /// Represents a Diffuse Texture
          /// &lt;/summary&gt;
          Diffuse,
          /// &lt;summary&gt;
          /// Represents a Normal Texture
          /// &lt;/summary&gt;
          Normal
      }
  
      public class Material
      {
          /// &lt;summary&gt;
          /// The name of the Material
          /// &lt;/summary&gt;
          public string Name;
          /// &lt;summary&gt;
          /// The Diffuse Texture
          /// &lt;/summary&gt;
          public int Diffuse;
          /// &lt;summary&gt;
          /// The Normal Texture
          /// &lt;/summary&gt;
          public int NormalMap;
          /// &lt;summary&gt;
          /// The Ambient Color for the Material
          /// &lt;/summary&gt;
          public Color AmbientColor;
  
          public Material( string materialName )
          {
              this.Name = materialName;
              this.AmbientColor = Color.White;
              this.Diffuse = 0;
              this.NormalMap = 0;
          }
  
          /// &lt;summary&gt;
          /// Loads a Bitmap as a Diffuse texture.
          /// &lt;/summary&gt;
          /// &lt;param name="bitmap"&gt;The bitmap.&lt;/param&gt;
          public void LoadDiffuse( Bitmap bitmap)
          {
              GL.Enable( EnableCap.Texture2D );
              //GL.Hint( HintTarget.PerspectiveCorrectionHint , HintMode.Nicest );
              GL.GenTextures( 1 , out Diffuse );
              GL.BindTexture( TextureTarget.Texture2D , Diffuse );
              GL.TexParameter( TextureTarget.Texture2D , TextureParameterName.TextureMinFilter , ( int )TextureMinFilter.Nearest );
              GL.TexParameter( TextureTarget.Texture2D , TextureParameterName.TextureMagFilter , ( int )TextureMagFilter.Nearest );
              BitmapData data = bitmap.LockBits( new Rectangle( 0 , 0 , bitmap.Width , bitmap.Height ) ,
                  ImageLockMode.ReadOnly , System.Drawing.Imaging.PixelFormat.Format32bppArgb );
              GL.TexImage2D( TextureTarget.Texture2D , 0 , PixelInternalFormat.Rgba , data.Width , data.Height , 0 ,
                  PixelFormat.Bgra , PixelType.UnsignedByte , data.Scan0 );
              bitmap.UnlockBits( data );
              GL.BindTexture( TextureTarget.Texture2D , 0 );
          }
      }
  }
  </code></pre>
  
  <p>I would really like it if someone could help me spot this bug; I am starting to tear my hair out(which I don't have to begin with, lol).</p>
  
  <p>EDIT:</p>
  
  <p>I forgot to mention how I am rendering this. I use OpenTK/OpenGL, and draw via immediate mode(for initial application testing).</p>
  
  <pre><code>private void DrawMesh( WavefrontModel m )
          {
  
              GL.Enable( EnableCap.Texture2D );
              GL.Color3( _modelMaterial.AmbientColor );
              if( _modelMaterial.Diffuse &gt; 0 )
              {
                  GL.BindTexture( TextureTarget.Texture2D , _modelMaterial.Diffuse );
              }
              GL.Begin( PrimitiveType.Triangles );
              for( int i = 0; i &lt; m.Faces.Count; i++ )
              {
                  for( int index = 0; index &lt; m.Faces[ i ].Indices.Length; index++ )
                  {
                      Vector3 v = m.Vertices[ m.Faces[ i ].Indices[ index ].Vector ];
                      Vector3 n = m.Normals[ m.Faces[ i ].Indices[ index ].Normal ];
                      Vector2 tc = m.TexCoords[ m.Faces[ i ].Indices[ index ].TextureCoordinateIndex ];
                      GL.Normal3( n.X , n.Y , n.Z );
                      GL.TexCoord2( tc.X , tc.Y );
                      GL.Vertex3( v.X , v.Y , v.Z );
                  }
              }
              GL.End();
          }
  </code></pre>