diff --git a/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java b/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java
index 20f50df12f..588a801b20 100644
--- a/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java
+++ b/jme3-core/src/plugins/java/com/jme3/texture/plugins/TGALoader.java
@@ -38,6 +38,12 @@
import com.jme3.texture.Image;
import com.jme3.texture.Image.Format;
import com.jme3.util.BufferUtils;
+
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferByte;
+import java.awt.image.Raster;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
@@ -48,13 +54,13 @@
* TextureManager provides static methods for building a
* Texture object. Typically, the information supplied is the
* filename and the texture properties.
- *
+ *
* @author Mark Powell
* @author Joshua Slack - cleaned, commented, added ability to read 16bit true color and color-mapped TGAs.
* @author Kirill Vainer - ported to jME3
* @version $Id: TGALoader.java 4131 2009-03-19 20:15:28Z blaine.dev $
*/
-public final class TGALoader implements AssetLoader {
+public class TGALoader implements AssetLoader {
// 0 - no image data in file
public static final int TYPE_NO_IMAGE = 0;
@@ -71,7 +77,18 @@ public final class TGALoader implements AssetLoader {
// 11 - run-length encoded, black and white image
public static final int TYPE_BLACKANDWHITE_RLE = 11;
+ protected static TGALoader loader;
+
+ public static void setLoader(TGALoader loader) {
+ TGALoader.loader = loader;
+ }
+
+ public TGALoader() {
+ setLoader(this);
+ }
+
public Object load(AssetInfo info) throws IOException {
+
if (!(info.getKey() instanceof TextureKey)) {
throw new IllegalArgumentException("Texture assets must be loaded using a TextureKey");
}
@@ -80,7 +97,7 @@ public Object load(AssetInfo info) throws IOException {
InputStream in = null;
try {
in = info.openStream();
- Image img = load(in, flip);
+ Image img = loadImage(in, flip);
return img;
} finally {
if (in != null) {
@@ -92,9 +109,9 @@ public Object load(AssetInfo info) throws IOException {
/**
* loadImage is a manual image loader which is entirely
* independent of AWT. OUT: RGB888 or RGBA8888 Image object
- *
- *
-
+ *
+ *
+
* @param in
* InputStream of an uncompressed 24b RGB or 32b RGBA TGA
* @param flip
@@ -104,6 +121,28 @@ public Object load(AssetInfo info) throws IOException {
* @throws java.io.IOException
*/
public static Image load(InputStream in, boolean flip) throws IOException {
+
+ if(loader == null) {
+ loader = new TGALoader();
+ }
+
+ return loader.loadImage(in, flip);
+ }
+ /**
+ * loadImage is a manual image loader which is entirely
+ * independent of AWT. OUT: RGB888 or RGBA8888 Image object
+ *
+ *
+
+ * @param in
+ * InputStream of an uncompressed 24b RGB or 32b RGBA TGA
+ * @param flip
+ * Flip the image vertically
+ * @return Image object that contains the
+ * image, either as a RGB888 or RGBA8888
+ * @throws java.io.IOException
+ */
+ public Image loadImage(InputStream in, boolean flip) throws IOException {
boolean flipH = false;
// open a stream to the file
@@ -463,29 +502,139 @@ public static Image load(InputStream in, boolean flip) throws IOException {
in.close();
+
+ return resizeImage(width, height, pixelDepth, format, rawData);
+ }
+
+ /**
+ * Change this image if need.
+ *
+ * @param width current width of image
+ * @param height current height of image
+ * @param pixelDepth pixel depth of image
+ * @param format format of image.
+ * @param rawData data of image.
+ * @return result image.
+ */
+ protected Image resizeImage(int width, int height, final int pixelDepth, final Format format, byte[] rawData) {
+
+ final int newWidth = getNewWidth(width);
+ final int newHeight = getNewHeight(height);
+
+ if(width != newWidth || height != newHeight) {
+
+ final int bufferedImageType = format == Format.RGBA8 ? BufferedImage.TYPE_4BYTE_ABGR : BufferedImage.TYPE_3BYTE_BGR;
+ final DataBufferByte sourceData = new DataBufferByte(rawData, rawData.length);
+
+ final BufferedImage sourceImage = new BufferedImage(width, height, bufferedImageType);
+ sourceImage.setData(Raster.createRaster(sourceImage.getSampleModel(), sourceData, null));
+
+ final Graphics2D graphics = sourceImage.createGraphics();
+
+ if (format == Format.RGBA8) {
+ graphics.setComposite(AlphaComposite.Src);
+ }
+
+ graphics.drawImage(sourceImage, 0, 0, newWidth, newHeight, null);
+ graphics.dispose();
+
+ final Raster newRaster = sourceImage.getData();
+ final DataBuffer newDataBuffer = newRaster.getDataBuffer();
+
+ if (pixelDepth == 32) {
+
+ rawData = new byte[width * height * 4];
+
+ for(int i = 0, g = 0, length = newDataBuffer.getSize(); i < length; i++) {
+
+ final int value = newDataBuffer.getElem(i);
+
+ final byte read = (byte) value;
+ final byte green = (byte) (value >> 8);
+ final byte blue = (byte) (value >> 16);
+ final byte alpha = (byte) (value >> 24);
+
+ rawData[g++] = alpha;
+ rawData[g++] = read;
+ rawData[g++] = green;
+ rawData[g++] = blue;
+ }
+
+ } else {
+
+ rawData = new byte[width * height * 3];
+
+ for(int i = 0, g = 0, length = newDataBuffer.getSize(); i < length; i++) {
+
+ final int value = newDataBuffer.getElem(i);
+
+ final byte red = (byte) value;
+ final byte green = (byte) (value >> 8);
+ final byte blue = (byte) (value >> 16);
+
+ rawData[g++] = red;
+ rawData[g++] = green;
+ rawData[g++] = blue;
+ }
+ }
+
+ width = newWidth;
+ height = newHeight;
+ }
+
+ return createImage(width, height, format, rawData);
+ }
+
+ /**
+ * Get the new height if need to scale.
+ *
+ * @param height height of source image.
+ * @return result height.
+ */
+ protected int getNewHeight(int height) {
+ return height;
+ }
+
+ /**
+ * Get the new width if need to scale.
+ *
+ * @param width width of source image.
+ * @return result width.
+ */
+ protected int getNewWidth(int width) {
+ return width;
+ }
+
+ protected Image createImage(int width, int height, Format format, byte[] rawData) {
+
// Get a pointer to the image memory
- ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);
+ final ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);
scratch.clear();
scratch.put(rawData);
scratch.rewind();
+
// Create the Image object
- Image textureImage = new Image();
+ final Image textureImage = new Image();
textureImage.setFormat(format);
textureImage.setWidth(width);
textureImage.setHeight(height);
textureImage.setData(scratch);
+
return textureImage;
}
private static byte getBitsAsByte(byte[] data, int offset, int length) {
+
int offsetBytes = offset / 8;
int indexBits = offset % 8;
int rVal = 0;
// start at data[offsetBytes]... spill into next byte as needed.
for (int i = length; --i >= 0;) {
+
byte b = data[offsetBytes];
int test = indexBits == 7 ? 1 : 2 << (6 - indexBits);
+
if ((b & test) != 0) {
if (i == 0) {
rVal++;
@@ -493,7 +642,9 @@ private static byte getBitsAsByte(byte[] data, int offset, int length) {
rVal += (2 << i - 1);
}
}
+
indexBits++;
+
if (indexBits == 8) {
indexBits = 0;
offsetBytes++;
@@ -506,7 +657,7 @@ private static byte getBitsAsByte(byte[] data, int offset, int length) {
/**
* flipEndian is used to flip the endian bit of the header
* file.
- *
+ *
* @param signedShort
* the bit to flip.
* @return the flipped bit.
@@ -516,9 +667,9 @@ private static short flipEndian(short signedShort) {
return (short) (input << 8 | (input & 0xFF00) >>> 8);
}
- static class ColorMapEntry {
+ protected static class ColorMapEntry {
- byte red, green, blue, alpha;
+ protected byte red, green, blue, alpha;
@Override
public String toString() {