2012年10月30日 星期二

Android:OpenGL 建立


專案連結
package com.example.opengltest1;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;

import javax.microedition.khronos.opengles.GL10;

public class Triangle {

 private IntBuffer myVertexBuffer;// 頂點座標資料緩衝
 //private FloatBuffer myVertexBuffer;// 頂點座標資料緩衝
 //private FloatBuffer myColorBuffer;// 頂點著色資料緩衝
 private IntBuffer myColorBuffer;// 頂點著色資料緩衝
 private ByteBuffer myIndexBuffer;// 頂點建構的索引資料緩衝
 int vCount = 0;// 頂點數量
 int iCount = 0;// 索引數量
 float yAngle = 0.0f;// 繞Y旋轉的角度
 float zAngle = 0.0f;// 繞Z旋轉的角度

 public Triangle() {
  //初始化三角形的頂點座標暫存
  vCount = 3;// 設定頂點數量
  int[] vertices = new int[] {// 建立頂點資料陣列
  -80000, 60000, 0,
  -80000, -60000, 0,
  80000, -60000, 0, };
     //float[] vertices =new float[] { -80000.0f, 60000.0f, 0.0f, // 0, 左上角
       //-80000.0f, -60000.0f, 0.0f, // 1, 左下角
       //80000.0f, -60000.0f, 0.0f, // 2, 右下角  
     //};
  /*建立頂點座標資料暫存,由於不同平台位元組順序不同,
   * 資料單位不是位元組的要經由ByteBuffer轉換
   */
  ByteBuffer vbb=ByteBuffer.allocateDirect(vertices.length*4);
  //配置新的區塊
  vbb.order(ByteOrder.nativeOrder());//設定為本機平台的位元組順序
  //myVertexBuffer=vbb.asFloatBuffer();
  myVertexBuffer=vbb.asIntBuffer();//轉換為Int形式的緩衝,並將頂點作標資料緩衝建立實例
  myVertexBuffer.put(vertices);//將頂點座標資料放進緩衝
  myVertexBuffer.position(0);//設定緩衝區的起始位置

  //初始化三角形的顏色資料暫存
  int[] color=new int[]{// 建立頂點顏色陣列,有三個頂點,四個色彩值為RGBA
   0,65535,65535,0,
   65535,65535,65535,0,
   65535,65535,65535,0,
  };
  //float[] color=new float[]{
    //1.0f,1.0f,1.0f,0.0f,
    //1.0f,1.0f,1.0f,0.0f,
    //1.0f,1.0f,1.0f,0.0f,
  //};

  /*建立顏色資料暫存,由於不同平台位元組順序不同,
   * 資料單位不是位元組的要經由ByteBuffer轉換
   */
  ByteBuffer cbb=ByteBuffer.allocateDirect(color.length*4);
  //配置新的區塊
  cbb.order(ByteOrder.nativeOrder());//設定本機平台的位元組順序
  myColorBuffer=cbb.asIntBuffer();//轉換為Int形式的Buffer,並建立顏色資料緩衝的實例
  //myColorBuffer=cbb.asFloatBuffer();
  myColorBuffer.put(color);//將顏色資料陣列放入緩衝
  myColorBuffer.position(0);

  //初始化三角型構造索引資料緩衝
  iCount=3;
  byte[]index=new byte[]{
   0,1,2
  };
  //建立三角形構造資料緩衝,因為此資料陣列本身就是Byte形式,因此不需要作轉換
  myIndexBuffer=ByteBuffer.allocateDirect(index.length);
  //配置新的區塊
  myIndexBuffer.put(index);
  myIndexBuffer.position(0);

 }

 public void drawself(GL10 gl) {
  // TODO Auto-generated method stub
  gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);//啟動頂點座標陣列
  gl.glEnableClientState(GL10.GL_COLOR_ARRAY);//啟動頂點顏色陣列
  gl.glRotatef(yAngle, 0, 1, 0);//根據yAngle的角度值,繞Y旋轉
  gl.glRotatef(zAngle, 0, 0, 1);//根據zAngle的角度值,繞z旋轉
  gl.glVertexPointer(3, GL10.GL_FIXED, 0, myVertexBuffer);
  gl.glColorPointer(4, GL10.GL_FIXED, 0, myColorBuffer);
  gl.glDrawElements(GL10.GL_TRIANGLES, iCount, GL10.GL_UNSIGNED_BYTE, myIndexBuffer);
 }
}

MainActivity.java
package com.example.opengltest1;

import android.os.Bundle;
import android.app.Activity;
import android.widget.LinearLayout;

public class MainActivity extends Activity
{
    private MySurfaceView mysurfaceview;
    private LinearLayout lin;
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lin=(LinearLayout)findViewById(R.id.LinearLayout1);
        mysurfaceview=new MySurfaceView(this);
        mysurfaceview.requestFocus();
        mysurfaceview.setFocusableInTouchMode(true);
        lin.addView(mysurfaceview);
    }
    @Override
    protected void onPause()
    {
        // TODO Auto-generated method stub
        super.onPause();
        mysurfaceview.onPause();
    }
    @Override
    protected void onResume()
    {
        // TODO Auto-generated method stub
        super.onResume();
        mysurfaceview.onResume();
    }


}

MyRenderer.java
package com.example.opengltest1;

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

import android.opengl.GLSurfaceView.Renderer;

public class MyRenderer implements Renderer
{
    Triangle tr = new Triangle();

    public void onDrawFrame(GL10 gl)
    {
        // TODO Auto-generated method stub
        gl.glEnable(GL10.GL_CULL_FACE);// 打開背面剪裁
        gl.glShadeModel(GL10.GL_SMOOTH);//設定著色模型為平滑著色
        gl.glFrontFace(GL10.GL_CCW);//設定自訂捲繞順序:逆時針為正面
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT|GL10.GL_DEPTH_BUFFER_BIT);//清除暫存
        gl.glMatrixMode(GL10.GL_MODELVIEW);//設定當前矩陣為模式矩陣
        gl.glLoadIdentity();//設定當前矩陣為單位矩陣,此方法相当于我们手机的重置功能,它将所选择的矩阵状态恢复成原始状态
        gl.glTranslatef(0, 0, -4.0f);//把座標系往Z軸負方向平移兩個單位
        tr.drawself(gl);
    }

    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        // TODO Auto-generated method stub
        gl.glViewport(0, 0, width, height);//設定視窗大小和位置
        gl.glMatrixMode(GL10.GL_PROJECTION);//設定矩陣為投影矩陣
        gl.glLoadIdentity();
        float ratio=(float)width/height;//比例大小
        gl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);//設定投影模式
    }

    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
        // TODO Auto-generated method stub
        gl.glDisable(GL10.GL_DITHER);//關閉抗抖動
        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,GL10.GL_FASTEST);//設置模式
        gl.glClearColorx(0, 0, 0, 0);//螢幕背景為黑色(RGBA)
        gl.glEnable(GL10.GL_DEPTH_TEST);//啟動深度檢測
    }

}

MySurfaceView.java
package com.example.opengltest1;

import android.content.Context;
import android.opengl.GLSurfaceView;
import android.view.MotionEvent;

public class MySurfaceView extends GLSurfaceView
{

    private final float TOUCH_SCALE_FATOR=180.0f/320;
    private MyRenderer myren;
    private float previousX;
    private float previousY;

    public MySurfaceView(Context context)
    {
        super(context);
        // TODO Auto-generated constructor stub
        myren=new MyRenderer();
        this.setRenderer(myren);
        this.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event)
    {
        // TODO Auto-generated method stub
        float x=event.getX();
        float y=event.getY();
        switch (event.getAction())
        {
        case MotionEvent.ACTION_MOVE:
            float dy=y-previousY;
            float dx=x-previousX;
            myren.tr.yAngle=myren.tr.yAngle+dx*TOUCH_SCALE_FATOR;
            myren.tr.zAngle=myren.tr.zAngle+dy*TOUCH_SCALE_FATOR;
            MySurfaceView.this.requestRender();
            //break;
        }
        previousY=y;
        previousX=x;
        return true;
    }



}