OpenGL ES 1.0 on Android – Triangle Example

Android LogoSince I spent quite a few hours trying to get my first OpenGL ES triangle on the Android phone’s screen I thought I should share the code with everyone to ease a bit the pain. Hopefully this will help someone get going on Android.


MainActivity.java

package com.ruibm;
 
import android.app.Activity;
import android.graphics.PointF;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.MotionEvent;
 
public class MainActivity extends Activity {
 
  private PointF touchStart;
  private GLSurfaceView glSurfaceView;  
  private TriangleRenderer renderer;
 
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    touchStart = new PointF();
    glSurfaceView = new GLSurfaceView(this);
    renderer = new TriangleRenderer();
    glSurfaceView.setRenderer(renderer);
    setContentView(glSurfaceView);
  }
 
  @Override
  protected void onResume() {
    super.onResume();
    glSurfaceView.onResume();
  }
 
  @Override
  protected void onPause() {
    super.onPause();
    glSurfaceView.onPause();
  }
 
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
      case MotionEvent.ACTION_MOVE:
        renderer.move(event.getX() - touchStart.x, touchStart.y - event.getY());
        touchStart.set(event.getX(), event.getY());
        glSurfaceView.requestRender();
        return true;
 
      case MotionEvent.ACTION_DOWN:
        touchStart.set(event.getX(), event.getY());
        return true;
 
      default:
        return super.onTouchEvent(event);
    }
  }
 
  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {
    switch (keyCode) {
      case KeyEvent.KEYCODE_DPAD_UP:
        renderer.move(0, 1);
        glSurfaceView.requestRender();
        return true;
 
      case KeyEvent.KEYCODE_DPAD_DOWN:
        renderer.move(0, -1);
        glSurfaceView.requestRender();
        return true;
 
      case KeyEvent.KEYCODE_DPAD_LEFT:
        renderer.move(-1, 0);
        glSurfaceView.requestRender();
        return true;
 
      case KeyEvent.KEYCODE_DPAD_RIGHT:
        renderer.move(1, 0);
        glSurfaceView.requestRender();
        return true;
 
      default:
        return super.onKeyDown(keyCode, event);      
    }
  }
}

TriangleRenderer.java

package com.ruibm;
 
import java.nio.ShortBuffer;
 
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
 
import android.graphics.PointF;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;
 
public class TriangleRenderer implements Renderer {
 
  private PointF surfaceSize;
  private PointF offset;
  private ShortBuffer triangleBuffer;
 
  public TriangleRenderer() {
    surfaceSize = new PointF();
    offset = new PointF();
  }
 
  public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  }
 
  public void onSurfaceChanged(GL10 gl, int width, int height) {
    surfaceSize.set(width, height);
 
    // Create our triangle.
    final int div = 1;
    short[] triangles = { 
        0, 0, 0,
        0, (short) (surfaceSize.y / div), 0,
        (short) (surfaceSize.x / div), (short) (surfaceSize.y / div), 0,
    };    
    triangleBuffer = ShortBuffer.wrap(triangles);
 
    // Disable a few things we are not going to use.
    gl.glDisable(GL10.GL_LIGHTING);
    gl.glDisable(GL10.GL_CULL_FACE);
    gl.glDisable(GL10.GL_DEPTH_BUFFER_BIT);
    gl.glDisable(GL10.GL_DEPTH_TEST);
    gl.glClearColor(.5f, .5f, .8f, 1.f);
    gl.glShadeModel(GL10.GL_SMOOTH);
 
    float ratio = surfaceSize.x / surfaceSize.y;
    gl.glViewport(0, 0, (int) surfaceSize.x, (int) surfaceSize.y);
 
    // Set our field of view.
    gl.glMatrixMode(GL10.GL_PROJECTION);
    gl.glLoadIdentity();
    gl.glFrustumf(
        -surfaceSize.x / 2, surfaceSize.x / 2, 
        -surfaceSize.y / 2, surfaceSize.y / 2,
        1, 3);
 
    // Position the camera at (0, 0, -2) looking down the -z axis.
    gl.glMatrixMode(GL10.GL_MODELVIEW);
    gl.glLoadIdentity();
    // Points rendered to z=0 will be exactly at the frustum's 
    // (farZ - nearZ) / 2 so the actual dimension of the triangle should be
    // half
    gl.glTranslatef(0, 0, -2);
  }
 
  public void onDrawFrame(GL10 gl) {    
    gl.glPushMatrix();
 
    gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    gl.glTranslatef(offset.x, offset.y, 0);
 
    gl.glColor4f(1.0f, 0.3f, 0.0f, .5f);    
    gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
    gl.glVertexPointer(3, GL10.GL_SHORT, 0, triangleBuffer);
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, 3);    
    gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
 
    gl.glPopMatrix();
  }
 
  public void move(float xDelta, float yDelta) {
    offset.x += xDelta;
    offset.y += yDelta;
    Log.d("TriangleRenderer", "offset=[" + offset.x + " ," + offset.y + "]");
  }
}
This entry was posted in Programming, Software, Tech. Bookmark the permalink.

Leave a Reply