テクスチャなし描画

テクスチャなし描画




いよいよ描画メソッドの実装です。
描画メソッドは長いのでまずはテクスチャなしメソッドから作ります。

描画メソッドを作る前に描画メソッドに渡すためのパラメータクラスを作ります。
クラスは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 );

ここまで設定してきた内容で描画します。

これでテクスチャなしの物体が描画できるようになりました。
次はテクスチャを使った描画を実装してみます。



<前のページ
次のページ>