0

I am creating a button class that will display a blue circle if it is not being pressed and a red circle if it is being pressed. I start by building a 4 vertex quad composed of two triangles. I generate my own bitmap and draw two circles on the bitmap next to each other, left to right. I then create a texture buffer with instead 4 uv points, I create it with 8, one that maps out the blue circle, one that maps out the red circle. I would then like to render the red circle when the button is pressed. Ideally I would like to call the

gl.glTexCoordPointer

method and pass in an offset, but that is not working. Here is my method that I used to generate the bitmap, draw on the bitmap using the canvas and paint objects and then attempt to map the textures. Note that I have to generate a texture that is a power of 2 so there is some math in there that allows me to generate a bigger bitmap than I need based of the width and height variables of the button that were specified in the constructor.

public void InitializeButton(GL10 gl, int upcolor, int downcolor, String symbol)
    {
        //Our variables for creating a bitmap and texture
        Canvas canvas   = null; 
        Bitmap bitmap   = null;
        Paint  paint    = null;

    //Set up the bitmap type
    Bitmap.Config conf = Bitmap.Config.ARGB_8888;


    /*
     * We now want to calculate the size of the texture. Remember it is best to be a square
     * texture or at least a power of 2. The below equation below will do this. For example
     * if the width of the button was say 20, we need to find the smallest power of 2 that is
     * greater than 20. In this case we know it is 32. But how do we calculate that? First we
     * have to find out the exponent of what 2^x = 20. Then we find the ceiling of tha number.
     * In order to make that calculation we have to take the log of that, but in order to use
     * the log function which is base 10, we have to switch to base 2 so that means 
     * we have to take the log(width)/log(2) to switch to base 2, then get the ceiling of that
     * number because it would be between 4 and 5 in this case. When we take the ceiling we get
     * 5 and 2^5 is 32.
     * 
     * Side note, we want to double the size to make sure there is room for the up and the down
     * actions.
     */
    widthTexture = (int) Math.pow(2,Math.ceil((Math.log(this.width*2)/Math.log(2))));
    heightTexture = (int) Math.pow(2,Math.ceil((Math.log(this.height*2)/Math.log(2))));

    /*
     * Now we will create the bitmap for the creation of the button
     */
    bitmap = Bitmap.createBitmap(widthTexture,heightTexture,conf);

    //Now create a new canvas from that bitmap
    canvas = new Canvas(bitmap);

    //Create a new Paint
    paint = new Paint();

    /*
     * Now we want to render the draw the up and down button on the texture. We are just going
     * to use two different colors to represent up and down. So we will draw the up circle button
     * starting at 0 0 and the down button off to the right.
     */
    paint.setColor(upcolor);
    paint.setAlpha(120);
    canvas.drawOval(new RectF(0,0,width,height), paint);
    paint.setColor(Color.BLACK);
    canvas.drawText(symbol, width/2, height/2, paint);
    paint.setColor(Color.WHITE);
    canvas.drawText(symbol, width/2+3, height/2+3, paint);

    //Draw the down color button
    paint.setColor(downcolor);
    paint.setAlpha(120);
    canvas.drawOval(new RectF(width,0,width*2,height), paint);
    paint.setColor(Color.WHITE);
    canvas.drawText(symbol, width+(width/2), height/2, paint);
    paint.setColor(Color.BLACK);
    canvas.drawText(symbol, width+(width/2)+3, height/2+3, paint);

    float widthpercent  =  ((float)width/(float)widthTexture);
    float heightpercent =  ((float)height/(float)heightTexture);

    /*
     * Now create two texture maps. One for the up button and one for the down button
     * You can change the offset of the draw texture thing to change the animations now
     */
    float uvTextures[] = {0f,                   heightpercent,
                          widthpercent,         heightpercent,
                          widthpercent,         0f,
                          0f,                   0f,
                          widthpercent,         heightpercent,
                          widthpercent*2,       heightpercent,
                          widthpercent*2,       0f,
                          widthpercent,         0f,
                          };

    /*
     * Allocate the byte buffer so it is a normal array of floats and not a java array.
     * load the uvTexture values inside.
     */
    ByteBuffer tbb = ByteBuffer.allocateDirect(uvTextures.length*4);
    tbb.order(ByteOrder.nativeOrder());
    textureBuffer = tbb.asFloatBuffer();
    textureBuffer.put(uvTextures);
    textureBuffer.position(0);  

    int [] textures = new int[1];

    gl.glGenTextures(1, textures,0);
    gl.glBindTexture(GL10.GL_TEXTURE_2D,  textures[0]);
    textureID = textures[0];
    gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_S,GL10.GL_REPEAT);
    gl.glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_WRAP_T,GL10.GL_REPEAT);
    GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0,bitmap,0);


    //Don't forget to deallocate the bitmap
    bitmap.recycle();
}

So eventually in the render method, I want to be able to render different coordinates on the texture map to the same vertices. So I call glTexCoordPointer and change the offset to "counter" where counter should have been 6*4 (6 vertices times 4 bytes per float) but that doesn't work, so I tried counter at 0 and incremented it and never found the magical number that will map the red button. On a side note, when I tried that, I would get very weird patterns drawn, sometimes showing 10 to 15 mini blue and red circles.

    if(isdown)
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,counter,textureBuffer);
    else
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer);
genpfault
  • 51,148
  • 11
  • 85
  • 139
Matthew
  • 3,886
  • 7
  • 47
  • 84
  • ``gl.glTexCoordPointer(..)`` third parameter is stride between elements, not offset exactly. If you want to have offset you can call ``textureBuffer.position(startPosition)`` before calling ``glTexCoordPointer``. – harism Dec 09 '12 at 17:21
  • Mr. @harism Genius! That works! I changed the position to 8 when the button is down and everything works perfectly! Do I take any kind of performance hit by changing the position of the buffer? (not O(n) copying or anything?) Also, if you don't mind answering the question I vote and accept it! – Matthew Dec 09 '12 at 19:13

1 Answers1

0

@Harism was correct for my situation. I hope I am still using this correctly. I was thinking the stride variable could be changed, but I had to change the position of the buffer. This worked for animating textures on 3D surfaces. I don't know if this is the "best" way to do it, but until then I'll be using this.

Matthew
  • 3,886
  • 7
  • 47
  • 84