title: Howto draw text on a square with Android and OpenGL ES 2.0
body: <p>I wanted to draw a square with <code>OpenGL ES 2.0</code> and put a dynamic text on it. I am trying to combine the instructions in <a href="https://stackoverflow.com/a/4336679/2039740">this</a> post (which I had to port to <em>OpenGL ES 2.0</em>) and the four lesson of <a href="http://www.learnopengles.com/android-lesson-four-introducing-basic-texturing/" rel="nofollow noreferrer">Learn OpenGL ES Tutorial</a>.</p>
  
  <p>I have an Activity just using a <code>GLSurfaceView</code>:</p>
  
  <pre><code>public class TexturedSquareDrawActivity extends Activity {
  
      private GLSurfaceView mGLView;
  
      @Override
      protected void onCreate(Bundle savedInstanceState) {
          super.onCreate(savedInstanceState);
          mGLView = new MyGLSurfaceViewTexture(this);
          setContentView(mGLView);
      }
  }
  </code></pre>
  
  <p>My <code>GLSurfaceView</code> just created the renderer and sets it:</p>
  
  <pre><code>public class MyGLSurfaceViewTexture extends GLSurfaceView {
      private final MyGLRendererTexture mRenderer;
  
      public MyGLSurfaceViewTexture(Context context){
          super(context);
  
          // Create an OpenGL ES 2.0 context
          setEGLContextClientVersion(2);
  
          mRenderer = new MyGLRendererTexture(context);
  
          // Set the Renderer for drawing on the GLSurfaceView
          setRenderer(mRenderer);
      }
  }
  </code></pre>
  
  <p>Then I define a <code>TextureSquare</code> class like this:</p>
  
  <pre><code>public class TexturedSquare {
  
      private final Context mContext;
      private FloatBuffer vertexBuffer;
      private ShortBuffer drawListBuffer;
  
      private int mProgram;
  
      private final String vertexShaderCode =
              // This matrix member variable provides a hook to manipulate
              // the coordinates of the objects that use this vertex shader
              "uniform mat4 uMVPMatrix;" +
                      "attribute vec4 vPosition;" +
                      "attribute vec2 a_TexCoordinate;" +
                      "varying vec2 v_TexCoordinate;" +
                      "void main() {" +
                      // the matrix must be included as a modifier of gl_Position
                      // Note that the uMVPMatrix factor *must be first* in order
                      // for the matrix multiplication product to be correct.
                      "  gl_Position = uMVPMatrix * vPosition;" +
                      "  v_TexCoordinate = a_TexCoordinate;" +
                      "}";
  
      private final String fragmentShaderCode =
              "precision mediump float;" +
                      "uniform sampler2D u_Texture;" +
                      "uniform vec4 vColor;" +
                      "varying vec2 v_TexCoordinate;" +
                      "void main() {" +
  //                    "  gl_FragColor = vColor;" +
                      "  gl_FragColor = vColor * texture2D(u_Texture, v_TexCoordinate);" +
                      "}";
      private int mMVPMatrixHandle;
  
  
      private int mPositionHandle;
      private int mColorHandle;
  
  
      // number of coordinates per vertex in this array
      static final int COORDS_PER_VERTEX = 3;
  
      private short drawOrder[] = {0, 1, 2, 0, 2, 3}; // order to draw vertices
  
  
      private final float[] mColor;
  
      private final int vertexStride = COORDS_PER_VERTEX * 4; // 4 bytes per vertex
  
  
      /**
       * Store our model data in a float buffer.
       */
      private final FloatBuffer mCubeTextureCoordinates;
  
      /**
       * This will be used to pass in the texture.
       */
      private int mTextureUniformHandle;
  
      /**
       * This will be used to pass in model texture coordinate information.
       */
      private int mTextureCoordinateHandle;
  
      /**
       * Size of the texture coordinate data in elements.
       */
      private final int mTextureCoordinateDataSize = 2;
  
      /**
       * This is a handle to our texture data.
       */
      private int mTextureDataHandle;
  
      // S, T (or X, Y)
      // Texture coordinate data.
      // Because images have a Y axis pointing downward (values increase as you move down the image) while
      // OpenGL has a Y axis pointing upward, we adjust for that here by flipping the Y axis.
      // What's more is that the texture coordinates are the same for every face.
      final float[] cubeTextureCoordinateData =
              {
                      // Front face
                      0.0f, 0.0f,
                      0.0f, 1.0f,
                      1.0f, 0.0f,
                      0.0f, 1.0f,
                      1.0f, 1.0f,
                      1.0f, 0.0f,
              };
  
      public TexturedSquare(Context context, final float[] squareCoords, final float[] color) {
          mContext = context;
          mColor = color;
  
          // initialize vertex byte buffer for shape coordinates
          ByteBuffer bb = ByteBuffer.allocateDirect(
                  // (# of coordinate values * 4 bytes per float)
                  squareCoords.length * 4);
          bb.order(ByteOrder.nativeOrder());
          vertexBuffer = bb.asFloatBuffer();
          vertexBuffer.put(squareCoords);
          vertexBuffer.position(0);
  
          // initialize byte buffer for the draw list
          ByteBuffer dlb = ByteBuffer.allocateDirect(
                  // (# of coordinate values * 2 bytes per short)
                  drawOrder.length * 2);
          dlb.order(ByteOrder.nativeOrder());
          drawListBuffer = dlb.asShortBuffer();
          drawListBuffer.put(drawOrder);
          drawListBuffer.position(0);
  
          mCubeTextureCoordinates = ByteBuffer.allocateDirect(cubeTextureCoordinateData.length * 4)
                  .order(ByteOrder.nativeOrder()).asFloatBuffer();
          mCubeTextureCoordinates.put(cubeTextureCoordinateData).position(0);
  
          linkShaderCode();
      }
  
      private void linkShaderCode() {
          int vertexShader = MyGLRendererTexture.loadShader(GLES20.GL_VERTEX_SHADER,
                  vertexShaderCode);
          int fragmentShader = MyGLRendererTexture.loadShader(GLES20.GL_FRAGMENT_SHADER,
                  fragmentShaderCode);
  
          // create empty OpenGL ES Program
          mProgram = GLES20.glCreateProgram();
  
          // add the vertex shader to program
          GLES20.glAttachShader(mProgram, vertexShader);
  
          // add the fragment shader to program
          GLES20.glAttachShader(mProgram, fragmentShader);
  
          // creates OpenGL ES program executables
          GLES20.glLinkProgram(mProgram);
      }
  
      public void draw(float[] mvpMatrix) {
          // Add program to OpenGL ES environment
          GLES20.glUseProgram(mProgram);
  
          // get handle to vertex shader's vPosition member
          mPositionHandle = GLES20.glGetAttribLocation(mProgram, "vPosition");
  
          // Enable a handle to the triangle vertices
          GLES20.glEnableVertexAttribArray(mPositionHandle);
  
          // Prepare the square coordinate data
          // Tell OpenGL how to handle the data in the vertexBuffer
          GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
                  GLES20.GL_FLOAT, false,
                  vertexStride, vertexBuffer);
  
          // get handle to fragment shader's vColor member
          mColorHandle = GLES20.glGetUniformLocation(mProgram, "vColor");
  
          // Set color for drawing the square
          // Pass the color to the shader
          GLES20.glUniform4fv(mColorHandle, 1, mColor, 0);
  
          // get handle to shape's transformation matrix
          mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
  
          // Pass the projection and view transformation to the shader
          GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);
  
          // Load the texture
  //        mTextureDataHandle = TextureHelper.loadTexture(mContext, R.drawable.background);
          mTextureDataHandle = TextureHelper.loadText(mContext, "01234");
  
          mTextureUniformHandle = GLES20.glGetUniformLocation(mProgram, "u_Texture");
          mTextureCoordinateHandle = GLES20.glGetAttribLocation(mProgram, "a_TexCoordinate");
  
  
          GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);
          GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false,
                  0, mCubeTextureCoordinates);
  
          // Set the active texture unit to texture unit 0.
          GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  
          // Bind the texture to this unit.
          GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureDataHandle);
  
          // Tell the texture uniform sampler to use this texture in the shader by binding to texture unit 0.
          GLES20.glUniform1i(mTextureUniformHandle, 0);
  
          GLES20.glDrawElements(
                  GLES20.GL_TRIANGLES, drawOrder.length,
                  GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
  
          // Disable vertex array
          GLES20.glDisableVertexAttribArray(mPositionHandle);
      }
  }
  </code></pre>
  
  <p>My renderer draws two squares. The first one shall be textured:</p>
  
  <pre><code>public class MyGLRendererTexture implements GLSurfaceView.Renderer {
  
      // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
      private final float[] mMVPMatrix = new float[16];
      private final float[] mProjectionMatrix = new float[16];
      private final float[] mViewMatrix = new float[16];
      private final Context mContext;
  
      private TexturedSquare mTexturedSquare;
      private TexturedSquare mTexturedSquare2;
  
      static float squareCoords[] = {
              -0.5f, 0.5f, 0.0f,   // top left
              -0.5f, -0.5f, 0.0f,   // bottom left
              0.5f, -0.5f, 0.0f,   // bottom right
              0.5f, 0.5f, 0.0f}; // top right
      // Set color with red, green, blue and alpha (opacity) values
      float color[] = {0.63671875f, 0.76953125f, 0.22265625f, 1.0f};
  
      static float squareCoords2[] = {
              -1.0f, 0.7f, 0.0f,   // top left
              -1.0f, 0.8f, 0.0f,   // bottom left
              -0.8f, 0.8f, 0.0f,   // bottom right
              -0.8f, 0.7f, 0.0f}; // top right
      // Set color with red, green, blue and alpha (opacity) values
      float color2[] = {0.11111111f, 0.26953125f, 0.52265625f, 1.0f};
  
      public MyGLRendererTexture(
              Context context) {
          mContext = context;
      }
  
  
      public static int loadShader(int type, String shaderCode) {
  
          // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
          // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
          int shader = GLES20.glCreateShader(type);
  
          // add the source code to the shader and compile it
          GLES20.glShaderSource(shader, shaderCode);
          GLES20.glCompileShader(shader);
  
          return shader;
      }
  
      @Override
      public void onSurfaceCreated(GL10 unused, EGLConfig config) {
          // Set the background frame color
          GLES20.glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
          // initialize a triangle
          // initialize a square
          mTexturedSquare = new TexturedSquare(mContext, squareCoords, color);
          mTexturedSquare2 = new TexturedSquare(mContext, squareCoords2, color2);
      }
  
  
      @Override
      public void onSurfaceChanged(GL10 unused, int width, int height) {
          GLES20.glViewport(0, 0, width, height);
  
          float ratio = (float) width / height;
  
          // this projection matrix is applied to object coordinates
          // in the onDrawFrame() method
          Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);
      }
  
      @Override
      public void onDrawFrame(GL10 unused) {
          // Redraw background color
          GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
  
          // Set the camera position (View matrix)
          Matrix.setLookAtM(mViewMatrix, 0, 0, 0, -3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
  
          // Calculate the projection and view transformation
          Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);
  
          mTexturedSquare.draw(mMVPMatrix);
          mTexturedSquare2.draw(mMVPMatrix);
      }
  }
  </code></pre>
  
  <p>And finally I have a helper class defining helper methods I am using in the upper code.</p>
  
  <pre><code>public class TextureHelper {
      public static int loadTexture(final Context context, final int resourceId) {
          final int[] textureHandle = new int[1];
  
          GLES20.glGenTextures(1, textureHandle, 0);
  
          if (textureHandle[0] != 0) {
              final BitmapFactory.Options options = new BitmapFactory.Options();
              options.inScaled = false;    // No pre-scaling
  
              // Read in the resource
              final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);
  
              // Bind to the texture in OpenGL
              GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
  
              // Set filtering
              GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
              GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
  
              // Load the bitmap into the bound texture.
              GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
  
              // Recycle the bitmap, since its data has been loaded into OpenGL.
              bitmap.recycle();
          }
  
          if (textureHandle[0] == 0) {
              throw new RuntimeException("Error loading texture.");
          }
  
          return textureHandle[0];
      }
  
      public static int loadText(final Context context, String text) {
          final int[] textureHandle = new int[1];
  
          GLES20.glGenTextures(1, textureHandle, 0);
  
          if (textureHandle[0] != 0) {
  
              // Create an empty, mutable bitmap
              Bitmap bitmap = Bitmap.createBitmap(256, 256, Bitmap.Config.ARGB_4444);
                  // get a canvas to paint over the bitmap
              Canvas canvas = new Canvas(bitmap);
              bitmap.eraseColor(0);
  
              // get a background image from resources
              // note the image format must match the bitmap format
              Drawable background = context.getResources().getDrawable(R.drawable.background);
              background.setBounds(0, 0, 256, 256);
              background.draw(canvas); // draw the background to our bitmap
  
              // Draw the text
              Paint textPaint = new Paint();
              textPaint.setTextSize(32);
              textPaint.setAntiAlias(true);
              textPaint.setARGB(0xff, 0x00, 0x00, 0x00);
              // draw the text centered
              canvas.drawText(text, 16,112, textPaint);
  
              // Bind to the texture in OpenGL
              GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);
  
              // Set filtering
              GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
              GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
  
              // Load the bitmap into the bound texture.
              GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
  
              // Recycle the bitmap, since its data has been loaded into OpenGL.
              bitmap.recycle();
          }
  
          if (textureHandle[0] == 0) {
              throw new RuntimeException("Error loading texture.");
          }
  
          return textureHandle[0];
      }
  }
  </code></pre>
  
  <p>But the texture is drawn for both triangles the square consists of. <strong>How can I just draw the texture once, placed horizontally within in the square?</strong></p>
  
  <p>I understand that the square is drawn by drawing two triangles. And I understand, that the texture is placed the same way. But I don't know how to tell <code>OpenGL</code> to place this texture only once within the square.</p>
  
  <p>EDIT:</p>
  
  <p>I have now edited the texture coordinates to:</p>
  
  <pre><code>final float[] cubeTextureCoordinateData =
  {
      -0.5f, 0.5f,
      -0.5f, -0.5f,
      0.5f, -0.5f,
      0.5f, 0.5f
  }
  </code></pre>
  
  <p>resulting in this:</p>
  
  <p><a href="https://i.stack.imgur.com/UmcYv.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/UmcYv.png" alt="First"></a></p>
  
  <p>These coordinates:</p>
  
  <pre><code>-1.0f, 1.0f,
  -1.0f, -1.0f,
  1.0f, -1.0f,
  1.0f, 1.0f
  </code></pre>
  
  <p>result in this:</p>
  
  <p><a href="https://i.stack.imgur.com/8A1o2.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/8A1o2.png" alt="Second"></a></p>
  
  <p>These coordinates:</p>
  
  <pre><code>0.5f, -0.5f,
  0.5f, 0.5f,
  -0.5f, 0.5f,
  -0.5f, -0.5f
  </code></pre>
  
  <p>result in this:</p>
  
  <p><a href="https://i.stack.imgur.com/aJKAl.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/aJKAl.png" alt="Third"></a></p>
  
  <p>And these coordinates:</p>
  
  <pre><code>1.0f, -1.0f,
  1.0f, 1.0f,
  -1.0f, 1.0f,
  -1.0f, -1.0f
  </code></pre>
  
  <p>result in this:</p>
  
  <p><a href="https://i.stack.imgur.com/Ih0CH.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/Ih0CH.png" alt="Fourth"></a></p>
  
  <p>So the 4th approach seems to be "the most right one". There the text is drawn at bottom right. It even seems that my square is divided into 4 smaller squares. Because as a texture I use this picture:</p>
  
  <p><a href="https://i.stack.imgur.com/MHcAX.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/MHcAX.png" alt="texture"></a></p>
  
  <p>Why is this divided into four parts?</p>