- LWJGL is now at the final 2.x release version. - Slick2D is now at the final (?) release version. - Added dependency for org.tukaani.xz, since it becomes optional in commons-compress 1.9 and is needed for LZMA compression. Signed-off-by: Jeffrey Han <itdelatrisu@gmail.com>
1476 lines
46 KiB
Java
1476 lines
46 KiB
Java
/*
|
|
* Copyright (c) 2013, Slick2D
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
* - Neither the name of the Slick2D nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
package org.newdawn.slick;
|
|
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
|
|
import org.newdawn.slick.opengl.ImageData;
|
|
import org.newdawn.slick.opengl.InternalTextureLoader;
|
|
import org.newdawn.slick.opengl.Texture;
|
|
import org.newdawn.slick.opengl.TextureImpl;
|
|
import org.newdawn.slick.opengl.pbuffer.GraphicsFactory;
|
|
import org.newdawn.slick.opengl.renderer.Renderer;
|
|
import org.newdawn.slick.opengl.renderer.SGL;
|
|
import org.newdawn.slick.util.Log;
|
|
|
|
/**
|
|
* An image loaded from a file and renderable to the canvas
|
|
*
|
|
* @author kevin
|
|
*/
|
|
@SuppressWarnings("unused")
|
|
public class Image implements Renderable {
|
|
/** The top left corner identifier */
|
|
public static final int TOP_LEFT = 0;
|
|
/** The top right corner identifier */
|
|
public static final int TOP_RIGHT = 1;
|
|
/** The bottom right corner identifier */
|
|
public static final int BOTTOM_RIGHT = 2;
|
|
/** The bottom left corner identifier */
|
|
public static final int BOTTOM_LEFT = 3;
|
|
|
|
/** The renderer to use for all GL operations */
|
|
protected static SGL GL = Renderer.get();
|
|
|
|
/** The sprite sheet currently in use */
|
|
protected static Image inUse;
|
|
/** Use Linear Filtering */
|
|
public static final int FILTER_LINEAR = 1;
|
|
/** Use Nearest Filtering */
|
|
public static final int FILTER_NEAREST = 2;
|
|
|
|
/** The OpenGL texture for this image */
|
|
protected Texture texture;
|
|
/** The width of the image */
|
|
protected int width;
|
|
/** The height of the image */
|
|
protected int height;
|
|
/** The texture coordinate width to use to find our image */
|
|
protected float textureWidth;
|
|
/** The texture coordinate height to use to find our image */
|
|
protected float textureHeight;
|
|
/** The x texture offset to use to find our image */
|
|
protected float textureOffsetX;
|
|
/** The y texture offset to use to find our image */
|
|
protected float textureOffsetY;
|
|
/** Angle to rotate the image to. */
|
|
protected float angle;
|
|
/** The alpha to draw the image at */
|
|
protected float alpha = 1.0f;
|
|
/** The name given for the image */
|
|
protected String ref;
|
|
/** True if this image's state has been initialised */
|
|
protected boolean inited = false;
|
|
/** A pixelData holding the pixel data if it's been read for this texture */
|
|
protected byte[] pixelData;
|
|
/** True if the image has been destroyed */
|
|
protected boolean destroyed;
|
|
|
|
/** The x coordinate of the centre of rotation */
|
|
protected float centerX;
|
|
/** The y coordinate of the centre of rotation */
|
|
protected float centerY;
|
|
|
|
/** A meaningful name provided by the user of the image to tag it */
|
|
protected String name;
|
|
|
|
/** The colours for each of the corners */
|
|
protected Color[] corners;
|
|
/** The OpenGL max filter */
|
|
private int filter = SGL.GL_LINEAR;
|
|
|
|
/** True if the image should be flipped vertically */
|
|
private boolean flipped;
|
|
/** The transparent colour set if any */
|
|
private Color transparent;
|
|
|
|
/**
|
|
* Create a texture as a copy of another
|
|
*
|
|
* @param other The other texture to copy
|
|
*/
|
|
protected Image(Image other) {
|
|
this.width = other.getWidth();
|
|
this.height = other.getHeight();
|
|
this.texture = other.texture;
|
|
this.textureWidth = other.textureWidth;
|
|
this.textureHeight = other.textureHeight;
|
|
this.ref = other.ref;
|
|
this.textureOffsetX = other.textureOffsetX;
|
|
this.textureOffsetY = other.textureOffsetY;
|
|
|
|
centerX = width / 2f;
|
|
centerY = height / 2f;
|
|
inited = true;
|
|
}
|
|
|
|
/**
|
|
* Cloning constructor - only used internally.
|
|
*/
|
|
protected Image() {
|
|
}
|
|
|
|
/**
|
|
* Creates an image using the specified texture
|
|
*
|
|
* @param texture
|
|
* The texture to use
|
|
*/
|
|
public Image(Texture texture) {
|
|
this.texture = texture;
|
|
ref = texture.toString();
|
|
clampTexture();
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param ref
|
|
* The location of the image file to load
|
|
* @throws SlickException
|
|
* Indicates a failure to load the image
|
|
*/
|
|
public Image(String ref) throws SlickException {
|
|
this(ref, false);
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param ref The location of the image file to load
|
|
* @param trans The color to be treated as transparent
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(String ref, Color trans) throws SlickException {
|
|
this(ref, false, FILTER_LINEAR, trans);
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param ref The location of the image file to load
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(String ref, boolean flipped) throws SlickException {
|
|
this(ref, flipped, FILTER_LINEAR);
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param ref The location of the image file to load
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @param filter The filtering method to use when scaling this image
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(String ref, boolean flipped, int filter) throws SlickException {
|
|
this(ref, flipped, filter, null);
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param ref The location of the image file to load
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @param f The filtering method to use when scaling this image
|
|
* @param transparent The color to treat as transparent
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(String ref, boolean flipped, int f, Color transparent) throws SlickException {
|
|
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
|
|
this.transparent = transparent;
|
|
this.flipped = flipped;
|
|
|
|
try {
|
|
this.ref = ref;
|
|
int[] trans = null;
|
|
if (transparent != null) {
|
|
trans = new int[3];
|
|
trans[0] = (int) (transparent.r * 255);
|
|
trans[1] = (int) (transparent.g * 255);
|
|
trans[2] = (int) (transparent.b * 255);
|
|
}
|
|
texture = InternalTextureLoader.get().getTexture(ref, flipped, filter, trans);
|
|
} catch (IOException e) {
|
|
Log.error(e);
|
|
throw new SlickException("Failed to load image from: "+ref, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the image filtering to be used. Note that this will also affect any
|
|
* image that was derived from this one (i.e. sub-images etc)
|
|
*
|
|
* @param f The filtering mode to use
|
|
*/
|
|
public void setFilter(int f) {
|
|
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
|
|
|
|
texture.bind();
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MIN_FILTER, filter);
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_MAG_FILTER, filter);
|
|
}
|
|
|
|
/**
|
|
* Create an empty image
|
|
*
|
|
* @param width The width of the image
|
|
* @param height The height of the image
|
|
* @throws SlickException Indicates a failure to create the underlying resource
|
|
*/
|
|
public Image(int width, int height) throws SlickException {
|
|
this(width, height, FILTER_NEAREST);
|
|
}
|
|
|
|
/**
|
|
* Create an empty image
|
|
*
|
|
* @param width The width of the image
|
|
* @param height The height of the image
|
|
* @param f The filter to apply to scaling the new image
|
|
* @throws SlickException Indicates a failure to create the underlying resource
|
|
*/
|
|
public Image(int width, int height, int f) throws SlickException {
|
|
ref = super.toString();
|
|
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
|
|
|
|
try {
|
|
texture = InternalTextureLoader.get().createTexture(width, height, this.filter);
|
|
} catch (IOException e) {
|
|
Log.error(e);
|
|
throw new SlickException("Failed to create empty image "+width+"x"+height);
|
|
}
|
|
|
|
init();
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param in The input stream to read the image from
|
|
* @param ref The name that should be assigned to the image
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(InputStream in, String ref, boolean flipped) throws SlickException {
|
|
this(in, ref, flipped, FILTER_LINEAR);
|
|
}
|
|
|
|
/**
|
|
* Create an image based on a file at the specified location
|
|
*
|
|
* @param in The input stream to read the image from
|
|
* @param ref The name that should be assigned to the image
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @param filter The filter to use when scaling this image
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
public Image(InputStream in, String ref, boolean flipped,int filter) throws SlickException {
|
|
load(in, ref, flipped, filter, null);
|
|
}
|
|
|
|
/**
|
|
* Create an image from a pixelData of pixels
|
|
*
|
|
* @param buffer The pixelData to use to create the image
|
|
*/
|
|
Image(ImageBuffer buffer) {
|
|
this(buffer, FILTER_LINEAR);
|
|
TextureImpl.bindNone();
|
|
}
|
|
|
|
/**
|
|
* Create an image from a pixelData of pixels
|
|
*
|
|
* @param buffer The pixelData to use to create the image
|
|
* @param filter The filter to use when scaling this image
|
|
*/
|
|
Image(ImageBuffer buffer, int filter) {
|
|
this((ImageData) buffer, filter);
|
|
TextureImpl.bindNone();
|
|
}
|
|
|
|
/**
|
|
* Create an image from a image data source
|
|
*
|
|
* @param data The pixelData to use to create the image
|
|
*/
|
|
public Image(ImageData data) {
|
|
this(data, FILTER_LINEAR);
|
|
}
|
|
|
|
/**
|
|
* Create an image from a image data source. Note that this method uses
|
|
*
|
|
* @param data The pixelData to use to create the image
|
|
* @param f The filter to use when scaling this image
|
|
*/
|
|
public Image(ImageData data, int f) {
|
|
try {
|
|
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
|
|
texture = InternalTextureLoader.get().getTexture(data, this.filter);
|
|
ref = texture.toString();
|
|
} catch (IOException e) {
|
|
Log.error(e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the OpenGL image filter in use
|
|
*
|
|
* @return The filter for magnification
|
|
*/
|
|
public int getFilter() {
|
|
return filter;
|
|
}
|
|
|
|
/**
|
|
* Get the reference to the resource this image was loaded from, if any. Note that
|
|
* this can be null in the cases where an image was programatically generated.
|
|
*
|
|
* @return The reference to the resource the reference was loaded from
|
|
*/
|
|
public String getResourceReference() {
|
|
return ref;
|
|
}
|
|
|
|
/**
|
|
* Set the filter to apply when drawing this image
|
|
*
|
|
* @param r The red component of the filter colour
|
|
* @param g The green component of the filter colour
|
|
* @param b The blue component of the filter colour
|
|
* @param a The alpha component of the filter colour
|
|
*/
|
|
public void setImageColor(float r, float g, float b, float a) {
|
|
setColor(TOP_LEFT, r, g, b, a);
|
|
setColor(TOP_RIGHT, r, g, b, a);
|
|
setColor(BOTTOM_LEFT, r, g, b, a);
|
|
setColor(BOTTOM_RIGHT, r, g, b, a);
|
|
}
|
|
|
|
/**
|
|
* Set the filter to apply when drawing this image
|
|
*
|
|
* @param r The red component of the filter colour
|
|
* @param g The green component of the filter colour
|
|
* @param b The blue component of the filter colour
|
|
*/
|
|
public void setImageColor(float r, float g, float b) {
|
|
setColor(TOP_LEFT, r, g, b);
|
|
setColor(TOP_RIGHT, r, g, b);
|
|
setColor(BOTTOM_LEFT, r, g, b);
|
|
setColor(BOTTOM_RIGHT, r, g, b);
|
|
}
|
|
|
|
/**
|
|
* Set the color of the given corner when this image is rendered. This is
|
|
* useful lots of visual effect but especially light maps
|
|
*
|
|
* @param corner The corner identifier for the corner to be set
|
|
* @param r The red component value to set (between 0 and 1)
|
|
* @param g The green component value to set (between 0 and 1)
|
|
* @param b The blue component value to set (between 0 and 1)
|
|
* @param a The alpha component value to set (between 0 and 1)
|
|
*/
|
|
public void setColor(int corner, float r, float g, float b, float a) {
|
|
if (corners == null) {
|
|
corners = new Color[] {new Color(1,1,1,1f),new Color(1,1,1,1f), new Color(1,1,1,1f), new Color(1,1,1,1f)};
|
|
}
|
|
|
|
corners[corner].r = r;
|
|
corners[corner].g = g;
|
|
corners[corner].b = b;
|
|
corners[corner].a = a;
|
|
}
|
|
|
|
/**
|
|
* Set the color of the given corner when this image is rendered. This is
|
|
* useful lots of visual effect but especially light maps
|
|
*
|
|
* @param corner The corner identifier for the corner to be set
|
|
* @param r The red component value to set (between 0 and 1)
|
|
* @param g The green component value to set (between 0 and 1)
|
|
* @param b The blue component value to set (between 0 and 1)
|
|
*/
|
|
public void setColor(int corner, float r, float g, float b) {
|
|
if (corners == null) {
|
|
corners = new Color[] {new Color(1,1,1,1f),new Color(1,1,1,1f), new Color(1,1,1,1f), new Color(1,1,1,1f)};
|
|
}
|
|
|
|
corners[corner].r = r;
|
|
corners[corner].g = g;
|
|
corners[corner].b = b;
|
|
}
|
|
|
|
/**
|
|
* Clamp the loaded texture to it's edges
|
|
*/
|
|
public void clampTexture() {
|
|
if (GL.canTextureMirrorClamp()) {
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT);
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_MIRROR_CLAMP_TO_EDGE_EXT);
|
|
} else {
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_S, SGL.GL_CLAMP);
|
|
GL.glTexParameteri(SGL.GL_TEXTURE_2D, SGL.GL_TEXTURE_WRAP_T, SGL.GL_CLAMP);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Give this image a meaningful tagging name. Can be used as user data/identifier
|
|
* for the image.
|
|
*
|
|
* @param name The name to assign the image
|
|
*/
|
|
public void setName(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
/**
|
|
* Return a meaningful tagging name that has been assigned to this image.
|
|
*
|
|
* @return A name or null if the name hasn't been set
|
|
*/
|
|
public String getName() {
|
|
return name;
|
|
}
|
|
|
|
/**
|
|
* Get a graphics context that can be used to draw to this image
|
|
*
|
|
* @return The graphics context used to render to this image
|
|
* @throws SlickException Indicates a failure to create a graphics context
|
|
*/
|
|
public Graphics getGraphics() throws SlickException {
|
|
return GraphicsFactory.getGraphicsForImage(this);
|
|
}
|
|
|
|
/**
|
|
* Load the image
|
|
*
|
|
* @param in The input stream to read the image from
|
|
* @param ref The name that should be assigned to the image
|
|
* @param flipped True if the image should be flipped on the y-axis on load
|
|
* @param f The filter to use when scaling this image
|
|
* @param transparent The color to treat as transparent
|
|
* @throws SlickException Indicates a failure to load the image
|
|
*/
|
|
private void load(InputStream in, String ref, boolean flipped, int f, Color transparent) throws SlickException {
|
|
this.filter = f == FILTER_LINEAR ? SGL.GL_LINEAR : SGL.GL_NEAREST;
|
|
|
|
try {
|
|
this.ref = ref;
|
|
int[] trans = null;
|
|
if (transparent != null) {
|
|
trans = new int[3];
|
|
trans[0] = (int) (transparent.r * 255);
|
|
trans[1] = (int) (transparent.g * 255);
|
|
trans[2] = (int) (transparent.b * 255);
|
|
}
|
|
texture = InternalTextureLoader.get().getTexture(in, ref, flipped, filter, trans);
|
|
} catch (IOException e) {
|
|
Log.error(e);
|
|
throw new SlickException("Failed to load image from: "+ref, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Bind to the texture of this image
|
|
*/
|
|
public void bind() {
|
|
texture.bind();
|
|
}
|
|
|
|
/**
|
|
* Reinitialise internal data
|
|
*/
|
|
protected void reinit() {
|
|
inited = false;
|
|
init();
|
|
}
|
|
|
|
/**
|
|
* Initialise internal data
|
|
*/
|
|
protected final void init() {
|
|
if (inited) {
|
|
return;
|
|
}
|
|
|
|
inited = true;
|
|
if (texture != null) {
|
|
width = texture.getImageWidth();
|
|
height = texture.getImageHeight();
|
|
textureOffsetX = 0;
|
|
textureOffsetY = 0;
|
|
textureWidth = texture.getWidth();
|
|
textureHeight = texture.getHeight();
|
|
}
|
|
|
|
initImpl();
|
|
|
|
centerX = width / 2f;
|
|
centerY = height / 2f;
|
|
}
|
|
|
|
/**
|
|
* Hook for subclasses to perform initialisation
|
|
*/
|
|
protected void initImpl() {
|
|
|
|
}
|
|
|
|
/**
|
|
* Draw this image at the current location
|
|
*/
|
|
public void draw() {
|
|
draw(0,0);
|
|
}
|
|
|
|
/**
|
|
* Draw the image based on its center
|
|
*
|
|
* @param x The x coordinate to place the image's center at
|
|
* @param y The y coordinate to place the image's center at
|
|
*/
|
|
public void drawCentered(float x, float y) {
|
|
draw(x-(getWidth()/2),y-(getHeight()/2));
|
|
}
|
|
|
|
/**
|
|
* Draw the image based on its center with a color filter
|
|
*
|
|
* @param x The x coordinate to place the image's center at
|
|
* @param y The y coordinate to place the image's center at
|
|
* @param color The color filter to apply
|
|
*/
|
|
public void drawCentered(float x, float y, Color color) {
|
|
draw(x - (getWidth() / 2f), y - (getHeight() / 2f), color);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at the specified location
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
*/
|
|
@Override
|
|
public void draw(float x, float y) {
|
|
init();
|
|
draw(x,y,width,height);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at the specified location
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param filter The color to filter with when drawing
|
|
*/
|
|
@Override
|
|
public void draw(float x, float y, Color filter) {
|
|
init();
|
|
draw(x,y,width,height, filter);
|
|
}
|
|
|
|
/**
|
|
* Draw this image as part of a collection of images
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param width The width to render the image at
|
|
* @param height The height to render the image at
|
|
*/
|
|
public void drawEmbedded(float x,float y,float width,float height) {
|
|
init();
|
|
|
|
if (corners == null) {
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
|
|
GL.glVertex3f(x, y, 0);
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
|
|
GL.glVertex3f(x, y + height, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
|
|
+ textureHeight);
|
|
GL.glVertex3f(x + width, y + height, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
|
|
GL.glVertex3f(x + width, y, 0);
|
|
} else {
|
|
corners[TOP_LEFT].bind();
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
|
|
GL.glVertex3f(x, y, 0);
|
|
corners[BOTTOM_LEFT].bind();
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
|
|
GL.glVertex3f(x, y + height, 0);
|
|
corners[BOTTOM_RIGHT].bind();
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
|
|
+ textureHeight);
|
|
GL.glVertex3f(x + width, y + height, 0);
|
|
corners[TOP_RIGHT].bind();
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
|
|
GL.glVertex3f(x + width, y, 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the x offset in texels into the source texture
|
|
*
|
|
* @return The x offset
|
|
*/
|
|
public float getTextureOffsetX() {
|
|
init();
|
|
|
|
return textureOffsetX;
|
|
}
|
|
|
|
/**
|
|
* Get the y offset in texels into the source texture
|
|
*
|
|
* @return The y offset
|
|
*/
|
|
public float getTextureOffsetY() {
|
|
init();
|
|
|
|
return textureOffsetY;
|
|
}
|
|
|
|
/**
|
|
* Get the width in texels into the source texture
|
|
*
|
|
* @return The width
|
|
*/
|
|
public float getTextureWidth() {
|
|
init();
|
|
|
|
return textureWidth;
|
|
}
|
|
|
|
/**
|
|
* Get the height in texels into the source texture
|
|
*
|
|
* @return The height
|
|
*/
|
|
public float getTextureHeight() {
|
|
init();
|
|
|
|
return textureHeight;
|
|
}
|
|
|
|
/**
|
|
* Draw the image with a given scale
|
|
*
|
|
* @param x The x position to draw the image at
|
|
* @param y The y position to draw the image at
|
|
* @param scale The scaling to apply
|
|
*/
|
|
public void draw(float x,float y,float scale) {
|
|
init();
|
|
draw(x,y,width*scale,height*scale,Color.white);
|
|
}
|
|
|
|
/**
|
|
* Draw the image with a given scale
|
|
*
|
|
* @param x The x position to draw the image at
|
|
* @param y The y position to draw the image at
|
|
* @param scale The scaling to apply
|
|
* @param filter The colour filter to adapt the image with
|
|
*/
|
|
public void draw(float x,float y,float scale,Color filter) {
|
|
init();
|
|
draw(x,y,width*scale,height*scale,filter);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size
|
|
*
|
|
* @param x
|
|
* The x location to draw the image at
|
|
* @param y
|
|
* The y location to draw the image at
|
|
* @param width
|
|
* The width to render the image at
|
|
* @param height
|
|
* The height to render the image at
|
|
*/
|
|
@Override
|
|
public void draw(float x,float y,float width,float height) {
|
|
init();
|
|
draw(x,y,width,height,Color.white);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param hshear The amount to shear the bottom points by horizontally
|
|
* @param vshear The amount to shear the right points by vertically
|
|
*/
|
|
public void drawSheared(float x,float y, float hshear, float vshear) {
|
|
this.drawSheared(x, y, hshear, vshear, Color.white);
|
|
}
|
|
/**
|
|
* Draw this image at a specified location and size
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param hshear The amount to shear the bottom points by horizontally
|
|
* @param vshear The amount to shear the right points by vertically
|
|
* @param filter The colour filter to apply
|
|
*/
|
|
public void drawSheared(float x,float y, float hshear, float vshear, Color filter) {
|
|
if (alpha != 1) {
|
|
if (filter == null) {
|
|
filter = Color.white;
|
|
}
|
|
|
|
filter = new Color(filter);
|
|
filter.a *= alpha;
|
|
}
|
|
if (filter != null) {
|
|
filter.bind();
|
|
}
|
|
|
|
texture.bind();
|
|
|
|
GL.glTranslatef(x, y, 0);
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
init();
|
|
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
|
|
GL.glVertex3f(0, 0, 0);
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
|
|
GL.glVertex3f(hshear, height, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
|
|
+ textureHeight);
|
|
GL.glVertex3f(width + hshear, height + vshear, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
|
|
GL.glVertex3f(width, vshear, 0);
|
|
GL.glEnd();
|
|
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
GL.glTranslatef(-x, -y, 0);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param width The width to render the image at
|
|
* @param height The height to render the image at
|
|
* @param filter The color to filter with while drawing
|
|
*/
|
|
@Override
|
|
public void draw(float x,float y,float width,float height,Color filter) {
|
|
if (alpha != 1) {
|
|
if (filter == null) {
|
|
filter = Color.white;
|
|
}
|
|
|
|
filter = new Color(filter);
|
|
filter.a *= alpha;
|
|
}
|
|
if (filter != null) {
|
|
filter.bind();
|
|
}
|
|
|
|
texture.bind();
|
|
|
|
GL.glTranslatef(x, y, 0);
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
drawEmbedded(0,0,width,height);
|
|
GL.glEnd();
|
|
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
GL.glTranslatef(-x, -y, 0);
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size as a silohette
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param width The width to render the image at
|
|
* @param height The height to render the image at
|
|
*/
|
|
public void drawFlash(float x,float y,float width,float height) {
|
|
drawFlash(x,y,width,height,Color.white);
|
|
}
|
|
|
|
/**
|
|
* Set the centre of the rotation when applied to this image
|
|
*
|
|
* @param x The x coordinate of center of rotation relative to the top left corner of the image
|
|
* @param y The y coordinate of center of rotation relative to the top left corner of the image
|
|
*/
|
|
public void setCenterOfRotation(float x, float y) {
|
|
centerX = x;
|
|
centerY = y;
|
|
}
|
|
|
|
/**
|
|
* Get the x component of the center of rotation of this image
|
|
*
|
|
* @return The x component of the center of rotation
|
|
*/
|
|
public float getCenterOfRotationX() {
|
|
init();
|
|
|
|
return centerX;
|
|
}
|
|
|
|
/**
|
|
* Get the y component of the center of rotation of this image
|
|
*
|
|
* @return The y component of the center of rotation
|
|
*/
|
|
public float getCenterOfRotationY() {
|
|
init();
|
|
|
|
return centerY;
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size as a silohette
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
* @param width The width to render the image at
|
|
* @param height The height to render the image at
|
|
* @param col The color for the sillohette
|
|
*/
|
|
public void drawFlash(float x,float y,float width,float height, Color col) {
|
|
init();
|
|
|
|
col.bind();
|
|
texture.bind();
|
|
|
|
if (GL.canSecondaryColor()) {
|
|
GL.glEnable(SGL.GL_COLOR_SUM_EXT);
|
|
GL.glSecondaryColor3ubEXT((byte)(col.r * 255),
|
|
(byte)(col.g * 255),
|
|
(byte)(col.b * 255));
|
|
}
|
|
|
|
GL.glTexEnvi(SGL.GL_TEXTURE_ENV, SGL.GL_TEXTURE_ENV_MODE, SGL.GL_MODULATE);
|
|
|
|
GL.glTranslatef(x, y, 0);
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
drawEmbedded(0,0,width,height);
|
|
GL.glEnd();
|
|
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
GL.glTranslatef(-x, -y, 0);
|
|
|
|
if (GL.canSecondaryColor()) {
|
|
GL.glDisable(SGL.GL_COLOR_SUM_EXT);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Draw this image at a specified location and size in a white silohette
|
|
*
|
|
* @param x The x location to draw the image at
|
|
* @param y The y location to draw the image at
|
|
*/
|
|
public void drawFlash(float x,float y) {
|
|
drawFlash(x,y,getWidth(),getHeight());
|
|
}
|
|
|
|
/**
|
|
* Set the angle to rotate this image to. The angle will be normalized to
|
|
* be {@literal 0 <= angle < 360}. The image will be rotated around its center.
|
|
*
|
|
* @param angle The angle to be set
|
|
*/
|
|
public void setRotation(float angle) {
|
|
this.angle = angle % 360.0f;
|
|
}
|
|
|
|
/**
|
|
* Get the current angle of rotation for this image.
|
|
* The image will be rotated around its center.
|
|
*
|
|
* @return The current angle.
|
|
*/
|
|
public float getRotation() {
|
|
return angle;
|
|
}
|
|
|
|
/**
|
|
* Get the alpha value to use when rendering this image
|
|
*
|
|
* @return The alpha value to use when rendering this image
|
|
*/
|
|
public float getAlpha() {
|
|
return alpha;
|
|
}
|
|
|
|
/**
|
|
* Set the alpha value to use when rendering this image
|
|
*
|
|
* @param alpha The alpha value to use when rendering this image
|
|
*/
|
|
public void setAlpha(float alpha) {
|
|
this.alpha = alpha;
|
|
}
|
|
|
|
/**
|
|
* Add the angle provided to the current rotation. The angle will be normalized to
|
|
* be {@literal 0 <= angle < 360}. The image will be rotated around its center.
|
|
*
|
|
* @param angle The angle to add.
|
|
*/
|
|
public void rotate(float angle) {
|
|
this.angle += angle;
|
|
this.angle = this.angle % 360;
|
|
}
|
|
|
|
/**
|
|
* Get a sub-part of this image. Note that the create image retains a reference to the
|
|
* image data so should anything change it will affect sub-images too.
|
|
*
|
|
* @param x The x coordinate of the sub-image
|
|
* @param y The y coordinate of the sub-image
|
|
* @param width The width of the sub-image
|
|
* @param height The height of the sub-image
|
|
* @return The image represent the sub-part of this image
|
|
*/
|
|
public Image getSubImage(int x,int y,int width,int height) {
|
|
init();
|
|
|
|
float newTextureOffsetX = ((x / (float) this.width) * textureWidth) + textureOffsetX;
|
|
float newTextureOffsetY = ((y / (float) this.height) * textureHeight) + textureOffsetY;
|
|
float newTextureWidth = ((width / (float) this.width) * textureWidth);
|
|
float newTextureHeight = ((height / (float) this.height) * textureHeight);
|
|
|
|
Image sub = new Image();
|
|
sub.inited = true;
|
|
sub.texture = this.texture;
|
|
sub.textureOffsetX = newTextureOffsetX;
|
|
sub.textureOffsetY = newTextureOffsetY;
|
|
sub.textureWidth = newTextureWidth;
|
|
sub.textureHeight = newTextureHeight;
|
|
|
|
sub.width = width;
|
|
sub.height = height;
|
|
sub.ref = ref;
|
|
sub.centerX = width / 2f;
|
|
sub.centerY = height / 2f;
|
|
|
|
return sub;
|
|
}
|
|
|
|
/**
|
|
* Draw a section of this image at a particular location and scale on the screen
|
|
*
|
|
* @param x The x position to draw the image
|
|
* @param y The y position to draw the image
|
|
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
*/
|
|
public void draw(float x, float y, float srcx, float srcy, float srcx2, float srcy2) {
|
|
draw(x,y,x+width,y+height,srcx,srcy,srcx2,srcy2);
|
|
}
|
|
|
|
/**
|
|
* Draw a section of this image at a particular location and scale on the screen
|
|
*
|
|
* @param x The x position to draw the image
|
|
* @param y The y position to draw the image
|
|
* @param x2 The x position of the bottom right corner of the drawn image
|
|
* @param y2 The y position of the bottom right corner of the drawn image
|
|
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
*/
|
|
public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
|
|
draw(x,y,x2,y2,srcx,srcy,srcx2,srcy2,Color.white);
|
|
}
|
|
|
|
/**
|
|
* Draw a section of this image at a particular location and scale on the screen
|
|
*
|
|
* @param x The x position to draw the image
|
|
* @param y The y position to draw the image
|
|
* @param x2 The x position of the bottom right corner of the drawn image
|
|
* @param y2 The y position of the bottom right corner of the drawn image
|
|
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param filter The colour filter to apply when drawing
|
|
*/
|
|
public void draw(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) {
|
|
init();
|
|
|
|
if (alpha != 1) {
|
|
if (filter == null) {
|
|
filter = Color.white;
|
|
}
|
|
|
|
filter = new Color(filter);
|
|
filter.a *= alpha;
|
|
}
|
|
filter.bind();
|
|
texture.bind();
|
|
|
|
GL.glTranslatef(x, y, 0);
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
drawEmbedded(0,0,x2-x,y2-y,srcx,srcy,srcx2,srcy2);
|
|
GL.glEnd();
|
|
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
GL.glTranslatef(-x, -y, 0);
|
|
|
|
// GL.glBegin(SGL.GL_QUADS);
|
|
// drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2);
|
|
// GL.glEnd();
|
|
}
|
|
|
|
/**
|
|
* Draw a section of this image at a particular location and scale on the screen, while this
|
|
* is image is "in use", i.e. between calls to startUse and endUse.
|
|
*
|
|
* @param x The x position to draw the image
|
|
* @param y The y position to draw the image
|
|
* @param x2 The x position of the bottom right corner of the drawn image
|
|
* @param y2 The y position of the bottom right corner of the drawn image
|
|
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
*/
|
|
public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2) {
|
|
drawEmbedded(x,y,x2,y2,srcx,srcy,srcx2,srcy2,null);
|
|
}
|
|
|
|
/**
|
|
* Draw a section of this image at a particular location and scale on the screen, while this
|
|
* is image is "in use", i.e. between calls to startUse and endUse.
|
|
*
|
|
* @param x The x position to draw the image
|
|
* @param y The y position to draw the image
|
|
* @param x2 The x position of the bottom right corner of the drawn image
|
|
* @param y2 The y position of the bottom right corner of the drawn image
|
|
* @param srcx The x position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy The y position of the rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcx2 The x position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param srcy2 The t position of the bottom right cornder of rectangle to draw from this image (i.e. relative to this image)
|
|
* @param filter The colour filter to apply when drawing
|
|
*/
|
|
public void drawEmbedded(float x, float y, float x2, float y2, float srcx, float srcy, float srcx2, float srcy2, Color filter) {
|
|
if (filter != null) {
|
|
filter.bind();
|
|
}
|
|
|
|
float mywidth = x2 - x;
|
|
float myheight = y2 - y;
|
|
float texwidth = srcx2 - srcx;
|
|
float texheight = srcy2 - srcy;
|
|
|
|
float newTextureOffsetX = (((srcx) / (width)) * textureWidth)
|
|
+ textureOffsetX;
|
|
float newTextureOffsetY = (((srcy) / (height)) * textureHeight)
|
|
+ textureOffsetY;
|
|
float newTextureWidth = ((texwidth) / (width))
|
|
* textureWidth;
|
|
float newTextureHeight = ((texheight) / (height))
|
|
* textureHeight;
|
|
|
|
GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY);
|
|
GL.glVertex3f(x,y, 0.0f);
|
|
GL.glTexCoord2f(newTextureOffsetX, newTextureOffsetY
|
|
+ newTextureHeight);
|
|
GL.glVertex3f(x,(y + myheight), 0.0f);
|
|
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
|
|
newTextureOffsetY + newTextureHeight);
|
|
GL.glVertex3f((x + mywidth),(y + myheight), 0.0f);
|
|
GL.glTexCoord2f(newTextureOffsetX + newTextureWidth,
|
|
newTextureOffsetY);
|
|
GL.glVertex3f((x + mywidth),y, 0.0f);
|
|
}
|
|
|
|
/**
|
|
* Draw the image in a warper rectangle. The effects this can
|
|
* have are many and varied, might be interesting though.
|
|
*
|
|
* @param x1 The top left corner x coordinate
|
|
* @param y1 The top left corner y coordinate
|
|
* @param x2 The top right corner x coordinate
|
|
* @param y2 The top right corner y coordinate
|
|
* @param x3 The bottom right corner x coordinate
|
|
* @param y3 The bottom right corner y coordinate
|
|
* @param x4 The bottom left corner x coordinate
|
|
* @param y4 The bottom left corner y coordinate
|
|
*/
|
|
public void drawWarped(float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4) {
|
|
Color.white.bind();
|
|
texture.bind();
|
|
|
|
GL.glTranslatef(x1, y1, 0);
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
init();
|
|
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY);
|
|
GL.glVertex3f(0, 0, 0);
|
|
GL.glTexCoord2f(textureOffsetX, textureOffsetY + textureHeight);
|
|
GL.glVertex3f(x2 - x1, y2 - y1, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY
|
|
+ textureHeight);
|
|
GL.glVertex3f(x3 - x1, y3 - y1, 0);
|
|
GL.glTexCoord2f(textureOffsetX + textureWidth, textureOffsetY);
|
|
GL.glVertex3f(x4 - x1, y4 - y1, 0);
|
|
GL.glEnd();
|
|
|
|
if (angle != 0) {
|
|
GL.glTranslatef(centerX, centerY, 0.0f);
|
|
GL.glRotatef(-angle, 0.0f, 0.0f, 1.0f);
|
|
GL.glTranslatef(-centerX, -centerY, 0.0f);
|
|
}
|
|
GL.glTranslatef(-x1, -y1, 0);
|
|
}
|
|
|
|
/**
|
|
* Get the width of this image
|
|
*
|
|
* @return The width of this image
|
|
*/
|
|
public int getWidth() {
|
|
init();
|
|
return width;
|
|
}
|
|
|
|
/**
|
|
* Get the height of this image
|
|
*
|
|
* @return The height of this image
|
|
*/
|
|
public int getHeight() {
|
|
init();
|
|
return height;
|
|
}
|
|
|
|
/**
|
|
* Get a copy of this image. This is a shallow copy and does not
|
|
* duplicate image adata.
|
|
*
|
|
* @return The copy of this image
|
|
*/
|
|
public Image copy() {
|
|
init();
|
|
return getSubImage(0,0,width,height);
|
|
}
|
|
|
|
/**
|
|
* Get a scaled copy of this image with a uniform scale
|
|
*
|
|
* @param scale The scale to apply
|
|
* @return The new scaled image
|
|
*/
|
|
public Image getScaledCopy(float scale) {
|
|
init();
|
|
return getScaledCopy((int) (width*scale),(int) (height*scale));
|
|
}
|
|
|
|
/**
|
|
* Get a scaled copy of this image
|
|
*
|
|
* @param width The width of the copy
|
|
* @param height The height of the copy
|
|
* @return The new scaled image
|
|
*/
|
|
public Image getScaledCopy(int width, int height) {
|
|
init();
|
|
Image image = copy();
|
|
image.width = width;
|
|
image.height = height;
|
|
image.centerX = width / 2f;
|
|
image.centerY = height / 2f;
|
|
return image;
|
|
}
|
|
|
|
/**
|
|
* Make sure the texture cordinates are inverse on the y axis
|
|
*/
|
|
public void ensureInverted() {
|
|
if (textureHeight > 0) {
|
|
textureOffsetY = textureOffsetY + textureHeight;
|
|
textureHeight = -textureHeight;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get a copy image flipped on potentially two axis
|
|
*
|
|
* @param flipHorizontal True if we want to flip the image horizontally
|
|
* @param flipVertical True if we want to flip the image vertically
|
|
* @return The flipped image instance
|
|
*/
|
|
public Image getFlippedCopy(boolean flipHorizontal, boolean flipVertical) {
|
|
init();
|
|
Image image = copy();
|
|
|
|
if (flipHorizontal) {
|
|
image.textureOffsetX = textureOffsetX + textureWidth;
|
|
image.textureWidth = -textureWidth;
|
|
}
|
|
if (flipVertical) {
|
|
image.textureOffsetY = textureOffsetY + textureHeight;
|
|
image.textureHeight = -textureHeight;
|
|
}
|
|
|
|
return image;
|
|
}
|
|
|
|
/**
|
|
* End the use of this sprite sheet and release the lock.
|
|
*
|
|
* @see #startUse
|
|
*/
|
|
public void endUse() {
|
|
if (inUse != this) {
|
|
throw new RuntimeException("The sprite sheet is not currently in use");
|
|
}
|
|
inUse = null;
|
|
GL.glEnd();
|
|
}
|
|
|
|
/**
|
|
* Start using this sheet. This method can be used for optimal rendering of a collection
|
|
* of sprites from a single sprite sheet. First, startUse(). Then render each sprite by
|
|
* calling renderInUse(). Finally, endUse(). Between start and end there can be no rendering
|
|
* of other sprites since the rendering is locked for this sprite sheet.
|
|
*/
|
|
public void startUse() {
|
|
if (inUse != null) {
|
|
throw new RuntimeException("Attempt to start use of a sprite sheet before ending use with another - see endUse()");
|
|
}
|
|
inUse = this;
|
|
init();
|
|
|
|
Color.white.bind();
|
|
texture.bind();
|
|
GL.glBegin(SGL.GL_QUADS);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
init();
|
|
|
|
return "[Image "+ref+" "+width+"x"+height+" "+textureOffsetX+","+textureOffsetY+","+textureWidth+","+textureHeight+"]";
|
|
}
|
|
|
|
/**
|
|
* Get the OpenGL texture holding this image
|
|
*
|
|
* @return The OpenGL texture holding this image
|
|
*/
|
|
public Texture getTexture() {
|
|
return texture;
|
|
}
|
|
|
|
/**
|
|
* Set the texture used by this image
|
|
*
|
|
* @param texture The texture used by this image
|
|
*/
|
|
public void setTexture(Texture texture) {
|
|
this.texture = texture;
|
|
reinit();
|
|
}
|
|
|
|
/**
|
|
* Translate an unsigned int into a signed integer
|
|
*
|
|
* @param b The byte to convert
|
|
* @return The integer value represented by the byte
|
|
*/
|
|
private int translate(byte b) {
|
|
if (b < 0) {
|
|
return 256 + b;
|
|
}
|
|
|
|
return b;
|
|
}
|
|
|
|
/**
|
|
* Get the colour of a pixel at a specified location in this image
|
|
*
|
|
* @param x The x coordinate of the pixel
|
|
* @param y The y coordinate of the pixel
|
|
* @return The Color of the pixel at the specified location
|
|
*/
|
|
public Color getColor(int x, int y) {
|
|
if (pixelData == null) {
|
|
pixelData = texture.getTextureData();
|
|
}
|
|
|
|
int xo = (int) (textureOffsetX * texture.getTextureWidth());
|
|
int yo = (int) (textureOffsetY * texture.getTextureHeight());
|
|
|
|
if (textureWidth < 0) {
|
|
x = xo - x;
|
|
} else {
|
|
x = xo + x;
|
|
}
|
|
|
|
if (textureHeight < 0) {
|
|
y = yo - y;
|
|
} else {
|
|
y = yo + y;
|
|
}
|
|
|
|
int offset = x + (y * texture.getTextureWidth());
|
|
offset *= texture.hasAlpha() ? 4 : 3;
|
|
|
|
if (texture.hasAlpha()) {
|
|
return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
|
|
translate(pixelData[offset+2]),translate(pixelData[offset+3]));
|
|
} else {
|
|
return new Color(translate(pixelData[offset]),translate(pixelData[offset+1]),
|
|
translate(pixelData[offset+2]));
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the alpha value of a pixel at a specified location in this image,
|
|
* or 1f if the image does not support transparency.
|
|
*
|
|
* @param x The x coordinate of the pixel
|
|
* @param y The y coordinate of the pixel
|
|
* @return The alpha level of the pixel at the specified location
|
|
*/
|
|
public float getAlphaAt(int x, int y) {
|
|
if (!texture.hasAlpha())
|
|
return 1f;
|
|
|
|
if (pixelData == null)
|
|
pixelData = texture.getTextureData();
|
|
|
|
// scale coordinates based on the image scale
|
|
x = x * texture.getImageWidth() / width;
|
|
y = y * texture.getImageHeight() / height;
|
|
|
|
int xo = (int) (textureOffsetX * texture.getTextureWidth());
|
|
int yo = (int) (textureOffsetY * texture.getTextureHeight());
|
|
|
|
x = (textureWidth < 0) ? xo - x : xo + x;
|
|
y = (textureHeight < 0) ? yo - y : yo + y;
|
|
|
|
int offset = x + (y * texture.getTextureWidth());
|
|
offset *= 4;
|
|
return (offset + 3 >= pixelData.length) ? 1f : translate(pixelData[offset + 3]) / 255f;
|
|
}
|
|
|
|
/**
|
|
* Check if this image has been destroyed
|
|
*
|
|
* @return True if this image has been destroyed
|
|
*/
|
|
public boolean isDestroyed() {
|
|
return destroyed;
|
|
}
|
|
|
|
/**
|
|
* Destroy the image and release any native resources.
|
|
* Calls on a destroyed image have undefined results
|
|
*
|
|
* @throws SlickException Indicates a failure to release resources on the graphics card
|
|
*/
|
|
public void destroy() throws SlickException {
|
|
if (isDestroyed()) {
|
|
return;
|
|
}
|
|
|
|
destroyed = true;
|
|
texture.release();
|
|
GraphicsFactory.releaseGraphicsForImage(this);
|
|
}
|
|
|
|
/**
|
|
* Flush the current pixel data to force a re-read next update
|
|
*/
|
|
public void flushPixelData() {
|
|
pixelData = null;
|
|
}
|
|
}
|