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();
   }
}