Files
Terrarum/src/com/badlogic/gdx/graphics/g2d/UnpackedColourSpriteBatch.java
2023-09-14 23:37:32 +09:00

1379 lines
43 KiB
Java

package com.badlogic.gdx.graphics.g2d;
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
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.glutils.ShaderProgram;
import com.badlogic.gdx.math.Affine2;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import net.torvald.gdx.graphics.Cvec;
import java.nio.Buffer;
/** Draws batched quads using indices.
* Created by minjaesong on 2023-09-14.
* @see Batch
* @author mzechner
* @author Nathan Sweet
* @author CuriousTorvald
*/
public class UnpackedColourSpriteBatch extends SpriteBatch {
/** @deprecated Do not use, this field is for testing only and is likely to be removed. Sets the {@link VertexDataType} to be
* used when gles 3 is not available, defaults to {@link VertexDataType#VertexArray}. */
@Deprecated public static VertexDataType defaultVertexDataType = VertexDataType.VertexArray;
private Mesh mesh;
final float[] vertices;
int idx = 0;
Texture lastTexture = null;
float invTexWidth = 0, invTexHeight = 0;
boolean drawing = false;
private final Matrix4 transformMatrix = new Matrix4();
private final Matrix4 projectionMatrix = new Matrix4();
private final Matrix4 combinedMatrix = new Matrix4();
private boolean blendingDisabled = false;
private int blendSrcFunc = GL20.GL_SRC_ALPHA;
private int blendDstFunc = GL20.GL_ONE_MINUS_SRC_ALPHA;
private int blendSrcFuncAlpha = GL20.GL_SRC_ALPHA;
private int blendDstFuncAlpha = GL20.GL_ONE_MINUS_SRC_ALPHA;
private final ShaderProgram shader;
private ShaderProgram customShader = null;
private boolean ownsShader;
private final Color color = new Color(1, 1, 1, 1);
private final Cvec generic = new Cvec(0);
float colorPacked = Color.WHITE_FLOAT_BITS;
/** Number of render calls since the last {@link #begin()}. **/
public int renderCalls = 0;
/** Number of rendering calls, ever. Will not be reset unless set manually. **/
public int totalRenderCalls = 0;
/** The maximum number of sprites rendered in one batch so far. **/
public int maxSpritesInBatch = 0;
/** Constructs a new SpriteBatch with a size of 1000, one buffer, and the default shader.
* @see SpriteBatch#SpriteBatch(int, ShaderProgram) */
public UnpackedColourSpriteBatch () {
this(1000, null);
}
/** Constructs a SpriteBatch with one buffer and the default shader.
* @see SpriteBatch#SpriteBatch(int, ShaderProgram) */
public UnpackedColourSpriteBatch (int size) {
this(size, null);
}
/** Constructs a new SpriteBatch. Sets the projection matrix to an orthographic projection with y-axis point upwards, x-axis
* point to the right and the origin being in the bottom left corner of the screen. The projection will be pixel perfect with
* respect to the current screen resolution.
* <p>
* The defaultShader specifies the shader to use. Note that the names for uniforms for this default shader are different than
* the ones expect for shaders set with {@link #setShader(ShaderProgram)}. See {@link #createDefaultShader()}.
* @param size The max number of sprites in a single batch. Max of 8191.
* @param defaultShader The default shader to use. This is not owned by the SpriteBatch and must be disposed separately. */
public UnpackedColourSpriteBatch (int size, ShaderProgram defaultShader) {
super(size, defaultShader);
// 32767 is max vertex index, so 32767 / 4 vertices per sprite = 8191 sprites max.
if (size > 8191) throw new IllegalArgumentException("Can't have more than 8191 sprites per batch: " + size);
VertexDataType vertexDataType = (Gdx.gl30 != null) ? VertexDataType.VertexBufferObjectWithVAO : defaultVertexDataType;
mesh = new Mesh(vertexDataType, false, size * 4, size * 6,
new VertexAttribute(Usage.Position, 2, "a_position"),
new VertexAttribute(Usage.ColorUnpacked, 4, "a_color"),
new VertexAttribute(Usage.TextureCoordinates, 2, "a_texCoord0"),
new VertexAttribute(Usage.Generic, 4, "a_generic"));
projectionMatrix.setToOrtho2D(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
vertices = new float[size * 48];
int len = size * 6;
short[] indices = new short[len];
short j = 0;
for (int i = 0; i < len; i += 6, j += 4) {
indices[i] = j;
indices[i + 1] = (short)(j + 1);
indices[i + 2] = (short)(j + 2);
indices[i + 3] = (short)(j + 2);
indices[i + 4] = (short)(j + 3);
indices[i + 5] = j;
}
mesh.setIndices(indices);
if (defaultShader == null) {
shader = createDefaultShader();
ownsShader = true;
} else
shader = defaultShader;
}
/** Returns a new instance of the default shader used by SpriteBatch for GL2 when no shader is specified. */
static public ShaderProgram createDefaultShader () {
String vertexShader = """
#version 150
in vec4 a_position;
in vec4 a_color;
in vec4 a_generic;
in vec2 a_texCoord0;
uniform mat4 u_projTrans;
out vec4 v_color;
out vec2 v_texCoords;
out vec4 v_generic;
void main() {
v_color = a_color;
v_texCoords = a_texCoord0;
v_generic = a_generic;
gl_Position = u_projTrans * a_position;
}""";
String fragmentShader = """
#version 150
#ifdef GL_ES
precision mediump float;
#endif
in vec4 v_color;
in vec4 v_generic;
in vec2 v_texCoords;
uniform sampler2D u_texture;
out vec4 fragColor;
void main() {
fragColor = v_color * texture(u_texture, v_texCoords);
}""";
ShaderProgram shader = new ShaderProgram(vertexShader, fragmentShader);
if (!shader.isCompiled()) throw new IllegalArgumentException("Error compiling shader: " + shader.getLog());
return shader;
}
@Override
public void begin () {
if (drawing) throw new IllegalStateException("SpriteBatch.end must be called before begin.");
renderCalls = 0;
Gdx.gl.glDepthMask(false);
if (customShader != null)
customShader.bind();
else
shader.bind();
setupMatrices();
drawing = true;
}
@Override
public void end () {
if (!drawing) throw new IllegalStateException("SpriteBatch.begin must be called before end.");
if (idx > 0) flush();
lastTexture = null;
drawing = false;
GL20 gl = Gdx.gl;
gl.glDepthMask(true);
if (isBlendingEnabled()) gl.glDisable(GL20.GL_BLEND);
}
@Override
public void setColor (Color tint) {
color.set(tint);
colorPacked = tint.toFloatBits();
}
@Override
public void setColor (float r, float g, float b, float a) {
color.set(r, g, b, a);
colorPacked = color.toFloatBits();
}
@Override
public Color getColor () {
return color;
}
public void setGeneric (Cvec xyzw) {
generic.set(xyzw);
}
public void setGeneric (float x, float y, float z, float w) {
generic.set(x, y, z, w);
}
public Cvec getGeneric () {
return generic;
}
@Override
public void setPackedColor (float packedColor) {
Color.abgr8888ToColor(color, packedColor);
this.colorPacked = packedColor;
}
@Override
public float getPackedColor () {
return colorPacked;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
if (texture != lastTexture)
switchTexture(texture);
else if (idx == vertices.length) //
flush();
// 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;
}
int idx = this.idx;
vertices[idx] = x1;
vertices[idx + 1] = y1;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x2;
vertices[idx + 13] = y2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = x3;
vertices[idx + 25] = y3;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = x4;
vertices[idx + 37] = y4;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
if (texture != lastTexture)
switchTexture(texture);
else if (idx == vertices.length) //
flush();
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;
}
int idx = this.idx;
vertices[idx] = x;
vertices[idx + 1] = y;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x;
vertices[idx + 13] = fy2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = fx2;
vertices[idx + 25] = fy2;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = fx2;
vertices[idx + 37] = y;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@Override
public void draw (Texture texture, float x, float y, int srcX, int srcY, int srcWidth, int srcHeight) {
if (!drawing) throw new IllegalStateException("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
if (texture != lastTexture)
switchTexture(texture);
else if (idx == vertices.length) //
flush();
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;
int idx = this.idx;
vertices[idx] = x;
vertices[idx + 1] = y;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x;
vertices[idx + 13] = fy2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = fx2;
vertices[idx + 25] = fy2;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = fx2;
vertices[idx + 37] = y;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
if (texture != lastTexture)
switchTexture(texture);
else if (idx == vertices.length) //
flush();
final float fx2 = x + width;
final float fy2 = y + height;
int idx = this.idx;
vertices[idx] = x;
vertices[idx + 1] = y;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x;
vertices[idx + 13] = fy2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = fx2;
vertices[idx + 25] = fy2;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = fx2;
vertices[idx + 37] = y;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
if (texture != lastTexture)
switchTexture(texture);
else if (idx == vertices.length) //
flush();
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;
int idx = this.idx;
vertices[idx] = x;
vertices[idx + 1] = y;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x;
vertices[idx + 13] = fy2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = fx2;
vertices[idx + 25] = fy2;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = fx2;
vertices[idx + 37] = y;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@Override
public void draw (Texture texture, float[] spriteVertices, int offset, int count) {
if (!drawing) throw new IllegalStateException("SpriteBatch.begin must be called before draw.");
int verticesLength = vertices.length;
int remainingVertices = verticesLength;
if (texture != lastTexture)
switchTexture(texture);
else {
remainingVertices -= idx;
if (remainingVertices == 0) {
flush();
remainingVertices = verticesLength;
}
}
int copyCount = Math.min(remainingVertices, count);
System.arraycopy(spriteVertices, offset, vertices, idx, copyCount);
idx += copyCount;
count -= copyCount;
while (count > 0) {
offset += copyCount;
flush();
copyCount = Math.min(verticesLength, count);
System.arraycopy(spriteVertices, offset, vertices, 0, copyCount);
idx += copyCount;
count -= copyCount;
}
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) //
flush();
final float fx2 = x + width;
final float fy2 = y + height;
final float u = region.u;
final float v = region.v2;
final float u2 = region.u2;
final float v2 = region.v;
int idx = this.idx;
vertices[idx] = x;
vertices[idx + 1] = y;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x;
vertices[idx + 13] = fy2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = fx2;
vertices[idx + 25] = fy2;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = fx2;
vertices[idx + 37] = y;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) //
flush();
// 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.u;
final float v = region.v2;
final float u2 = region.u2;
final float v2 = region.v;
int idx = this.idx;
vertices[idx] = x1;
vertices[idx + 1] = y1;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x2;
vertices[idx + 13] = y2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = x3;
vertices[idx + 25] = y3;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = x4;
vertices[idx + 37] = y4;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@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("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) //
flush();
// 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.u2;
v1 = region.v2;
u2 = region.u;
v2 = region.v2;
u3 = region.u;
v3 = region.v;
u4 = region.u2;
v4 = region.v;
} else {
u1 = region.u;
v1 = region.v;
u2 = region.u2;
v2 = region.v;
u3 = region.u2;
v3 = region.v2;
u4 = region.u;
v4 = region.v2;
}
int idx = this.idx;
vertices[idx] = x1;
vertices[idx + 1] = y1;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u1;
vertices[idx + 7] = v1;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x2;
vertices[idx + 13] = y2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u2;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = x3;
vertices[idx + 25] = y3;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u3;
vertices[idx + 31] = v3;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = x4;
vertices[idx + 37] = y4;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u4;
vertices[idx + 43] = v4;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@Override
public void draw (TextureRegion region, float width, float height, Affine2 transform) {
if (!drawing) throw new IllegalStateException("SpriteBatch.begin must be called before draw.");
float[] vertices = this.vertices;
Texture texture = region.texture;
if (texture != lastTexture) {
switchTexture(texture);
} else if (idx == vertices.length) {
flush();
}
// 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;
float u = region.u;
float v = region.v2;
float u2 = region.u2;
float v2 = region.v;
int idx = this.idx;
vertices[idx] = x1;
vertices[idx + 1] = y1;
vertices[idx + 2] = color.r;
vertices[idx + 3] = color.g;
vertices[idx + 4] = color.b;
vertices[idx + 5] = color.a;
vertices[idx + 6] = u;
vertices[idx + 7] = v;
vertices[idx + 8] = generic.r;
vertices[idx + 9] = generic.g;
vertices[idx + 10] = generic.b;
vertices[idx + 11] = generic.a;
vertices[idx + 12] = x2;
vertices[idx + 13] = y2;
vertices[idx + 14] = color.r;
vertices[idx + 15] = color.g;
vertices[idx + 16] = color.b;
vertices[idx + 17] = color.a;
vertices[idx + 18] = u;
vertices[idx + 19] = v2;
vertices[idx + 20] = generic.r;
vertices[idx + 21] = generic.g;
vertices[idx + 22] = generic.b;
vertices[idx + 23] = generic.a;
vertices[idx + 24] = x3;
vertices[idx + 25] = y3;
vertices[idx + 26] = color.r;
vertices[idx + 27] = color.g;
vertices[idx + 28] = color.b;
vertices[idx + 29] = color.a;
vertices[idx + 30] = u2;
vertices[idx + 31] = v2;
vertices[idx + 32] = generic.r;
vertices[idx + 33] = generic.g;
vertices[idx + 34] = generic.b;
vertices[idx + 35] = generic.a;
vertices[idx + 36] = x4;
vertices[idx + 37] = y4;
vertices[idx + 38] = color.r;
vertices[idx + 39] = color.g;
vertices[idx + 40] = color.b;
vertices[idx + 41] = color.a;
vertices[idx + 42] = u2;
vertices[idx + 43] = v;
vertices[idx + 44] = generic.r;
vertices[idx + 45] = generic.g;
vertices[idx + 46] = generic.b;
vertices[idx + 47] = generic.a;
this.idx = idx + 48;
}
@Override
public void flush () {
if (idx == 0) return;
renderCalls++;
totalRenderCalls++;
int spritesInBatch = idx / 48;
if (spritesInBatch > maxSpritesInBatch) maxSpritesInBatch = spritesInBatch;
int count = spritesInBatch * 6;
lastTexture.bind();
Mesh mesh = this.mesh;
mesh.setVertices(vertices, 0, idx);
((Buffer)mesh.getIndicesBuffer()).position(0);
((Buffer)mesh.getIndicesBuffer()).limit(count);
if (blendingDisabled) {
Gdx.gl.glDisable(GL20.GL_BLEND);
} else {
Gdx.gl.glEnable(GL20.GL_BLEND);
if (blendSrcFunc != -1) Gdx.gl.glBlendFuncSeparate(blendSrcFunc, blendDstFunc, blendSrcFuncAlpha, blendDstFuncAlpha);
}
mesh.render(customShader != null ? customShader : shader, GL20.GL_TRIANGLES, 0, count);
idx = 0;
}
@Override
public void disableBlending () {
if (blendingDisabled) return;
flush();
blendingDisabled = true;
}
@Override
public void enableBlending () {
if (!blendingDisabled) return;
flush();
blendingDisabled = false;
}
@Override
public void setBlendFunction (int srcFunc, int dstFunc) {
setBlendFunctionSeparate(srcFunc, dstFunc, srcFunc, dstFunc);
}
@Override
public void setBlendFunctionSeparate (int srcFuncColor, int dstFuncColor, int srcFuncAlpha, int dstFuncAlpha) {
if (blendSrcFunc == srcFuncColor && blendDstFunc == dstFuncColor && blendSrcFuncAlpha == srcFuncAlpha
&& blendDstFuncAlpha == dstFuncAlpha) return;
flush();
blendSrcFunc = srcFuncColor;
blendDstFunc = dstFuncColor;
blendSrcFuncAlpha = srcFuncAlpha;
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;
}
@Override
public void dispose () {
mesh.dispose();
if (ownsShader && shader != null) shader.dispose();
}
@Override
public Matrix4 getProjectionMatrix () {
return projectionMatrix;
}
@Override
public Matrix4 getTransformMatrix () {
return transformMatrix;
}
@Override
public void setProjectionMatrix (Matrix4 projection) {
if (drawing) flush();
projectionMatrix.set(projection);
if (drawing) setupMatrices();
}
@Override
public void setTransformMatrix (Matrix4 transform) {
if (drawing) flush();
transformMatrix.set(transform);
if (drawing) setupMatrices();
}
protected void setupMatrices () {
combinedMatrix.set(projectionMatrix).mul(transformMatrix);
if (customShader != null) {
customShader.setUniformMatrix("u_projTrans", combinedMatrix);
customShader.setUniformi("u_texture", 0);
} else {
shader.setUniformMatrix("u_projTrans", combinedMatrix);
shader.setUniformi("u_texture", 0);
}
}
protected void switchTexture (Texture texture) {
flush();
lastTexture = texture;
invTexWidth = 1.0f / texture.getWidth();
invTexHeight = 1.0f / texture.getHeight();
}
@Override
public void setShader (ShaderProgram shader) {
if (drawing) {
flush();
}
customShader = shader;
if (drawing) {
if (customShader != null)
customShader.bind();
else
this.shader.bind();
setupMatrices();
}
}
@Override
public ShaderProgram getShader () {
if (customShader == null) {
return shader;
}
return customShader;
}
@Override
public boolean isBlendingEnabled () {
return !blendingDisabled;
}
public boolean isDrawing () {
return drawing;
}
}