title: How is android opengl texture-mapping affected by vertex order?
body: <p>I'm trying to understand the correct way to apply a texture mapping to an opengl triangle, on the android platform.
  I found a weird behaviour: it seems that the texture mapping get affected by the order in which i specify the vertex.</p>
  
  <p>Here is the concrete problem. In this picture you can see the texture, the triangle and the desired mapping: (i had to combine the 2 images into a single link, sorry)</p>
  
  <p><a href="http://www.flickr.com/photos/21134083@N07/5398416606/" rel="nofollow">combined images</a></p>
  
  <p>The actual texture picture is a 2x2 png.</p>
  
  <p>The code is subdivided basically in 2 classes: the renderer and the model.</p>
  
  <ul>
  <li>The renderer</li>
  </ul>
  
  <p>This is the opengl initialization (there are many things in here that i still didn't fully understand, i just adopted this code from an example:</p>
  
  <pre><code>[...]
  public void onSurfaceCreated(GL10 gl, EGLConfig config)
  {
      glDisable(GL_DITHER);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_AMBIENT, lightAmbientBuffer);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_DIFFUSE, lightDiffuseBuffer);
      gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, lightPositionBuffer);
      gl.glEnable(GL10.GL_LIGHT0);
  
      gl.glShadeModel(GL10.GL_SMOOTH);
      gl.glClearColor(0.0f, 0.5f, 0.5f, 1f);
  
      // per rimuovere superfici nascoste
      gl.glClearDepthf(1.0f);
      gl.glEnable(GL10.GL_DEPTH_TEST);
      gl.glDepthFunc(GL10.GL_LEQUAL);
  
      gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
  
      // caricamento texture
      glEnable(GL_TEXTURE_2D);
      int[] textures = new int[1];
      gl.glGenTextures(1, textures, 0);
  
      textureId = textures[0];
      gl.glBindTexture(GL_TEXTURE_2D, textureId);
  
      gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
      gl.glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
      gl.glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  
      for (Drawable m : models) { // the models are kept in a Vector 
          if (m.getTextureLoader() != null)
              m.getTextureLoader().load(gl);
      }
  }
  </code></pre>
  
  <p>And here the frame rendering function (the actual drawing gets done in the m.draw(gl) call):</p>
  
  <pre><code>public void onDrawFrame(GL10 gl)
  {
      glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
              GL_MODULATE);
  
      // Clear Screen And Depth Buffer
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
      gl.glLoadIdentity();
      gl.glEnable(GL10.GL_LIGHTING);
      gl.glTranslatef(0.0f, -1.2f, -z); // just a little translation in order to see the complete drawing
      glActiveTexture(GL_TEXTURE0);
      glBindTexture(GL_TEXTURE_2D, textureId);
  
      gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gl.GL_CLAMP_TO_EDGE);
      gl.glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gl.GL_CLAMP_TO_EDGE);
  
      for (Drawable m : models) {
          m.draw(gl);
      }
  
      gl.glLoadIdentity();
  }
  </code></pre>
  
  <ul>
  <li>The model</li>
  </ul>
  
  <p>Here is the model class:</p>
  
  <pre><code>public class OneTriangle implements Drawable {
  
      Context     context;
      FloatBuffer textureMappingBuffer;
      FloatBuffer vertexBuffer;
      ShortBuffer facesIdxBuffer;
  
      public OneTriangle(Context context) {
          this.context = context;
          float[] v = {
                  -2, 2, 0, //A
                  2, 2, 0,//B
                  -2, -2, 0 };//C
       //correct
      /*  
         short[] idx = {0,1,2};
          float[] vt ={
                  0,0,//red
                  1,0,//green
                  0,1};//yellow
                  */
  
      //wrong
         short[] idx = {1,2,0};
          float[] vt ={
                  1,0,//green
                  0,1,//yellow
                  0,0//red
                  };
          {
              ByteBuffer vBuf = ByteBuffer.allocateDirect(v.length * Float.SIZE / 8);
              vBuf.order(ByteOrder.nativeOrder());
              vertexBuffer = vBuf.asFloatBuffer();
              vertexBuffer.put(v);
              vertexBuffer.position(0);
          }
  
          {
              ByteBuffer fBuf = ByteBuffer.allocateDirect(idx.length * Short.SIZE / 8);
              fBuf.order(ByteOrder.nativeOrder());
              facesIdxBuffer = fBuf.asShortBuffer();
              facesIdxBuffer.put(idx);
              facesIdxBuffer.position(0);
          }
          {
              ByteBuffer vBuf = ByteBuffer.allocateDirect(vt.length * Float.SIZE / 8);
              vBuf.order(ByteOrder.nativeOrder());
              textureMappingBuffer = vBuf.asFloatBuffer();
              textureMappingBuffer.put(vt);
              textureMappingBuffer.position(0);
          }
      }
  
      public void draw(GL10 gl)
      {
          glEnableClientState(GL_VERTEX_ARRAY);
          glEnableClientState(GL_TEXTURE_COORD_ARRAY);
  
          glVertexPointer(3, GL_FLOAT, 0, vertexBuffer);
          glTexCoordPointer(2, GL_FLOAT, 0, textureMappingBuffer);
          glDrawElements(GL_TRIANGLES, facesIdxBuffer.capacity(), GL_UNSIGNED_SHORT, facesIdxBuffer);
  
          glDisableClientState(GL_VERTEX_ARRAY);
          glDisableClientState(GL_TEXTURE_COORD_ARRAY);
      }
  
      public TextureLoader getTextureLoader()
      {
          return new AssetTextureLoader(context, "tetraedro.png");
      }
  
  }
  </code></pre>
  
  <p>and finally here is the AssetTextureLoader class, which load the texture file from the "assets" folder in the project (cleaned of boring exception handling code):</p>
  
  <pre><code>public class AssetTextureLoader implements TextureLoader {
      private Context context;
      private String  filename;
  
      public AssetTextureLoader(Context context, String filename) {
          this.context = context;
          this.filename = filename;
      }
  
      public void load(GL10 gl)
      {
          InputStream is;
          is = context.getResources().getAssets().open(filename);
          Bitmap bitmap = BitmapFactory.decodeStream(is);
          is.close();
          Log.d("texture loader", "internal format:" + GLUtils.getInternalFormat(bitmap)+", type: "+GLUtils.getType(bitmap));
          GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
          bitmap.recycle();
      }
  }
  </code></pre>
  
  <p>Ok. As you can see in the OneTriangle class there is a commented "correct" initialization which basically lists the vertices in the A-B-C order and the mappings  in the red-green-yellow order. That code produce the correct texture mapping. </p>
  
  <p>Then i tried to simply change the order of the vertices in the "wrong" section: B-C-A and green-yellow-red. I would expect to get the exact same output, because A is always mapped to red, B is mapped to green and C is mapped to yellow. But instead i get a completely different output.</p>
  
  <p>Here you can see the 2 outputs: (see the second part of the image before)</p>
  
  <p>But there is more! If i change again the model initialization in this way:</p>
  
  <pre><code>     //should be wrong but is correct
         short[] idx = {1,0,2};
          float[] vt ={
                  0,0,//red
                  1,0,//green
                  0,1};//yellow
  </code></pre>
  
  <p>.. i get the correct mapping! In fact, i can choose any arbitrary order for the idx array and it doesn't matter: as long as the vt array is in that specific r-g-y order i get the correct image. </p>
  
  <p>Why is opengl so hostile to me? </p>
  
  <p>I'm sorry for the very long post, but the mistake (if any) may hide anywhere in the implementation..</p>