http://www.enfis.it/archives/14
As promised, here is my personal implementation of a small 3D tunnel demo in
Android, with support of
OpenGL ES. I have never coded in OpenGL ES before and the first impact was negative, shortly: I don’t like it! Compared with OpenGL (standard version), ES has some limitations, in particular on direct vertex handling. Crudely, the
glBegin/glEnd and
glVertex## functions are missing. The intensive use of “
buffers” (
java.nio.Buffer) to render textures and primitives, with all it’s subclasses (
ByteBuffer,
CharBuffer,
DoubleBuffer,
FloatBuffer,
IntBuffer,
LongBuffer and
ShortBuffer), is a useless waste of time and memory, in my humble opinion. If you must dynamically build your 3D object, for example to make a morphing mesh like my tunnel, you’ll go crazy. In fact you should hold a copy of vertices in Java memory (for example a float[] array) and a copy of vertices in system memory (a
ByteBuffer object instantiated with
allocateDirect); then for each frame you must re-calculate the vertices and
blit them from the array in Java memory to the buffer in system memory. What the fuck… Alternatively you can use the
putFloat method directly on the
ByteBuffer object, due to eliminate the Java array, but this is fucking slow compared with a single
put method call. I haven’t spent so much time on this topic, probably exists a “cool” method to eliminate that
blit phase, please leave me a comment if you knows.
I am almost sure, to speed-up an OpenGL system on a mobile device, the best way is hold 3D engine data in system memory, that’s the reason of buffers use. An easy task instead, is hooking the OpenGL surface with a
View object. You can also render your OpenGL scene and then write some graphics using the
Canvas methods on the same surface:
COOL ![8)](http://www.enfis.it/wp-includes/images/smilies/icon_cool.gif)
Next time I’ll do further experiments on OpenGL ES, maybe I’m wrong.
Ok, attached in this post you’ll find the complete source code of my 3D tunnel. Code is not very clean and commented, but you can take a look if you wish: feel free to download and use it. Please, leave me a comment: your ideas will be appreciated!
I got it running in 1.5(cup cake) by making the following changes to the AMain and GLView classes.
public class AMain extends Activity{
private GLSurfaceView mGLView;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFormat(PixelFormat.TRANSLUCENT);
mGLView = new GLSurfaceView(this);
mGLView.setEGLConfigChooser(false);
mGLView.setRenderer(new GLView(this));
setContentView(mGLView);
}
@Override
protected void onPause() {
super.onPause();
mGLView.onPause();
}
@Override
protected void onResume() {
super.onResume();
mGLView.onResume();
}
….
public class GLView implements GLSurfaceView.Renderer{
private Context mContext;
private Tunnel3D tunnel;
private boolean created;
private GL10 gl;
private int w;
private int h;
private Bitmap bmp;
private int tex;
public GLView (Context context)
{
mContext = context;
// Internal members..
tunnel = new Tunnel3D (10, 20);
created = false;
}
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
created = true;
// Enabling the state…
gl.glEnable (GL10.GL_DEPTH_TEST);
gl.glEnable (GL10.GL_TEXTURE_2D);
gl.glEnableClientState (GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState (GL10.GL_COLOR_ARRAY);
gl.glEnableClientState (GL10.GL_TEXTURE_COORD_ARRAY);
// Loading texture…
bmp = BitmapFactory.decodeResource (mContext.getResources(), R.drawable.plants03);
tex = loadTexture (gl, bmp);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
this.w = width;
this.h = height;
}
@Override
public void onDrawFrame(GL10 gl) {
// Check the created flag…
boolean c = false;
synchronized (this)
{
c = created;
}
if (!c) return;
// Setting up the projection…
float ratio = (float)w / h;
gl.glMatrixMode (GL10.GL_PROJECTION);
gl.glLoadIdentity ();
gl.glViewport (0, 0, w, h);
GLU.gluPerspective (gl, 45.0f, ((float)w)/h, 1f, 100f);
// Setting up the modelview…
gl.glMatrixMode (GL10.GL_MODELVIEW);
gl.glLoadIdentity ();
// Clear the z-buffer…
gl.glClear (GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
// Render the tunnel…
tunnel.render (gl, -1.6f);
tunnel.nextFrame ();
// OpenGL finish
gl.glFlush ();
gl.glFinish ();
}
private int loadTexture (GL10 gl, Bitmap bmp)
{
ByteBuffer bb = ByteBuffer.allocateDirect(bmp.getHeight()*bmp.getWidth()*4);
bb.order(ByteOrder.nativeOrder());
IntBuffer ib = bb.asIntBuffer();
for (int y=0;y