mirror of
https://github.com/curioustorvald/Terrarum.git
synced 2026-03-07 20:31:51 +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_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.
|
||||
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
|
||||
|
||||
|
||||
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