2012/07/25

How to use OpenGL in Android

This article  teaches how to use OpenGL in Android phone.
There are two classes must be create and implement GLSurfaceView and Renderer.
The article OpenGL explains classes do. I just focus the implement step.

Step1:Create a new project in the Eclipse. I supposed that you already known how.
Step2:.Modify the layout file "main.xml".
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/frameLayout1">
</FrameLayout>

Step3:Create a new class i named OpenGLRenderer.The class must implement the Renderer class.
package my.project.MyFirstOpenGL;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.content.Context;
import android.opengl.GLSurfaceView.Renderer;
import android.widget.FrameLayout;

public class OpenGLRenderer implements Renderer
{
 public OpenGLRenderer(Context context, FrameLayout mainLayout)
 {  
 }
 
 @Override
 public void onDrawFrame(GL10 arg0) 
 {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void onSurfaceChanged(GL10 arg0, int arg1, int arg2) 
 {
  // TODO Auto-generated method stub
  
 }

 @Override
 public void onSurfaceCreated(GL10 arg0, EGLConfig arg1) 
 {
  // TODO Auto-generated method stub
  
 }

} 
Step4:In the OpenGLRenderer constructor, we need the Context and FrameLayout parameters. And create the GLSurfaceView add to the frameLayout.
 
public OpenGLRenderer(Context context, FrameLayout mainLayout)
{  
 this.context = context;
 //
 // Create GLSurfaceView and set this class as the renderer.
 //
 GLSurfaceView glView = new GLSurfaceView(context);
 glView.setRenderer(this);  
   
 //put to Main layout
 mainLayout.addView(glView, new LayoutParams(LayoutParams.FILL_PARENT,   LayoutParams.FILL_PARENT));
 }
 
Step5:Put some basic OpenGL code to the other functions.
 
 public void onDrawFrame(GL10 gl) 
 {
  // Clear the whole screen and depth.
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  
  // Setting the GL_MODELVIEW matrix
  gl.glMatrixMode(GL10.GL_MODELVIEW); 
  // Load the Identity matrix
  gl.glLoadIdentity();
 }
 
 public void onSurfaceChanged(GL10 gl, int width, int height) 
 {
  // Set OpenGL viewport
  gl.glViewport(0, 0, width, height);
  
  // Setting the GL_PROJECTION matrix
  gl.glMatrixMode(GL10.GL_PROJECTION);
  // Load the Identity matrix
  gl.glLoadIdentity();
  
  float ratio = (float) width / height;
  // Set the fovy to 45 degree. near depth is 0.1f and far depth is 100.f.
  // And maintain the screen ratio.
  GLU.gluPerspective(gl, 45, ratio, 0.1f, 100.f);
 }
 
 public void onSurfaceCreated(GL10 gl, EGLConfig arg1) 
 {
  // Set the background to black
  gl.glClearColor(0, 0, 0, 0);
 } 
Step6:And now we can add OpenGLRenderer class to the main code.
    
 public void onCreate(Bundle savedInstanceState) 
 {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.main);
   FrameLayout mainLayout = (FrameLayout) findViewById(R.id.frameLayout1);
   //
   // Create OpenGL surface and render
   // 
   OpenGLRenderer gl3DView = new OpenGLRenderer(this, mainLayout);
 } 
Step7:OK, We put the necessarily code to the project.Now we can run this project on emulator.But there is nothing in the screen but the black.

















Step8:At this stage, we create a OpenGL environment, but we did not put things in there.
   I want load a picture and map to a plane , then rotate it.
 //
 // Load the  Texture
 //
 private void LoadTexture(GL10 gl, Context cont)
 {
   gl.glTexParameterf(GL10.GL_TEXTURE_2D, 
                         GL10.GL_TEXTURE_MAG_FILTER, 
                         GL10.GL_LINEAR);
   InputStream istream = cont.getResources().openRawResource(R.drawable.guam);
   
   Bitmap bitmap;
   try{
    bitmap = BitmapFactory.decodeStream(istream);
   }
   finally{
    try{
     istream.close();
    }
    catch(IOException e){}
   } 
   gl.glGenTextures(MAX_TEXTURE, textureID, 0);
   gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID[0]);
   GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bitmap, 0 ); 
   gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
   
   bitmap.recycle();
   mTextureBuffer = getNativeFloatBuffer(squTex);
   mVerticesBuffer = getNativeFloatBuffer(squVtx);
   mIndexBuffer = getNativeShortBuffer(squInx);
 } 
 //
 // Draw the scene
 //
 private void DrawTheScene(GL10 gl)
 { 
  gl.glEnable( GL10.GL_TEXTURE_2D);
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);  
  gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

  gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, mVerticesBuffer);
  gl.glTexCoordPointer( 2, GL10.GL_FLOAT, 0, mTextureBuffer);
  
  gl.glBindTexture(GL10.GL_TEXTURE_2D, textureID[0]); 
  
  gl.glDrawElements( GL10.GL_TRIANGLE_FAN,
       squInx.length, 
                      GL10.GL_UNSIGNED_SHORT, 
                      mIndexBuffer);
  
  gl.glDisable(GL10.GL_TEXTURE_2D);
  gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
  gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
 } 
 
Step9:We need some variables.
 private float orientation = 0.0f;;
 
 final int MAX_TEXTURE = 20;
 private int[] textureID = new int[MAX_TEXTURE];
 

 //     UV Coordinates             
 //          _________ 
 //  v0(0,0) |         | v3(1,0) 
 //          |         |
 //          |         |
 //  v1(0,1) |_________| v2(1,1)
 //
 //
 //   plane vertices
 //     _________ 
 //  p0 |         | p3 
 //     |         |
 //     |         |
 //  p1 |_________| p2
 //

 float squVtx[] = {   
            -1.0f,  1.0f,  0.0f, //p0 Left-Top corner
            -1.0f, -1.0f,  0.0f, //p1 Left-bottom corner 
             1.0f, -1.0f,  0.0f, //p2 Right-bottom corner 
             1.0f,  1.0f,  0.0f };//p3 Right-top corner 

 // USE GL_TRIANGLE_FAN
 short squInx[] = {  0, 1, 2, 3}; //0-1-2 first triangle
                                  //0-2-3 second triangle 
 float squTex[] ={  0.0f, 0.0f,  //v0 Left-Top corner
                    0.0f, 1.0f,  //v1 Left-bottom corner 
                    1.0f, 1.0f,  //v2 Right-top corner
                    1.0f, 0.0f };//v3 Right-bottom corner 
 
 // Our UV texture buffer.
 private FloatBuffer mTextureBuffer; 
 private FloatBuffer mVerticesBuffer;
 private ShortBuffer mIndexBuffer;
 
Step10:Add LoadTexture() and DrawTheScene() to the code.
 public void onSurfaceCreated(GL10 gl, EGLConfig arg1) 
 {
  // Set the background to black
  gl.glClearColor(0, 0, 0, 0);
  
  //Load the texture
  LoadTexture(gl, context);  
 }
 public void onDrawFrame(GL10 gl) 
 {
  // Clear the whole screen and depth.
  gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
  
  // Setting the GL_MODELVIEW matrix
  gl.glMatrixMode(GL10.GL_MODELVIEW); 
  // Load the Identity matrix
  gl.glLoadIdentity();
  
  // Move to Z = -10
  gl.glTranslatef(0, 0, -10f);
  // Rotate y-asix
  gl.glRotatef(orientation, 0, 1.0f, 0);
  
  //every time plus 1 defgee.
  orientation += 1.0f;
  if ( orientation >= 360 )
   orientation = 0.0f;

  // Draw the scene
  DrawTheScene(gl);
 }
 
Step11:Another functions.
 private FloatBuffer getNativeFloatBuffer(float[] buffer)
 {
  ByteBuffer ibb = ByteBuffer.allocateDirect(buffer.length*4);
  ibb.order(ByteOrder.nativeOrder());
  FloatBuffer fbf = ibb.asFloatBuffer();

  fbf.put(buffer);
  fbf.position(0);
  return fbf;
 } 
 
 private ShortBuffer getNativeShortBuffer(short[] buffer)
 {
  ByteBuffer ibb = ByteBuffer.allocateDirect(buffer.length*2);
  ibb.order(ByteOrder.nativeOrder());
  ShortBuffer sbf = ibb.asShortBuffer();

  sbf.put(buffer);
  sbf.position(0);
  return sbf;
 } 
Step12:Finally, we put the picture to the OpenGL texture resources and draw 2 triangles to show the picture. Then rotate it frame by fame.

No comments:

Post a Comment