/* $Id: $ */
package com.oreilly.demo.android.pa.viewdemo.widget;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.opengles.GL10;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.os.SystemClock;
import android.util.AttributeSet;
import com.example.android.apis.graphics.GLSurfaceView;
import com.oreilly.demo.android.pa.viewdemo.R;
/**
* Trivial OpenGL widget
* Based on Google's Triangle API Demo
* and the GLSurfaceView
*/
public class GLDemoWidget extends GLSurfaceView
implements GLSurfaceView.Renderer
{
private final Context context;
private final FloatBuffer vertexBuf;
private final FloatBuffer textureBuf;
private final ShortBuffer indexBuf;
/**
* @param context the app context
* @param attrs the view attributes
*/
public GLDemoWidget(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
setRenderer(this);
float[] coords = {
-1.0f, 0.7f, 1.0f,
-1.0f, -0.3f, -1.0f,
0.0f, 0.7f, 1.0f,
1.0f, -0.3f, -1.0f,
1.0f, 0.7f, 1.0f,
};
// The points defining the shape have to be
// somewhere safe from the GC
ByteBuffer vbb = ByteBuffer.allocateDirect(5 * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
vertexBuf = vbb.asFloatBuffer();
for (int i = 0; i < 5; i++) {
for(int j = 0; j < 3; j++) {
vertexBuf.put(coords[i * 3 + j] * 2.0f);
}
}
vertexBuf.position(0);
ByteBuffer tbb = ByteBuffer.allocateDirect(5 * 2 * 4);
tbb.order(ByteOrder.nativeOrder());
textureBuf = tbb.asFloatBuffer();
for (int i = 0; i < 5; i++) {
for(int j = 0; j < 2; j++) {
textureBuf.put(coords[i * 3 + j] * 2.0f + 0.5f);
}
}
textureBuf.position(0);
ByteBuffer ibb = ByteBuffer.allocateDirect(5 * 2);
ibb.order(ByteOrder.nativeOrder());
indexBuf = ibb.asShortBuffer();
for(int i = 0; i < 5; i++) {
indexBuf.put((short) i);
}
indexBuf.position(0);
}
/**
* We don't need a depth buffer and don't care about our color depth.
*/
@Override
public int[] getConfigSpec() {
return new int[] {
EGL10.EGL_DEPTH_SIZE,
0,
EGL10.EGL_NONE
};
}
/**
* Handle change of size.
*/
@Override
public void sizeChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
float ratio = (float) w / h;
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
}
/**
* Create some big objects that we want
* around only when we're drawing.
*/
@Override
public void surfaceCreated(GL10 gl) {
// set up the surface
gl.glDisable(GL10.GL_DITHER);
gl.glHint(
GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(0.2f, 0.1f, 0.8f, 0.1f);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
// fetch the checker-board
initImage(gl);
}
/**
* Draw the moving checker-board.
*/
@Override
public void drawFrame(GL10 gl) {
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glLoadIdentity();
GLU.gluLookAt(gl, 0, 0, -5, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
// apply the checker-board to the shape
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glTexEnvx(
GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_MODULATE);
gl.glTexParameterx(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_REPEAT);
gl.glTexParameterx(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_REPEAT);
// animation
int t = (int) (SystemClock.uptimeMillis() % (10 * 1000L));
gl.glTranslatef(6.0f - (0.0013f * t), 0, 0);
// draw
gl.glFrontFace(GL10.GL_CCW);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuf);
gl.glEnable(GL10.GL_TEXTURE_2D);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuf);
gl.glDrawElements(
GL10.GL_TRIANGLE_STRIP,
5,
GL10.GL_UNSIGNED_SHORT, indexBuf);
}
/*
* Get the checker-board image and make it a texture.
*/
private void initImage(GL10 gl) {
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MIN_FILTER,
GL10.GL_NEAREST);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_MAG_FILTER,
GL10.GL_LINEAR);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexParameterf(
GL10.GL_TEXTURE_2D,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE);
gl.glTexEnvf(
GL10.GL_TEXTURE_ENV,
GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_REPLACE);
InputStream in
= context.getResources().openRawResource(R.drawable.cb);
Bitmap image;
try { image = BitmapFactory.decodeStream(in); }
finally {
try { in.close(); } catch(IOException e) { }
}
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, image, 0);
image.recycle();
}
}