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!