Subversion Repositories AndroidProjects

Rev

Blame | Last modification | View Log | RSS feed

package com.gebauz.bauzoid.graphics.sprite;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Texture;
import com.gebauz.bauzoid.app.Consts;
import com.gebauz.bauzoid.graphics.Graphics;
import com.gebauz.bauzoid.graphics.GraphicsObject;
import com.gebauz.bauzoid.graphics.model.IndexStream;
import com.gebauz.bauzoid.graphics.model.VertexAttribute;
import com.gebauz.bauzoid.graphics.model.VertexStream;
import com.gebauz.bauzoid.graphics.renderstates.RenderStates;
import com.gebauz.bauzoid.graphics.sprite.SpriteShader;
import com.gebauz.bauzoid.math.MathUtil;
import com.gebauz.bauzoid.math.Vector4;

/** Batcher that collects Texture draw calls and batches them into a single VBO.
 * A possibly faster alternative to Sprite and AtlasSprite which have rather
 * small geometry objects.
 *
 * It is designed to be easy to convert code that used AtlasSprite and Sprite
 * to use TileBatch instead.
 *
 * Also contains convenience functions to import Sprite and AtlasSprite info.
 *
 * @author chiu
 *
 */

public class TileBatch extends GraphicsObject
{

        // Constants========================================================================================
       
        public static final int POSITION_COORD_PER_ELEMENT = 3;
        public static final int NORMAL_COORD_PER_ELEMENT = 3;
        public static final int COLOR_COORD_PER_ELEMENT = 4;
        public static final int TEXCOORD_COORD_PER_ELEMENT = 2;
       
        public static final Vector4 WHITE_COLOR = new Vector4(1, 1, 1, 1);
       
        public static final int COORDS_PER_ELEMENT = POSITION_COORD_PER_ELEMENT + COLOR_COORD_PER_ELEMENT + TEXCOORD_COORD_PER_ELEMENT;

        // Embedded Types===================================================================================

        // Fields===========================================================================================
       
        /** Number of vertices. */
        private int mSize = 0;
        private float mVertices[] = null;
        private int mNumQuads = 0;
       
//      private SimpleGeometry mMesh = null;
        private Texture mCurrentTexture = null;
        private boolean mIsDrawing = false;
       
        private VertexStream mVertexStream= null;
        private IndexStream mIndexStream = null;


        // Methods==========================================================================================

        public TileBatch(Graphics graphics)
        {
                this(graphics, 250);
        }
       
        public TileBatch(Graphics graphics, int size)
        {
                super(graphics);
                mSize = size;
               
                mVertexStream = new VertexStream(
                                getGraphics(),
                                VertexStream.StreamType.INTERLEAVED,
                                "Vertices",
                                new VertexAttribute[]
                                        {
                                                new VertexAttribute(VertexAttribute.POSITION, POSITION_COORD_PER_ELEMENT, 0),
                                                new VertexAttribute(VertexAttribute.COLOR, COLOR_COORD_PER_ELEMENT, POSITION_COORD_PER_ELEMENT*Consts.SIZEOF_FLOAT),
                                                new VertexAttribute(VertexAttribute.TEXCOORD0, TEXCOORD_COORD_PER_ELEMENT, (POSITION_COORD_PER_ELEMENT+COLOR_COORD_PER_ELEMENT)*Consts.SIZEOF_FLOAT)
                                        },
                                false);
               
                mIndexStream = new IndexStream(getGraphics());
               
                mVertices = new float[size * 4 * (COORDS_PER_ELEMENT)];
                //mCurrentVertex = 0;
                mNumQuads = 0;
               
                // create indices as those will stay the same
                int len = size * 6;
                short[] indices = new short[len];
                short j = 0;
                for (int i = 0; i < len; i += 6, j += 4)
                {
                        indices[i + 0] = (short)(j + 0);
                        indices[i + 1] = (short)(j + 1);
                        indices[i + 2] = (short)(j + 2);
                        indices[i + 3] = (short)(j + 0);
                        indices[i + 4] = (short)(j + 2);
                        indices[i + 5] = (short)(j + 3);
                }
                mIndexStream.setData(indices);
                mIndexStream.upload();
        }
       
        public void dispose()
        {
                if (mVertexStream != null)
                {
                        mVertexStream.dispose();
                        mVertexStream = null;
                }
               
                if (mIndexStream != null)
                {
                        mIndexStream.dispose();
                        mIndexStream = null;
                }
        }
       
        /** Initialize internal variables for a new batch. */
        public void begin()
        {
                if (mIsDrawing)
                        return;
               
                mIsDrawing = true;
                //mCurrentVertex = 0;
                mNumQuads = 0;
        }
       
        /** Stops collecting and renders what's left on the screen. */
        public void end()
        {
                if (!mIsDrawing)
                        return;
               
                if (mNumQuads == 0)
                        return;
               
                flush();
        }
       
        /** Flush everything collected so far to screen and clear everything for new collection. */
        public void flush()
        {
                if (mCurrentTexture == null)
                        return;
               
                SpriteShader shader = getGraphics().getSpriteShader();
                RenderStates rs = getRenderStates();

                // bind VBO and upload geometry
               
                mVertexStream.setData(mVertices, COORDS_PER_ELEMENT, COORDS_PER_ELEMENT * Consts.SIZEOF_FLOAT);
                mVertexStream.reupload();              
               
                // bind texture and render
                rs.pushModelMatrix();
                {
                        rs.model.identity();
                       
                        // draw sprite
                        shader.activate(mCurrentTexture, 1.0f, WHITE_COLOR);
                        {
                                rs.blending.setEnabled(true);
                                rs.culling.setEnabled(false);
                                rs.activate();
                                {
                                        mVertexStream.activate();
                                        mIndexStream.activate();
                                        Gdx.gl20.glDrawElements(GL20.GL_TRIANGLES, mNumQuads*6, GL20.GL_UNSIGNED_SHORT, 0);
                                        mVertexStream.deactivate();
                                        mIndexStream.deactivate();
                                }
                                rs.deactivate();
                        }
                        shader.deactivate();
                }
                rs.popModelMatrix();
               
                //mCurrentVertex = 0;
                mNumQuads = 0;
        }
       
        /** Takes a sprite and uses its own properties to add it to the VBO. */
        public void drawSprite(SpriteInstance sprite)
        {
                drawSprite(sprite, sprite.transform);
        }

        /** Takes a sprite and sprite properties and adds it to the VBO. */
        public void drawSprite(SpriteInstance sprite, SpriteTransform param)
        {
                if (!isDrawing())
                        return;
               
                if (sprite.getSprite().getTexture() != mCurrentTexture)
                        flush();
               
                if ((mNumQuads+1) > mSize)
                        flush();
               
                mCurrentTexture = sprite.getSprite().getTexture();
               
                // transform quad vertices based on sprite's properties
                SpriteRegion r = sprite.getSpriteRegion(); //sprite.getSprite().getRegion(sprite.getRegionIndex());
               
                // bottom left and top right corner points relative to origin
                final float worldOriginX = param.x + param.pivotX;
                final float worldOriginY = param.y + param.pivotY;
                float fx = -param.pivotX;
                float fy = -param.pivotY;
                float fx2 = param.w - param.pivotX;
                float fy2 = param.h - param.pivotY;

                // construct corner points, start from top left and go counter clockwise
                final float p1x = fx;
                final float p1y = fy;
                final float p2x = fx;
                final float p2y = fy2;
                final float p3x = fx2;
                final float p3y = fy2;
                final float p4x = fx2;
                final float p4y = fy;

                float x1;
                float y1;
                float x2;
                float y2;
                float x3;
                float y3;
                float x4;
                float y4;

                // rotate
                if (param.angle != 0)
                {
                        final float cos = MathUtil.cos(param.angle);
                       
                        // Angle is CCW
                        final float sin = -MathUtil.sin(param.angle);

                        x1 = cos * p1x - sin * p1y;
                        y1 = sin * p1x + cos * p1y;

                        x2 = cos * p2x - sin * p2y;
                        y2 = sin * p2x + cos * p2y;

                        x3 = cos * p3x - sin * p3y;
                        y3 = sin * p3x + cos * p3y;

                        x4 = x1 + (x3 - x2);
                        y4 = y3 - (y2 - y1);
                }
                else
                {
                        x1 = p1x;
                        y1 = p1y;

                        x2 = p2x;
                        y2 = p2y;

                        x3 = p3x;
                        y3 = p3y;

                        x4 = p4x;
                        y4 = p4y;
                }

                x1 += worldOriginX - param.pivotX;
                y1 += worldOriginY - param.pivotY;
                x2 += worldOriginX - param.pivotX;
                y2 += worldOriginY - param.pivotY;
                x3 += worldOriginX - param.pivotX;
                y3 += worldOriginY - param.pivotY;
                x4 += worldOriginX - param.pivotX;
                y4 += worldOriginY - param.pivotY;
               
                float u = r.left;
                float v = r.top;
                float u2 = r.right;
                float v2 = r.bottom;

                if (param.mirrorX)
                {
                        float tmp = u;
                        u = u2;
                        u2 = tmp;
                }

                if (param.mirrorY)
                {
                        float tmp = v;
                        v = v2;
                        v2 = tmp;
                }
               
                // add vertices to buffer
                int n = mNumQuads * 4 * (COORDS_PER_ELEMENT);
               
                mVertices[n++] = x1;
                mVertices[n++] = y1;
                mVertices[n++] = 0;
                mVertices[n++] = sprite.color.x;
                mVertices[n++] = sprite.color.y;
                mVertices[n++] = sprite.color.z;
                mVertices[n++] = sprite.color.w;
                mVertices[n++] = u;
                mVertices[n++] = v;
                //mVertices[n++] = texCoords[0];
                //mVertices[n++] = texCoords[1];
               
                mVertices[n++] = x2;
                mVertices[n++] = y2;
                mVertices[n++] = 0;
                mVertices[n++] = sprite.color.x;
                mVertices[n++] = sprite.color.y;
                mVertices[n++] = sprite.color.z;
                mVertices[n++] = sprite.color.w;
                mVertices[n++] = u;
                mVertices[n++] = v2;
                //mVertices[n++] = texCoords[2];
                //mVertices[n++] = texCoords[3];
               
                mVertices[n++] = x3;
                mVertices[n++] = y3;
                mVertices[n++] = 0;
                mVertices[n++] = sprite.color.x;
                mVertices[n++] = sprite.color.y;
                mVertices[n++] = sprite.color.z;
                mVertices[n++] = sprite.color.w;
                mVertices[n++] = u2;
                mVertices[n++] = v2;
                //mVertices[n++] = texCoords[4];
                //mVertices[n++] = texCoords[5];
               
                mVertices[n++] = x4;
                mVertices[n++] = y4;
                mVertices[n++] = 0;
                mVertices[n++] = sprite.color.x;
                mVertices[n++] = sprite.color.y;
                mVertices[n++] = sprite.color.z;
                mVertices[n++] = sprite.color.w;
                mVertices[n++] = u2;
                mVertices[n++] = v;
                //mVertices[n++] = texCoords[6];
                //mVertices[n++] = texCoords[7];
               
                //mCurrentVertex += 4;
                mNumQuads++;
        }
       
        // Getters/Setters==================================================================================
       
       
        private boolean isDrawing() { return mIsDrawing; }
       
}