mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-13 15:16:07 +09:00
Proper tga.gz loading using own imagedata
This commit is contained in:
328
src/net/torvald/slick/opengl/TGAGzImageData.java
Normal file
328
src/net/torvald/slick/opengl/TGAGzImageData.java
Normal file
@@ -0,0 +1,328 @@
|
|||||||
|
package net.torvald.slick.opengl;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A utility to load .tga.gz
|
||||||
|
*
|
||||||
|
* Created by SKYHi14 on 2017-04-19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.DataInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.ByteOrder;
|
||||||
|
import java.util.zip.GZIPInputStream;
|
||||||
|
|
||||||
|
import org.lwjgl.BufferUtils;
|
||||||
|
import org.newdawn.slick.opengl.LoadableImageData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A utility to load TGAs. Note: NOT THREAD SAFE
|
||||||
|
*
|
||||||
|
* Fresh cut of code but largely influeneced by the TGA loading class
|
||||||
|
* provided as part of the Java Monkey Engine (JME). Why not check out
|
||||||
|
* what they're doing over at http://www.jmonkeyengine.com. kudos to
|
||||||
|
* Mark Powell.
|
||||||
|
*
|
||||||
|
* @author Kevin Glass
|
||||||
|
*/
|
||||||
|
public class TGAGzImageData implements LoadableImageData {
|
||||||
|
/** The width of the texture that needs to be generated */
|
||||||
|
private int texWidth;
|
||||||
|
/** The height of the texture that needs to be generated */
|
||||||
|
private int texHeight;
|
||||||
|
/** The width of the TGA image */
|
||||||
|
private int width;
|
||||||
|
/** The height of the TGA image */
|
||||||
|
private int height;
|
||||||
|
/** The bit depth of the image */
|
||||||
|
private short pixelDepth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new TGA Loader
|
||||||
|
*/
|
||||||
|
public TGAGzImageData() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flip the endian-ness of the short
|
||||||
|
*
|
||||||
|
* @param signedShort The short to flip
|
||||||
|
* @return The flipped short
|
||||||
|
*/
|
||||||
|
private short flipEndian(short signedShort) {
|
||||||
|
int input = signedShort & 0xFFFF;
|
||||||
|
return (short) (input << 8 | (input & 0xFF00) >>> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getDepth()
|
||||||
|
*/
|
||||||
|
public int getDepth() {
|
||||||
|
return pixelDepth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getWidth()
|
||||||
|
*/
|
||||||
|
public int getWidth() {
|
||||||
|
return width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getHeight()
|
||||||
|
*/
|
||||||
|
public int getHeight() {
|
||||||
|
return height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getTexWidth()
|
||||||
|
*/
|
||||||
|
public int getTexWidth() {
|
||||||
|
return texWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getTexHeight()
|
||||||
|
*/
|
||||||
|
public int getTexHeight() {
|
||||||
|
return texHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream)
|
||||||
|
*/
|
||||||
|
public ByteBuffer loadImage(InputStream fis) throws IOException {
|
||||||
|
return loadImage(fis,true, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream, boolean, int[])
|
||||||
|
*/
|
||||||
|
public ByteBuffer loadImage(InputStream fis, boolean flipped, int[] transparent) throws IOException {
|
||||||
|
return loadImage(fis, flipped, false, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream, boolean, boolean, int[])
|
||||||
|
*/
|
||||||
|
public ByteBuffer loadImage(InputStream fis, boolean flipped, boolean forceAlpha, int[] transparent) throws IOException {
|
||||||
|
if (transparent != null) {
|
||||||
|
forceAlpha = true;
|
||||||
|
}
|
||||||
|
byte red = 0;
|
||||||
|
byte green = 0;
|
||||||
|
byte blue = 0;
|
||||||
|
byte alpha = 0;
|
||||||
|
|
||||||
|
BufferedInputStream bis = new BufferedInputStream(new GZIPInputStream(fis, 8192), 16384);
|
||||||
|
DataInputStream dis = new DataInputStream(bis);
|
||||||
|
|
||||||
|
// Read in the Header
|
||||||
|
short idLength = (short) dis.read();
|
||||||
|
short colorMapType = (short) dis.read();
|
||||||
|
short imageType = (short) dis.read();
|
||||||
|
short cMapStart = flipEndian(dis.readShort());
|
||||||
|
short cMapLength = flipEndian(dis.readShort());
|
||||||
|
short cMapDepth = (short) dis.read();
|
||||||
|
short xOffset = flipEndian(dis.readShort());
|
||||||
|
short yOffset = flipEndian(dis.readShort());
|
||||||
|
|
||||||
|
if (imageType != 2) {
|
||||||
|
throw new IOException("Slick only supports uncompressed RGB(A) TGA images");
|
||||||
|
}
|
||||||
|
|
||||||
|
width = flipEndian(dis.readShort());
|
||||||
|
height = flipEndian(dis.readShort());
|
||||||
|
pixelDepth = (short) dis.read();
|
||||||
|
if (pixelDepth == 32) {
|
||||||
|
forceAlpha = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
texWidth = get2Fold(width);
|
||||||
|
texHeight = get2Fold(height);
|
||||||
|
|
||||||
|
short imageDescriptor = (short) dis.read();
|
||||||
|
if ((imageDescriptor & 0x0020) == 0) {
|
||||||
|
flipped = !flipped;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip image ID
|
||||||
|
if (idLength > 0) {
|
||||||
|
bis.skip(idLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] rawData = null;
|
||||||
|
if ((pixelDepth == 32) || (forceAlpha)) {
|
||||||
|
pixelDepth = 32;
|
||||||
|
rawData = new byte[texWidth * texHeight * 4];
|
||||||
|
} else if (pixelDepth == 24) {
|
||||||
|
rawData = new byte[texWidth * texHeight * 3];
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Only 24 and 32 bit TGAs are supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixelDepth == 24) {
|
||||||
|
if (flipped) {
|
||||||
|
for (int i = height-1; i >= 0; i--) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
blue = dis.readByte();
|
||||||
|
green = dis.readByte();
|
||||||
|
red = dis.readByte();
|
||||||
|
|
||||||
|
int ofs = ((j + (i * texWidth)) * 3);
|
||||||
|
rawData[ofs] = red;
|
||||||
|
rawData[ofs + 1] = green;
|
||||||
|
rawData[ofs + 2] = blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
blue = dis.readByte();
|
||||||
|
green = dis.readByte();
|
||||||
|
red = dis.readByte();
|
||||||
|
|
||||||
|
int ofs = ((j + (i * texWidth)) * 3);
|
||||||
|
rawData[ofs] = red;
|
||||||
|
rawData[ofs + 1] = green;
|
||||||
|
rawData[ofs + 2] = blue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (pixelDepth == 32) {
|
||||||
|
if (flipped) {
|
||||||
|
for (int i = height-1; i >= 0; i--) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
blue = dis.readByte();
|
||||||
|
green = dis.readByte();
|
||||||
|
red = dis.readByte();
|
||||||
|
if (forceAlpha) {
|
||||||
|
alpha = (byte) 255;
|
||||||
|
} else {
|
||||||
|
alpha = dis.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ofs = ((j + (i * texWidth)) * 4);
|
||||||
|
|
||||||
|
rawData[ofs] = red;
|
||||||
|
rawData[ofs + 1] = green;
|
||||||
|
rawData[ofs + 2] = blue;
|
||||||
|
rawData[ofs + 3] = alpha;
|
||||||
|
|
||||||
|
if (alpha == 0) {
|
||||||
|
rawData[ofs + 2] = (byte) 0;
|
||||||
|
rawData[ofs + 1] = (byte) 0;
|
||||||
|
rawData[ofs] = (byte) 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < height; i++) {
|
||||||
|
for (int j = 0; j < width; j++) {
|
||||||
|
blue = dis.readByte();
|
||||||
|
green = dis.readByte();
|
||||||
|
red = dis.readByte();
|
||||||
|
if (forceAlpha) {
|
||||||
|
alpha = (byte) 255;
|
||||||
|
} else {
|
||||||
|
alpha = dis.readByte();
|
||||||
|
}
|
||||||
|
|
||||||
|
int ofs = ((j + (i * texWidth)) * 4);
|
||||||
|
|
||||||
|
if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {
|
||||||
|
rawData[ofs] = red;
|
||||||
|
rawData[ofs + 1] = green;
|
||||||
|
rawData[ofs + 2] = blue;
|
||||||
|
rawData[ofs + 3] = alpha;
|
||||||
|
} else {
|
||||||
|
rawData[ofs] = red;
|
||||||
|
rawData[ofs + 1] = green;
|
||||||
|
rawData[ofs + 2] = blue;
|
||||||
|
rawData[ofs + 3] = alpha;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alpha == 0) {
|
||||||
|
rawData[ofs + 2] = 0;
|
||||||
|
rawData[ofs + 1] = 0;
|
||||||
|
rawData[ofs] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fis.close();
|
||||||
|
|
||||||
|
if (transparent != null) {
|
||||||
|
for (int i=0;i<rawData.length;i+=4) {
|
||||||
|
boolean match = true;
|
||||||
|
for (int c=0;c<3;c++) {
|
||||||
|
if (rawData[i+c] != transparent[c]) {
|
||||||
|
match = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (match) {
|
||||||
|
rawData[i+3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a pointer to the image memory
|
||||||
|
ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);
|
||||||
|
scratch.put(rawData);
|
||||||
|
|
||||||
|
int perPixel = pixelDepth / 8;
|
||||||
|
if (height < texHeight-1) {
|
||||||
|
int topOffset = (texHeight-1) * (texWidth*perPixel);
|
||||||
|
int bottomOffset = (height-1) * (texWidth*perPixel);
|
||||||
|
for (int x=0;x<texWidth*perPixel;x++) {
|
||||||
|
scratch.put(topOffset+x, scratch.get(x));
|
||||||
|
scratch.put(bottomOffset+(texWidth*perPixel)+x, scratch.get((texWidth*perPixel)+x));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (width < texWidth-1) {
|
||||||
|
for (int y=0;y<texHeight;y++) {
|
||||||
|
for (int i=0;i<perPixel;i++) {
|
||||||
|
scratch.put(((y+1)*(texWidth*perPixel))-perPixel+i, scratch.get(y*(texWidth*perPixel)+i));
|
||||||
|
scratch.put((y*(texWidth*perPixel))+(width*perPixel)+i, scratch.get((y*(texWidth*perPixel))+((width-1)*perPixel)+i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scratch.flip();
|
||||||
|
|
||||||
|
return scratch;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the closest greater power of 2 to the fold number
|
||||||
|
*
|
||||||
|
* @param fold The target number
|
||||||
|
* @return The power of 2
|
||||||
|
*/
|
||||||
|
private int get2Fold(int fold) {
|
||||||
|
int ret = 2;
|
||||||
|
while (ret < fold) {
|
||||||
|
ret *= 2;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.ImageData#getImageBufferData()
|
||||||
|
*/
|
||||||
|
public ByteBuffer getImageBufferData() {
|
||||||
|
throw new RuntimeException("TGAImageData doesn't store it's image.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.newdawn.slick.opengl.LoadableImageData#configureEdging(boolean)
|
||||||
|
*/
|
||||||
|
public void configureEdging(boolean edging) {
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -33,40 +33,10 @@ object TilesDrawer {
|
|||||||
private val TILE_SIZE = FeaturesDrawer.TILE_SIZE
|
private val TILE_SIZE = FeaturesDrawer.TILE_SIZE
|
||||||
private val TILE_SIZEF = FeaturesDrawer.TILE_SIZE.toFloat()
|
private val TILE_SIZEF = FeaturesDrawer.TILE_SIZE.toFloat()
|
||||||
|
|
||||||
//val tilesTerrain = SpriteSheet(ModMgr.getPath("basegame", "tiles/terrain.tga"), TILE_SIZE, TILE_SIZE)
|
val tilesTerrain = SpriteSheet(ModMgr.getPath("basegame", "tiles/terrain.tga.gz"), TILE_SIZE, TILE_SIZE)
|
||||||
// Slick has some weird quirks with PNG's transparency. I'm using 32-bit targa here.
|
// Slick has some weird quirks with PNG's transparency. I'm using 32-bit targa here.
|
||||||
val tilesWire = SpriteSheet(ModMgr.getPath("basegame", "tiles/wire.tga"), TILE_SIZE, TILE_SIZE)
|
val tilesWire = SpriteSheet(ModMgr.getPath("basegame", "tiles/wire.tga"), TILE_SIZE, TILE_SIZE)
|
||||||
|
|
||||||
val tilesTerrain: SpriteSheet
|
|
||||||
|
|
||||||
init {
|
|
||||||
// read DEFLATEd terrain.tar
|
|
||||||
val tgaLoader = TGAImageData()
|
|
||||||
val terrainImageData = tgaLoader.loadImage(
|
|
||||||
GZIPInputStream(
|
|
||||||
FileInputStream(ModMgr.getFile("basegame", "tiles/terrain.tga.gz")),
|
|
||||||
8192
|
|
||||||
), false, null)
|
|
||||||
terrainImageData.rewind()
|
|
||||||
/*val terrainTex = InternalTextureLoader.get().getTexture(object : ImageData {
|
|
||||||
override fun getHeight(): Int = tgaLoader.height
|
|
||||||
override fun getTexWidth(): Int = tgaLoader.texWidth
|
|
||||||
override fun getDepth(): Int = tgaLoader.depth
|
|
||||||
override fun getImageBufferData(): ByteBuffer = terrainImageData
|
|
||||||
override fun getWidth(): Int = tgaLoader.width
|
|
||||||
override fun getTexHeight(): Int = tgaLoader.texHeight
|
|
||||||
}, Image.FILTER_NEAREST)*/
|
|
||||||
|
|
||||||
//// method 1
|
|
||||||
//val terrainImage = Image(terrainTex)
|
|
||||||
//tilesTerrain = SpriteSheet(terrainImage, TILE_SIZE, TILE_SIZE)
|
|
||||||
|
|
||||||
//// method 2
|
|
||||||
val terrainImgBuffer = ImageBuffer(tgaLoader.width, tgaLoader.height)
|
|
||||||
terrainImageData.get(terrainImgBuffer.rgba)
|
|
||||||
tilesTerrain = SpriteSheet(terrainImgBuffer.image, TILE_SIZE, TILE_SIZE)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val breakAnimSteps = 10
|
val breakAnimSteps = 10
|
||||||
|
|
||||||
|
|||||||
87
src/org/newdawn/slick/opengl/ImageDataFactory.java
Normal file
87
src/org/newdawn/slick/opengl/ImageDataFactory.java
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
package org.newdawn.slick.opengl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Modifications: Added support for .tga.gz
|
||||||
|
*
|
||||||
|
* Created by SKYHi14 on 2017-04-19.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import net.torvald.slick.opengl.TGAGzImageData;
|
||||||
|
import org.newdawn.slick.util.Log;
|
||||||
|
|
||||||
|
import java.security.AccessController;
|
||||||
|
import java.security.PrivilegedAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static utility to create the appropriate image data for a particular reference.
|
||||||
|
*
|
||||||
|
* @author kevin
|
||||||
|
*/
|
||||||
|
public class ImageDataFactory {
|
||||||
|
/** True if we're going to use the native PNG loader - cached so it doesn't have
|
||||||
|
* the security check repeatedly
|
||||||
|
*/
|
||||||
|
private static boolean usePngLoader = true;
|
||||||
|
/** True if the PNG loader property has been checked */
|
||||||
|
private static boolean pngLoaderPropertyChecked = false;
|
||||||
|
|
||||||
|
/** The name of the PNG loader configuration property */
|
||||||
|
private static final String PNG_LOADER = "org.newdawn.slick.pngloader";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check PNG loader property. If set the native PNG loader will
|
||||||
|
* not be used.
|
||||||
|
*/
|
||||||
|
private static void checkProperty() {
|
||||||
|
if (!pngLoaderPropertyChecked) {
|
||||||
|
pngLoaderPropertyChecked = true;
|
||||||
|
|
||||||
|
try {
|
||||||
|
AccessController.doPrivileged(new PrivilegedAction() {
|
||||||
|
public Object run() {
|
||||||
|
String val = System.getProperty(PNG_LOADER);
|
||||||
|
if ("false".equalsIgnoreCase(val)) {
|
||||||
|
usePngLoader = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.info("Use Java PNG Loader = " + usePngLoader);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (Throwable e) {
|
||||||
|
// ignore, security failure - probably an applet
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an image data that is appropriate for the reference supplied
|
||||||
|
*
|
||||||
|
* @param ref The reference to the image to retrieve
|
||||||
|
* @return The image data that can be used to retrieve the data for that resource
|
||||||
|
*/
|
||||||
|
public static LoadableImageData getImageDataFor(String ref) {
|
||||||
|
LoadableImageData imageData;
|
||||||
|
checkProperty();
|
||||||
|
|
||||||
|
ref = ref.toLowerCase();
|
||||||
|
|
||||||
|
if (ref.endsWith(".tga")) {
|
||||||
|
return new TGAImageData();
|
||||||
|
}
|
||||||
|
if (ref.endsWith(".tga.gz")) {
|
||||||
|
return new TGAGzImageData();
|
||||||
|
}
|
||||||
|
if (ref.endsWith(".png")) {
|
||||||
|
CompositeImageData data = new CompositeImageData();
|
||||||
|
if (usePngLoader) {
|
||||||
|
data.add(new PNGImageData());
|
||||||
|
}
|
||||||
|
data.add(new ImageIOImageData());
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new ImageIOImageData();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user