Path: blob/master/SLICK_HOME/src/org/newdawn/slick/opengl/TGAImageData.java
1461 views
package org.newdawn.slick.opengl;12import java.io.BufferedInputStream;3import java.io.DataInputStream;4import java.io.IOException;5import java.io.InputStream;6import java.nio.ByteBuffer;7import java.nio.ByteOrder;89import org.lwjgl.BufferUtils;1011/**12* A utility to load TGAs. Note: NOT THREAD SAFE13*14* Fresh cut of code but largely influeneced by the TGA loading class15* provided as part of the Java Monkey Engine (JME). Why not check out16* what they're doing over at http://www.jmonkeyengine.com. kudos to17* Mark Powell.18*19* @author Kevin Glass20*/21public class TGAImageData implements LoadableImageData {22/** The width of the texture that needs to be generated */23private int texWidth;24/** The height of the texture that needs to be generated */25private int texHeight;26/** The width of the TGA image */27private int width;28/** The height of the TGA image */29private int height;30/** The bit depth of the image */31private short pixelDepth;3233/**34* Create a new TGA Loader35*/36public TGAImageData() {37}3839/**40* Flip the endian-ness of the short41*42* @param signedShort The short to flip43* @return The flipped short44*/45private short flipEndian(short signedShort) {46int input = signedShort & 0xFFFF;47return (short) (input << 8 | (input & 0xFF00) >>> 8);48}4950/**51* @see org.newdawn.slick.opengl.ImageData#getDepth()52*/53public int getDepth() {54return pixelDepth;55}5657/**58* @see org.newdawn.slick.opengl.ImageData#getWidth()59*/60public int getWidth() {61return width;62}6364/**65* @see org.newdawn.slick.opengl.ImageData#getHeight()66*/67public int getHeight() {68return height;69}7071/**72* @see org.newdawn.slick.opengl.ImageData#getTexWidth()73*/74public int getTexWidth() {75return texWidth;76}7778/**79* @see org.newdawn.slick.opengl.ImageData#getTexHeight()80*/81public int getTexHeight() {82return texHeight;83}8485/**86* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream)87*/88public ByteBuffer loadImage(InputStream fis) throws IOException {89return loadImage(fis,true, null);90}9192/**93* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream, boolean, int[])94*/95public ByteBuffer loadImage(InputStream fis, boolean flipped, int[] transparent) throws IOException {96return loadImage(fis, flipped, false, transparent);97}9899/**100* @see org.newdawn.slick.opengl.LoadableImageData#loadImage(java.io.InputStream, boolean, boolean, int[])101*/102public ByteBuffer loadImage(InputStream fis, boolean flipped, boolean forceAlpha, int[] transparent) throws IOException {103if (transparent != null) {104forceAlpha = true;105}106byte red = 0;107byte green = 0;108byte blue = 0;109byte alpha = 0;110111BufferedInputStream bis = new BufferedInputStream(fis, 100000);112DataInputStream dis = new DataInputStream(bis);113114// Read in the Header115short idLength = (short) dis.read();116short colorMapType = (short) dis.read();117short imageType = (short) dis.read();118short cMapStart = flipEndian(dis.readShort());119short cMapLength = flipEndian(dis.readShort());120short cMapDepth = (short) dis.read();121short xOffset = flipEndian(dis.readShort());122short yOffset = flipEndian(dis.readShort());123124width = flipEndian(dis.readShort());125height = flipEndian(dis.readShort());126pixelDepth = (short) dis.read();127if (pixelDepth == 32) {128forceAlpha = false;129}130131texWidth = get2Fold(width);132texHeight = get2Fold(height);133134short imageDescriptor = (short) dis.read();135if ((imageDescriptor & 0x0020) == 0) {136flipped = !flipped;137}138139// Skip image ID140if (idLength > 0) {141bis.skip(idLength);142}143144byte[] rawData = null;145if ((pixelDepth == 32) || (forceAlpha)) {146pixelDepth = 32;147rawData = new byte[texWidth * texHeight * 4];148} else if (pixelDepth == 24) {149rawData = new byte[texWidth * texHeight * 3];150} else {151throw new RuntimeException("Only 24 and 32 bit TGAs are supported");152}153154if (pixelDepth == 24) {155if (flipped) {156for (int i = height-1; i >= 0; i--) {157for (int j = 0; j < width; j++) {158blue = dis.readByte();159green = dis.readByte();160red = dis.readByte();161162int ofs = ((j + (i * texWidth)) * 3);163rawData[ofs] = red;164rawData[ofs + 1] = green;165rawData[ofs + 2] = blue;166}167}168} else {169for (int i = 0; i < height; i++) {170for (int j = 0; j < width; j++) {171blue = dis.readByte();172green = dis.readByte();173red = dis.readByte();174175int ofs = ((j + (i * texWidth)) * 3);176rawData[ofs] = red;177rawData[ofs + 1] = green;178rawData[ofs + 2] = blue;179}180}181}182} else if (pixelDepth == 32) {183if (flipped) {184for (int i = height-1; i >= 0; i--) {185for (int j = 0; j < width; j++) {186blue = dis.readByte();187green = dis.readByte();188red = dis.readByte();189if (forceAlpha) {190alpha = (byte) 255;191} else {192alpha = dis.readByte();193}194195int ofs = ((j + (i * texWidth)) * 4);196197rawData[ofs] = red;198rawData[ofs + 1] = green;199rawData[ofs + 2] = blue;200rawData[ofs + 3] = alpha;201202if (alpha == 0) {203rawData[ofs + 2] = (byte) 0;204rawData[ofs + 1] = (byte) 0;205rawData[ofs] = (byte) 0;206}207}208}209} else {210for (int i = 0; i < height; i++) {211for (int j = 0; j < width; j++) {212blue = dis.readByte();213green = dis.readByte();214red = dis.readByte();215if (forceAlpha) {216alpha = (byte) 255;217} else {218alpha = dis.readByte();219}220221int ofs = ((j + (i * texWidth)) * 4);222223if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) {224rawData[ofs] = red;225rawData[ofs + 1] = green;226rawData[ofs + 2] = blue;227rawData[ofs + 3] = alpha;228} else {229rawData[ofs] = red;230rawData[ofs + 1] = green;231rawData[ofs + 2] = blue;232rawData[ofs + 3] = alpha;233}234235if (alpha == 0) {236rawData[ofs + 2] = 0;237rawData[ofs + 1] = 0;238rawData[ofs] = 0;239}240}241}242}243}244fis.close();245246if (transparent != null) {247for (int i=0;i<rawData.length;i+=4) {248boolean match = true;249for (int c=0;c<3;c++) {250if (rawData[i+c] != transparent[c]) {251match = false;252}253}254255if (match) {256rawData[i+3] = 0;257}258}259}260261// Get a pointer to the image memory262ByteBuffer scratch = BufferUtils.createByteBuffer(rawData.length);263scratch.put(rawData);264265int perPixel = pixelDepth / 8;266if (height < texHeight-1) {267int topOffset = (texHeight-1) * (texWidth*perPixel);268int bottomOffset = (height-1) * (texWidth*perPixel);269for (int x=0;x<texWidth*perPixel;x++) {270scratch.put(topOffset+x, scratch.get(x));271scratch.put(bottomOffset+(texWidth*perPixel)+x, scratch.get((texWidth*perPixel)+x));272}273}274if (width < texWidth-1) {275for (int y=0;y<texHeight;y++) {276for (int i=0;i<perPixel;i++) {277scratch.put(((y+1)*(texWidth*perPixel))-perPixel+i, scratch.get(y*(texWidth*perPixel)+i));278scratch.put((y*(texWidth*perPixel))+(width*perPixel)+i, scratch.get((y*(texWidth*perPixel))+((width-1)*perPixel)+i));279}280}281}282283scratch.flip();284285return scratch;286}287288/**289* Get the closest greater power of 2 to the fold number290*291* @param fold The target number292* @return The power of 2293*/294private int get2Fold(int fold) {295int ret = 2;296while (ret < fold) {297ret *= 2;298}299return ret;300}301302/**303* @see org.newdawn.slick.opengl.ImageData#getImageBufferData()304*/305public ByteBuffer getImageBufferData() {306throw new RuntimeException("TGAImageData doesn't store it's image.");307}308309/**310* @see org.newdawn.slick.opengl.LoadableImageData#configureEdging(boolean)311*/312public void configureEdging(boolean edging) {313}314}315316317