All Downloads are FREE. Search and download functionalities are using the official Maven repository.

games.rednblack.editor.renderer.utils.CpuPolygonSpriteBatch Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * 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.
 ******************************************************************************/

package games.rednblack.editor.renderer.utils;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.PolygonRegion;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
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.GdxRuntimeException;

/**
 * CpuSpriteBatch behaves like SpriteBatch, except it doesn't flush automatically whenever the transformation matrix changes.
 * Instead, the vertices get adjusted on subsequent draws to match the running batch. This can improve performance through longer
 * batches, for example when drawing Groups with transform enabled.
 *
 * @author Valentin Milea
 * @author https://github.com/wangwangla
 * @see SpriteBatch#renderCalls
 * @see com.badlogic.gdx.scenes.scene2d.Group#setTransform(boolean) Group.setTransform()
 */
public class CpuPolygonSpriteBatch extends PolygonSpriteBatch implements CpuBatch {

    private final Matrix4 virtualMatrix = new Matrix4();
    private final Affine2 adjustAffine = new Affine2();
    private boolean adjustNeeded;
    private boolean haveIdentityRealMatrix = true;

    private final Affine2 tmpAffine = new Affine2();

    /**
     * Constructs a CpuSpriteBatch with a size of 2000 and the default shader.
     *
     * @see SpriteBatch#SpriteBatch()
     */
    public CpuPolygonSpriteBatch() {
        this(2000);
    }

    /**
     * Constructs a CpuSpriteBatch with the default shader.
     *
     * @see SpriteBatch#SpriteBatch(int)
     */
    public CpuPolygonSpriteBatch(int size) {
        this(size, null);
    }

    /**
     * Constructs a CpuSpriteBatch with a custom shader.
     *
     * @see SpriteBatch#SpriteBatch(int, ShaderProgram)
     */
    public CpuPolygonSpriteBatch(int size, ShaderProgram defaultShader) {
        super(size, defaultShader);
    }

    /**
     * 

* Flushes the batch and realigns the real matrix on the GPU. Subsequent draws won't need adjustment and will be slightly * faster as long as the transform matrix is not {@link #setTransformMatrix(Matrix4) changed}. *

*

* Note: The real transform matrix must be invertible. If a singular matrix is detected, GdxRuntimeException will be * thrown. *

* * @see SpriteBatch#flush() */ @Override public void flushAndSyncTransformMatrix() { flush(); if (adjustNeeded) { // vertices flushed, safe now to replace matrix haveIdentityRealMatrix = checkIdt(virtualMatrix); if (!haveIdentityRealMatrix && virtualMatrix.det() == 0) throw new GdxRuntimeException("Transform matrix is singular, can't sync"); adjustNeeded = false; super.setTransformMatrix(virtualMatrix); } } @Override public Matrix4 getTransformMatrix() { return (adjustNeeded ? virtualMatrix : super.getTransformMatrix()); } /** * Sets the transform matrix to be used by this Batch. Even if this is called inside a {@link #begin()}/{@link #end()} block, * the current batch is not flushed to the GPU. Instead, for every subsequent draw() the vertices will be transformed * on the CPU to match the original batch matrix. This adjustment must be performed until the matrices are realigned by * restoring the original matrix, or by calling {@link #flushAndSyncTransformMatrix()}. */ @Override public void setTransformMatrix(Matrix4 transform) { Matrix4 realMatrix = super.getTransformMatrix(); if (checkEqual(realMatrix, transform)) { adjustNeeded = false; } else { if (isDrawing()) { virtualMatrix.setAsAffine(transform); adjustNeeded = true; // adjust = inverse(real) x virtual // real x adjust x vertex = virtual x vertex if (haveIdentityRealMatrix) { adjustAffine.set(transform); } else { tmpAffine.set(transform); adjustAffine.set(realMatrix).inv().mul(tmpAffine); } } else { realMatrix.setAsAffine(transform); haveIdentityRealMatrix = checkIdt(realMatrix); } } } /** * Sets the transform matrix to be used by this Batch. Even if this is called inside a {@link #begin()}/{@link #end()} block, * the current batch is not flushed to the GPU. Instead, for every subsequent draw() the vertices will be transformed * on the CPU to match the original batch matrix. This adjustment must be performed until the matrices are realigned by * restoring the original matrix, or by calling {@link #flushAndSyncTransformMatrix()} or {@link #end()}. */ @Override public void setTransformMatrix(Affine2 transform) { Matrix4 realMatrix = super.getTransformMatrix(); if (checkEqual(realMatrix, transform)) { adjustNeeded = false; } else { virtualMatrix.setAsAffine(transform); if (isDrawing()) { adjustNeeded = true; // adjust = inverse(real) x virtual // real x adjust x vertex = virtual x vertex if (haveIdentityRealMatrix) { adjustAffine.set(transform); } else { adjustAffine.set(realMatrix).inv().mul(transform); } } else { realMatrix.setAsAffine(transform); haveIdentityRealMatrix = checkIdt(realMatrix); } } } @Override public void draw(PolygonRegion region, float x, float y) { if (!adjustNeeded) { super.draw(region, x, y); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 > 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 color = this.colorPacked; final float[] textureCoords = region.getTextureCoords(); Affine2 t = adjustAffine; for (int i = 0; i < regionVerticesLength; i += 2) { float x1 = regionVertices[i] + x; float y1 = regionVertices[i + 1] + y; vertices[vertexIndex++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[vertexIndex++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[vertexIndex++] = color; vertices[vertexIndex++] = textureCoords[i]; vertices[vertexIndex++] = textureCoords[i + 1]; } this.vertexIndex = vertexIndex; } } @Override public void draw(PolygonRegion region, float x, float y, float originX, float originY, float width, float height, float scaleX, float scaleY, float rotation) { if (!adjustNeeded) { super.draw(region, x, y, originX, originY, width, height, scaleX, scaleY, rotation); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 + 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 color = this.colorPacked; 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; Affine2 t = adjustAffine; for (int i = 0; i < regionVerticesLength; i += 2) { fx = (regionVertices[i] * sX - originX) * scaleX; fy = (regionVertices[i + 1] * sY - originY) * scaleY; float x1 = cos * fx - sin * fy + worldOriginX; float y1 = sin * fx + cos * fy + worldOriginY; vertices[vertexIndex++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[vertexIndex++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[vertexIndex++] = color; vertices[vertexIndex++] = textureCoords[i]; vertices[vertexIndex++] = textureCoords[i + 1]; } this.vertexIndex = vertexIndex; } } @Override public void draw(PolygonRegion region, float x, float y, float width, float height) { if (!adjustNeeded) { super.draw(region, x, y, width, height); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; final float[] textureCoords = region.getTextureCoords(); final float sX = width / textureRegion.getRegionWidth(); final float sY = height / textureRegion.getRegionHeight(); Affine2 t = adjustAffine; for (int i = 0; i < regionVerticesLength; i += 2) { float x1 = regionVertices[i] * sX + x; float y1 = regionVertices[i + 1] * sY + y; vertices[vertexIndex++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[vertexIndex++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[vertexIndex++] = color; vertices[vertexIndex++] = textureCoords[i]; vertices[vertexIndex++] = textureCoords[i + 1]; } this.vertexIndex = vertexIndex; } } @Override public void draw(Texture texture, float x, float y) { if (!adjustNeeded) { super.draw(texture, x, y); } else { float width = texture.getWidth(); float height = texture.getHeight(); if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; this.vertexIndex = idx; } } @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 (!adjustNeeded) { super.draw(texture, x, y, originX, originY, width, height, scaleX, scaleY, rotation, srcX, srcY, srcWidth, srcHeight, flipX, flipY); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[idx++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x2 + t.m01 * y2 + t.m02; vertices[idx++] = t.m10 * x2 + t.m11 * y2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * x3 + t.m01 * y3 + t.m02; vertices[idx++] = t.m10 * x3 + t.m11 * y3 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * x4 + t.m01 * y4 + t.m02; vertices[idx++] = t.m10 * x4 + t.m11 * y4 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; this.vertexIndex = idx; } } @Override public void draw(Texture texture, float x, float y, float width, float height) { if (!adjustNeeded) { super.draw(texture, x, y, width, height); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; 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 (!adjustNeeded) { super.draw(texture, x, y, width, height, u, v, u2, v2); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; 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 (!adjustNeeded) { super.draw(texture, x, y, width, height, srcX, srcY, srcWidth, srcHeight, flipX, flipY); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; 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 (!adjustNeeded) { super.draw(texture, x, y, srcX, srcY, srcWidth, srcHeight); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; this.vertexIndex = idx; } } /** * Draws the polygon using the given vertices and triangles. Each vertices must be made up of 5 elements in this order: x, y, * color, u, v. */ @Override public void draw(Texture texture, float[] polygonVertices, int verticesOffset, int verticesCount, short[] polygonTriangles, int trianglesOffset, int trianglesCount) { if (!adjustNeeded) { super.draw(texture, polygonVertices, verticesOffset, verticesCount, polygonTriangles, trianglesOffset, trianglesCount); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.begin must be called before draw."); final short[] triangles = this.triangles; final float[] vertices = this.vertices; if (texture != lastTexture) switchTexture(texture); else if (triangleIndex + trianglesCount > triangles.length || vertexIndex + verticesCount > vertices.length) // flush(); int triangleIndex = this.triangleIndex; final int vertexIndex = this.vertexIndex; final int startVertex = vertexIndex / VERTEX_SIZE; for (int i = trianglesOffset, n = i + trianglesCount; i < n; i++) triangles[triangleIndex++] = (short) (polygonTriangles[i] + startVertex); this.triangleIndex = triangleIndex; Affine2 t = adjustAffine; int vdin = vertexIndex; for (int offsetin = verticesOffset; offsetin < verticesCount + verticesOffset; offsetin += 5, vdin += 5) { float x = polygonVertices[offsetin]; float y = polygonVertices[offsetin + 1]; vertices[vdin] = t.m00 * x + t.m01 * y + t.m02; // x vertices[vdin + 1] = t.m10 * x + t.m11 * y + t.m12; // y vertices[vdin + 2] = polygonVertices[offsetin + 2]; // color vertices[vdin + 3] = polygonVertices[offsetin + 3]; // u vertices[vdin + 4] = polygonVertices[offsetin + 4]; // v } // System.arraycopy(polygonVertices, verticesOffset, vertices, vertexIndex, verticesCount); this.vertexIndex += verticesCount; } } @Override public void draw(Texture texture, float[] spriteVertices, int offset, int count) { if (!adjustNeeded) { super.draw(texture, spriteVertices, offset, count); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.begin must be called before draw."); final short[] triangles = this.triangles; final float[] vertices = this.vertices; int triangleCount = count / SPRITE_SIZE * 6; int batch; if (texture != lastTexture) { switchTexture(texture); batch = Math.min(Math.min(count, vertices.length - (vertices.length % SPRITE_SIZE)), triangles.length / 6 * SPRITE_SIZE); triangleCount = batch / SPRITE_SIZE * 6; } else if (triangleIndex + triangleCount > triangles.length || vertexIndex + count > vertices.length) { flush(); batch = Math.min(Math.min(count, vertices.length - (vertices.length % SPRITE_SIZE)), triangles.length / 6 * SPRITE_SIZE); triangleCount = batch / SPRITE_SIZE * 6; } else batch = count; int vertexIndex = this.vertexIndex; short vertex = (short) (vertexIndex / VERTEX_SIZE); int triangleIndex = this.triangleIndex; 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; } while (true) { Affine2 t = adjustAffine; int vdin = vertexIndex; for (int offsetin = offset; offsetin < batch + offset; offsetin += 5, vdin += 5) { float x = spriteVertices[offsetin]; float y = spriteVertices[offsetin + 1]; vertices[vdin] = t.m00 * x + t.m01 * y + t.m02; // x vertices[vdin + 1] = t.m10 * x + t.m11 * y + t.m12; // y vertices[vdin + 2] = spriteVertices[offsetin + 2]; // color vertices[vdin + 3] = spriteVertices[offsetin + 3]; // u vertices[vdin + 4] = spriteVertices[offsetin + 4]; // v } //System.arraycopy(spriteVertices, offset, vertices, vertexIndex, batch); this.vertexIndex = vertexIndex + batch; this.triangleIndex = triangleIndex; count -= batch; if (count == 0) break; offset += batch; flush(); vertexIndex = 0; if (batch > count) { batch = Math.min(count, triangles.length / 6 * SPRITE_SIZE); triangleIndex = batch / SPRITE_SIZE * 6; } } } } @Override public void draw(TextureRegion region, float width, float height, Affine2 transform) { if (!adjustNeeded) { super.draw(region, width, height, transform); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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; float u = region.getU(); float v = region.getV2(); float u2 = region.getU2(); float v2 = region.getV(); float color = this.colorPacked; int idx = vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[idx++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x2 + t.m01 * y2 + t.m02; vertices[idx++] = t.m10 * x2 + t.m11 * y2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * x3 + t.m01 * y3 + t.m02; vertices[idx++] = t.m10 * x3 + t.m11 * y3 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * x4 + t.m01 * y4 + t.m02; vertices[idx++] = t.m10 * x4 + t.m11 * y4 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; vertexIndex = idx; } } @Override public void draw(TextureRegion region, float x, float y) { if (!adjustNeeded) { super.draw(region, x, y); } else { float width = region.getRegionWidth(); float height = region.getRegionHeight(); if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; 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 (!adjustNeeded) { super.draw(region, x, y, originX, originY, width, height, scaleX, scaleY, rotation); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[idx++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x2 + t.m01 * y2 + t.m02; vertices[idx++] = t.m10 * x2 + t.m11 * y2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * x3 + t.m01 * y3 + t.m02; vertices[idx++] = t.m10 * x3 + t.m11 * y3 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * x4 + t.m01 * y4 + t.m02; vertices[idx++] = t.m10 * x4 + t.m11 * y4 + t.m12; vertices[idx++] = color; 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 (!adjustNeeded) { super.draw(region, x, y, originX, originY, width, height, scaleX, scaleY, rotation, clockwise); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x1 + t.m01 * y1 + t.m02; vertices[idx++] = t.m10 * x1 + t.m11 * y1 + t.m12; vertices[idx++] = color; vertices[idx++] = u1; vertices[idx++] = v1; vertices[idx++] = t.m00 * x2 + t.m01 * y2 + t.m02; vertices[idx++] = t.m10 * x2 + t.m11 * y2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * x3 + t.m01 * y3 + t.m02; vertices[idx++] = t.m10 * x3 + t.m11 * y3 + t.m12; vertices[idx++] = color; vertices[idx++] = u3; vertices[idx++] = v3; vertices[idx++] = t.m00 * x4 + t.m01 * y4 + t.m02; vertices[idx++] = t.m10 * x4 + t.m11 * y4 + t.m12; vertices[idx++] = color; vertices[idx++] = u4; vertices[idx++] = v4; this.vertexIndex = idx; } } @Override public void draw(TextureRegion region, float x, float y, float width, float height) { if (!adjustNeeded) { super.draw(region, x, y, width, height); } else { if (!drawing) throw new IllegalStateException("CpuPolygonSpriteBatch.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 color = this.colorPacked; int idx = this.vertexIndex; Affine2 t = adjustAffine; vertices[idx++] = t.m00 * x + t.m01 * y + t.m02; vertices[idx++] = t.m10 * x + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v; vertices[idx++] = t.m00 * x + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * x + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * fy2 + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * fy2 + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v2; vertices[idx++] = t.m00 * fx2 + t.m01 * y + t.m02; vertices[idx++] = t.m10 * fx2 + t.m11 * y + t.m12; vertices[idx++] = color; vertices[idx++] = u2; vertices[idx++] = v; this.vertexIndex = idx; } } private static boolean checkEqual(Matrix4 a, Matrix4 b) { if (a == b) return true; // matrices are assumed to be 2D transformations return (a.val[Matrix4.M00] == b.val[Matrix4.M00] && a.val[Matrix4.M10] == b.val[Matrix4.M10] && a.val[Matrix4.M01] == b.val[Matrix4.M01] && a.val[Matrix4.M11] == b.val[Matrix4.M11] && a.val[Matrix4.M03] == b.val[Matrix4.M03] && a.val[Matrix4.M13] == b.val[Matrix4.M13]); } private static boolean checkEqual(Matrix4 matrix, Affine2 affine) { final float[] val = matrix.getValues(); // matrix is assumed to be 2D transformation return (val[Matrix4.M00] == affine.m00 && val[Matrix4.M10] == affine.m10 && val[Matrix4.M01] == affine.m01 && val[Matrix4.M11] == affine.m11 && val[Matrix4.M03] == affine.m02 && val[Matrix4.M13] == affine.m12); } private static boolean checkIdt(Matrix4 matrix) { final float[] val = matrix.getValues(); // matrix is assumed to be 2D transformation return (val[Matrix4.M00] == 1 && val[Matrix4.M10] == 0 && val[Matrix4.M01] == 0 && val[Matrix4.M11] == 1 && val[Matrix4.M03] == 0 && val[Matrix4.M13] == 0); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy