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
; }
}