NeHe Android Ports
As Android supports OpenGL ES, I wanted to provide the basic and probably most read OpenGL tutorials available for the Android platform. The NeHe OpenGL tutorials are what every OpenGL starter is beginning with or pointed at. The set of nearly 50 tutorials give an overview about OpenGL functions and principles and are easy to understand and to be converted to the own needs. They are already available in many versions, many different programming languages (e.g. C#, D, Java) as well as for many frameworks (e.g. JOGL, REALBasic).
I ported/am porting the original tutorials to the Android platform, adapted to the specifics and requirements and in a somehow more Object-Oriented way. Some specifics and requirements given from the OpenGL ES Android implementation require changes such as
- glBegin/glEnd is a common way to immediately draw something to the OpenGL screen and permanently used in the NeHe tutorials. But as these are not supported on the Android platform, everything will be handled by Arrays (Vertex, Indices, Colors, Textures Coordinates). Anyway, we are still immediately drawing these, but for future tasks and buffer binding on GL11 supporting devices, this is the basic way to go, therefore the change should be seen as an advantage (Anyway, glBegin and End will drop out of the OpenGL Specification).
- GL_QUADS are not available. Therefore, in correlation with the used Vertex and Index Arrays most things will be drawn with GL_TRIANGLES, which again is no direct disadvantage.
and some more things. Overall, I try to keep everything as near as possible to the NeHe source and comments, so that everybody can use these sources with the description of the original tutorials. Additional elements and structures added for a better utilization, visibility, style and organisation are commented by myself here on this page as well as in the source code itself. If questions occur, please comment to this page.
Please note that the source is a mere port and is not necessarily best practice or for best performance. It is just a plain port to show how to accomplish the original intend on the Android platform. This source has been developed and tested with the Android 1.5r3 SDK in an Eclipse 3.5 environment. All ran fine on the provided emulator.
Not every little aspect of Android or Java is explained. You should now how the basics work to understand the lessons.
In this very first tutorial you will get a quick overview where to get all you need (of course, depending on your personal preferences you have to adapt the tutorial) to start developing Android applications.
In this first OpenGL tutorial you will see the basic structure to initiate an OpenGL View on an Android system. It contains four classes: One Runner, to base the activity on (will be nearly the same for each lesson), the OpenGL View and the two objects which are drawn. Both objects are properly separated but resemble the same structure to be drawn by vertex buffers. As mentioned, this should be the preferred way and could also be used as an initial idea for a later game entity design structure.
Note: As JoshuaFalken pointed out it is to note that by creating the GLSurfaceView and setting the renderer the drawing process is continously. This means you do not have to make any loop yourself. While in most cases this is what you want, to draw all the time. If you need or want to do it on your own you can set the render mode to RENDERMODE_WHEN_DIRTY. By that you would have to requestRender on the GLSurfaceView by yourself. You can read about it here.
Changes regarding NeHe: The biggest changes to the original tutorial come from the Android platform and classes structure. Everything is separated into its own classes (Renderer, Triangle and Square), as well as the objects are drawn by Vertex Buffers (see remark above). The init, resize and draw methods are nearly the same but they refer to the respective instanced objects of the Triangle and Square. In addition to fit the normal up-side screen layout I changed the location of both to be among each other.
In this lesson you add colors to the objects. The triangle gets colored with with a gradient and the Square is colored in blue.
Changes to previous: The changes are only made in both object classes, Triangle and Square. In Sqaure.java only one line has been added to the draw method, which defines the color before drawing. The Triangle.java does not only draw one color but many. These are again defined by values in a buffer like the vertices. The values are based on RGB and luminance. In the draw method this buffer is also added like the vertex buffer and the mapped colors are drawn according to their order.
Now that we have colored Triangles and Squares we need to spin these round n’ round. Whoohi^^’!!! In this tutorial you will add rotation to both objects.
Changes to previous: Only the method onDrawFrame(GL10 gl) in Lesson04.java has been altered. Before we draw the Triangle and Square we rotate the drawing matrix. A dynamic value, which is increased in each drawing round ensures that our objects start spinning. Between both drawing procedures we reset the matrix by calling gl.glLoadIdentity(). This is very important, otherwise the following translation and rotation is based on the position set through the previous translation and rotation. Just try and comment that line. Funny results ^^°!
In this tutorial you will enter another dimension: The THIRD! based on our Triangle and Square you will create the three-dimensional representation of these. Therefore, we change the Triangle to a Pyramid and the Square to a Cube.
Changes to previous: The biggest changes are done to our objects. We converted and extended both to three-dimensional representations. If you have a look at the Cube and Pyramid class you will notice that they resemble the structure of the Square and Triangle. We just added additional vertices and indices to the Cube. It is important to notice the difference between e.g. Square and Cube to understand how to draw and how to create objects. The Cube uses as mentioned indices to gl.glDrawElements itself. To understand the indices it is important to understand a cube. A cube has 8 vertices, 12 edges and 6 faces. All faces share different vertices and this is what we want to use to our advantage. If we draw a cube we would have to put every vertex in the array and so that the drawing function can follow the vertices to conclude in surfaces. Now, we just define the 8 vertices a cube has overall and put them in “drawing order” through our indices. The values in the index buffer are to be seen as pointer to the defined vertices. 0 for the first, 1 for the second and so on.
Note: Please note that the Pyramid has no “base”. In the original NeHe tutorial this was not needed because of the perspective. But as I altered the code to fit the normal screen layout you can see into the Pyramid. I was too lazy to add the floor but you could add it to test and see if you understood the lesson.
In this tutorial we will concentrate and continue with the Cube. We step away from the psychedelic colors and add a texture. In honour of the original tutorials I keep the original texture.
Changes to previous: Some small changes are in Lesson06.java where there were some variables added, 2D textures are enabled (gl.glEnable(GL10.GL_TEXTURE_2D)) and the texture is loaded in the Cube class. The biggest change experience the Cube.java. First of all the color array was replaced by the texture array, which contains the texture mapping coordinates. Therefore, instead of the color array the texture array is enabled in the draw method (gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY)). You will notice much more vertices than before. This results from the fact that we do not want to color them but to texture them. Now, if we use vertices for more than one face the texture mapping becomes inconsistent. Therefore, each “real” face vertex has been defined and the according texture mapping with one mapping per vertex. There are possible cases where texture mapping with shared vertices can work but not with this cube. The biggest extension to the Cube class is the loadGLTexture method. It combines the OpenGL texture generation with the Android resource loading possibilities and shows best the advantages and possibilities Android can provide for such a development.
In this tutorial we change our texture, add texture filters, lighting AND controls.
Changes to previous: Several changes have been made to the Run, Cube and Lesson07 classes. The Lesson07.java now defines light arrays for ambient, diffuse and position values and converts these into the buffers in the constructor. What can be noticed here also is that the constructor sets itself as renderer, what was done before in the Run class. If you look up in the class you will see that I changed the class from a Renderer to a full GLSurfaceView, Renderer and some InputListener. The Run class now only instances the Lesson07 and sets it as content view. I have changed this because of the input functionality in this lesson. It is quicker and easier to implement a change of values in the same class these are used and drawn. It is no best practice as you should really use a real input manager for yourself, but to keep it simple to understand and near to the original I chose this way. When the surface is created a OpenGL light is created. This can be enabled through input and a flag queried in the draw method. The Cube class is nearly the same but it got another array (yes, another one): Normals! Please refer to the Wikipedia entry for further information about normals. We need them, otherwise OpenGL would not know how to work with the light if it hits the surface. The buffer is enabled and added as the other ones. Everything common here. But the Texture loading method has changed a bit as different filters are now created: Nearest, Linear and Mipmapped. Nearest and Linear are just different in flags but the mipmapping needs some changes. Please refer to this post of me, where I described it in more detail. But overall the probably biggest change to the NeHe tutorial are the controls.
Controls: As first lesson this one has controls to control what should happen on the screen. The emulator has a keyboard but I wanted to also use this lesson to give away some InputHandler basics. Therefore, I converted all controls of the original tutorial to the Touchscreen and D+Pad. The controls are:
- D+Pad: Acceleration in the respective direction
- D+Pad Button: Change the filter
- Touchscreen: Control the Box by spinning it according to your movement on the touchscreen
- Upper Touchscreen: From left to right you can zoom in and out by moving on the screen
- Lower Touchscreen: By clicking in the lower part you can enable and disable the lighting
The implementation is done in the Lesson07 class as mentioned. It is pretty straight forward if you know the listener principles in Java. We catch key and touch events and interpret these to set the according variables in our code (that is why I wanted to have Renderer and Listener in one class). It should be self-explanatory, but a very important point is done in the constructor. By setting it focusable in touchscreen mode and requesting the focus the D+Pad is catched for that Activity. Always ensure this.
In this tutorial we again change the texture and enable blending for the textures.
Changes to previous: There are not that many changes to this lesson as it only sets and enables blending in the Lesson08 class with the according flags and method to blend in-between textures.
Controls: The controls are the same as in the previous lesson but the lower touchscreen has been split into left and right
- Lower Touchscreen LEFT: By clicking you can enable and disable the blending
- Lower Touchscreen RIGHT: By clicking you can enable and disable the lighting
This tutorial slightly leaves the previous tutorials and shows how to move and blend textured objects in our 3D space.
Changes to previous: Basically, you will find much same code as before, as I kept the basic structure to have everything as clear as possible. Two bigger changes have been made: Now, there is a Stars and a Star class. The Star.java is basically the textured object class representation of one single star. It has the vertices and texture coordinates, handles to draw itself. The Stars class is instanced and called by our renderer and initiates the star texture once, sets random colors and iterates through all stars. This can show how a possible “world” representation could call its sub-objects. In the Lesson09 class you can change the number of stars or for example change glBlendFunc to see which effects occur. This may help to understand blending.
Controls: The controls are just:
- Lower Touchscreen LEFT: By clicking you can enable and disable the blending (just looks funny ^^)
- Lower Touchscreen RIGHT: By clicking you can enable and disable twinkling
This tutorial is different from the ones before as it does not only show a geometric object but allows you to move through a 3D world.
Changes: The changes here are basically additions. The drawing and rendering is pretty similar to the NeHe Android Port structure before. But this time, we do not define the vertices etc. by hand, but read these from a text file. Therefore, the World class is a representation of a World, based on what has been read from the world.txt file. The biggest additions are made here, in the World class. The text file is interpreted and the controls are moved here. The controls are similar to the original but converted to the Android platform.
Controls: The controls are moving by pressing the D-Pad or your arrow keys on the keyboard. In addition you can look up and down and turn around by scrolling on the touchscreen. The texture filter can be changed with the D-Pad Center button and by pressing
- Lower Touchscreen LEFT: By clicking you can enable and disable the blending (just looks funny ^^)
This tutorial is based on tutorial 07 and adds fog.
Changes to lesson 07/08: The changes to Lesson 07/08 are minimal and are just in the Lesson16 class. In the beginning we define specific fog color, mode and filter variables. In onSurfaceCreated() we set the OpenGL Fog settings and in draw check which fog mode filter should be used. The listener onTouchEvent() now checks for presses in the lower left and changes the fog mode accordingly.
Controls: The controls are the same as in Lesson 07/08 but
- Lower Touchscreen LEFT: By clicking you can switch the fog mode
…more to come…
I hope these ports can help at least some people trying to figure out the platform. If you like it, have questions, are mad at me or you have ideas for improvement, please let me know. The comments are open!

Very nice!
I was thinking of converting some of the NeHe tutorials myself (while learning OpenGL ES), but it seems you beat me to it. I dont complain, though…
Now i can just learn from your code – *evil cackle*
Keep it up!
Hi!
Must say that this is excellent. I’ve been looking for good OpenGL Android tutorials.
I have one question regarding OpenGL and Android.
how do you do to convert the screen touch coordinates to OpenGL coordinates?
Could you maybe add an example of that to the list of tutorials?
Hachaso,
Take a look at gluProject and gluUnProject:
http://developer.android.com/r.....l/GLU.html
Good luck!
Thanks lot Ante.
One question.
I can see the the gluUnProject takes Offset parameter. What kind of values exactly do I put there. I have seen that it looks a bit different from the normal gluUnProject used.
Thanks
First of all, Hi ^^
The thing with gluUnProject is tricky at the moment. It is THE method to use, BUT (the big butt) it awaits the current matrix, which actually cannot be read from OpenGL ES 1.0. This is actually a big problem also for other things…
Again but, you could have a look in the Android SDK ApiDemos and the classes of MatrixTrackingGL and others. There is code which computes its own matrix in a GL Wrapper. It could be used for such things. It is a set of three classes I think.
There are some tries from users, e.g. here:
http://osdir.com/ml/AndroidDev.....04352.html
I would probably go with the MatrixTrackingGL. But you should always have in mind that the computation of the matrix does not necessarily resembles the original current matrix. There seems to be a difference between the computational and original. But anyways I tried it once and it worked fine for me. So you would have to test what does not work correctly.
Anyway, another way would always be to just take the screen coordinates from a touchevent and convert it through a e.g. raycast to OpenGL coordinates and what it hits.
Regards
Thanks a lot!
What I can’t understand is why is gluUnProject included in the API’s if it is not working as it should?
Maybe a simple example how to solve this would be perfect. I think lots of people would enjoy it.
Thanks
Hi
As some of the GL11 methods it is just already there to prepare also the device manufacturers for what is coming. It WILL be someday fully used and supported, but not at the moment. The same with GL11, it is already there, some methods and flags even do work, but not all methods work (some throw NotImplemented Exceptions) and you cannot rely on these as the devices do not necessarily have to support them. That for example is a reason why I posted this two-way solution for mipmaps: One for GL11 and one for GL10.
Now, for glUnProject there is no specific example possible and actually I would not use the method at the moment. The Matrix hack, which is needed as parameter, is not 100% correct and the “get” Functions needed from GL11 are not supported at the moment.
I know this may not be a satisfying answer but that is the current state, Even if the method is there. Any “example” given would not be the same on any device, possibly even computer. Therefore, the method should not be used possibly until Android SDK 2.0. And even then it has to be seen how the devices integrate the functionality.
It is just to understand that the API is just laid-out and not fully implemented yet. That’s how it is. Have a look at the .net Compact Framework and you will find a whole bunch of methods like that. I know its not great but unlike .netCF we can hope for Android and Google to constantly upgrade and better the API. The jump from 1.0 to 1.5 was already a very big one with many changes and additions.
So, I try to motivate you by: Hold out on Android and the SDK and at the moment try some other things to solve your specific problem. That’s all I can offer at the moment. Sorry…
Regards
Hello.
In Lesson7, the mipmapped filtered cube is all white. I read your post about mip-mapping and tried the different methods. The GL11 implementation doesnt work for me and neither does the modified buildMipMap function. Still a white cube..
Any ideas?
Hi
Do you tried the lesson with the emulator or on your phone? If, which phone do you have? You also tried the pixelation by hand, which was suggested in my post but is not on this lessons code?
I have a HTC Magic and tried everything on that phone as well as the emulator. I also had problems with white cubes but I got around it with pixelating the bitmaps myself. Maybe this helps.
Hi.
I have a HTC Hero.
I get a white cube with all three implementations:
* GL11 (and i made sure it stepped to this code)
* buildMipmap (GL11 commented out)
* buildMipmap (with pixelation part added)
In the emulator the GL11 implementation works, but not the original buildMipmap function (without the pixelation part).
What to do ?
On another note.
Is there any interest in starting an #android-opengl or #android-opengles channel on FreeNode?
Hi Ante
I am currently on a trip and will be home at saturday evening again. Therefore, I will have a look at the problem at sunday.
Hope this is ok.
Regards
No problem what so ever.
I am glad for whatever help i recieve
My MSN/Hotmail: darkante@hotmail.com
or ante on #android-dev @ FreeNode
Have a good weekend
Heya.
I managed to fix the buildMipmap function (at least for me). It now works in the emulator and on my HTC Hero.
A problem i noticed with Bitmap.createScaledBitmap is that it returns the new bitmap in RGB_565 format. The original bitmal was in ARGB_8888 format. I dont know if this is good or bad, but i added some code to make sure the scaled bitmaps are ARGB_8888 as well.
The cube was rendered slightly blueish, so I converted each pixel in the bitmap from ARGB to RGBA, before storing them in the buffer. This solved the “blueish” problem for me and i got a lovely mip mapped cube without any flaky pixels
Here’s the function:
——————–
private void buildMipmap(GL10 gl, Bitmap bitmap)
{
int level = 0;
int height = bitmap.getHeight();
int width = bitmap.getWidth();
while(height >= 1 || width >= 1)
{
ByteBuffer bytebuf = ByteBuffer.allocateDirect(height * width * 4);
bytebuf.order(ByteOrder.nativeOrder());
for(int y = 0; y < bitmap.getHeight(); y++)
& 0xFF);
{
for(int x = 0; x > 16) & 0xFF);
byte green = (byte) ((pixel >>
byte blue = (byte) (pixel & 0xFF);
bytebuf.put(new byte[] {red, green, blue, (byte) 255});
}
}
bytebuf.position(0);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, level, GL10.GL_RGBA, width, height, 0, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, bytebuf);
if(height == 1 || width == 1) {
break;
}
level++;
height /= 2;
width /= 2;
// Bitmap.createScaledBitmap creates RGB_565 bitmaps by default. Convert to ARGB_8888.
Bitmap bitmap2 = Bitmap.createScaledBitmap(bitmap, width, height, false).copy(Config.ARGB_8888, false);
bitmap.recycle();
bitmap = bitmap2;
}
}
——————–
Does it work on your device(s) ?
Best regards
Hmm..
That code wasnt copy/paste right..
Here’s a link to the function instead:
http://www.pastebin.org/15193
regards
Hi
You are right with the ARGB problem. I actually read about it but totally forget/ignored the fact. I have of course the same effect on my Magic, maybe I justed started it when I was testing. I do not know anymore, as I made the lessons pretty in parallel.
I will correct the lesson and upload the new version this week.
Many many thanks for the remark!!!
I am sorry I was a little quiet, but I will also upload another tutorial port soon which shows basic Shadowing, which I think is another rudimentary but nice to know feature.
Regards
Wow, thanks, I think that your port of lesson 6 is great and very clean.
I’ve tried many other OpenGL ES texture mapping snippets+tutorials, and am having flickering problems on Android.
I believe this is because I issue many calls to glDrawElements(), whereas you call this method only once at every draw iteration.
This may also come from the fact that I’m putting different, rather large, textures on each side of the cube.
I would however like to try and use my 6 different textures, but do a single call to glDrawElements() as you do.
How can I achieve this ? Your unique call to glBindTexture() before settings all coords makes it non-obvious to me… Whereas the original lesson 6 was very easy to adapt for multiple textures.
Hi there
First of all, flickering does not necessarily has to be connected to draw calls but to other elements like syncing or sometimes dithering etc. But overall you are right: draw calls should be a minimum. That’s a pratical OpenGL issue. draw calls, translations and bindings should be minimized in the code. Therefore, a good own scene management can help to achieve this and reduce the calls.
Now if you already know what textures you want to use and on what object it could be ise to combine many textures to one and use offsets for the texture coordinates to map the different textures to the object. This is always a good way, also to reduce the amount of files and therefore loading.
Regards
Looking forward to your new tutorial.
Best regards
Thanks a lot for the amazing tutorial which is really helping me in learning Open Gl real quick. Just one help, I compiled the lesson 10 in the eclipse and i am getting an error for onKey & onTouch method in World.java
The error is that the above methods (onKey & onTouch) of type World must override a superclass method.
However I could see the “@Override” keyword in the two methods.
Could you please help with this.
Hi baleshn
This is normally an error of the compliance level set up in e.g. Eclipse. For Java5.0 it is that the @Override annotation may only indicate the override of a class method, whereas since Java6.0 compliance it may also be annotated for interfaces.
Therefore, if you are using Eclipse: Have a look at the Project Properties -> Java Compiler -> Compiler compliance level. This should be 1.6. If you do not want to change this setting just remove the @Override Annotations in the source from me. They are not necessary to compile and run it.
I hope this helps.
Regards
Great ports!
In the “Lesson 06: Texture Mapping”, when loading a Bitmap:
InputStream is = context.getResources().openRawResource(R.drawable.nehe);
Bitmap bitmap = null;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
is = null;
} catch (IOException e) {
}
}
I prefer using:
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.nehe);
Hi juande
That’s also a fine way. What I did is more of a larger chunk if anything more is wanted. For example, personally I have normally all my resources in the res/ folder and work with the resourceloader instead of R and drawables. Therefore, just personal preferences…
…but I like one-liners ^^’
Regards
Awesome suggestion NeA and yes it got fixed and I am amazed with your response !!!! You Rock !!!
You rules! I’m starting learning OpenGL-ES and this is a great help. Thank you very much for your work.
Thanks for putting up the tutorials, this has been a big help.
I noticed that you set the gl.glFrontFace(GL10.GL_CW), but the tutorials have the vertices counter clockwise. If I turn on culling, this could be important. By default it looks like front face is set to GL10.GL_CCW.
Hey HeyYou ^^
Yes, you are right and regarding culling you should definitely see into it. Basically why it is still in the lessons even is not needed is because of classic oldskool copy and paste of my very first Android OpenGL class I read. ^^’
So, in these lessons it is neither needed nor respected by the code besides, but for cases like starting culling it is important. But this is also important if you start reading larger chunks of vertices through any means of file formats then. And yes, standard should be ccw.
Regards
Thank you for providing these very helpful tutorials!
I have a question about Lesson 04: How is the redraw for the animation actually triggered? In most windowing toolkits / frameworks I know, the redraw of the OpenGL window has to be triggered explicitly somehow. However, I cannot find any such code in the Android port. Does Android simply redraw the screen continuously?
Thanks!
Just to reply to myself here…. found the answer. GLSurfaceView.setRenderMode(). By default chooses continuous rendering. This is the ONLY windowing / UI toolkit I have ever seen both in the desktop and mobile space which by default keeps redrawing the GL surface whether there are graphical updates or not.
From the docs:
“Using RENDERMODE_WHEN_DIRTY can improve battery life and overall system performance by allowing the GPU and CPU to idle when the view does not need to be updated.”
Haha… I would think so!
Hi
Yes, this is a functionality added explicitly to Android1.5 allowing to constantly or redraw by request.
The main thing here to be noted should be that OpenGL itself is not necessarily a windowing toolkit and in other cases OpenGL is also constantly redrawn but not by the UI toolkit but another threading manager. Whether its good to have this way or the other way round can be discussed. But the Android Blog says it pretty right: Most OpenGL need constant redrawing, therefore why don’t do it automatically. And for the others, use another rendermode, as you pointed out and requestRender yourself.
Of course it is possible and can be considered to do it like that all the time and handle the drawing loop yourself for e.g. fixed framerates. But this was no real part of the tutorials and can be discussed ALL DAY LONG ^^’
Best regards
Hello!
Thanks for the reply. I didn’t mean to critize Android or the demo code. It’s just that I’ve worked with OpenGL for around 10 years and with various windowing toolkits – GLAux, GLUT, fltk, Qt, SDL, and also recently OpenGL ES on the iPhone. I don’t think I’ve ever encountered any toolkit which by default permanently triggers a redraw. Not to start a pointless debate about the wisdom of this – it is true that maybe 90% of the applications need a constant redraw anyway. I am just wondering whether it would make sense to add a comment explaining this to the info box of lesson 04, as I am sure other people moving to Android from different OpenGL environments might be confused initially, too.
Hi
No no, I didn’t take that as offence. Your point is totally right. The idea to add it to the info box is good. I will reconsider it and how to add it there and think update the text. Hopefully this weekend, as I also have a Shadowing tutorial I want to publish.
Best regards