いよいよ描画メソッドの実装です。
描画メソッドは長いのでまずはテクスチャなしメソッドから作ります。
描画メソッドを作る前に描画メソッドに渡すためのパラメータクラスを作ります。
クラスはpublicなインナークラスとして作ります。
// 描画パラメータクラス public class DrawParam { public DrawParam( Texture image ) { m_Image = image; m_Pos = new PointF(); m_RotationZ = 0.0f; m_Scale = new PointF( 1.0f, 1.0f ); m_ImageRect = new Rect(); m_ImageCenter = new PointF(); m_Color = Color.White(); } public Texture m_Image; public PointF m_Pos; public float m_RotationZ; public PointF m_Scale; public Rect m_ImageRect; public PointF m_ImageCenter; public Color m_Color; }
描画パラメータを作るメソッドを用意します。
アプリケーション側はこのメソッドを叩いて作られたDrawParamのメンバをいじリます。
public DrawParam CreateDrawParamNoTexture() { return new DrawParam( null ); }
そして描画メソッド本体です。
引くほど長いので覚悟してください!
// テクスチャ無し描画 public void DrawNoTexture( DrawParam param ) { if( !_IsDrawEnable( param )) return; GL10 gl = m_DrawDevice.GetGl(); final Rect imageRect = param.m_ImageRect; final PointF imageCenter = param.m_ImageCenter; final Color color = param.m_Color; // 表示用行列設定 _UpdateWorldMatrix( gl, param ); // テクスチャ設定 gl.glDisable( GL10.GL_TEXTURE_2D ); // 頂点の位置設定 { final float leftPos = -imageCenter.x; final float topPos = -imageCenter.y; final float rightPos = leftPos + imageRect.width(); final float bottomPos = topPos + imageRect.height(); final float aVerticalPos[] = { leftPos, topPos, rightPos, topPos, leftPos, bottomPos, rightPos, bottomPos, }; m_VertexPos.SetArray( aVerticalPos ); gl.glVertexPointer( VERTEX_POS_ELEMENT_NUM, GL10.GL_FLOAT, 0, m_VertexPos.GetFloatBuffer()); } // 色設定 m_DrawColor.set( m_ScaleColor ); m_DrawColor.Mul( color ); if( !m_PrevDrawColor.equals( m_DrawColor )) { final float colorR = m_DrawColor.GetR(); final float colorG = m_DrawColor.GetG(); final float colorB = m_DrawColor.GetB(); final float colorA = m_DrawColor.GetA(); final float aColor[] = { colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, }; m_VertexColor.SetArray( aColor ); gl.glColorPointer( VERTEX_COLOR_ELEMET_NUM, GL10.GL_FLOAT, 0, m_VertexColor.GetFloatBuffer()); m_PrevDrawColor.set( m_DrawColor ); } // テクスチャ座標無効化 gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY ); // 描画 gl.glDrawArrays( GL10.GL_TRIANGLE_STRIP, 0, VERTEX_NUM ); } // ワールドマトリクス更新 private final void _UpdateWorldMatrix( GL10 gl, DrawParam param ) { PointF pos = param.m_Pos; PointF scale = param.m_Scale; if( !m_bScreenMode ) { // 注視点設定モードのときは座標変更 pos.x = pos.x + m_CameraModeOffset.x; pos.y = -pos.y + m_CameraModeOffset.y; } gl.glMatrixMode( GL10.GL_MODELVIEW ); gl.glLoadIdentity(); gl.glTranslatef( pos.x, pos.y, 0.0f ); gl.glRotatef( param.m_RotationZ, 0.0f, 0.0f, 1.0f ); gl.glScalef( scale.x, scale.y, 0.0f ); } // 描画する意味があるか? private final boolean _IsDrawEnable( DrawParam param ) { // アルファが0なら描画する意味無し if( param.m_Color.GetA() == 0.0f ) return false; final Rect imageRect = param.m_ImageRect; final PointF imageCenter = param.m_ImageCenter; final float imageLeft = -imageCenter.x; final float imageTop = -imageCenter.y; final float imageRight = imageRect.width() - imageCenter.x; final float imageBottom = imageRect.height() - imageCenter.y; final PointF scale = param.m_Scale; final float rotZ = param.m_RotationZ; final PointF pos = param.m_Pos; // モデルの位置計算 float drawLeftTopX = imageLeft; float drawLeftTopY = imageTop; float drawLeftBottomX = imageLeft; float drawLeftBottomY = imageBottom; float drawRightTopX = imageRight; float drawRightTopY = imageTop; float drawRightBottomX = imageRight; float drawRightBottomY = imageBottom; { // 拡大率 { drawLeftTopX *= scale.x; drawLeftTopY *= scale.y; drawLeftBottomX *= scale.x; drawLeftBottomY *= scale.y; drawRightTopX *= scale.x; drawRightTopY *= scale.y; drawRightBottomX *= scale.x; drawRightBottomY *= scale.y; } // Z軸回転 if( rotZ != 0.0f ) { final float rad = ( float )Math.toRadians( rotZ ); final float sin = ( float )Math.sin( rad ); final float cos = ( float )Math.cos( rad ); drawLeftTopX = drawLeftTopX * cos - drawLeftTopY * sin; drawLeftTopY = drawLeftTopX * sin + drawLeftTopY * cos; drawLeftBottomX = drawLeftBottomX * cos - drawLeftBottomY * sin; drawLeftBottomY = drawLeftBottomX * sin + drawLeftBottomY * cos; drawRightTopX = drawRightTopX * cos - drawRightTopY * sin; drawRightTopY = drawRightTopX * sin + drawRightTopY * cos; drawRightBottomX = drawRightBottomX * cos - drawRightBottomY * sin; drawRightBottomY = drawRightBottomX * sin + drawRightBottomY * cos; } // 位置計算 { final float posX = pos.x; final float posY = (( m_bScreenMode )? pos.y : -pos.y ); drawLeftTopX += posX; drawLeftTopY += posY; drawLeftBottomX += posX; drawLeftBottomY += posY; drawRightTopX += posX; drawRightTopY += posY; drawRightBottomX += posX; drawRightBottomY += posY; } } // 描画位置計算 // カメラモードのときはカメラ位置の分だけオフセットがある if( !m_bScreenMode ) { drawLeftTopX += m_CameraModeOffset.x; drawLeftTopY += m_CameraModeOffset.y; drawLeftBottomX += m_CameraModeOffset.x; drawLeftBottomY += m_CameraModeOffset.y; drawRightTopX += m_CameraModeOffset.x; drawRightTopY += m_CameraModeOffset.y; drawRightBottomX += m_CameraModeOffset.x; drawRightBottomY += m_CameraModeOffset.y; } // 上下左右の領域計算 final float left = Math.min( Math.min( Math.min( drawLeftTopX, drawLeftBottomX ), drawRightTopX ), drawRightBottomX ); final float top = Math.min( Math.min( Math.min( drawLeftTopY, drawLeftBottomY ), drawRightTopY ), drawRightBottomY ); final float right = Math.max( Math.max( Math.max( drawLeftTopX, drawLeftBottomX ), drawRightTopX ), drawRightBottomX ); final float bottom = Math.max( Math.max( Math.max( drawLeftTopY, drawLeftBottomY ), drawRightTopY ), drawRightBottomY ); // 描画範囲外なら描画する意味無し if(( left > DrawDevice.DRAW_WIDTH ) || ( top > DrawDevice.DRAW_HEIGHT ) || ( right < 0.0f ) || ( bottom < 0.0f )) return false; return true; }
あまりに長すぎるので細かく切って解説していきます。
if( !_IsDrawEnable( param )) return;
ここでは描画する意味がなければ描画しないようにしています。
_IsDrawEnable()の中身は、
アルファが0の時は何も描画されないので描画しない。
その後の行は画面外なら描画しても表示されないのでそのような場合は弾く。
といったことをやっています。
// 表示用行列設定 _UpdateWorldMatrix( gl, param );
ここでは、注視点の位置を考慮した変換行列をOpenGLに設定しています。
また、描画する画像の位置、回転角度、拡大率も設定しています。
// テクスチャ設定 gl.glDisable( GL10.GL_TEXTURE_2D ); : : // テクスチャ座標無効化 gl.glEnableClientState( GL10.GL_TEXTURE_COORD_ARRAY );
今回はテクスチャは表示しないので無効化しています。
// 頂点の位置設定 { final float leftPos = -imageCenter.x; final float topPos = -imageCenter.y; final float rightPos = leftPos + imageRect.width(); final float bottomPos = topPos + imageRect.height(); final float aVerticalPos[] = { leftPos, topPos, rightPos, topPos, leftPos, bottomPos, rightPos, bottomPos, }; m_VertexPos.SetArray( aVerticalPos ); gl.glVertexPointer( VERTEX_POS_ELEMENT_NUM, GL10.GL_FLOAT, 0, m_VertexPos.GetFloatBuffer()); }
各頂点の位置をOpenGLに設定しています。
ここで設定する座標系はローカル座標系です。
画像の中心位置を考慮して設定しています。
// 色設定 m_DrawColor.set( m_ScaleColor ); m_DrawColor.Mul( color ); if( !m_PrevDrawColor.equals( m_DrawColor )) { final float colorR = m_DrawColor.GetR(); final float colorG = m_DrawColor.GetG(); final float colorB = m_DrawColor.GetB(); final float colorA = m_DrawColor.GetA(); final float aColor[] = { colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, colorR, colorG, colorB, colorA, }; m_VertexColor.SetArray( aColor ); gl.glColorPointer( VERTEX_COLOR_ELEMET_NUM, GL10.GL_FLOAT, 0, m_VertexColor.GetFloatBuffer()); m_PrevDrawColor.set( m_DrawColor ); }
各頂点ごとの色を設定しています。
今回は全部の頂点で同じ色を使います。
また、SetScaleColor()で設定した色の影響も受けるようにしています。
なお、この処理がかなり重い上に色はほとんど変わらないので
前に設定した色と同じなら処理を弾くようにしています。
// 描画 gl.glDrawArrays( GL10.GL_TRIANGLE_STRIP, 0, VERTEX_NUM );
ここまで設定してきた内容で描画します。
これでテクスチャなしの物体が描画できるようになりました。
次はテクスチャを使った描画を実装してみます。