2012年7月21日土曜日

日記ちゃんあんどろ


GL10PrimitiveEx1.apk
size: 62KB
 とりあえずオブジェクトの描画と音をならせるようになった。
GLSurfaceViewにおまかせコース。
頂点をバッファに登録していき、一度に全部描く方法をとった。
実機だと三角形32個ぐらいの描画が限界で、これじゃあどうにもならなそうだ。
頂点数が問題ならともかく、描画面積的に限界がきてるっぽいから背景描いたりとかもちろんできない。



以下ソースコード。面倒だったから1ファイルに全部書いた。
某所のサンプルをいじくったので痕跡が残ってる。
package my.gl10primitiveex;
 
import android.app.Activity;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
 
import java.nio.ByteBuffer;
import java.nio.ShortBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.Random;
 
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;
 
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLUtils;
import android.opengl.GLU;
 
import android.media.SoundPool;
import android.media.AudioManager;
import android.content.Context;
 
 
 
 
 
public class GL10PrimitiveEx1 extends Activity
{
  private GLSurfaceView glView;
  
  
//  @Override
  protected void onCreate( Bundle bundle )
  {
    super.onCreate( bundle );
    
    glView = new GLSurfaceView( this );
    glView.setRenderer( new GLRenderer(this) );
//    glView.setRenderMode( GLSurfaceView.RENDERMODE_WHEN_DIRTY );
  //  glView.setDebugFlags( GLSurfaceView.DEBUG_CHECK_GL_ERROR | GLSurfaceView.DEBUG_LOG_GL_CALLS );
    setContentView( glView );
    
    AppObject.getInstance().getSoundManager().create( this );
  }
  
//  @Override
  public void onResume()
  {
    super.onResume();
    glView.onResume();
  }
  
//  @Override
  public void onPause()
  {
    super.onPause();
    glView.onPause();
  }
}
 
 
 
 
 
class AppObject
{
  private ImageArray imageArray = new ImageArray( 128 );
  private TestObject[] testObj = new TestObject[ 32 ];
  private Texture texture = new Texture();
  FPSCount fps = new FPSCount();
  SoundManager sound = new SoundManager();
  
  
  
  static private AppObject instance = null;
  static public AppObject getInstance()
  {
    if ( instance == null ) instance = new AppObject();
    return instance;
  }
  
  FPSCount getFPSCount() { return fps; }
  SoundManager getSoundManager() { return sound; }
  
  private AppObject()
  {
    Random random = new Random();
    for (int i=0; i<testObj.length; ++i)
    {
      float x = (random.nextFloat() * 2 - 1) * 2;
      float y = (random.nextFloat() * 2 - 1) * 2;
      testObj[i] = new TestObject( x, y );
      testObj[i].width = 0.5f; 
      testObj[i].height = 0.5f;
      testObj[i].vx = (random.nextFloat()*2-1) * 0.0625f;
      testObj[i].vy = (random.nextFloat()*2-1) * 0.0625f;
      testObj[i].setUVs( 256, 256, 0, 0, 32 , 32 );
    }
  }
  
  
  
  public void makeTexture( GL10 gl, Bitmap bmp )
  {
    texture.makeTexture( gl, bmp );
  }
  
  public void update()
  {
    int n = testObj.length;
    for (int i=0; i<n; ++i)
    {
      testObj[i].update();
    }
    
    sound.update();
  }
  
  public void render( GL11 gl )
  {
    imageArray.clear();
 
    int n = testObj.length;
    for (int i=0; i<n; ++i)
    {
      imageArray.push( testObj[i] );
    }
 
    renderNum( fps.getFps() );
 
    imageArray.render( gl, texture.getTextureID() );
  }
  
  public void renderNum( int num )
  {
    RenderObject obj = new RenderObject();
    obj.x = 0;
    obj.y = 0;
    obj.width = 0.5f;
    obj.height = 0.5f;
    for (;;)
    {
      obj.setUVs( 256, 256, 0 + (num%10)*16, 48, 16, 16 );
      imageArray.push( obj );
      
      
      num /= 10;
      if ( num == 0 ) break;
      obj.x -= 0.5f;
    }
  }
}
 
 
 
 
 
class GLRenderer implements GLSurfaceView.Renderer
{
  private Activity activity;
  private float aspect;
  private long prevTime;
 
 
  GLRenderer( Activity activity )
  {
    this.activity = activity;
    prevTime = 0;
  }
 
//  @Override
  public void onSurfaceCreated( GL10 gl, EGLConfig eglConfig )
  {
    gl.glEnableClientState( GL10.GL_VERTEX_ARRAY );
    gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );
    gl.glEnable( GL10.GL_TEXTURE_2D );
    ///*
    gl.glFrontFace( GL10.GL_CCW );
    gl.glEnable( GL10.GL_CULL_FACE );
    gl.glCullFace( GL10.GL_BACK );
    //*/
 
    Bitmap bmp = BitmapFactory.decodeResource( activity.getResources(), R.drawable.image );
    AppObject.getInstance().makeTexture( gl, bmp );
 
    gl.glEnable( GL10.GL_BLEND );
    gl.glBlendFunc( GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA );
  }
 
//  @Override
  public void onSurfaceChanged( GL10 gl, int w, int h )
  {
    gl.glViewport( 0, 0, w, h );
    aspect = (float)w / (float)h;
    
  }
  
//  @Override
  public void onDrawFrame( GL10 gl )
  {
    
    AppObject.getInstance().update();
 
    
    
    gl.glClearColor( 1, 1, 1, 1 );
    gl.glClear( GL10.GL_COLOR_BUFFER_BIT );
 
    gl.glMatrixMode( GL10.GL_PROJECTION );
    gl.glLoadIdentity();
    GLU.gluPerspective( gl, 45.f, aspect, 0.01f, 100 );
    
    gl.glMatrixMode( GL10.GL_MODELVIEW );
    gl.glLoadIdentity();
    GLU.gluLookAt( gl, 0,0,5, 0,0,0, 0,1,0 );
 
//    gl.glTexParameterx( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR );
//    gl.glTexParameterx( GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR );
    AppObject.getInstance().render( (GL11)gl );
    
    
    
    long now = System.currentTimeMillis();
    if ( now-prevTime < 33 )
    {
      try
      {
        Thread.sleep( 33 - (now-prevTime) );
      }
      catch ( Exception e ) {}
    }
    prevTime = now;
    
    AppObject.getInstance().getFPSCount().update( now );
  }
}
 
 
 
 
class Texture
{
  private int textureID;
  
  public Texture()
  {
    textureID = 0;
  }
  
 
  public void dispose( GL10 gl )
  {
    if ( textureID != 0 )
    {
      gl.glDeleteTextures( 0, new int[]{textureID}, 0 );
      textureID = 0;
    }
  }
  
  public int makeTexture( GL10 gl, Bitmap bmp )
  {
    dispose( gl );
    
    int[] textureIDs = new int[1];
    gl.glGenTextures( 1, textureIDs, 0 );
    
    gl.glActiveTexture( GL10.GL_TEXTURE0 );
    gl.glBindTexture( GL10.GL_TEXTURE_2D, textureIDs[0] );
    GLUtils.texImage2D( GL10.GL_TEXTURE_2D, 0, bmp, 0 );
    
    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_NEAREST );
    
    textureID = textureIDs[0];
    return textureIDs[0]; 
  }
  
  
  int getTextureID() { return textureID; }
}
 
 
 
 
 
class ImageArray
{
  private FloatBuffer vertexBuffer;
  private FloatBuffer uvBuffer;
  private ShortBuffer indexBuffer;
  private int maxNumOfSprite;
  private int numOfRenderSprite;
  
  /**
   * constructor
   * @param num numOfSprite
   */
  public ImageArray( int numOfSprite )
  {
    this.maxNumOfSprite = numOfSprite;
 
    // 四角の数*(x,y,z)*4(=四角で必要な頂点数)*sizeof(float)
    vertexBuffer = ByteBuffer.allocateDirect( numOfSprite * 3 * 4 * 4 ).order( ByteOrder.nativeOrder() ).asFloatBuffer();
    // 四角の数*(u,v)*4(=四角で必要な頂点数)*sizeof(float)
    uvBuffer = ByteBuffer.allocateDirect( numOfSprite * 2 * 4 * 4 ).order( ByteOrder.nativeOrder() ).asFloatBuffer();
    // 四角の数*6(=四角で必要な頂点index数) * sizeof(short)
    indexBuffer = ByteBuffer.allocateDirect( numOfSprite * 6 * 2 ).order( ByteOrder.nativeOrder() ).asShortBuffer();
 
    setIndexs();
    
    vertexBuffer.position( 0 );
    uvBuffer.position( 0 );
    indexBuffer.position( 0 );
    numOfRenderSprite = 0;
  }
  
  public void push( RenderObject obj )
  {
    if ( numOfRenderSprite < maxNumOfSprite )
    {
      int n = numOfRenderSprite;
//      float c = (float)Math.cos( obj.angle / 180 * Math.PI );
//      float s = (float)Math.sin( obj.angle / 180 * Math.PI );
      
      vertexBuffer.put( n*3*4+0, -0.5f*obj.width + obj.x );
      vertexBuffer.put( n*3*4+1, 0.5f*obj.height+ obj.y );
      vertexBuffer.put( n*3*4+2, 0 );
      vertexBuffer.put( n*3*4+3, 0.5f*obj.width + obj.x );
      vertexBuffer.put( n*3*4+4, 0.5f*obj.height + obj.y );
      vertexBuffer.put( n*3*4+5, 0 );
      vertexBuffer.put( n*3*4+6, -0.5f*obj.width + obj.x );
      vertexBuffer.put( n*3*4+7, -0.5f*obj.height + obj.y );
      vertexBuffer.put( n*3*4+8, 0 );
      vertexBuffer.put( n*3*4+9, 0.5f*obj.width + obj.x );
      vertexBuffer.put( n*3*4+10, -0.5f*obj.height + obj.y );
      vertexBuffer.put( n*3*4+11, 0 );
      
      uvBuffer.put( n*2*4+0, obj.uvs[0] ); //u1[0]
      uvBuffer.put( n*2*4+1, obj.uvs[1] ); //v1
      uvBuffer.put( n*2*4+2, obj.uvs[2] ); //u2[1]
      uvBuffer.put( n*2*4+3, obj.uvs[1] ); //v1
      uvBuffer.put( n*2*4+4, obj.uvs[0] ); //u1[2]
      uvBuffer.put( n*2*4+5, obj.uvs[3] ); //v2
      uvBuffer.put( n*2*4+6, obj.uvs[2] ); //u2[3]
      uvBuffer.put( n*2*4+7, obj.uvs[3] ); //v2
      
      numOfRenderSprite++;
    }
  }
  
  public void render( GL11 gl, int textureID )
  {
    if ( numOfRenderSprite > 0 )
    {
      vertexBuffer.position( 0 );
      uvBuffer.position( 0 );
      indexBuffer.position( 0 );
  
      gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, vertexBuffer );
      gl.glActiveTexture( GL10.GL_TEXTURE0 );
      gl.glBindTexture( GL10.GL_TEXTURE_2D, textureID );
      gl.glTexCoordPointer( 2, GL10.GL_FLOAT, 0, uvBuffer );
      gl.glDrawElements( GL10.GL_TRIANGLES, 3*2*numOfRenderSprite, GL10.GL_UNSIGNED_SHORT, indexBuffer );
    }
  }
  
  public void render( GL11 gl, int textureID, int startIndex, int endIndex )
  {
    if ( numOfRenderSprite > 0 &&
        startIndex < numOfRenderSprite && endIndex < numOfRenderSprite )
    {
      vertexBuffer.position( startIndex*3*4 );
      uvBuffer.position( startIndex*2*4 );
      indexBuffer.position( startIndex*3*2 );
      
      gl.glVertexPointer( 3, GL10.GL_FLOAT, 0, vertexBuffer );
      gl.glActiveTexture( GL10.GL_TEXTURE0 );
      gl.glBindTexture( GL10.GL_TEXTURE_2D, textureID );
      gl.glTexCoordPointer( 2, GL10.GL_FLOAT, 0, uvBuffer );
      gl.glDrawElements( GL10.GL_TRIANGLES, 3*2*(endIndex-startIndex), GL10.GL_UNSIGNED_SHORT, indexBuffer );
    }
  }
  
  public void clear() { numOfRenderSprite = 0; }
  
  public FloatBuffer getVertexBuffer() { return vertexBuffer; }
  public FloatBuffer getUVBuffer() { return uvBuffer; }
  public ShortBuffer getIndexBuffer() { return indexBuffer; }
  public int getMaxNumOfSprite() { return maxNumOfSprite; }
  public int getNumOfRenderSprite() { return numOfRenderSprite; }
  
  
  
  private void setIndexs()
  {
    int n = maxNumOfSprite;
    for (int i=0; i<n; ++i)
    {
      indexBuffer.put( i*6 + 0, (short)(0 + i*4) );
      indexBuffer.put( i*6 + 1, (short)(2 + i*4) );
      indexBuffer.put( i*6 + 2, (short)(1 + i*4) );
      indexBuffer.put( i*6 + 3, (short)(2 + i*4) );
      indexBuffer.put( i*6 + 4, (short)(3 + i*4) );
      indexBuffer.put( i*6 + 5, (short)(1 + i*4) );
    }
  }
}
 
 
 
 
 
class RenderObject
{
  public float x, y, width, height;
  public float angle;  // no use
  public float[] uvs = new float[ 4 ];  //< u1, v1, u2, v2
  
  protected void setUVs( int texWidth, int texHeight, int srcX, int srcY, int width, int height )
  {
    uvs[0] = (float)srcX / (float)texWidth;
    uvs[1] = (float)srcY / (float)texHeight;
    uvs[2] = (float)(srcX+width) / (float)texWidth;
    uvs[3] = (float)(srcY+height) / (float)texHeight;
  }
}
 
 
class TestObject extends RenderObject
{
  public float vx;
  public float vy;
 
  public TestObject( float x, float y )
  {
    this.x = x;
    this.y = y;
    vx = -0.5f;
    vy = -0.5f;
  }
  
  void update()
  {
    x += vx;
    y += vy;
    boolean playSound = false;
    if ( x < -3 || x > 3 ) { vx = -vx; playSound = true; }
    if ( y < -2 || y > 2 ) { vy = -vy; playSound = true; }
    
    if ( playSound )
    {
      AppObject.getInstance().getSoundManager().play();
    }
  }
}
 
 
 
 
 
 
 
class FPSCount
{
  private int fps;
  private int[] data = new int[ 32 ];
  private int lastSecond;
  
  public FPSCount()
  {
    int n = data.length;
    for (int i=0; i<n; ++i)
    {
      data[i] = 0;
    }
    
    fps = 0;
    lastSecond = 0;
  }
  
  void update( long now )
  {
    //long now = System.currentTimeMillis();
    int a = (int)(now / 200);
    data[ a & 31 ]++;
    
    if ( a != lastSecond )
    {
      lastSecond = a;
      fps = 0;
      for (int i=1; i<=5; ++i)
      {
        fps += data[ (a-i)&31 ];
      }
      for (int i=5; i<=20; ++i) data[ (a+i)&31 ] = 0;
    }
  }
  
  public int getFps() { return fps; }
}
 
 
 
class SoundManager
{
  private SoundPool sound = new SoundPool( 8, AudioManager.STREAM_MUSIC, 0 );
  private int soundID = 0;
  private int useStreamID = 0;
  private boolean play = false;
  
  
  
  
  
  
  void update()
  {
    if ( play )
    {
      if ( useStreamID != 0 )
      {
        sound.stop( useStreamID );
      }
 
      useStreamID = sound.play( soundID, 1.0f, 1.0f, 0, 0, 1.0f );
      play = false;
    }
  }
 
  void create( Context context )
  {
    soundID = sound.load( context, R.raw.sound, 1 );
  }
  
  void release()
  {
    sound.unload( soundID );
  }
  
  public void play()
  {
    play = true;
  }
}

0 件のコメント: