package org.andengine.opengl.texture.compressed.pvr; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.zip.GZIPInputStream; import java.util.zip.Inflater; import java.util.zip.InflaterInputStream; import org.andengine.opengl.texture.ITextureStateListener; import org.andengine.opengl.texture.TextureManager; import org.andengine.opengl.texture.TextureOptions; import org.andengine.opengl.texture.compressed.pvr.pixelbufferstrategy.IPVRTexturePixelBufferStrategy; import org.andengine.util.StreamUtils; import org.andengine.util.adt.array.ArrayUtils; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Nicolas Gramlich * @since 14:17:23 - 27.07.2011 */ public abstract class PVRCCZTexture extends PVRTexture { // =========================================================== // Constants // =========================================================== // =========================================================== // Fields // =========================================================== private CCZHeader mCCZHeader; // =========================================================== // Constructors // =========================================================== public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final IPVRTexturePixelBufferStrategy pPVRTexturePixelBufferStrategy) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pPVRTexturePixelBufferStrategy); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final ITextureStateListener pTextureStateListener) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pTextureStateListener); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final IPVRTexturePixelBufferStrategy pPVRTexturePixelBufferStrategy, final ITextureStateListener pTextureStateListener) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pPVRTexturePixelBufferStrategy, pTextureStateListener); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final TextureOptions pTextureOptions) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pTextureOptions); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final IPVRTexturePixelBufferStrategy pPVRTexturePixelBufferStrategy, final TextureOptions pTextureOptions) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pPVRTexturePixelBufferStrategy, pTextureOptions); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final TextureOptions pTextureOptions, final ITextureStateListener pTextureStateListener) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pTextureOptions, pTextureStateListener); } public PVRCCZTexture(final TextureManager pTextureManager, final PVRTextureFormat pPVRTextureFormat, final IPVRTexturePixelBufferStrategy pPVRTexturePixelBufferStrategy, final TextureOptions pTextureOptions, final ITextureStateListener pTextureStateListener) throws IllegalArgumentException, IOException { super(pTextureManager, pPVRTextureFormat, pPVRTexturePixelBufferStrategy, pTextureOptions, pTextureStateListener); } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override public final InflaterInputStream getInputStream() throws IOException { final InputStream inputStream = this.onGetInputStream(); this.mCCZHeader = new CCZHeader(StreamUtils.streamToBytes(inputStream, CCZHeader.SIZE)); return this.mCCZHeader.getCCZCompressionFormat().wrap(inputStream); } @Override public ByteBuffer getPVRTextureBuffer() throws IOException { final InputStream inputStream = this.getInputStream(); try { final byte[] data = new byte[this.mCCZHeader.getUncompressedSize()]; StreamUtils.copy(inputStream, data); return ByteBuffer.wrap(data); } finally { StreamUtils.close(inputStream); } } // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== public static class CCZHeader { // =========================================================== // Constants // =========================================================== static final byte[] MAGIC_IDENTIFIER = { (byte)'C', (byte)'C', (byte)'Z', (byte)'!' }; public static final int SIZE = 16; // =========================================================== // Fields // =========================================================== private final ByteBuffer mDataByteBuffer; private final CCZCompressionFormat mCCZCompressionFormat; // =========================================================== // Constructors // =========================================================== public CCZHeader(final byte[] pData) { this.mDataByteBuffer = ByteBuffer.wrap(pData); this.mDataByteBuffer.rewind(); this.mDataByteBuffer.order(ByteOrder.BIG_ENDIAN); /* Check magic bytes. */ if(!ArrayUtils.equals(pData, 0, CCZHeader.MAGIC_IDENTIFIER, 0, CCZHeader.MAGIC_IDENTIFIER.length)) { throw new IllegalArgumentException("Invalid " + this.getClass().getSimpleName() + "!"); } // TODO Check the version? this.mCCZCompressionFormat = CCZCompressionFormat.fromID(this.getCCZCompressionFormatID()); } // =========================================================== // Getter & Setter // =========================================================== private short getCCZCompressionFormatID() { return this.mDataByteBuffer.getShort(4); } public CCZCompressionFormat getCCZCompressionFormat() { return this.mCCZCompressionFormat; } public short getVersion() { return this.mDataByteBuffer.getShort(6); } public int getUserdata() { return this.mDataByteBuffer.getInt(8); } public int getUncompressedSize() { return this.mDataByteBuffer.getInt(12); } // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== } public static enum CCZCompressionFormat { // =========================================================== // Elements // =========================================================== ZLIB((short)0), BZIP2((short)1), GZIP((short)2), NONE((short)3); // =========================================================== // Constants // =========================================================== // =========================================================== // Fields // =========================================================== private final short mID; // =========================================================== // Constructors // =========================================================== private CCZCompressionFormat(final short pID) { this.mID = pID; } public InflaterInputStream wrap(final InputStream pInputStream) throws IOException { switch(this) { case GZIP: return new GZIPInputStream(pInputStream); case ZLIB: return new InflaterInputStream(pInputStream, new Inflater()); case NONE: case BZIP2: default: throw new IllegalArgumentException("Unexpected " + CCZCompressionFormat.class.getSimpleName() + ": '" + this + "'."); } } public static CCZCompressionFormat fromID(final short pID) { final CCZCompressionFormat[] cczCompressionFormats = CCZCompressionFormat.values(); final int cczCompressionFormatCount = cczCompressionFormats.length; for(int i = 0; i < cczCompressionFormatCount; i++) { final CCZCompressionFormat cczCompressionFormat = cczCompressionFormats[i]; if(cczCompressionFormat.mID == pID) { return cczCompressionFormat; } } throw new IllegalArgumentException("Unexpected " + CCZCompressionFormat.class.getSimpleName() + "-ID: '" + pID + "'."); } // =========================================================== // Getter & Setter // =========================================================== // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== // =========================================================== // Methods // =========================================================== // =========================================================== // Inner and Anonymous Classes // =========================================================== } }