2011年5月31日火曜日

AndroidでMetasequoiaのmqoを読み込むコード その2 Textureクラス

大分空きましたが続きー

VBOとTextureをワンセットにすることで、DirectXで言うサブセットみたいな処理ができるので、Textureクラスも当然必要です(テクスチャの切り替えを最小限にするため)

  1. package com.dividebyzero.KszGameBase;  
  2.   
  3. import java.util.HashMap;  
  4.   
  5. import javax.microedition.khronos.opengles.GL10;  
  6. import javax.microedition.khronos.opengles.GL11;  
  7.   
  8. import android.content.Context;  
  9. import android.graphics.Bitmap;  
  10. import android.graphics.BitmapFactory;  
  11. import android.opengl.GLUtils;  
  12. import android.util.Log;  
  13.   
  14. /** 
  15.  * テクスチャクラス 
  16.  * @author ksz 
  17.  * 
  18.  */  
  19. public class Texture {  
  20.  public int resID, texID, w, h;  
  21.  private static final RenderParam param = new RenderParam();  
  22.   
  23.  /** 
  24.   * @param resID リソースID 
  25.   * @param texID OpenGLでのテクスチャID 
  26.   * @param w 横幅 
  27.   * @param h 縦幅 
  28.   */  
  29.  public Texture(int resID, int texID, int w, int h) {  
  30.   this.resID = resID;  
  31.   this.texID = texID;  
  32.   this.w = w;  
  33.   this.h = h;  
  34.  }  
  35.   
  36.  /** 
  37.   * staticのrenderを呼びやすくしただけ 
  38.   */  
  39.  public void render(float x,float y){  
  40.   render(this,x,y,0,param.init());  
  41.  }  
  42.    
  43.  /** 
  44.   * staticのrenderを呼びやすくしただけ 
  45.   */  
  46.  public void render(float x, float y, RenderParam param) {  
  47.   render(this, x, y, 0, param);  
  48.  }  
  49.   
  50.  /** 
  51.   * staticのrenderを呼びやすくしただけ 
  52.   */  
  53.  public void render(float x, float y, float z, RenderParam param) {  
  54.   render(this, x, y, z, param);  
  55.  }  
  56.   
  57.  /** 
  58.   * staticのポリラインを呼びやすくしただけ 
  59.   */  
  60.  public void renderPolyLine(float sx, float sy, float ex, float ey, RenderParam param) {  
  61.   renderPolyLine(this, sx, sy, ex, ey, param);  
  62.  }  
  63.   
  64.  /** 
  65.   * テクスチャのバインド 
  66.   */  
  67.  public void bind() {  
  68.   setTexture(texID);  
  69.  }  
  70.   
  71.  //////////////////ここから管理ゾーン  
  72.  public static HashMap<Integer, Texture> texMap = new HashMap<:Integer, Texture>();  
  73.   
  74.  /** 
  75.   * リソースIDではなく、文字列からテクスチャインスタンスを作成 
  76.   * @param resName 読み込みたい文字列 "***.png"のようにしても、拡張子部分は捨てられる 
  77.   * @return 作成されたテクスチャインスタンス 
  78.   */  
  79.  public static Texture get(String resName) {  
  80.   Context context = Global.view.getContext();  
  81.   int point = resName.lastIndexOf(".");  
  82.   if (point != -1) {  
  83.    resName = resName.substring(0, point);  
  84.   }  
  85.   Log.v("debug", resName);  
  86.   int id = context.getResources().getIdentifier(resName, "drawable", context.getPackageName());  
  87.   return get(id);  
  88.  }  
  89.   
  90.  /** 
  91.   * リソースIDからテクスチャインスタンスを作成 
  92.   * @param resID 読み込みたいリソース 
  93.   * @return 作成されたテクスチャインスタンス。既に読み込まれている場合はそのインスタンス 
  94.   */  
  95.  public static Texture get(int resID) {  
  96.   if (texMap.containsKey(resID)) {  
  97.    return texMap.get(resID);  
  98.   }  
  99.   
  100.   GL10 gl = Global.gl;  
  101.   //リソースBMPを読み込む  
  102.   BitmapFactory.Options opt = new BitmapFactory.Options();  
  103.   opt.inScaled = false//勝手に拡大縮小するので止める  
  104.   Bitmap bitmap = BitmapFactory.decodeResource(Global.view.getResources(), resID, opt);  
  105.   //グラボのテクスチャとして登録  
  106.   int[] texID = new int[1]; //グラボからテクスチャIDを受け取るための変数  
  107.   gl.glGenTextures(1, texID, 0); //グラボから使ってないテクスチャIDを取得  
  108.   Texture.setTexture(texID[0]);  
  109.   //BMPをテクスチャに割り当てる  
  110.   GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);  
  111.   //テクスチャパラメータをセット  
  112.   gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, //拡大の時は  
  113.     GL10.GL_LINEAR); //線形補間  
  114.   gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, //縮小の時は  
  115.     GL10.GL_LINEAR); //線形補間  
  116.   gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, //UVがはみ出したときどうしますか  
  117.     GL10.GL_CLAMP_TO_EDGE); //端っこで止める  
  118.   gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, //UVがはみ出したときどうしますか  
  119.     GL10.GL_CLAMP_TO_EDGE); //端っこで止める  
  120.   
  121.   Texture tex = new Texture(resID, texID[0], bitmap.getWidth(), bitmap.getHeight());  
  122.   bitmap.recycle();  
  123.   texMap.put(resID, tex);  
  124.   return tex;  
  125.  }  
  126.   
  127.  private static Vbo vbo = null;  
  128.  private static int currentTexID = -1;  
  129.   
  130.  /** 
  131.   * テクスチャをOpenGLにセット 
  132.   * 同じテクスチャが連続でセットされないようにしている 
  133.   * @param id セットしたいテクスチャ 
  134.   */  
  135.  public static void setTexture(int id) {  
  136.   if (currentTexID != id) {  
  137.    currentTexID = id;  
  138.    Global.gl.glBindTexture(GL10.GL_TEXTURE_2D, id);  
  139.   }  
  140.  }  
  141.   
  142.  /** 
  143.   * 指定されたテクスチャを描画 z軸が無いVer 
  144.   * @param tex 描画したいテクスチャ 
  145.   * @param x 座標x 
  146.   * @param y 座標y 
  147.   * @param param 描画パラメータ 
  148.   */  
  149.  public static void render(Texture tex, float x, float y, RenderParam param) {  
  150.   render(tex, x, y, 0, param);  
  151.  }  
  152.   
  153.  /** 
  154.   * 指定されたテクスチャを描画 
  155.   * @param tex 描画したいテクスチャ 
  156.   * @param x 座標x 
  157.   * @param y 座標y 
  158.   * @param z 座標z 2Dゲームの場合は0で 
  159.   * @param param 描画パラメータ  
  160.   */  
  161.  public static void render(Texture tex, float x, float y, float z, RenderParam param) {  
  162.   if (vbo == null) {  
  163.    //頂点4つ分用意  
  164.    float v[] = {  
  165.      //頂点  
  166.      000010100110,  
  167.    };  
  168.    float t[] = {  
  169.      //UV  
  170.      00011011,  
  171.    };  
  172.   
  173.    vbo = new Vbo();  
  174.    vbo.makeBuffer(v, t);  
  175.   }  
  176.   vbo.bindVBO();  
  177.   GL11 gl = Global.gl;  
  178.   
  179.   setTexture(tex.texID);  
  180.   gl.glColor4f(param.r, param.g, param.b, param.a);  
  181.   
  182.   if (param.cw + param.ch < 0) {  
  183.    param.cw = (float) tex.w;  
  184.    param.ch = (float) tex.h;  
  185.   }  
  186.   if (param.isCenterOrigin) {  
  187.    if (param.isDestsize) {  
  188.     param.ox = param.dw / 2;  
  189.     param.oy = param.dh / 2;  
  190.    } else {  
  191.     param.ox = param.cw * Math.abs(param.sx) / 2;  
  192.     param.oy = param.ch * Math.abs(param.sy) / 2;  
  193.    }  
  194.   }  
  195.   if (RenderParam.oldAddAlphaMode != param.isAddAlpha) {  
  196.    if (param.isAddAlpha) {  
  197.     gl.glDisable(GL10.GL_DEPTH_TEST);  
  198.     gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);  
  199.    } else {  
  200.     gl.glEnable(GL10.GL_DEPTH_TEST);  
  201.     gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);  
  202.    }  
  203.   }  
  204.   RenderParam.oldAddAlphaMode = param.isAddAlpha;  
  205.   
  206.   gl.glMatrixMode(GL10.GL_TEXTURE);  
  207.   gl.glLoadIdentity();  
  208.   gl.glTranslatef(param.cx + param.cw / tex.w * param.xindex, param.cy + param.ch / tex.h * param.yindex, 0);  
  209.   gl.glScalef(param.cw / tex.w, param.ch / tex.h, 1);  
  210.   
  211.   gl.glMatrixMode(GL10.GL_MODELVIEW);  
  212.   gl.glPushMatrix(); //カメラ行列を退避  
  213.   
  214.   //移動させつつ、原点指定しつつ  
  215.   if (param.isDestsize) {  
  216.    gl.glTranslatef(0.5f * param.dw - param.ox + x, 0.5f * param.dh - param.oy + y, z);  
  217.   } else {  
  218.    gl.glTranslatef(0.5f * param.cw * Math.abs(param.sx) - param.ox + x, 0.5f * param.ch * Math.abs(param.sy)  
  219.      - param.oy + y, z);  
  220.   }  
  221.   gl.glRotatef(param.ax, 001); //回転(なぜかラジアンじゃない)  
  222.   if (param.isDestsize) {  
  223.    gl.glScalef(param.dw, param.dh, 1); //拡大縮小  
  224.   } else {  
  225.    gl.glScalef(param.sx * param.cw, param.sy * param.ch, 1); //拡大縮小  
  226.   }  
  227.   gl.glTranslatef(-0.5f, -0.5f, 0); //中心を原点に回転するための小細工  
  228.   
  229.   gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 04); //横1縦1の頂点描画  
  230.   
  231.   gl.glPopMatrix(); //カメラ行列を戻す  
  232.  }  
  233.   
  234.  /** 
  235.   * ポリライン(テクスチャを線のように描画) 
  236.   * @param tex 描画したいテクスチャ 
  237.   * @param sx 始点x 
  238.   * @param sy 始点y 
  239.   * @param ex 終点x 
  240.   * @param ey 終点y 
  241.   * @param param パラメータ、幅など 
  242.   */  
  243.  void renderPolyLine(Texture tex, float sx, float sy, float ex, float ey, RenderParam param) {  
  244.   Vec3 tang = new Vec3(ex - sx, ey - sy, 0);  
  245.   float angle = (float) Math.atan2(tang.y, tang.x) * Util.TOANGLE;  
  246.   param.setDestSize(Math.abs(tang.getLength()), Math.abs(param.sx)).setAngle(angle);  
  247.   param.setCenterOrigin(true);  
  248.   render(tex, sx + tang.x / 2, sy + tang.y / 2, param);  
  249.  }  
  250.   
  251.  /** 
  252.   * 指定されたリソースを描画  
  253.   * 指定されたリソースがまだ読み込まれていない場合は読み込まれる 
  254.   * @param resID R.drawable.iconなど、リソースのIDを直指定 
  255.   * @param x 描画位置x 
  256.   * @param y 描画位置y 
  257.   * @param param RenderParamのインスタンスによって描画パラメータを操作 
  258.   */  
  259.  public static void render(int resID, int x, int y, RenderParam param) {  
  260.   render(get(resID), x, y, param);  
  261.  }  
  262.   
  263.  /** 
  264.   * 管理されているテクスチャを全て開放 
  265.   */  
  266.  public static void release() {  
  267.   int textureID[] = new int[1];  
  268.   for(Texture tex:texMap.values()){  
  269.    textureID[0] = tex.texID;  
  270.    Global.gl.glDeleteTextures(1, textureID, 0);  
  271.   }  
  272.   texMap.clear();  
  273.   texMap = null;    
  274.  }  
  275.   
  276.  /** 
  277.   * 画面クリア処理 
  278.   * Textureクラスに入れるのが適当がどうかは微妙なところ 
  279.   * 深度を有効化しないと、深度バッファのクリアがうまくいかない場合があるようなので、毎回入れてます。 負荷だけど。 
  280.   */  
  281.  public static void clear() {    
  282.   Global.gl.glEnable(GL10.GL_DEPTH_TEST);  
  283.   Global.gl.glDepthMask(true); // 深度バッファ書き込み有効  
  284.   Global.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
  285.  }  
  286.   
  287.  /** 
  288.   * 画面をクリアします 
  289.   * @param r 赤(0.0f~1.0f) 
  290.   * @param g 緑(0.0f~1.0f) 
  291.   * @param b 青(0.0f~1.0f) 
  292.   * @param a アルファ値(0.0f~1.0f) 
  293.   */  
  294.  public static void clear(float r,float g,float b,float a) {  
  295.   Global.gl.glClearColor(r,g,b,a);  
  296.   clear();  
  297.  }  
  298.  /** 
  299.   * 画面をクリアします 
  300.   * @param r 赤(0~255) 
  301.   * @param g 緑(0~255) 
  302.   * @param b 青(0~255) 
  303.   * @param a アルファ値(0~255) 
  304.   */  
  305.  public static void clear(int r,int g,int b,int a) {  
  306.   Global.gl.glClearColor(r/255.0f,g/255.0f,b/255.0f, a / 255.0f);  
  307.   clear();  
  308.  }  
  309. }  

しかし、ソースのほとんどが2D用だっていうのは僕と君だけの秘密だぞ。

2011年5月25日水曜日

AndroidでMetasequoiaのmqoを読み込むコード その1 VBO

以前書いた記事でmqo読んでるぜーって書いたらなんだか奇特な方がソースを晒してくれってな事だったので、ざっと。

でも、結構絡み合ってるんですよ? これが?

まず、VertexObjectで描画が基本なので、VBOクラスから。

  1. import java.nio.FloatBuffer;  
  2. import java.util.ArrayList;  
  3.   
  4. import javax.microedition.khronos.opengles.GL10;  
  5. import javax.microedition.khronos.opengles.GL11;  
  6.   
  7. /** 
  8.  * VertexBufferObjectクラス 
  9.  * @author ksz 
  10.  */  
  11. public class Vbo {  
  12.  public float r=1,g=1,b=1,a=1,diffuse=1,ambient=1;  
  13.  public int vSize, tSize;  
  14.  private int vboID = -1;  
  15.  private static int oldID = -1;  
  16.   
  17.  /** 
  18.   * GLにVBOをセット 
  19.   */  
  20.  public void bindVBO() {  
  21.   if (oldID == vboID) return//既に同じバッファがセットされていたら無視  
  22.   if (vboID < 0return//makeBufferされてないようなので無視  
  23.   
  24.   oldID = vboID;  
  25.   GL11 gl = Global.gl;  
  26.   gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vboID);  
  27.   gl.glVertexPointer(3, GL11.GL_FLOAT, 00); //頂点バッファ  
  28.   
  29.   if (tSize != 0) {  
  30.    gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, vSize); //UVバッファ  
  31.   }  
  32.  }  
  33.   
  34.  /** 
  35.   * VBOを描画します 
  36.   */  
  37.  public void draw() {  
  38.   GL11 gl = Global.gl;  
  39.     
  40.   //テクスチャ行列を外す  
  41.   gl.glMatrixMode(GL10.GL_TEXTURE);  
  42.   gl.glLoadIdentity();  
  43.   
  44.   gl.glColor4f(r, g, b, a);  
  45.   
  46.   bindVBO();  
  47.     
  48.   //vSizeは頂点配列のバイト数なので、floatにするのに/4 TRIANGLESなので3角ポリで/3 で/12  
  49.   gl.glDrawArrays(GL10.GL_TRIANGLES, 0, vSize / 12);  
  50.  }  
  51.   
  52.  /** 
  53.   * 頂点とUVの配列からVBO作成 
  54.   * @param v 頂点配列 
  55.   * @param t UV配列 
  56.   */  
  57.  public void makeBuffer(float v[], float t[]) {  
  58.   vSize = v.length;  
  59.   tSize = 0;  
  60.   if (t != null && t.length != 0) {  
  61.    tSize = t.length;  
  62.   }  
  63.   makeBuffer(v,vSize, t,tSize);    
  64.  }  
  65.   
  66.  /** 
  67.   * 頂点とUVの配列からVBO作成(サイズ指定版) 
  68.   * @param v  頂点配列 
  69.   * @param vCnt 頂点配列の有効要素数 
  70.   * @param t  UV配列 
  71.   * @param tCnt UV配列の有効要素数 
  72.   */  
  73.  public void makeBuffer(float v[],int vCnt, float t[],int tCnt) {  
  74.   GL11 gl = Global.gl;  
  75.   vSize = vCnt * 4;  
  76.   tSize = tCnt * 4;  
  77.   
  78.   int vbo[] = new int[1];  
  79.   gl.glGenBuffers(1, vbo, 0);  
  80.   gl.glBindBuffer(GL11.GL_ARRAY_BUFFER, vbo[0]);  
  81.   gl.glBufferData(GL11.GL_ARRAY_BUFFER, vSize + tSize, null, GL11.GL_STATIC_DRAW);  
  82.   gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, 0, vSize, FloatBuffer.wrap(v));  
  83.   if (tSize != 0) {  
  84.    gl.glBufferSubData(GL11.GL_ARRAY_BUFFER, vSize, tSize, FloatBuffer.wrap(t));  
  85.   }  
  86.   vboID = vbo[0];  
  87.  }  
  88. }  

ちなみに、ライティングは無視してるので、勝手に拡張してね。
Global.gl とかがさも当然のように使われてますが、GL11インスタンスはいろんなところから使うので、グローバルっぽく使うためにpublic static な領域にGl11インスタンスを渡してある前提で。

まだまだ続きます。

2011年5月19日木曜日

ARの前にカメラのプレビュー画像とOpenGLの画像を重ねてみた


カメラ用のSurfaceView作って、FrameLayoutでOpenGLのViewと重ねるだけじゃん? って思ってたら結構はまりました。

いろんなところですでに言われてますが、

①普通に考えるとカメラの画像にOpenGLを重ねるので、
カメラビューの追加 → OpenGLビューの追加
となると思いきや、
OpenGLビューの追加 → カメラビューの追加
にしないといけない罠
  1. public void onCreate(Bundle savedInstanceState) {  
  2.  super.onCreate(savedInstanceState);  
  3.  FrameLayout layout = new FrameLayout(this);  
  4.  setContentView(layout);    
  5.  layout.addView(new GameView(thisnew OpeningScene(), 640480));  
  6.  layout.addView(new CameraSurfaceView(this));  
  7. }  

②OpenGLの方のピクセルフォーマットを透過にしなければいけない罠+ChoosConfigの時にEGL_ALPHA_SIZEを指定しないと機種によっては表示がバグる罠。
※でもなんか、PixelFormat.RGBA_8888でも大丈夫だった、うん?
  1. getHolder().setFormat(PixelFormat.RGBA_8888);  
  2. getHolder().setType(SurfaceHolder.SURFACE_TYPE_GPU);  
  3. getHolder().addCallback(this);  
  1. int[] spec = {  
  2.  EGL10.EGL_ALPHA_SIZE,1,  
  3.  EGL10.EGL_DEPTH_SIZE,1,  
  4.  EGL10.EGL_NONE  
  5. };   
  6. EGLConfig[] configs = new EGLConfig[1];  
  7. egl.eglChooseConfig(display, spec, configs, 1new int[1]);  

③glClearColorのアルファの指定を1以外にしないとカメラビューが映らない罠
  1. public static void clear() {    
  2.  Global.gl.glClearColor(1,1,1,0);  
  3.  Global.gl.glEnable(GL10.GL_DEPTH_TEST);  
  4.  Global.gl.glDepthMask(true); // 深度バッファ書き込み有効  
  5.  Global.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);  
  6. }  

ARとか程遠い。

2011年5月12日木曜日

縦画面対応


ちなみに前回書き忘れましたがモデルはココのをお借りしております。

2D画像の板ポリを球っぽく並べたまではいいんですが、実はこいつらビルボード化してないのですよな。
ちゅーか、ビルボードの為の計算量がもったいないっちゅーか。 ポイントスプライトってないのかなぁ。

2011年5月6日金曜日

Androidでメタセコイアのmqoファイルを読み込んでみるテスト

エミュレータではとてもじゃないけど開発する気にならない3Dですが、実機(IS01・Life Touch Note)ではサクサク動くので、3Dにも手を出してみることに。

最初はXファイル読み込ませようかとも思ったんですが、あのフォーマットは手に負えないのでメタセコイア(Metasequoia)のtxtのmqoファイルを読み込ます事に。
理論上は完璧だと思ってたら、穴が空きまくったり(DEPTH_SIZEが問題だった)
2Dと両用を考えてたんだけど(3Dだけど、スコア表示は2Dなど)Lief Touch Noteの射影マトリクスのスタックの数が1か2ぐらいしかなくて、glPushMatrix()・glPopMatrix()が役立たずだったりしましたとさ。

ソースコードはもうちょっとリファクタリングしたら晒したいなぁ。