| package com.plusminus.craft; | |
| import java.awt.Graphics; | |
| import java.awt.Graphics2D; | |
| import java.awt.color.ColorSpace; | |
| import java.awt.image.BufferedImage; | |
| import java.awt.image.ColorModel; | |
| import java.awt.image.ComponentColorModel; | |
| import java.awt.image.ComponentSampleModel; | |
| import java.awt.image.DataBuffer; | |
| import java.awt.image.DataBufferByte; | |
| import java.awt.image.Raster; | |
| import java.awt.image.SampleModel; | |
| import java.awt.image.WritableRaster; | |
| import java.nio.ByteBuffer; | |
| import java.nio.ByteOrder; | |
| import java.util.Hashtable; | |
| import org.lwjgl.opengl.GL11; | |
| /*** | |
| * Represents a texture with methods to quickly (!) update it from a given BufferedImage | |
| * | |
| * I took this from a previous project | |
| * | |
| * The most interesting about this is the 'update' method, which will redraw an image into a texture compatible buffer and update the texture | |
| * | |
| * @todo more documentation | |
| * @author Vincent | |
| */ | |
| public class Texture { | |
| private BufferedImage image; | |
| private WritableRaster raster; | |
| private BufferedImage texImage; | |
| private byte[] iBuffer; | |
| private byte[] tBuffer; | |
| private ByteBuffer textureCompatibleBuffer; | |
| private int[] bankOffsets; | |
| private int textureWidth = -1; | |
| private int textureHeight = -1; | |
| private int imageWidth; | |
| private int imageHeight; | |
| private int xScaleUnit; | |
| private int yScaleUnit; | |
| private ComponentSampleModel imageSampleModel; | |
| private int scanLineStride; | |
| private int pixelStride; | |
| private int frameNum; | |
| private long playTime; | |
| private long delayTime; | |
| private boolean flip = false; | |
| private Object syncObj = new Object(); | |
| private int textureId = -1; | |
| /*public static final ColorModel glAlphaColorModel = new ComponentColorModel( | |
| ColorSpace.getInstance(ColorSpace.CS_sRGB), | |
| new int[] { 8, 8, 8, 8 }, true, false, | |
| ComponentColorModel.TRANSLUCENT, DataBuffer.TYPE_BYTE); | |
| public static final ColorModel glColorModel = new ComponentColorModel( | |
| ColorSpace.getInstance(ColorSpace.CS_sRGB), | |
| new int[] { 8, 8, 8, 0 }, false, false, ComponentColorModel.OPAQUE, | |
| DataBuffer.TYPE_BYTE);*/ | |
| public Texture(BufferedImage image, int frameNum, long playTime, | |
| long delayTime) { | |
| // System.out.println(image.hashCode()); | |
| this.image = image; | |
| this.frameNum = frameNum; | |
| this.playTime = playTime; | |
| this.delayTime = delayTime; | |
| this.textureCompatibleBuffer = null; | |
| } | |
| public Texture(BufferedImage image) { | |
| // System.out.println(image.hashCode()); | |
| this.image = image; | |
| this.frameNum = -1; | |
| this.playTime = -1; | |
| this.delayTime = -1; | |
| this.textureCompatibleBuffer = null; | |
| } | |
| public int getTextureId() { | |
| return this.textureId; | |
| } | |
| public void setTextureId(int id) { | |
| this.textureId = id; | |
| } | |
| public void setFlip(boolean flip) { | |
| this.flip = flip; | |
| } | |
| public boolean getFlip() { | |
| return flip; | |
| } | |
| public int getTextureWidth() { | |
| return this.textureWidth; | |
| } | |
| public int getTextureHeight() { | |
| return this.textureHeight; | |
| } | |
| public long getDelayTime() { | |
| return delayTime; | |
| } | |
| public void setDelayTime(long delayTime) { | |
| this.delayTime = delayTime; | |
| } | |
| public int getFrameNum() { | |
| return frameNum; | |
| } | |
| public void setFrameNum(int frameNum) { | |
| this.frameNum = frameNum; | |
| } | |
| public BufferedImage getImage() { | |
| return image; | |
| } | |
| public void setImage(BufferedImage image) { | |
| this.image = image; | |
| } | |
| public long getPlayTime() { | |
| return playTime; | |
| } | |
| public void setPlayTime(long playTime) { | |
| this.playTime = playTime; | |
| } | |
| public byte[] getTextureData() { | |
| return this.tBuffer; | |
| } | |
| public byte[] getImageData() { | |
| return this.iBuffer; | |
| } | |
| public void setImageData(byte[] iBuffer) { | |
| this.iBuffer = iBuffer; | |
| } | |
| public void initializeTextureCompatibleBuffer() { | |
| textureWidth = TextureTool.get2Fold(image.getWidth()); | |
| textureHeight = TextureTool.get2Fold(image.getHeight()); | |
| // generate an interleaved byte-based ARGB raster and image | |
| raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, | |
| this.textureWidth, this.textureHeight, 4, null); | |
| texImage = new BufferedImage(TextureTool.glAlphaColorModel, raster, false, | |
| new Hashtable()); | |
| // get the pointers to the data of the [t]exture buffer | |
| // and the data of the [i]image buffer | |
| iBuffer = ((DataBufferByte) image.getRaster().getDataBuffer()) | |
| .getData(); | |
| tBuffer = ((DataBufferByte) texImage.getRaster() | |
| .getDataBuffer()).getData(); | |
| // get information on how the image is stored in the buffer | |
| ComponentSampleModel imageSampleModel = (ComponentSampleModel) image | |
| .getSampleModel(); | |
| scanLineStride = imageSampleModel.getScanlineStride(); | |
| pixelStride = imageSampleModel.getPixelStride(); | |
| bankOffsets = imageSampleModel.getBandOffsets(); | |
| // generate a fixed point floating point number | |
| // which will allow us to calculate for a given x or y on the | |
| // texture | |
| // where the source pixel on the image is | |
| xScaleUnit = (int) (((double) image.getWidth() / (double) textureWidth) * 65536); | |
| yScaleUnit = (int) (((double) image.getHeight() / (double) textureHeight) * 65536); | |
| // generate a bytebuffer to store the resulting image | |
| textureCompatibleBuffer = ByteBuffer | |
| .allocateDirect(tBuffer.length); | |
| textureCompatibleBuffer.order(ByteOrder.nativeOrder()); | |
| } | |
| public void updateTextureCompatibleBuffer() { | |
| synchronized (this.syncObj) { | |
| // long time = System.currentTimeMillis(); | |
| int adr = 0; // the address in the texture buffer | |
| int xOffset = 0; // the x coordinate in the image | |
| int bufferOffset = 0; // the final buffer offset in the image | |
| int yOffset = 0; // the y coordinate in the image | |
| int yBufferOffset = 0; // a temp value containing the start of the | |
| // scanline in the image | |
| int x,y; // the coordinates on the texture image | |
| if(flip) { | |
| yOffset = (image.getHeight()-1) * 65536; | |
| if (bankOffsets.length > 3) { // RGBA or ABGR images | |
| int bOff0 = bankOffsets[0]; | |
| int bOff1 = bankOffsets[1]; | |
| int bOff2 = bankOffsets[2]; | |
| int bOff3 = bankOffsets[3]; | |
| for (y = 1; y < textureHeight; y++) { | |
| xOffset = 0; | |
| yBufferOffset = (yOffset >> 16) * scanLineStride; | |
| for (x = 0; x < textureWidth; x++) { | |
| bufferOffset = yBufferOffset + (xOffset >> 16) | |
| * pixelStride; | |
| tBuffer[adr] = iBuffer[bufferOffset + bOff0]; | |
| tBuffer[adr+1] = iBuffer[bufferOffset + bOff1]; | |
| tBuffer[adr+2] = iBuffer[bufferOffset + bOff2]; | |
| tBuffer[adr+3] = iBuffer[bufferOffset + bOff3]; | |
| xOffset += xScaleUnit; | |
| adr += 4; | |
| } | |
| yOffset -= yScaleUnit; | |
| } | |
| } else { // RGB or BGR images | |
| //int y; | |
| //int x; | |
| int bOff0 = bankOffsets[0]; | |
| int bOff1 = bankOffsets[1]; | |
| int bOff2 = bankOffsets[2]; | |
| for (y = 1; y < textureHeight; y++) { | |
| xOffset = 0; | |
| yBufferOffset = (yOffset >> 16) * scanLineStride; | |
| for (x = 0; x < textureWidth; x++) { | |
| bufferOffset = yBufferOffset + (xOffset >> 16) | |
| * pixelStride; | |
| tBuffer[adr] = iBuffer[bufferOffset + bOff0]; | |
| tBuffer[adr+1] = iBuffer[bufferOffset + bOff1]; | |
| tBuffer[adr+2] = iBuffer[bufferOffset + bOff2]; | |
| tBuffer[adr+3] = -1; // -1 signed = 255 unsigned | |
| xOffset += xScaleUnit; | |
| adr += 4; | |
| } | |
| yOffset -= yScaleUnit; | |
| } | |
| } | |
| } else { | |
| if (bankOffsets.length > 3) { // RGBA or ABGR images | |
| int bOff0 = bankOffsets[0]; | |
| int bOff1 = bankOffsets[1]; | |
| int bOff2 = bankOffsets[2]; | |
| int bOff3 = bankOffsets[3]; | |
| for (y = 0; y < textureHeight; y++) { | |
| xOffset = 0; | |
| yBufferOffset = (yOffset >> 16) * scanLineStride; | |
| for (x = 0; x < textureWidth; x++) { | |
| bufferOffset = yBufferOffset + (xOffset >> 16) | |
| * pixelStride; | |
| tBuffer[adr] = iBuffer[bufferOffset + bOff0]; | |
| tBuffer[adr+1] = iBuffer[bufferOffset + bOff1]; | |
| tBuffer[adr+2] = iBuffer[bufferOffset + bOff2]; | |
| tBuffer[adr+3] = iBuffer[bufferOffset + bOff3]; | |
| xOffset += xScaleUnit; | |
| adr += 4; | |
| } | |
| yOffset += yScaleUnit; | |
| } | |
| } else { // RGB or BGR images | |
| //int y; | |
| //int x; | |
| int bOff0 = bankOffsets[0]; | |
| int bOff1 = bankOffsets[1]; | |
| int bOff2 = bankOffsets[2]; | |
| for (y = 0; y < textureHeight; y++) { | |
| xOffset = 0; | |
| yBufferOffset = (yOffset >> 16) * scanLineStride; | |
| for (x = 0; x < textureWidth; x++) { | |
| bufferOffset = yBufferOffset + (xOffset >> 16) | |
| * pixelStride; | |
| tBuffer[adr] = iBuffer[bufferOffset + bOff0]; | |
| tBuffer[adr+1] = iBuffer[bufferOffset + bOff1]; | |
| tBuffer[adr+2] = iBuffer[bufferOffset + bOff2]; | |
| tBuffer[adr+3] = -1; // -1 signed = 255 unsigned | |
| xOffset += xScaleUnit; | |
| adr += 4; | |
| } | |
| yOffset += yScaleUnit; | |
| } | |
| } | |
| } | |
| textureCompatibleBuffer.rewind(); | |
| textureCompatibleBuffer.put(tBuffer, 0, tBuffer.length); | |
| } | |
| } | |
| public void bind() { | |
| GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); | |
| } | |
| public ByteBuffer getTextureCompatibleBuffer() { | |
| synchronized (this.syncObj) { | |
| return (ByteBuffer) textureCompatibleBuffer.rewind(); | |
| } | |
| } | |
| public synchronized void setTextureCompatibleBuffer( | |
| ByteBuffer textureCompatibleBuffer) { | |
| synchronized (this.syncObj) { | |
| this.textureCompatibleBuffer = textureCompatibleBuffer; | |
| } | |
| } | |
| public void update() { | |
| updateTextureCompatibleBuffer(); | |
| GL11.glBindTexture(GL11.GL_TEXTURE_2D, textureId); | |
| textureCompatibleBuffer.rewind(); | |
| GL11.glTexSubImage2D(GL11.GL_TEXTURE_2D, 0, 0, 0, textureWidth, textureHeight, GL11.GL_RGBA, GL11.GL_UNSIGNED_BYTE, textureCompatibleBuffer); | |
| } | |
| } |