gdx-toolbox/src/com/blarg/gdx/graphics/ExtendedSpriteBatch.java

199 lines
6.7 KiB
Java

package com.blarg.gdx.graphics;
import com.badlogic.gdx.graphics.Camera;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
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.Vector3;
/**
* Various additional {@link SpriteBatch#draw} methods mostly for convenience. Most of these additional overloads
* are to make drawing sprites at projected screen coordinates easier.
*
* Projected screen coordinate sprite rendering requires a perspective camera to project the 3D coordinates correctly.
* A camera _must_ be set via {@link #begin(Camera)} (instead of using {@link #begin()}) before any of these draw
* methods are called.
*/
public class ExtendedSpriteBatch extends SpriteBatch {
static final float DEFAULT_COLOR = Color.WHITE.toFloatBits();
static final Vector3 tmp1 = new Vector3();
Camera projectionCamera;
int pixelScale = 1;
public ExtendedSpriteBatch() {
super();
}
public ExtendedSpriteBatch(int size) {
super(size);
}
public ExtendedSpriteBatch(int size, ShaderProgram defaultShader) {
super(size, defaultShader);
}
public ExtendedSpriteBatch(int size, int buffers) {
super(size, buffers);
}
public ExtendedSpriteBatch(int size, int buffers, ShaderProgram defaultShader) {
super(size, buffers, defaultShader);
}
public void setPixelScale(int pixelScale) {
if (pixelScale <= 0)
throw new IllegalArgumentException();
this.pixelScale = pixelScale;
}
@Override
public void begin() {
super.begin();
setColor(DEFAULT_COLOR);
}
public void begin(Camera projectionCamera) {
begin();
this.projectionCamera = projectionCamera;
}
@Override
public void end() {
super.end();
this.projectionCamera = null;
}
/**************************************************************************/
public void draw(Texture texture, float x, float y, float z) {
draw(texture, x, y, z, texture.getWidth(), texture.getHeight(), 0.0f, 1.0f, 1.0f, 0.0f);
}
public void draw(Texture texture, float x, float y, float z, float width, float height) {
draw(texture, x, y, z, width, height, 0.0f, 1.0f, 1.0f, 0.0f);
}
public void draw(Texture texture, float x, float y, float z, float width, float height, float u, float v, float u2, float v2) {
getProjectedCenteredPosition(x, y, z, width, height, tmp1);
draw(texture, tmp1.x, tmp1.y, width, height, u, v, u2, v2);
}
public void draw(Texture texture, float x, float y, float z, int srcX, int srcY, int srcWidth, int srcHeight) {
draw(texture, x, y, z, Math.abs(srcWidth), Math.abs(srcHeight), srcX, srcY, srcWidth, srcHeight);
}
public void draw(Texture texture, float x, float y, float z, float width, float height, int srcX, int srcY, int srcWidth, int srcHeight) {
getProjectedCenteredPosition(x, y, z, width, height, tmp1);
draw(texture, tmp1.x, tmp1.y, width, height, srcX, srcY, srcWidth, srcHeight, false, false);
}
/**************************************************************************/
public void draw(TextureRegion region, float x, float y, float z) {
draw(region, x, y, z, region.getRegionWidth(), region.getRegionHeight());
}
public void draw(TextureRegion region, float x, float y, float z, float width, float height) {
getProjectedCenteredPosition(x, y, z, width, height, tmp1);
draw(region, tmp1.x, tmp1.y, width, height);
}
/**************************************************************************/
// NOTE: these are not going to be as fast as BitmapFont's draw() method due to it's use of BitmapFontCache
// probably don't need these ones with x,y only and just keep the x,y,z variants ...
public void draw(BitmapFont font, float x, float y, CharSequence str) {
draw(font, x, y, str, 1.0f);
}
public void draw(BitmapFont font, float x, float y, CharSequence str, float scale) {
BitmapFont.BitmapFontData fontData = font.getData();
Texture fontTexture = font.getRegion().getTexture();
float currentX = x;
float currentY = y;
float lineHeight = fontData.lineHeight * scale;
float spaceWidth = fontData.spaceWidth * scale;
for (int i = 0; i < str.length(); ++i) {
char c = str.charAt(i);
// multiline support
if (c == '\r')
continue; // can't render this anyway, and likely a '\n' is right behind ...
if (c == '\n') {
currentY -= lineHeight;
currentX = x;
continue;
}
BitmapFont.Glyph glyph = fontData.getGlyph(c);
if (glyph == null) {
// TODO: maybe rendering some special char here instead would be better?
currentX += spaceWidth;
continue;
}
float glyphWidth = ((float)glyph.width * scale);
float glyphHeight = ((float)glyph.height * scale);
float glyphXoffset = ((float)glyph.xoffset * scale);
float glyphYoffset = ((float)glyph.yoffset * scale);
draw(
fontTexture,
currentX + glyphXoffset, currentY + glyphYoffset,
glyphWidth, glyphHeight,
glyph.srcX, glyph.srcY, glyph.width, glyph.height,
false, false
);
currentX += ((float)glyph.xadvance * scale);
}
}
/**************************************************************************/
public void draw(BitmapFont font, float x, float y, float z, CharSequence str) {
draw(font, x, y, z, str, 1.0f);
}
public void draw(BitmapFont font, float x, float y, float z, CharSequence str, float scale) {
BitmapFont.TextBounds bounds = font.getMultiLineBounds(str);
float scaledBoundsWidth = bounds.width * scale;
float scaledBoundsHeight = bounds.height * scale;
getProjectedCenteredPosition(x, y, z, scaledBoundsWidth, scaledBoundsHeight, tmp1);
// getProjectedCenteredPosition will actually center the Y coord incorrectly... we need to add
// instead of subtract, but since that's already been done we need to add twice... (hence, *2)
// TODO: this is the only place we need to do this right now, but if that changes, should
// probably just move the centering calcs to each method
tmp1.y += (scaledBoundsHeight / 2) * 2.0f;
draw(font, tmp1.x, tmp1.y, str, scale);
}
/**************************************************************************/
private void getProjectedCenteredPosition(float x, float y, float z, float width, float height, Vector3 result) {
if (projectionCamera == null)
throw new IllegalStateException("Cannot project 3D coordinates to screen space when no projection camera is set.");
result.set(x, y, z);
projectionCamera.project(result);
// screen coordinates will be unscaled, need to apply appropriate scaling
result.x /= pixelScale;
result.y /= pixelScale;
// now center them on the bounds given
result.x -= (width / 2.0f);
result.y -= (height / 2.0f);
}
}