mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-10 13:51:53 +09:00
Former-commit-id: 1647fa32ef6894bd7db44f741f07c2f4dcdf9054 Former-commit-id: 0e5810dcfbe1fd59b13e7cabe9f1e93c5542da2d
530 lines
18 KiB
Java
530 lines
18 KiB
Java
package org.newdawn.slick.opengl;
|
|
|
|
import java.io.BufferedInputStream;
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.lang.ref.SoftReference;
|
|
import java.nio.ByteBuffer;
|
|
import java.nio.ByteOrder;
|
|
import java.nio.IntBuffer;
|
|
import java.util.HashMap;
|
|
import java.util.Iterator;
|
|
|
|
import org.lwjgl.BufferUtils;
|
|
import org.newdawn.slick.opengl.renderer.Renderer;
|
|
import org.newdawn.slick.opengl.renderer.SGL;
|
|
import org.newdawn.slick.util.ResourceLoader;
|
|
|
|
/**
|
|
* A texture loaded based on many old versions that will load image data from a file
|
|
* and produce OpenGL textures.
|
|
*
|
|
* @see ImageData
|
|
*
|
|
* @author kevin
|
|
*/
|
|
public class InternalTextureLoader {
|
|
/** The renderer to use for all GL operations */
|
|
protected static SGL GL = Renderer.get();
|
|
/** The standard texture loaded used everywhere */
|
|
private static final InternalTextureLoader loader = new InternalTextureLoader();
|
|
|
|
/**
|
|
* Get the single instance of this texture loader
|
|
*
|
|
* @return The single instance of the texture loader
|
|
*/
|
|
public static InternalTextureLoader get() {
|
|
return loader;
|
|
}
|
|
|
|
/** The table of textures that have been loaded in this loader */
|
|
private HashMap texturesLinear = new HashMap();
|
|
/** The table of textures that have been loaded in this loader */
|
|
private HashMap texturesNearest = new HashMap();
|
|
/** The destination pixel format */
|
|
private int dstPixelFormat = SGL.GL_RGBA8;
|
|
/** True if we're using deferred loading */
|
|
private boolean deferred;
|
|
/** True if we should hold texture data */
|
|
private boolean holdTextureData;
|
|
|
|
/**
|
|
* Create a new texture loader based on the game panel
|
|
*/
|
|
private InternalTextureLoader() {
|
|
}
|
|
|
|
/**
|
|
* Indicate where texture data should be held for reinitialising at a future
|
|
* point.
|
|
*
|
|
* @param holdTextureData True if we should hold texture data
|
|
*/
|
|
public void setHoldTextureData(boolean holdTextureData) {
|
|
this.holdTextureData = holdTextureData;
|
|
}
|
|
|
|
/**
|
|
* True if we should only record the request to load in the intention
|
|
* of loading the texture later
|
|
*
|
|
* @param deferred True if the we should load a token
|
|
*/
|
|
public void setDeferredLoading(boolean deferred) {
|
|
this.deferred = deferred;
|
|
}
|
|
|
|
/**
|
|
* Check if we're using deferred loading
|
|
*
|
|
* @return True if we're loading deferred textures
|
|
*/
|
|
public boolean isDeferredLoading() {
|
|
return deferred;
|
|
}
|
|
|
|
/**
|
|
* Remove a particular named image from the cache
|
|
*
|
|
* @param name The name of the image to be cleared
|
|
*/
|
|
public void clear(String name) {
|
|
texturesLinear.remove(name);
|
|
texturesNearest.remove(name);
|
|
}
|
|
|
|
/**
|
|
* Clear out the cached textures
|
|
*/
|
|
public void clear() {
|
|
texturesLinear.clear();
|
|
texturesNearest.clear();
|
|
}
|
|
|
|
/**
|
|
* Tell the loader to produce 16 bit textures
|
|
*/
|
|
public void set16BitMode() {
|
|
dstPixelFormat = SGL.GL_RGBA16;
|
|
}
|
|
|
|
/**
|
|
* Create a new texture ID
|
|
*
|
|
* @return A new texture ID
|
|
*/
|
|
public static int createTextureID()
|
|
{
|
|
IntBuffer tmp = createIntBuffer(1);
|
|
GL.glGenTextures(tmp);
|
|
return tmp.get(0);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a specific file
|
|
*
|
|
* @param source The file to load the texture from
|
|
* @param flipped True if we should flip the texture on the y axis while loading
|
|
* @param filter The filter to use
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public Texture getTexture(File source, boolean flipped,int filter) throws IOException {
|
|
String resourceName = source.getAbsolutePath();
|
|
InputStream in = new FileInputStream(source);
|
|
|
|
return getTexture(in, resourceName, flipped, filter, null);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a specific file
|
|
*
|
|
* @param source The file to load the texture from
|
|
* @param flipped True if we should flip the texture on the y axis while loading
|
|
* @param filter The filter to use
|
|
* @param transparent The colour to interpret as transparent or null if none
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public Texture getTexture(File source, boolean flipped,int filter, int[] transparent) throws IOException {
|
|
String resourceName = source.getAbsolutePath();
|
|
InputStream in = new FileInputStream(source);
|
|
|
|
return getTexture(in, resourceName, flipped, filter, transparent);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a resource location
|
|
*
|
|
* @param resourceName The location to load the texture from
|
|
* @param flipped True if we should flip the texture on the y axis while loading
|
|
* @param filter The filter to use when scaling the texture
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public Texture getTexture(String resourceName, boolean flipped, int filter) throws IOException {
|
|
InputStream in = ResourceLoader.getResourceAsStream(resourceName);
|
|
|
|
return getTexture(in, resourceName, flipped, filter, null);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a resource location
|
|
*
|
|
* @param resourceName The location to load the texture from
|
|
* @param flipped True if we should flip the texture on the y axis while loading
|
|
* @param filter The filter to use when scaling the texture
|
|
* @param transparent The colour to interpret as transparent or null if none
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public Texture getTexture(String resourceName, boolean flipped, int filter, int[] transparent) throws IOException {
|
|
InputStream in = ResourceLoader.getResourceAsStream(resourceName);
|
|
|
|
return getTexture(in, resourceName, flipped, filter, transparent);
|
|
}
|
|
/**
|
|
* Get a texture from a image file
|
|
*
|
|
* @param in The stream from which we can load the image
|
|
* @param resourceName The name to give this image in the internal cache
|
|
* @param flipped True if we should flip the image on the y-axis while loading
|
|
* @param filter The filter to use when scaling the texture
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public Texture getTexture(InputStream in, String resourceName, boolean flipped, int filter) throws IOException {
|
|
return getTexture(in, resourceName, flipped, filter, null);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a image file
|
|
*
|
|
* @param in The stream from which we can load the image
|
|
* @param resourceName The name to give this image in the internal cache
|
|
* @param flipped True if we should flip the image on the y-axis while loading
|
|
* @param filter The filter to use when scaling the texture
|
|
* @param transparent The colour to interpret as transparent or null if none
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
public TextureImpl getTexture(InputStream in, String resourceName, boolean flipped, int filter, int[] transparent) throws IOException {
|
|
if (deferred) {
|
|
return new DeferredTexture(in, resourceName, flipped, filter, transparent);
|
|
}
|
|
|
|
HashMap hash = texturesLinear;
|
|
if (filter == SGL.GL_NEAREST) {
|
|
hash = texturesNearest;
|
|
}
|
|
|
|
String resName = resourceName;
|
|
if (transparent != null) {
|
|
resName += ":"+transparent[0]+":"+transparent[1]+":"+transparent[2];
|
|
}
|
|
resName += ":"+flipped;
|
|
|
|
if (holdTextureData) {
|
|
TextureImpl tex = (TextureImpl) hash.get(resName);
|
|
if (tex != null) {
|
|
return tex;
|
|
}
|
|
} else {
|
|
SoftReference ref = (SoftReference) hash.get(resName);
|
|
if (ref != null) {
|
|
TextureImpl tex = (TextureImpl) ref.get();
|
|
if (tex != null) {
|
|
return tex;
|
|
} else {
|
|
hash.remove(resName);
|
|
}
|
|
}
|
|
}
|
|
|
|
// horrible test until I can find something more suitable
|
|
try {
|
|
GL.glGetError();
|
|
} catch (NullPointerException e) {
|
|
throw new RuntimeException("Image based resources must be loaded as part of init() or the game loop. They cannot be loaded before initialisation.");
|
|
}
|
|
|
|
TextureImpl tex = getTexture(in, resourceName,
|
|
SGL.GL_TEXTURE_2D,
|
|
filter,
|
|
filter, flipped, transparent);
|
|
|
|
tex.setCacheName(resName);
|
|
if (holdTextureData) {
|
|
hash.put(resName, tex);
|
|
} else {
|
|
hash.put(resName, new SoftReference(tex));
|
|
}
|
|
|
|
return tex;
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a image file
|
|
*
|
|
* @param in The stream from which we can load the image
|
|
* @param resourceName The name to give this image in the internal cache
|
|
* @param flipped True if we should flip the image on the y-axis while loading
|
|
* @param target The texture target we're loading this texture into
|
|
* @param minFilter The scaling down filter
|
|
* @param magFilter The scaling up filter
|
|
* @param transparent The colour to interpret as transparent or null if none
|
|
* @return The texture loaded
|
|
* @throws IOException Indicates a failure to load the image
|
|
*/
|
|
private TextureImpl getTexture(InputStream in,
|
|
String resourceName,
|
|
int target,
|
|
int magFilter,
|
|
int minFilter, boolean flipped, int[] transparent) throws IOException
|
|
{
|
|
// create the texture ID for this texture
|
|
ByteBuffer textureBuffer;
|
|
|
|
LoadableImageData imageData = ImageDataFactory.getImageDataFor(resourceName);
|
|
textureBuffer = imageData.loadImage(new BufferedInputStream(in), flipped, transparent);
|
|
|
|
int textureID = createTextureID();
|
|
TextureImpl texture = new TextureImpl(resourceName, target, textureID);
|
|
// bind this texture
|
|
GL.glBindTexture(target, textureID);
|
|
|
|
int width;
|
|
int height;
|
|
int texWidth;
|
|
int texHeight;
|
|
|
|
boolean hasAlpha;
|
|
|
|
width = imageData.getWidth();
|
|
height = imageData.getHeight();
|
|
hasAlpha = imageData.getDepth() == 32;
|
|
|
|
texture.setTextureWidth(imageData.getTexWidth());
|
|
texture.setTextureHeight(imageData.getTexHeight());
|
|
|
|
texWidth = texture.getTextureWidth();
|
|
texHeight = texture.getTextureHeight();
|
|
|
|
IntBuffer temp = BufferUtils.createIntBuffer(16);
|
|
GL.glGetInteger(SGL.GL_MAX_TEXTURE_SIZE, temp);
|
|
int max = temp.get(0);
|
|
if ((texWidth > max) || (texHeight > max)) {
|
|
throw new IOException("Attempt to allocate a texture to big for the current hardware");
|
|
}
|
|
|
|
int srcPixelFormat = hasAlpha ? SGL.GL_RGBA : SGL.GL_RGB;
|
|
int componentCount = hasAlpha ? 4 : 3;
|
|
|
|
texture.setWidth(width);
|
|
texture.setHeight(height);
|
|
texture.setAlpha(hasAlpha);
|
|
|
|
if (holdTextureData) {
|
|
texture.setTextureData(srcPixelFormat, componentCount, minFilter, magFilter, textureBuffer);
|
|
}
|
|
|
|
GL.glTexParameteri(target, GL.GL_TEXTURE_MIN_FILTER, minFilter);
|
|
GL.glTexParameteri(target, GL.GL_TEXTURE_MAG_FILTER, magFilter);
|
|
|
|
// produce a texture from the byte buffer
|
|
GL.glTexImage2D(target,
|
|
0,
|
|
dstPixelFormat,
|
|
get2Fold(width),
|
|
get2Fold(height),
|
|
0,
|
|
srcPixelFormat,
|
|
SGL.GL_UNSIGNED_BYTE,
|
|
textureBuffer);
|
|
|
|
return texture;
|
|
}
|
|
|
|
/**
|
|
* Create an empty texture
|
|
*
|
|
* @param width The width of the new texture
|
|
* @param height The height of the new texture
|
|
* @return The created empty texture
|
|
* @throws IOException Indicates a failure to create the texture on the graphics hardware
|
|
*/
|
|
public Texture createTexture(final int width, final int height) throws IOException {
|
|
return createTexture(width, height, SGL.GL_NEAREST);
|
|
}
|
|
|
|
/**
|
|
* Create an empty texture
|
|
*
|
|
* @param width The width of the new texture
|
|
* @param height The height of the new texture
|
|
* @return The created empty texture
|
|
* @throws IOException Indicates a failure to create the texture on the graphics hardware
|
|
*/
|
|
public Texture createTexture(final int width, final int height, final int filter) throws IOException {
|
|
ImageData ds = new EmptyImageData(width, height);
|
|
|
|
return getTexture(ds, filter);
|
|
}
|
|
|
|
/**
|
|
* Get a texture from a image file
|
|
*
|
|
* @param dataSource The image data to generate the texture from
|
|
* @param filter The filter to use when scaling the texture
|
|
* @return The texture created
|
|
* @throws IOException Indicates the texture is too big for the hardware
|
|
*/
|
|
public Texture getTexture(ImageData dataSource, int filter) throws IOException
|
|
{
|
|
int target = SGL.GL_TEXTURE_2D;
|
|
|
|
ByteBuffer textureBuffer;
|
|
textureBuffer = dataSource.getImageBufferData();
|
|
|
|
// create the texture ID for this texture
|
|
int textureID = createTextureID();
|
|
TextureImpl texture = new TextureImpl("generated:"+dataSource, target ,textureID);
|
|
|
|
int minFilter = filter;
|
|
int magFilter = filter;
|
|
boolean flipped = false;
|
|
|
|
// bind this texture
|
|
GL.glBindTexture(target, textureID);
|
|
|
|
int width;
|
|
int height;
|
|
int texWidth;
|
|
int texHeight;
|
|
|
|
boolean hasAlpha;
|
|
|
|
width = dataSource.getWidth();
|
|
height = dataSource.getHeight();
|
|
hasAlpha = dataSource.getDepth() == 32;
|
|
|
|
texture.setTextureWidth(dataSource.getTexWidth());
|
|
texture.setTextureHeight(dataSource.getTexHeight());
|
|
|
|
texWidth = texture.getTextureWidth();
|
|
texHeight = texture.getTextureHeight();
|
|
|
|
int srcPixelFormat = hasAlpha ? SGL.GL_RGBA : SGL.GL_RGB;
|
|
int componentCount = hasAlpha ? 4 : 3;
|
|
|
|
texture.setWidth(width);
|
|
texture.setHeight(height);
|
|
texture.setAlpha(hasAlpha);
|
|
|
|
IntBuffer temp = BufferUtils.createIntBuffer(16);
|
|
GL.glGetInteger(SGL.GL_MAX_TEXTURE_SIZE, temp);
|
|
int max = temp.get(0);
|
|
if ((texWidth > max) || (texHeight > max)) {
|
|
throw new IOException("Attempt to allocate a texture to big for the current hardware");
|
|
}
|
|
|
|
if (holdTextureData) {
|
|
texture.setTextureData(srcPixelFormat, componentCount, minFilter, magFilter, textureBuffer);
|
|
}
|
|
|
|
GL.glTexParameteri(target, SGL.GL_TEXTURE_MIN_FILTER, minFilter);
|
|
GL.glTexParameteri(target, SGL.GL_TEXTURE_MAG_FILTER, magFilter);
|
|
|
|
// produce a texture from the byte buffer
|
|
GL.glTexImage2D(target,
|
|
0,
|
|
dstPixelFormat,
|
|
get2Fold(width),
|
|
get2Fold(height),
|
|
0,
|
|
srcPixelFormat,
|
|
SGL.GL_UNSIGNED_BYTE,
|
|
textureBuffer);
|
|
|
|
return texture;
|
|
}
|
|
|
|
/**
|
|
* Get the closest greater power of 2 to the fold number
|
|
*
|
|
* @param fold The target number
|
|
* @return The power of 2
|
|
*/
|
|
public static int get2Fold(int fold) {
|
|
int ret = 2;
|
|
while (ret < fold) {
|
|
ret *= 2;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/**
|
|
* Creates an integer buffer to hold specified ints
|
|
* - strictly a utility method
|
|
*
|
|
* @param size how many int to contain
|
|
* @return created IntBuffer
|
|
*/
|
|
public static IntBuffer createIntBuffer(int size) {
|
|
ByteBuffer temp = ByteBuffer.allocateDirect(4 * size);
|
|
temp.order(ByteOrder.nativeOrder());
|
|
|
|
return temp.asIntBuffer();
|
|
}
|
|
|
|
/**
|
|
* Reload all the textures loaded in this loader
|
|
*/
|
|
public void reload() {
|
|
Iterator texs = texturesLinear.values().iterator();
|
|
while (texs.hasNext()) {
|
|
((TextureImpl) texs.next()).reload();
|
|
}
|
|
texs = texturesNearest.values().iterator();
|
|
while (texs.hasNext()) {
|
|
((TextureImpl) texs.next()).reload();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reload a given texture blob
|
|
*
|
|
* @param texture The texture being reloaded
|
|
* @param srcPixelFormat The source pixel format
|
|
* @param componentCount The component count
|
|
* @param minFilter The minification filter
|
|
* @param magFilter The magnification filter
|
|
* @param textureBuffer The pixel data
|
|
* @return The ID of the newly created texture
|
|
*/
|
|
public int reload(TextureImpl texture, int srcPixelFormat, int componentCount,
|
|
int minFilter, int magFilter, ByteBuffer textureBuffer) {
|
|
int target = SGL.GL_TEXTURE_2D;
|
|
int textureID = createTextureID();
|
|
GL.glBindTexture(target, textureID);
|
|
|
|
GL.glTexParameteri(target, SGL.GL_TEXTURE_MIN_FILTER, minFilter);
|
|
GL.glTexParameteri(target, SGL.GL_TEXTURE_MAG_FILTER, magFilter);
|
|
|
|
// produce a texture from the byte buffer
|
|
GL.glTexImage2D(target,
|
|
0,
|
|
dstPixelFormat,
|
|
texture.getTextureWidth(),
|
|
texture.getTextureHeight(),
|
|
0,
|
|
srcPixelFormat,
|
|
SGL.GL_UNSIGNED_BYTE,
|
|
textureBuffer);
|
|
|
|
return textureID;
|
|
}
|
|
} |