In the last part we have just seen the basic setup of the opengl view, Now we will work on how to create/load the textures in opengl and render them on the screen at given x and y of screen coordinates.
Let’s start with the initial commands required to render an image.
Add these opengl statements once the surface is initialized
Clear the color. The color value is red
glClearColor(1, 0, 0, 1);
Clear the depth buffer
glClearDepthf(1.0f);
disable depth buffer for objects not to occlude
glDisable(GL10.GL_DEPTH_TEST);
Enable blending for
transparency
glEnable(GL10.GL_BLEND);
glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
Add these statements in onDrawFrame
Clear the buffers
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
Load the projection Matrix since we are more into 2d we set projection matrix to be 2d view
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
GLU.gluOrtho2D(gl, 0.0f,surfacewidth,surfaceheight,0.0f);
Avoid the back potion of the image to be visible.
glDisable(GL10.GL_CULL_FACE);
NOTE: Since onDrawFrame is called every frame we need to perform the above operation on every frame.
Loading a Texture:
A Texture is nothing but an image data.
All we need to do is get a texture ID first.(A texture ID is a unique id for a texture to be loaded provided by following opengl function which can be later used to render). Texture Id generally starts with 1.
glGenTextures(1, array, 0);
1 Indicates number of texture ids to be created
array is the array we pass to save the texture Id in it.
0 – is the offset of the texture.
Now, the above function reads the texture Id in the array passed. Here, the size of the array is 1 since we have only one texture to load at once.
Next, Create a bitmap by passing an input stream which holds the image to be loaded.
bmp = BitmapFactory.decodeStream(inputStream, null, opts);
you got the bitmap and now you need to describe the pixel format of the image, this can be done as follows.
texImage2D(GL10.GL_TEXTURE_2D, 0, bmp, 0);
texImage2D provides us to define the internal format of texture, As we are working with 2d textures we pass the first parameter as 2D texture, and also pass the bitmap bmp created earlier,
The second and last parameters are pixel level and offset of the texture respectively which we don’t have to bother for now, hence passing zero.
The next step would be to create the filters for the texture. Texture filters provides us the flexibility of how the pixels of the texture (called as texels) should match with the pixels on the screen.
Opengl provides with the two different kinds of texture filters Minifying texture filters and Magnifying texture filters.
The texture minifying function is used whenever the pixel being textured maps to an area greater than one texture element. There are six defined minifying functions.
The texture magnification function is used when the pixel being textured maps to an area less than or equal to one texture element.
For example, Consider we are using filter “GL_NEAREST” as minifying filter. Now, If one texel of the image is smaller than one pixel of the screen then the remaining part of the pixel is covered with the nearest pixel color.
Minifying filter
glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MIN_FILTER,GL10.GL_NEAREST).
Magnifying filter
glTexParameterf(GL10.GL_TEXTURE_2D,GL10.GL_TEXTURE_MAG_FILTER,GL10.GL_LINEAR).
Till now, we have just loaded a texture. Here comes the core part of rendering a texture.
In opengl the render actual takes in steps, one is getting the vertex data and placing it in appropriate screen coordinates, the other thing is texturing the vertex data respectively.
Steps to be followed:
-
To draw an image on the screen we actually need to divide the image into two triangles (as any image would be in the form of rectangular or square shape including alpha).
-
Create a vertex data/buffer for each of the triangle.
-
Create a texture data/buffer for each of the triangle.
Creating a vertex data/buffer:
Assume that the size of the image is 100x100(width x height), and you want to draw the image at 10,10 (where x-coordinate is 10 and y-coordinate is also 10).
As I told you that image is a combination of triangles, we have two triangles in our example which are described as follows.
NOTE: A, B, C, D, E and F are the vertices of the triangle, Each vertex has x and y coordinates respectively. Totally we have 6 vertices for two triangles.
The value of x-coordinate in our example is 10 and the value y-coordinate is 10.
So, x =10 and y = 10; width = 100, height = 100;
Now, the vertex A is drawn at x, y of the screen coordinates(which is 10,10 respectively).
Vertex B is drawn at x , y +height (10, 10 +100)
Vertex C is drawn at x + width , y +height (10+100, 10+100)
Vertex D is drawn at x + width , y (10+100, 10)
Vertex E is drawn at x , y (10,10)
Vertex F is drawn at x + width , y + height (10+100, 10+100);
The final image when we combine these two triangles would be as follows
Observe that vertex A, E are similar and vertex C, F are similar because though we are combining these vertices two form an image a vertex should be individual for both the triangles.
NOTE: The order of the vertices must be followed (order is A,B,C,D,E,F).
Till now we are only done with the vertex data/buffer, now we see how to place the texture coordinates for the respective vertex coordinates.
Texture coordinates represents the image data used to map the vertices on the screen coordinates.
They usually known as U,V values with respect to image. Both these values start from top left corner of the image. U along x-axis(horizontal) and V along y-axis(vertical).The values range from 0 to 1.
Now, we will match these texture coordinates with the above shown vertices. Each vertex has its own texture coordinates (U, V). The mapping would be as follows
Vertex A will have texture coordinates as U = 0 and V = 0;
Vertex B will have texture coordinates as U = 0 and V = 1;
Vertex C will have texture coordinates as U = 1 and V = 1;
Vertex D will have texture coordinates as U = 1 and V = 0;
Vertex E will have texture coordinates as U = 0 and V = 0;
Vertex F will have texture coordinates as U = 1 and V = 1;
Observe that U, V values are similar for A, E vertices and C, F vertices as seen in the example above creating vertex buffer.
NOTE: The order of the texture coordinates must be followed. The minimum value of U is 0 and the maximum value of U is 1, similarly for V.
We are done with creating vertex buffer and texture buffers, now we need to pass these buffers to the respective functions of opengl to render an image.
Before that, we have few steps to be followed for every frame to render
Enable the texture2d as we are dealing with 2D stuff
glEnable(GL10.GL_TEXTURE_2D);
Activate the texture.
glActiveTexture(GL10.GL_TEXTURE0);
Bind the texture using the texture ID which we have generated in the very first stage
glBindTexture(GL10.GL_TEXTURE_2D, textureID);
enable the vertex coordinate array
glEnableClientState(GL10.GL_VERTEX_ARRAY);
enable the texture coordinate array
glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
here comes the vertex data usage, pass the vertex buffer
glVertexPointer(2, GL10.GL_FLOAT, 0, vertexBuffer);
pass the texure buffer
glTexCoordPointer (2, GL10.GL_FLOAT, 0, textureBuffer);
And the final step which we were waiting for is here which draws the image with specified vertex data/buffer and texture data/buffer passed in the previous steps.
glDrawArrays(GL10.GL_TRIANGLES, 0, 6);
GL_TRIANGLES is the mode to be specified to draw, we are using triangles for our example.
0 represents the first index of the buffer, and 6 indicates the number of vertices we are drawing. We have two triangles, each triangles has 3 vertices and so total 3 * 2 = 6 vertices.
you can download the complete code
here