Ch10 Listings
satya - Saturday, February 20, 2010 11:22:17 AM
Listing 10?1. Vertex Coordinates Example for an OpenGL Triangle
float[] coords = {
-0.5f, -0.5f, 0, //p1: (x1,y1,z1)
0.5f, -0.5f, 0, //p2: (x1,y1,z1)
0.0f, 0.5f, 0 //p3: (x1,y1,z1)
};
satya - Saturday, February 20, 2010 11:24:26 AM
Listing 10-2. Creating NIO Float Buffers
jva.nio.ByteBuffer vbb = java.nio.ByteBuffer.allocateDirect(3 * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
java.nio.FloatBuffer mFVertexBuffer = vbb.asFloatBuffer();
satya - Saturday, February 20, 2010 11:25:14 AM
Listing 10-3. glVertexPointer API Definition
glVertexPointer(
// Are we using (x,y) or (x,y,z) in each point
3,
// each value is a float value in the buffer
GL10.GL_FLOAT,
// Between two points there is no space
0,
// pointer to the start of the buffer
mFVertexBuffer);
satya - Saturday, February 20, 2010 11:27:38 AM
Listing 10-4. Example of glDrawElements
glDrawElements(
// type of shape
GL10.GL_TRIANGLE_STRIP,
// Number of indices
3,
// How big each index is
GL10.GL_UNSIGNED_SHORT,
// buffer containing the 3 indices
mIndexBuffer);
satya - Saturday, February 20, 2010 11:32:04 AM
Listing 10-5. Converting Java Array to NIO Buffers
//Figure out how you want to arrange your points
short[] myIndecesArray = {0,1,2};
//get a short buffer
java.nio.ShortBuffer mIndexBuffer;
//Allocate 2 bytes each for each index value
ByteBuffer ibb = ByteBuffer.allocateDirect(3 * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
//stuff that into the buffer
for (int i=0;i<3;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
satya - Saturday, February 20, 2010 11:34:46 AM
Listing 10?6. Specifying a Frustum through glFrustum
//calculate aspect ratio first
float ratio = (float) w / h;
//indicate that we want a perspective projection
glMatrixMode(GL10.GL_PROJECTION);
//Specify the frustum: the viewing volume
gl.glFrustumf(
-ratio, // Left side of the viewing box
ratio, // right side of the viewing box
1, // top of the viewing box
-1, // bottom of the viewing box
3, // how far is the front of the box from the camera
7); // how far is the back of the box from the camera
satya - Saturday, February 20, 2010 11:38:15 AM
Listing 10-7. Defining a ViewPort through glViewPort
glViewport(0, // lower left "x" of the rectangle on the screen
0, // lower left "y" of the rectangle on the screen
width, // width of the rectangle on the screen
height); // height of the rectangle on the screen
satya - Saturday, February 20, 2010 11:45:02 AM
Listing 10-8. A Simple OpenGLTestHarnessActivity
public class OpenGLTestHarnessActivity extends Activity {
private GLSurfaceView mTestHarness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTestHarness = new GLSurfaceView(this);
mTestHarness.setEGLConfigChooser(false);
mTestHarness.setRenderer(new SimpleTriangleRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
//mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
setContentView(mTestHarness);
}
@Override
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
}
satya - Saturday, February 20, 2010 11:46:55 AM
Listing 10-9. The Renderer Interface
public static interface GLSurfaceView.Renderer
{
void onDrawFrame(GL10 gl);
void onSuraceChanged(GL10 gl, int width, int height);
void onSurfaceCreated(GL10 gl, EGLConfig config);
}
satya - Saturday, February 20, 2010 11:49:38 AM
Listing 10-10. The AbstractRenderer
//filename: AbstractRenderer.java
public abstract class AbstractRenderer
implements GLSurfaceView.Renderer
{
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
gl.glDisable(GL10.GL_DITHER);
gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
GL10.GL_FASTEST);
gl.glClearColor(.5f, .5f, .5f, 1);
gl.glShadeModel(GL10.GL_SMOOTH);
gl.glEnable(GL10.GL_DEPTH_TEST);
}
public void onSurfaceChanged(GL10 gl, int w, int h) {
gl.glViewport(0, 0, w, h);
float ratio = (float) w / h;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glLoadIdentity();
gl.glFrustumf(-ratio, ratio, -1, 1, 3, 7);
}
public void onDrawFrame(GL10 gl)
{
gl.glDisable(GL10.GL_DITHER);
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);
draw(gl);
}
protected abstract void draw(GL10 gl);
}
satya - Saturday, February 20, 2010 11:53:22 AM
Listing 10-11. SimpleTriangleRenderer
//filename: SimpleTriangleRenderer.java
public class SimpleTriangleRenderer extends AbstractRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 3;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
public SimpleTriangleRenderer(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-0.5f, -0.5f, 0, // (x1,y1,z1)
0.5f, -0.5f, 0,
0.0f, 0.5f, 0
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2};
for (int i=0;i<3;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, VERTS,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 12:02:32 PM
Listing 10-12. The SimpleTriangleRenderer2 Class
//filename: SimpleTriangleRenderer2.java
public class SimpleTriangleRenderer2 extends AbstractRenderer
{
private final static int VERTS = 4;
private FloatBuffer mFVertexBuffer;
private ShortBuffer mIndexBuffer;
public SimpleTriangleRenderer2(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(6 * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-1.0f, -1.0f, 0, // (x1,y1,z1)
1.0f, -1.0f, 0,
0.0f, 1.0f, 0,
1.0f, 1.0f, 0
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2, 0,2,3};
for (int i=0;i<6;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
protected void draw(GL10 gl)
{
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, 6, GL10.GL_UNSIGNED_SHORT,
mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 12:03:29 PM
Listing 10-13. Specifying Continuous-Rendering Mode
//get a GLSurfaceView
GLSurfaceView openGLView;
//Set the mode to continuous draw mode
openGLView.setRenderingMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
satya - Saturday, February 20, 2010 12:05:36 PM
Listing 10-14. AnimatedTriangleActivity Source Code
//filename: AnimatedTriangleActivity.java
public class AnimatedTriangleActivity extends Activity {
private GLSurfaceView mTestHarness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTestHarness = new GLSurfaceView(this);
mTestHarness.setEGLConfigChooser(false);
mTestHarness.setRenderer(new AnimatedSimpleTriangleRenderer(this));
//mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
}
@Override
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
}
satya - Saturday, February 20, 2010 12:09:06 PM
Listing 10-15. AnimatedSimpleTriangleRenderer Source Code
//filename: AnimatedSimpleTriangleRenderer.java
public class AnimatedSimpleTriangleRenderer extends AbstractRenderer
{
private int scale = 1;
//Number of points or vertices we want to use
private final static int VERTS = 3;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
public AnimatedSimpleTriangleRenderer(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(VERTS * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-0.5f, -0.5f, 0, // (x1,y1,z1)
0.5f, -0.5f, 0,
0.0f, 0.5f, 0
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2};
for (int i=0;i<3;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
//overridden method
protected void draw(GL10 gl)
{
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
gl.glRotatef(angle, 0, 0, 1.0f);
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, VERTS,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 12:10:50 PM
Listing 10-16. Invoking the Animated Activity
private void invoke15SimpleTriangle()
{
Intent intent = new Intent(this,AnimatedTriangleActivity.class);
startActivity(intent);
}
satya - Saturday, February 20, 2010 12:16:27 PM
Listing 10-17. Registering the New Activity in the AndroidManifest.xml File
<activity android:name=".AnimatedTriangleActivity"
android:label="OpenGL Animated Test Harness"/>
satya - Saturday, February 20, 2010 12:18:04 PM
Listing 10-18. Menu Structure for OpenGL Demos
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<!-- This group uses the default category. -->
<group android:id="@+id/menuGroup_Main">
<item android:id="@+id/mid_OpenGL_SimpleTriangle"
android:title="Simple Triangle" />
<item android:id="@+id/mid_OpenGL_AnimatedTriangle15"
android:title="Animated Triangle" />
<item android:id="@+id/mid_rectangle"
android:title="rectangle" />
<item android:id="@+id/mid_square_polygon"
android:title="square polygon" />
<item android:id="@+id/mid_polygon"
android:title="polygon" />
<item android:id="@+id/mid_textured_square"
android:title="textured square" />
<item android:id="@+id/mid_textured_polygon"
android:title="textured polygon" />
<item android:id="@+id/mid_OpenGL_Current"
android:title="Current" />
<item android:id="@+id/menu_clear"
android:title="clear" />
</group>
</menu>
satya - Saturday, February 20, 2010 12:21:18 PM
Listing 10-19. MultiViewTestHarnessActivity
public class MultiViewTestHarnessActivity extends Activity {
private GLSurfaceView mTestHarness;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mTestHarness = new GLSurfaceView(this);
mTestHarness.setEGLConfigChooser(false);
Intent intent = getIntent();
int mid = intent.getIntExtra("com.ai.menuid", R.id.MenuId_OpenGL15_Current);
if (mid == R.id.MenuId_OpenGL15_Current)
{
mTestHarness.setRenderer(new TexturedPolygonRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_OpenGL15_SimpleTriangle)
{
mTestHarness.setRenderer(new SimpleTriangleRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_OpenGL15_AnimatedTriangle15)
{
mTestHarness.setRenderer(new AnimatedSimpleTriangleRenderer(this));
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_rectangle)
{
mTestHarness.setRenderer(new SimpleRectRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_square_polygon)
{
mTestHarness.setRenderer(new SquareRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_polygon)
{
mTestHarness.setRenderer(new PolygonRenderer(this));
setContentView(mTestHarness);
return;
}
if (mid == R.id.mid_textured_square)
{
mTestHarness.setRenderer(new TexturedSquareRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
setContentView(mTestHarness);
return;
}
//otherwise do this
mTestHarness.setRenderer(new TexturedPolygonRenderer(this));
mTestHarness.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
setContentView(mTestHarness);
return;
}
@Override
protected void onResume() {
super.onResume();
mTestHarness.onResume();
}
@Override
protected void onPause() {
super.onPause();
mTestHarness.onPause();
}
}
satya - Saturday, February 20, 2010 10:09:16 PM
Listing 10-20. Reading Menu ID from an Intent
Intent intent = getIntent();
int mid = intent.getIntExtra("com.ai.menuid", R.id.mid_OpenGL_Current);
if (mid == R.id.MenuId_OpenGL15_Current)
{
....
}
satya - Saturday, February 20, 2010 10:11:34 PM
Listing 10-21. Transferring Menu ID through an Intent
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
if (item.getItemId() == R.id.mid_OpenGL10_SimpleTriangle)
{
//..Direct this menu item locally to the main activity
//..which you may be using for other purposes
return true;
}
//These menu items, direct them to the multiview
this.invokeMultiView(item.getItemId());
return true;
}
//here is invoking the multiview through a loaded intent
//carrying the menu id
//mid: menu id
private void invokeMultiView(int mid)
{
Intent intent = new Intent(this,MultiViewTestHarnessActivity.class);
intent.putExtra("com.ai.menuid", mid);
startActivity(intent);
}
satya - Saturday, February 20, 2010 10:14:42 PM
Listing 10-22. Simple Rectangle Renderer
public class SimpleRectangleRenderer extends AbstractRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 4;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
public SimpleRectRenderer(Context context)
{
ByteBuffer vbb = ByteBuffer.allocateDirect(VERTS * 3 * 4);
vbb.order(ByteOrder.nativeOrder());
mFVertexBuffer = vbb.asFloatBuffer();
ByteBuffer ibb = ByteBuffer.allocateDirect(6 * 2);
ibb.order(ByteOrder.nativeOrder());
mIndexBuffer = ibb.asShortBuffer();
float[] coords = {
-0.5f, -0.5f, 0, // (x1,y1,z1)
0.5f, -0.5f, 0,
0.5f, 0.5f, 0,
-0.5f, 0.5f, 0,
};
for (int i = 0; i < VERTS; i++) {
for(int j = 0; j < 3; j++) {
mFVertexBuffer.put(coords[i*3+j]);
}
}
short[] myIndecesArray = {0,1,2,0,2,3};
for (int i=0;i<6;i++)
{
mIndexBuffer.put(myIndecesArray[i]);
}
mFVertexBuffer.position(0);
mIndexBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
RegularPolygon.test();
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, 6,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 10:17:11 PM
Listing 10-23. Using a RegularPolygon Object
//A polygon with 4 sides and a radious of 0.5
//and located at (x,y,z) of (0,0,0)
RegularPolygon square = new RegularPolygon(0,0,0,0.5f,4);
//Let the polygon return the vertices
mFVertexBuffer = square.getVertexBuffer();
//Let the polygon return the triangles
mIndexBuffer = square.getIndexBuffer();
//you will need this for glDrawElements
numOfIndices = square.getNumberOfIndices();
//set the buffers to the start
this.mFVertexBuffer.position(0);
this.mIndexBuffer.position(0);
//set the vertex pointer
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
//draw it with the given number of Indices
gl.glDrawElements(GL10.GL_TRIANGLES, numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
satya - Saturday, February 20, 2010 10:27:59 PM
Listing 10-24. Implementing a RegularPolygon Shape
public class RegularPolygon
{
//Space to hold (x,y,z) of the center: cx,cy,cz
//and the radius "r"
private float cx, cy, cz, r;
private int sides;
//coordinate array: (x,y) vertex points
private float[] xarray = null;
private float[] yarray = null;
//texture arrray: (x,y) also called (s,t) points
//where the figure is going to be mapped to a texture bitmap
private float[] sarray = null;
private float[] tarray = null;
//**********************************************
// Constructor
//**********************************************
public RegularPolygon(float incx, float incy, float incz, // (x,y,z) center
float inr, // radius
int insides) // number of sides
{
cx = incx;
cy = incy;
cz = incz;
r = inr;
sides = insides;
//allocate memory for the arrays
xarray = new float[sides];
yarray = new float[sides];
//allocate memory for texture point arrays
sarray = new float[sides];
tarray = new float[sides];
//calculate vertex points
calcArrays();
//calculate texture points
calcTextureArrays();
}
//**********************************************
//Get and convert the vertex coordinates
//based on origin and radius.
//Real logic of angles happen inside getMultiplierArray() functions
//**********************************************
private void calcArrays()
{
//Get the vertex points assuming a circle
//with a radius of "1" and located at "origin" zero
float[] xmarray = this.getXMultiplierArray();
float[] ymarray = this.getYMultiplierArray();
//calc xarray: get the vertex
//by adding the "x" portion of the origin
//multiply the coordinate with radius (scale)
for(int i=0;i<sides;i++)
{
float curm = xmarray[i];
float xcoord = cx + r * curm;
xarray[i] = xcoord;
}
this.printArray(xarray, "xarray");
//calc yarray: do the same for y coordinates
for(int i=0;i<sides;i++)
{
float curm = ymarray[i];
float ycoord = cy + r * curm;
yarray[i] = ycoord;
}
this.printArray(yarray, "yarray");
}
//**********************************************
//Calculate texture arrays
//See Texture subsection for more discussion on this
//Very similar approach.
//In this case the polygon has to map into a space
//that is a square
//**********************************************
private void calcTextureArrays()
{
float[] xmarray = this.getXMultiplierArray();
float[] ymarray = this.getYMultiplierArray();
//calc xarray
for(int i=0;i<sides;i++)
{
float curm = xmarray[i];
float xcoord = 0.5f + 0.5f * curm;
sarray[i] = xcoord;
}
this.printArray(sarray, "sarray");
//calc yarray
for(int i=0;i<sides;i++)
{
float curm = ymarray[i];
float ycoord = 0.5f + 0.5f * curm;
tarray[i] = ycoord;
}
this.printArray(tarray, "tarray");
}
//**********************************************
//Convert the java array of vertices
//into an nio float buffer
//**********************************************
public FloatBuffer getVertexBuffer()
{
int vertices = sides + 1;
int coordinates = 3;
int floatsize = 4;
int spacePerVertex = coordinates * floatsize;
ByteBuffer vbb = ByteBuffer.allocateDirect(spacePerVertex * vertices);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer mFVertexBuffer = vbb.asFloatBuffer();
//Put the first coordinate (x,y,z:0,0,0)
mFVertexBuffer.put(cx); //x
mFVertexBuffer.put(cy); //y
mFVertexBuffer.put(0.0f); //z
int totalPuts = 3;
for (int i=0;i<sides;i++)
{
mFVertexBuffer.put(xarray[i]); //x
mFVertexBuffer.put(yarray[i]); //y
mFVertexBuffer.put(0.0f); //z
totalPuts += 3;
}
Log.d("total puts:",Integer.toString(totalPuts));
return mFVertexBuffer;
}
//**********************************************
//Convert texture buffer to an nio buffer
//**********************************************
public FloatBuffer getTextureBuffer()
{
int vertices = sides + 1;
int coordinates = 2;
int floatsize = 4;
int spacePerVertex = coordinates * floatsize;
ByteBuffer vbb = ByteBuffer.allocateDirect(spacePerVertex * vertices);
vbb.order(ByteOrder.nativeOrder());
FloatBuffer mFTextureBuffer = vbb.asFloatBuffer();
//Put the first coordinate (x,y (s,t):0,0)
mFTextureBuffer.put(0.5f); //x or s
mFTextureBuffer.put(0.5f); //y or t
int totalPuts = 2;
for (int i=0;i<sides;i++)
{
mFTextureBuffer.put(sarray[i]); //x
mFTextureBuffer.put(tarray[i]); //y
totalPuts += 2;
}
Log.d("total texture puts:",Integer.toString(totalPuts));
return mFTextureBuffer;
}
//**********************************************
//Calculate indices forming multiple triangles.
//Start with the center vertex which is at 0
//Then count them in a clockwise direction such as
//0,1,2, 0,2,3, 0,3,4..etc
//**********************************************
public ShortBuffer getIndexBuffer()
{
short[] iarray = new short[sides * 3];
ByteBuffer ibb = ByteBuffer.allocateDirect(sides * 3 * 2);
ibb.order(ByteOrder.nativeOrder());
ShortBuffer mIndexBuffer = ibb.asShortBuffer();
for (int i=0;i<sides;i++)
{
short index1 = 0;
short index2 = (short)(i+1);
short index3 = (short)(i+2);
if (index3 == sides+1)
{
index3 = 1;
}
mIndexBuffer.put(index1);
mIndexBuffer.put(index2);
mIndexBuffer.put(index3);
iarray[i*3 + 0]=index1;
iarray[i*3 + 1]=index2;
iarray[i*3 + 2]=index3;
}
this.printShortArray(iarray, "index array");
return mIndexBuffer;
}
//**********************************************
//This is where you take the angle array
//for each vertex and calculate their projection multiplier
//on the x axis
//**********************************************
private float[] getXMultiplierArray()
{
float[] angleArray = getAngleArrays();
float[] xmultiplierArray = new float[sides];
for(int i=0;i<angleArray.length;i++)
{
float curAngle = angleArray[i];
float sinvalue = (float)Math.cos(Math.toRadians(curAngle));
float absSinValue = Math.abs(sinvalue);
if (isXPositiveQuadrant(curAngle))
{
sinvalue = absSinValue;
}
else
{
sinvalue = -absSinValue;
}
xmultiplierArray[i] = this.getApproxValue(sinvalue);
}
this.printArray(xmultiplierArray, "xmultiplierArray");
return xmultiplierArray;
}
//**********************************************
//This is where you take the angle array
//for each vertex and calculate their projection multiplier
//on the y axis
//**********************************************
private float[] getYMultiplierArray() {
float[] angleArray = getAngleArrays();
float[] ymultiplierArray = new float[sides];
for(int i=0;i<angleArray.length;i++) {
float curAngle = angleArray[i];
float sinvalue = (float)Math.sin(Math.toRadians(curAngle));
float absSinValue = Math.abs(sinvalue);
if (isYPositiveQuadrant(curAngle)) {
sinvalue = absSinValue;
}
else {
sinvalue = -absSinValue;
}
ymultiplierArray[i] = this.getApproxValue(sinvalue);
}
this.printArray(ymultiplierArray, "ymultiplierArray");
return ymultiplierArray;
}
//**********************************************
//This function may not be needed
//Test it yourself and discard it if you dont need
//**********************************************
private boolean isXPositiveQuadrant(float angle) {
if ((0 <= angle) && (angle <= 90)) { return true; }
if ((angle < 0) && (angle >= -90)) { return true; }
return false;
}
//**********************************************
//This function may not be needed
//Test it yourself and discard it if you dont need
//**********************************************
private boolean isYPositiveQuadrant(float angle) {
if ((0 <= angle) && (angle <= 90)) { return true; }
if ((angle < 180) && (angle >= 90)) {return true;}
return false;
}
//**********************************************
//This is where you calculate angles
//for each line going from center to each vertex
//**********************************************
private float[] getAngleArrays() {
float[] angleArray = new float[sides];
float commonAngle = 360.0f/sides;
float halfAngle = commonAngle/2.0f;
float firstAngle = 360.0f - (90+halfAngle);
angleArray[0] = firstAngle;
float curAngle = firstAngle;
for(int i=1;i<sides;i++)
{
float newAngle = curAngle - commonAngle;
angleArray[i] = newAngle;
curAngle = newAngle;
}
printArray(angleArray, "angleArray");
return angleArray;
}
//**********************************************
//Some rounding if needed
//**********************************************
private float getApproxValue(float f) {
return (Math.abs(f) < 0.001) ? 0 : f;
}
//**********************************************
//Return how many Indices you will need
//given the number of sides
//This is the count of number of triangles needed
//to make the polygon multiplied by 3
//It just happens that the number of triangles is
// same as the number of sides
//**********************************************
public int getNumberOfIndices() {
return sides * 3;
}
public static void test() {
RegularPolygon triangle = new RegularPolygon(0,0,0,1,3);
}
private void printArray(float array[], String tag) {
StringBuilder sb = new StringBuilder(tag);
for(int i=0;i<array.length;i++) {
sb.append(";").append(array[i]);
}
Log.d("hh",sb.toString());
}
private void printShortArray(short array[], String tag) {
StringBuilder sb = new StringBuilder(tag);
for(int i=0;i<array.length;i++) {
sb.append(";").append(array[i]);
}
Log.d(tag,sb.toString());
}
}
satya - Saturday, February 20, 2010 10:30:48 PM
Listing 10-25. SquareRenderer
public class SquareRenderer extends AbstractRenderer
{
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
private int numOfIndices = 0;
private int sides = 4;
public SquareRenderer(Context context)
{
prepareBuffers(sides);
}
private void prepareBuffers(int sides)
{
RegularPolygon t = new RegularPolygon(0,0,0,0.5f,sides);
//RegularPolygon t = new RegularPolygon(1,1,0,1,sides);
this.mFVertexBuffer = t.getVertexBuffer();
this.mIndexBuffer = t.getIndexBuffer();
this.numOfIndices = t.getNumberOfIndices();
this.mFVertexBuffer.position(0);
this.mIndexBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
prepareBuffers(sides);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, this.numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 10:34:03 PM
Listing 10-26. PolygonRenderer
public class PolygonRenderer extends AbstractRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 4;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
private int numOfIndices = 0;
private long prevtime = SystemClock.uptimeMillis();
private int sides = 3;
public PolygonRenderer(Context context)
{
//EvenPolygon t = new EvenPolygon(0,0,0,1,3);
//EvenPolygon t = new EvenPolygon(0,0,0,1,4);
prepareBuffers(sides);
}
private void prepareBuffers(int sides)
{
RegularPolygon t = new RegularPolygon(0,0,0,1,sides);
//RegularPolygon t = new RegularPolygon(1,1,0,1,sides);
this.mFVertexBuffer = t.getVertexBuffer();
this.mIndexBuffer = t.getIndexBuffer();
this.numOfIndices = t.getNumberOfIndices();
this.mFVertexBuffer.position(0);
this.mIndexBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
long curtime = SystemClock.uptimeMillis();
if ((curtime - prevtime) > 2000)
{
prevtime = curtime;
sides += 1;
if (sides > 20)
{
sides = 3;
}
this.prepareBuffers(sides);
}
//EvenPolygon.test();
gl.glColor4f(1.0f, 0, 0, 0.5f);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, this.numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 10:40:01 PM
Listing 10-27. Abstracting Single Texturing Support
public abstract class AbstractSingleTexturedRenderer
extends AbstractRenderer
{
int mTextureID;
int mImageResourceId;
Context mContext;
public AbstractSingleTexturedRenderer(Context ctx,
int imageResourceId) {
mImageResourceId = imageResourceId;
mContext = ctx;
}
public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
super.onSurfaceCreated(gl, eglConfig);
gl.glEnable(GL10.GL_TEXTURE_2D);
prepareTexture(gl);
}
private void prepareTexture(GL10 gl)
{
int[] textures = new int[1];
gl.glGenTextures(1, textures, 0);
mTextureID = textures[0];
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
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 is = mContext.getResources()
.openRawResource(this.mImageResourceId);
Bitmap bitmap;
try {
bitmap = BitmapFactory.decodeStream(is);
} finally {
try {
is.close();
} catch(IOException e) {
// Ignore.
}
}
GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
bitmap.recycle();
}
public void onDrawFrame(GL10 gl)
{
gl.glDisable(GL10.GL_DITHER);
gl.glTexEnvx(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
GL10.GL_MODULATE);
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);
gl.glActiveTexture(GL10.GL_TEXTURE0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, mTextureID);
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);
draw(gl);
}
}
satya - Saturday, February 20, 2010 10:43:32 PM
Listing 10-28. TexturedSquareRenderer
public class TexturedSquareRenderer extends AbstractSingleTexturedRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 4;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFTextureBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
private int numOfIndices = 0;
private int sides = 4;
public TexturedSquareRenderer(Context context)
{
super(context,com.ai.android.OpenGL.R.drawable.robot);
prepareBuffers(sides);
}
private void prepareBuffers(int sides)
{
RegularPolygon t = new RegularPolygon(0,0,0,0.5f,sides);
this.mFVertexBuffer = t.getVertexBuffer();
this.mFTextureBuffer = t.getTextureBuffer();
this.mIndexBuffer = t.getIndexBuffer();
this.numOfIndices = t.getNumberOfIndices();
this.mFVertexBuffer.position(0);
this.mIndexBuffer.position(0);
this.mFTextureBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
prepareBuffers(sides);
gl.glEnable(GL10.GL_TEXTURE_2D);
CHAPTER 10: Programming 3D Graphics with OpenGL 55
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mFTextureBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, this.numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
}
}
satya - Saturday, February 20, 2010 10:46:44 PM
Listing 10-29. Textured Polygon Renderer
public class TexturedPolygonRenderer extends AbstractSingleTexturedRenderer
{
//Number of points or vertices we want to use
private final static int VERTS = 4;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFVertexBuffer;
//A raw native buffer to hold the point coordinates
private FloatBuffer mFTextureBuffer;
//A raw native buffer to hold indices
//allowing a reuse of points.
private ShortBuffer mIndexBuffer;
private int numOfIndices = 0;
private long prevtime = SystemClock.uptimeMillis();
private int sides = 3;
public TexturedPolygonRenderer(Context context)
{
super(context,com.ai.android.OpenGL.R.drawable.robot);
//EvenPolygon t = new EvenPolygon(0,0,0,1,3);
//EvenPolygon t = new EvenPolygon(0,0,0,1,4);
prepareBuffers(sides);
}
private void prepareBuffers(int sides)
{
RegularPolygon t = new RegularPolygon(0,0,0,0.5f,sides);
//RegularPolygon t = new RegularPolygon(1,1,0,1,sides);
this.mFVertexBuffer = t.getVertexBuffer();
this.mFTextureBuffer = t.getTextureBuffer();
this.mIndexBuffer = t.getIndexBuffer();
this.numOfIndices = t.getNumberOfIndices();
this.mFVertexBuffer.position(0);
this.mIndexBuffer.position(0);
this.mFTextureBuffer.position(0);
}
//overriden method
protected void draw(GL10 gl)
{
long curtime = SystemClock.uptimeMillis();
if ((curtime - prevtime) > 2000)
{
prevtime = curtime;
sides += 1;
if (sides > 20)
{
sides = 3;
}
this.prepareBuffers(sides);
}
gl.glEnable(GL10.GL_TEXTURE_2D);
//Draw once to the left
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mFVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mFTextureBuffer);
gl.glPushMatrix();
gl.glScalef(0.5f, 0.5f, 1.0f);
gl.glTranslatef(0.5f,0, 0);
gl.glDrawElements(GL10.GL_TRIANGLES, this.numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
//Draw again to the right
gl.glPopMatrix();
gl.glPushMatrix();
gl.glScalef(0.5f, 0.5f, 1.0f);
gl.glTranslatef(-0.5f,0, 0);
gl.glDrawElements(GL10.GL_TRIANGLES, this.numOfIndices,
GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
gl.glPopMatrix();
}
}