Android OpenGL: Texture from Canvas
Posted by Dimitri | Nov 2nd, 2010 | Filed under Programming
Another post about Android programming, although this time, it’s going to incorporate some OpenGL techniques. The code below shows how to draw a Canvas into a Bitmap, and then, load it as a OpenGL texture object. This means that it is possible to use all Canvas methods to draw into a texture, like drawCircle(), drawPoints() or drawText(). This is useful to render text to a texture and to dynamically generate textures.
So here’s the code:
//creates or uses a named texture at index 0 gl.glBindTexture(GL10.GL_TEXTURE_2D,0); //sets the texture environment. gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_COLOR, GL10.GL_BLEND); // setup texture parameters gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR_MIPMAP_LINEAR); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE); gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE); //creates a Paint object Paint yellowPaint = new Paint(); //makes it yellow yellowPaint.setColor(Color.YELLOW); //sets the anti-aliasing for texts yellowPaint.setAntiAlias(true); //creates a new mutable bitmap, with 128px of width and height Bitmap textBitmap = Bitmap.createBitmap(128, 128, Config.ARGB_8888); //creates a new canvas that will draw into a bitmap instead of rendering into the screen Canvas bitmapCanvas = new Canvas(texBitmap); //draws a text at x=20px and y=20px in the canvas bitmapCanvas.drawText("41Post.com", "20", "20", yellowPaint); //any other Canvas drawing methods goes here... //. //. //. //assigns the OpenGL texture with the Bitmap GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, texBitmap, 0); //free memory resources associated with this texture textBitmap.recycle();
It work’s like this: the OpenGL texture is initialized with the glBindTexture(), glTexEnvf() and glTexParameterx() function calls. Then, a Paint object has been created, and it is used to define how elements will be drawn into the Canvas. After that, in line 19, a mutable Bitmap has been instantiated. Mutable bitmaps are the ones that can be either read or written to.
The Canvas object has been created at the line 21, and the mutable bitmap is passed as a parameter to the Canvas constructor. At this point we have our Bitmap to draw our Canvas to, so we need to put something there. In this code, a text is written to the Canvas (line 24), with the drawText() method.
Last but not least, the texture is assigned with the GLUtils.texImage2D() method (line 31) and texture resources are released (line 33). That’s it! This results in OpenGL texture with the text “41Post.com” written to it.
I wouldn’t recommend using this kind of code at run time, as it allocates memory, which may trigger the Garbage Collector, causing some performance loss. This is specially critical when programming an Android game. So, use this inside your app’s initialization code.
Hi. Very interesting note.
Currently, i’m working on a 2D game for android (no opengl), but i’m trying to decide how to make previous drawings on a Bitmap through the use of a Canvas. I don’t want to draw directly into the Canvas of my SurfaceView, but instead draw on another canvas until my scene is ready. In the end, i’d like to copy what is on my temp Canvas to my SurfaceView Canvas.
My concern is if this will impact on performance when used in every frame.
Do you have any advice?
I think it will impact the performance if used on every frame, specially for animated sprites, but I’m not sure. However, if your game uses a tiled background or something static that is composed by other images and multiple draw calls, rendering to a temporary canvas can be beneficial because you can render everything to it only once, at initialization.
Thanks for the answer! I guess to know it as a fact i’ll need to test it.
I come from a C++/SDL background and this is what i used to do with SDL_Surface.
Everything worked fine and with a nice framerate, so let’s hope it works in android as well.
Nice blog!
Thanks a lot!
It would be awesome if you could share the results from your tests.