diff --git a/spine-libgdx/spine-libgdx/pom.xml b/spine-libgdx/spine-libgdx/pom.xml
index 2a85313b2..b1ec5ddfe 100644
--- a/spine-libgdx/spine-libgdx/pom.xml
+++ b/spine-libgdx/spine-libgdx/pom.xml
@@ -50,7 +50,7 @@
UTF-8
- 1.9.6
+ 1.9.8
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/TwoColorPolygonBatch.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/TwoColorPolygonBatch.java
index 62af40b87..22f713552 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/TwoColorPolygonBatch.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/TwoColorPolygonBatch.java
@@ -31,26 +31,35 @@
package com.esotericsoftware.spine.utils;
import com.badlogic.gdx.Gdx;
-import com.badlogic.gdx.graphics.GL20;
-import com.badlogic.gdx.graphics.Mesh;
+import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.Mesh.VertexDataType;
-import com.badlogic.gdx.graphics.Texture;
-import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
+import com.badlogic.gdx.graphics.g2d.Batch;
+import com.badlogic.gdx.graphics.g2d.PolygonRegion;
+import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;
+import com.badlogic.gdx.math.Affine2;
+import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
+import com.badlogic.gdx.utils.NumberUtils;
+
+public class TwoColorPolygonBatch implements Batch {
+ static final int VERTEX_SIZE = 2 + 1 + 1 + 2;
+ static final int SPRITE_SIZE = 4 * VERTEX_SIZE;
-public class TwoColorPolygonBatch {
private final Mesh mesh;
private final float[] vertices;
+ private final float[] tempSpriteVertices = new float[SPRITE_SIZE];
private final short[] triangles;
private final Matrix4 transformMatrix = new Matrix4();
private final Matrix4 projectionMatrix = new Matrix4();
private final Matrix4 combinedMatrix = new Matrix4();
+ private boolean blendingDisabled;
private final ShaderProgram defaultShader;
private ShaderProgram shader;
private int vertexIndex, triangleIndex;
private Texture lastTexture;
+ private float invTexWidth = 0, invTexHeight = 0;
private boolean drawing;
private int blendSrcFunc = GL20.GL_SRC_ALPHA;
private int blendDstFunc = GL20.GL_ONE_MINUS_SRC_ALPHA;
@@ -58,6 +67,14 @@ public class TwoColorPolygonBatch {
private int blendDstFuncAlpha = GL20.GL_ONE_MINUS_SRC_ALPHA;
private boolean premultipliedAlpha;
+ private float light = Color.WHITE.toFloatBits();
+ private float dark = Color.BLACK.toFloatBits();
+ private Color tempColor = new Color(1, 1, 1, 1);
+
+ public TwoColorPolygonBatch () {
+ this(2000);
+ }
+
public TwoColorPolygonBatch (int size) {
this(size, size * 2);
}
@@ -82,6 +99,7 @@ public TwoColorPolygonBatch (int maxVertices, int maxTriangles) {
projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
}
+ @Override
public void begin () {
if (drawing) throw new IllegalStateException("end must be called before begin.");
Gdx.gl.glDepthMask(false);
@@ -90,16 +108,215 @@ public void begin () {
drawing = true;
}
+ @Override
public void end () {
if (!drawing) throw new IllegalStateException("begin must be called before end.");
if (vertexIndex > 0) flush();
shader.end();
Gdx.gl.glDepthMask(true);
- Gdx.gl.glDisable(GL20.GL_BLEND);
+ if (isBlendingEnabled()) Gdx.gl.glDisable(GL20.GL_BLEND);
+
lastTexture = null;
drawing = false;
}
+ @Override
+ public void setColor (Color tint) {
+ light = tint.toFloatBits();
+ }
+
+ @Override
+ public void setColor (float r, float g, float b, float a) {
+ int intBits = (int)(255 * a) << 24 | (int)(255 * b) << 16 | (int)(255 * g) << 8 | (int)(255 * r);
+ light = NumberUtils.intToFloatColor(intBits);
+ }
+
+ @Override
+ public void setColor (float color) {
+ this.light = color;
+ }
+
+ @Override
+ public Color getColor () {
+ int intBits = NumberUtils.floatToIntColor(light);
+ Color color = this.tempColor;
+ color.r = (intBits & 0xff) / 255f;
+ color.g = ((intBits >>> 8) & 0xff) / 255f;
+ color.b = ((intBits >>> 16) & 0xff) / 255f;
+ color.a = ((intBits >>> 24) & 0xff) / 255f;
+ return color;
+ }
+
+ @Override
+ public float getPackedColor () {
+ return light;
+ }
+
+ public void setDarkColor (Color tint) {
+ dark = tint.toFloatBits();
+ }
+
+ public void setDarkColor (float r, float g, float b, float a) {
+ int intBits = (int)(255 * a) << 24 | (int)(255 * b) << 16 | (int)(255 * g) << 8 | (int)(255 * r);
+ dark = NumberUtils.intToFloatColor(intBits);
+ }
+
+ public void setDarkColor (float color) {
+ this.dark = color;
+ }
+
+ public Color getDarkColor () {
+ int intBits = NumberUtils.floatToIntColor(dark);
+ Color color = this.tempColor;
+ color.r = (intBits & 0xff) / 255f;
+ color.g = ((intBits >>> 8) & 0xff) / 255f;
+ color.b = ((intBits >>> 16) & 0xff) / 255f;
+ color.a = ((intBits >>> 24) & 0xff) / 255f;
+ return color;
+ }
+
+ public float getPackedDarkColor () {
+ return dark;
+ }
+
+ /** Draws a polygon region with the bottom left corner at x,y having the width and height of the region. */
+ public void draw (PolygonRegion region, float x, float y) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final short[] regionTriangles = region.getTriangles();
+ final int regionTrianglesLength = regionTriangles.length;
+ final float[] regionVertices = region.getVertices();
+ final int regionVerticesLength = regionVertices.length;
+
+ final Texture texture = region.getRegion().getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + regionTrianglesLength > triangles.length
+ || vertexIndex + regionVerticesLength * VERTEX_SIZE / 2 > vertices.length) flush();
+
+ int triangleIndex = this.triangleIndex;
+ int vertexIndex = this.vertexIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+
+ for (int i = 0; i < regionTrianglesLength; i++)
+ triangles[triangleIndex++] = (short)(regionTriangles[i] + startVertex);
+ this.triangleIndex = triangleIndex;
+
+ final float[] vertices = this.vertices;
+ final float light = this.light;
+ final float dark = this.dark;
+ final float[] textureCoords = region.getTextureCoords();
+
+ for (int i = 0; i < regionVerticesLength; i += 2) {
+ vertices[vertexIndex++] = regionVertices[i] + x;
+ vertices[vertexIndex++] = regionVertices[i + 1] + y;
+ vertices[vertexIndex++] = light;
+ vertices[vertexIndex++] = dark;
+ vertices[vertexIndex++] = textureCoords[i];
+ vertices[vertexIndex++] = textureCoords[i + 1];
+ }
+ this.vertexIndex = vertexIndex;
+ }
+
+ /** Draws a polygon region with the bottom left corner at x,y and stretching the region to cover the given width and height. */
+ public void draw (PolygonRegion region, float x, float y, float width, float height) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final short[] regionTriangles = region.getTriangles();
+ final int regionTrianglesLength = regionTriangles.length;
+ final float[] regionVertices = region.getVertices();
+ final int regionVerticesLength = regionVertices.length;
+ final TextureRegion textureRegion = region.getRegion();
+
+ final Texture texture = textureRegion.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + regionTrianglesLength > triangles.length
+ || vertexIndex + regionVerticesLength * VERTEX_SIZE / 2 > vertices.length) flush();
+
+ int triangleIndex = this.triangleIndex;
+ int vertexIndex = this.vertexIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+
+ for (int i = 0, n = regionTriangles.length; i < n; i++)
+ triangles[triangleIndex++] = (short)(regionTriangles[i] + startVertex);
+ this.triangleIndex = triangleIndex;
+
+ final float[] vertices = this.vertices;
+ final float light = this.light;
+ final float dark = this.dark;
+ final float[] textureCoords = region.getTextureCoords();
+ final float sX = width / textureRegion.getRegionWidth();
+ final float sY = height / textureRegion.getRegionHeight();
+
+ for (int i = 0; i < regionVerticesLength; i += 2) {
+ vertices[vertexIndex++] = regionVertices[i] * sX + x;
+ vertices[vertexIndex++] = regionVertices[i + 1] * sY + y;
+ vertices[vertexIndex++] = light;
+ vertices[vertexIndex++] = dark;
+ vertices[vertexIndex++] = textureCoords[i];
+ vertices[vertexIndex++] = textureCoords[i + 1];
+ }
+ this.vertexIndex = vertexIndex;
+ }
+
+ /** Draws the polygon region with the bottom left corner at x,y and stretching the region to cover the given width and height.
+ * The polygon region is offset by originX, originY relative to the origin. Scale specifies the scaling factor by which the
+ * polygon region should be scaled around originX, originY. Rotation specifies the angle of counter clockwise rotation of the
+ * rectangle around originX, originY. */
+ public void draw (PolygonRegion region, float x, float y, float originX, float originY, float width, float height,
+ float scaleX, float scaleY, float rotation) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final short[] regionTriangles = region.getTriangles();
+ final int regionTrianglesLength = regionTriangles.length;
+ final float[] regionVertices = region.getVertices();
+ final int regionVerticesLength = regionVertices.length;
+ final TextureRegion textureRegion = region.getRegion();
+
+ Texture texture = textureRegion.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + regionTrianglesLength > triangles.length
+ || vertexIndex + regionVerticesLength * VERTEX_SIZE / 2 > vertices.length) flush();
+
+ int triangleIndex = this.triangleIndex;
+ int vertexIndex = this.vertexIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+
+ for (int i = 0; i < regionTrianglesLength; i++)
+ triangles[triangleIndex++] = (short)(regionTriangles[i] + startVertex);
+ this.triangleIndex = triangleIndex;
+
+ final float[] vertices = this.vertices;
+ final float light = this.light;
+ final float dark = this.dark;
+ final float[] textureCoords = region.getTextureCoords();
+
+ final float worldOriginX = x + originX;
+ final float worldOriginY = y + originY;
+ final float sX = width / textureRegion.getRegionWidth();
+ final float sY = height / textureRegion.getRegionHeight();
+ final float cos = MathUtils.cosDeg(rotation);
+ final float sin = MathUtils.sinDeg(rotation);
+
+ float fx, fy;
+ for (int i = 0; i < regionVerticesLength; i += 2) {
+ fx = (regionVertices[i] * sX - originX) * scaleX;
+ fy = (regionVertices[i + 1] * sY - originY) * scaleY;
+ vertices[vertexIndex++] = cos * fx - sin * fy + worldOriginX;
+ vertices[vertexIndex++] = sin * fx + cos * fy + worldOriginY;
+ vertices[vertexIndex++] = light;
+ vertices[vertexIndex++] = dark;
+ vertices[vertexIndex++] = textureCoords[i];
+ vertices[vertexIndex++] = textureCoords[i + 1];
+ }
+ this.vertexIndex = vertexIndex;
+ }
+
public void draw (Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount, short[] polygonTriangles,
int trianglesOffset, int trianglesCount) {
if (!drawing) throw new IllegalStateException("begin must be called before draw.");
@@ -108,8 +325,7 @@ public void draw (Texture texture, float[] polygonVertices, int verticesOffset,
final float[] vertices = this.vertices;
if (texture != lastTexture) {
- flush();
- lastTexture = texture;
+ switchTexture(texture);
} else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount > vertices.length) //
flush();
@@ -125,6 +341,890 @@ public void draw (Texture texture, float[] polygonVertices, int verticesOffset,
this.vertexIndex += verticesCount;
}
+ @Override
+ public void draw (Texture texture, float x, float y, float originX, float originY, float width, float height, float scaleX,
+ float scaleY, float rotation, int srcX, int srcY, int srcWidth, int srcHeight, boolean flipX, boolean flipY) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ // bottom left and top right corner points relative to origin
+ final float worldOriginX = x + originX;
+ final float worldOriginY = y + originY;
+ float fx = -originX;
+ float fy = -originY;
+ float fx2 = width - originX;
+ float fy2 = height - originY;
+
+ // scale
+ if (scaleX != 1 || scaleY != 1) {
+ fx *= scaleX;
+ fy *= scaleY;
+ fx2 *= scaleX;
+ fy2 *= scaleY;
+ }
+
+ // 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 (rotation != 0) {
+ final float cos = MathUtils.cosDeg(rotation);
+ final float sin = MathUtils.sinDeg(rotation);
+
+ 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;
+ y1 += worldOriginY;
+ x2 += worldOriginX;
+ y2 += worldOriginY;
+ x3 += worldOriginX;
+ y3 += worldOriginY;
+ x4 += worldOriginX;
+ y4 += worldOriginY;
+
+ float u = srcX * invTexWidth;
+ float v = (srcY + srcHeight) * invTexHeight;
+ float u2 = (srcX + srcWidth) * invTexWidth;
+ float v2 = srcY * invTexHeight;
+
+ if (flipX) {
+ float tmp = u;
+ u = u2;
+ u2 = tmp;
+ }
+
+ if (flipY) {
+ float tmp = v;
+ v = v2;
+ v2 = tmp;
+ }
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x1;
+ vertices[idx++] = y1;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x2;
+ vertices[idx++] = y2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x3;
+ vertices[idx++] = y3;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x4;
+ vertices[idx++] = y4;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (Texture texture, float x, float y, float width, float height, int srcX, int srcY, int srcWidth,
+ int srcHeight, boolean flipX, boolean flipY) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ float u = srcX * invTexWidth;
+ float v = (srcY + srcHeight) * invTexHeight;
+ float u2 = (srcX + srcWidth) * invTexWidth;
+ float v2 = srcY * invTexHeight;
+ final float fx2 = x + width;
+ final float fy2 = y + height;
+
+ if (flipX) {
+ float tmp = u;
+ u = u2;
+ u2 = tmp;
+ }
+
+ if (flipY) {
+ float tmp = v;
+ v = v2;
+ v2 = tmp;
+ }
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (Texture texture, float x, float y, int srcX, int srcY, int srcWidth, int srcHeight) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ final float u = srcX * invTexWidth;
+ final float v = (srcY + srcHeight) * invTexHeight;
+ final float u2 = (srcX + srcWidth) * invTexWidth;
+ final float v2 = srcY * invTexHeight;
+ final float fx2 = x + srcWidth;
+ final float fy2 = y + srcHeight;
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (Texture texture, float x, float y, float width, float height, float u, float v, float u2, float v2) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ final float fx2 = x + width;
+ final float fy2 = y + height;
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (Texture texture, float x, float y) {
+ draw(texture, x, y, texture.getWidth(), texture.getHeight());
+ }
+
+ @Override
+ public void draw (Texture texture, float x, float y, float width, float height) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ final float fx2 = x + width;
+ final float fy2 = y + height;
+ final float u = 0;
+ final float v = 1;
+ final float u2 = 1;
+ final float v2 = 0;
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ /** Draws a rectangle using the given vertices. There must be 4 vertices, each made up of 6 elements in this order: x, y, lightColor, darkColor,
+ * u, v. The {@link #getColor()} and {@link #getDarkColor()} from the TwoColorPolygonBatch is not applied. */
+ @Override
+ public void draw (Texture texture, float[] spriteVertices, int offset, int count) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ // odds are this is a sprite, we meed to convert it
+ if (spriteVertices.length == 20 && offset == 0 && count == 20) {
+ final float[] vertices = tempSpriteVertices;
+ int idx = 0;
+ for (int i = 0; i < 20; i += 5) {
+ vertices[idx++] = spriteVertices[i];
+ vertices[idx++] = spriteVertices[i + 1];
+ vertices[idx++] = spriteVertices[i + 2];
+ vertices[idx++] = 0; // dark
+ vertices[idx++] = spriteVertices[i + 3];
+ vertices[idx++] = spriteVertices[i + 4];
+ }
+ spriteVertices = vertices;
+ count = SPRITE_SIZE;
+ }
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ final int triangleCount = count / SPRITE_SIZE * 6;
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + triangleCount > triangles.length || vertexIndex + count > vertices.length) //
+ flush();
+
+ final int vertexIndex = this.vertexIndex;
+ int triangleIndex = this.triangleIndex;
+ short vertex = (short)(vertexIndex / VERTEX_SIZE);
+ for (int n = triangleIndex + triangleCount; triangleIndex < n; triangleIndex += 6, vertex += 4) {
+ triangles[triangleIndex] = vertex;
+ triangles[triangleIndex + 1] = (short)(vertex + 1);
+ triangles[triangleIndex + 2] = (short)(vertex + 2);
+ triangles[triangleIndex + 3] = (short)(vertex + 2);
+ triangles[triangleIndex + 4] = (short)(vertex + 3);
+ triangles[triangleIndex + 5] = vertex;
+ }
+ this.triangleIndex = triangleIndex;
+
+ System.arraycopy(spriteVertices, offset, vertices, vertexIndex, count);
+ this.vertexIndex += count;
+ }
+
+ @Override
+ public void draw (TextureRegion region, float x, float y) {
+ draw(region, x, y, region.getRegionWidth(), region.getRegionHeight());
+ }
+
+ @Override
+ public void draw (TextureRegion region, float x, float y, float width, float height) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ Texture texture = region.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ final float fx2 = x + width;
+ final float fy2 = y + height;
+ final float u = region.getU();
+ final float v = region.getV2();
+ final float u2 = region.getU2();
+ final float v2 = region.getV();
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = fy2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = fx2;
+ vertices[idx++] = y;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (TextureRegion region, float x, float y, float originX, float originY, float width, float height,
+ float scaleX, float scaleY, float rotation) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ Texture texture = region.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ // bottom left and top right corner points relative to origin
+ final float worldOriginX = x + originX;
+ final float worldOriginY = y + originY;
+ float fx = -originX;
+ float fy = -originY;
+ float fx2 = width - originX;
+ float fy2 = height - originY;
+
+ // scale
+ if (scaleX != 1 || scaleY != 1) {
+ fx *= scaleX;
+ fy *= scaleY;
+ fx2 *= scaleX;
+ fy2 *= scaleY;
+ }
+
+ // 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 (rotation != 0) {
+ final float cos = MathUtils.cosDeg(rotation);
+ final float sin = MathUtils.sinDeg(rotation);
+
+ 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;
+ y1 += worldOriginY;
+ x2 += worldOriginX;
+ y2 += worldOriginY;
+ x3 += worldOriginX;
+ y3 += worldOriginY;
+ x4 += worldOriginX;
+ y4 += worldOriginY;
+
+ final float u = region.getU();
+ final float v = region.getV2();
+ final float u2 = region.getU2();
+ final float v2 = region.getV();
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x1;
+ vertices[idx++] = y1;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x2;
+ vertices[idx++] = y2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x3;
+ vertices[idx++] = y3;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x4;
+ vertices[idx++] = y4;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (TextureRegion region, float x, float y, float originX, float originY, float width, float height,
+ float scaleX, float scaleY, float rotation, boolean clockwise) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ Texture texture = region.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ // bottom left and top right corner points relative to origin
+ final float worldOriginX = x + originX;
+ final float worldOriginY = y + originY;
+ float fx = -originX;
+ float fy = -originY;
+ float fx2 = width - originX;
+ float fy2 = height - originY;
+
+ // scale
+ if (scaleX != 1 || scaleY != 1) {
+ fx *= scaleX;
+ fy *= scaleY;
+ fx2 *= scaleX;
+ fy2 *= scaleY;
+ }
+
+ // 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 (rotation != 0) {
+ final float cos = MathUtils.cosDeg(rotation);
+ final float sin = MathUtils.sinDeg(rotation);
+
+ 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;
+ y1 += worldOriginY;
+ x2 += worldOriginX;
+ y2 += worldOriginY;
+ x3 += worldOriginX;
+ y3 += worldOriginY;
+ x4 += worldOriginX;
+ y4 += worldOriginY;
+
+ float u1, v1, u2, v2, u3, v3, u4, v4;
+ if (clockwise) {
+ u1 = region.getU2();
+ v1 = region.getV2();
+ u2 = region.getU();
+ v2 = region.getV2();
+ u3 = region.getU();
+ v3 = region.getV();
+ u4 = region.getU2();
+ v4 = region.getV();
+ } else {
+ u1 = region.getU();
+ v1 = region.getV();
+ u2 = region.getU2();
+ v2 = region.getV();
+ u3 = region.getU2();
+ v3 = region.getV2();
+ u4 = region.getU();
+ v4 = region.getV2();
+ }
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = this.vertexIndex;
+ vertices[idx++] = x1;
+ vertices[idx++] = y1;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u1;
+ vertices[idx++] = v1;
+
+ vertices[idx++] = x2;
+ vertices[idx++] = y2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x3;
+ vertices[idx++] = y3;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u3;
+ vertices[idx++] = v3;
+
+ vertices[idx++] = x4;
+ vertices[idx++] = y4;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u4;
+ vertices[idx++] = v4;
+ this.vertexIndex = idx;
+ }
+
+ @Override
+ public void draw (TextureRegion region, float width, float height, Affine2 transform) {
+ if (!drawing) throw new IllegalStateException("begin must be called before draw.");
+
+ final short[] triangles = this.triangles;
+ final float[] vertices = this.vertices;
+
+ Texture texture = region.getTexture();
+ if (texture != lastTexture)
+ switchTexture(texture);
+ else if (triangleIndex + 6 > triangles.length || vertexIndex + SPRITE_SIZE > vertices.length) //
+ flush();
+
+ int triangleIndex = this.triangleIndex;
+ final int startVertex = vertexIndex / VERTEX_SIZE;
+ triangles[triangleIndex++] = (short)startVertex;
+ triangles[triangleIndex++] = (short)(startVertex + 1);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 2);
+ triangles[triangleIndex++] = (short)(startVertex + 3);
+ triangles[triangleIndex++] = (short)startVertex;
+ this.triangleIndex = triangleIndex;
+
+ // construct corner points
+ float x1 = transform.m02;
+ float y1 = transform.m12;
+ float x2 = transform.m01 * height + transform.m02;
+ float y2 = transform.m11 * height + transform.m12;
+ float x3 = transform.m00 * width + transform.m01 * height + transform.m02;
+ float y3 = transform.m10 * width + transform.m11 * height + transform.m12;
+ float x4 = transform.m00 * width + transform.m02;
+ float y4 = transform.m10 * width + transform.m12;
+
+ final float u = region.getU();
+ final float v = region.getV2();
+ final float u2 = region.getU2();
+ final float v2 = region.getV();
+
+ float light = this.light;
+ float dark = this.dark;
+ int idx = vertexIndex;
+ vertices[idx++] = x1;
+ vertices[idx++] = y1;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v;
+
+ vertices[idx++] = x2;
+ vertices[idx++] = y2;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x3;
+ vertices[idx++] = y3;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v2;
+
+ vertices[idx++] = x4;
+ vertices[idx++] = y4;
+ vertices[idx++] = light;
+ vertices[idx++] = dark;
+ vertices[idx++] = u2;
+ vertices[idx++] = v;
+ vertexIndex = idx;
+ }
+
+ @Override
public void flush () {
if (vertexIndex == 0) return;
@@ -140,20 +1240,36 @@ public void flush () {
triangleIndex = 0;
}
+ @Override
+ public void disableBlending() {
+ flush();
+ blendingDisabled = true;
+ }
+
+ @Override
+ public void enableBlending() {
+ flush();
+ blendingDisabled = false;
+ }
+
+ @Override
public void dispose () {
mesh.dispose();
shader.dispose();
}
+ @Override
public Matrix4 getProjectionMatrix () {
return projectionMatrix;
}
+ @Override
public Matrix4 getTransformMatrix () {
return transformMatrix;
}
/** Flushes the batch. */
+ @Override
public void setProjectionMatrix (Matrix4 projection) {
if (drawing) flush();
projectionMatrix.set(projection);
@@ -161,6 +1277,7 @@ public void setProjectionMatrix (Matrix4 projection) {
}
/** Flushes the batch. */
+ @Override
public void setTransformMatrix (Matrix4 transform) {
if (drawing) flush();
transformMatrix.set(transform);
@@ -183,7 +1300,15 @@ private void setupMatrices () {
shader.setUniformi("u_texture", 0);
}
+ private void switchTexture (Texture texture) {
+ flush();
+ lastTexture = texture;
+ invTexWidth = 1.0f / texture.getWidth();
+ invTexHeight = 1.0f / texture.getHeight();
+ }
+
/** Flushes the batch if the shader was changed. */
+ @Override
public void setShader (ShaderProgram newShader) {
if (shader == newShader) return;
if (drawing) {
@@ -197,12 +1322,29 @@ public void setShader (ShaderProgram newShader) {
}
}
+ @Override
+ public ShaderProgram getShader() {
+ return shader;
+ }
+
+ @Override
+ public boolean isBlendingEnabled () {
+ return !blendingDisabled;
+ }
+
+ @Override
+ public boolean isDrawing () {
+ return drawing;
+ }
+
/** Flushes the batch if the blend function was changed. */
+ @Override
public void setBlendFunction (int srcFunc, int dstFunc) {
setBlendFunctionSeparate(srcFunc, dstFunc, srcFunc, dstFunc);
}
/** Flushes the batch if the blend function was changed. */
+ @Override
public void setBlendFunctionSeparate (int srcFuncColor, int dstFuncColor, int srcFuncAlpha, int dstFuncAlpha) {
if (blendSrcFunc == srcFuncColor && blendDstFunc == dstFuncColor && blendSrcFuncAlpha == srcFuncAlpha
&& blendDstFuncAlpha == dstFuncAlpha) return;
@@ -213,6 +1355,26 @@ public void setBlendFunctionSeparate (int srcFuncColor, int dstFuncColor, int sr
blendDstFuncAlpha = dstFuncAlpha;
}
+ @Override
+ public int getBlendSrcFunc () {
+ return blendSrcFunc;
+ }
+
+ @Override
+ public int getBlendDstFunc () {
+ return blendDstFunc;
+ }
+
+ @Override
+ public int getBlendSrcFuncAlpha() {
+ return blendSrcFuncAlpha;
+ }
+
+ @Override
+ public int getBlendDstFuncAlpha() {
+ return blendDstFuncAlpha;
+ }
+
private ShaderProgram createDefaultShader () {
String vertexShader = "attribute vec4 a_position;\n" //
+ "attribute vec4 a_light;\n" //