package org.andengine.opengl.texture.compressed.pvr.pixelbufferstrategy;
import java.io.IOException;
import java.io.InputStream;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import org.andengine.opengl.texture.PixelFormat;
import org.andengine.opengl.texture.compressed.pvr.PVRTexture;
import org.andengine.opengl.texture.compressed.pvr.PVRTexture.PVRTextureHeader;
import org.andengine.util.StreamUtils;
import org.andengine.util.exception.AndEngineRuntimeException;
import android.opengl.GLES20;
/**
* (c) Zynga 2011
*
* @author Nicolas Gramlich <ngramlich@zynga.com>
* @since 11:26:07 - 27.09.2011
*/
public class SmartPVRTexturePixelBufferStrategy implements IPVRTexturePixelBufferStrategy {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final int mAllocationSizeMaximum;
// ===========================================================
// Constructors
// ===========================================================
public SmartPVRTexturePixelBufferStrategy(final int pAllocationSizeMaximum) {
this.mAllocationSizeMaximum = pAllocationSizeMaximum;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public IPVRTexturePixelBufferStrategyBufferManager newPVRTexturePixelBufferStrategyManager(final PVRTexture pPVRTexture) throws IOException {
return new SmartPVRTexturePixelBufferStrategyBufferManager(pPVRTexture);
}
@Override
public void loadPVRTextureData(final IPVRTexturePixelBufferStrategyBufferManager pPVRTexturePixelBufferStrategyManager, final int pWidth, final int pHeight, final int pBytesPerPixel, final PixelFormat pPixelFormat, final int pLevel, final int pCurrentPixelDataOffset, final int pCurrentPixelDataSize) throws IOException {
final int glFormat = pPixelFormat.getGLFormat();
final int glType = pPixelFormat.getGLType();
/* Create the texture with the required parameters but without data. */
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, pLevel, pPixelFormat.getGLInternalFormat(), pWidth, pHeight, 0, glFormat, glType, null);
final int bytesPerRow = pWidth * pBytesPerPixel;
final int stripeHeight = Math.max(1, this.mAllocationSizeMaximum / bytesPerRow);
/* Load stripes. */
int currentStripePixelDataOffset = pCurrentPixelDataOffset;
int currentStripeOffsetY = 0;
while(currentStripeOffsetY < pHeight) {
final int currentStripeHeight = Math.min(pHeight - currentStripeOffsetY, stripeHeight);
final int currentStripePixelDataSize = currentStripeHeight * bytesPerRow;
/* Adjust buffer. */
final Buffer pixelBuffer = pPVRTexturePixelBufferStrategyManager.getPixelBuffer(PVRTextureHeader.SIZE + currentStripePixelDataOffset, currentStripePixelDataSize);
/* Send to hardware. */
GLES20.glTexSubImage2D(GLES20.GL_TEXTURE_2D, pLevel, 0, currentStripeOffsetY, pWidth, currentStripeHeight, glFormat, glType, pixelBuffer);
currentStripePixelDataOffset += currentStripePixelDataSize;
currentStripeOffsetY += currentStripeHeight;
}
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static class SmartPVRTexturePixelBufferStrategyBufferManager implements IPVRTexturePixelBufferStrategyBufferManager {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final InputStream mInputStream;
private int mInputStreamPosition;
private byte[] mData;
// ===========================================================
// Constructors
// ===========================================================
public SmartPVRTexturePixelBufferStrategyBufferManager(final PVRTexture pPVRTexture) throws IOException {
this.mInputStream = pPVRTexture.getInputStream();
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public ByteBuffer getPixelBuffer(final int pStart, final int pByteCount) throws IOException {
if(pStart < this.mInputStreamPosition) {
throw new AndEngineRuntimeException("Cannot read data that has been read already. (pStart: '" + pStart + "', this.mInputStreamPosition: '" + this.mInputStreamPosition + "')");
}
/* Ensure data buffer is bug enough. */
if(this.mData == null || this.mData.length < pByteCount) {
this.mData = new byte[pByteCount];
}
/* If needed, skip bytes up to where the data was requested. */
if(this.mInputStreamPosition < pStart) {
final int bytesToSkip = pStart - this.mInputStreamPosition;
final long skipped = this.mInputStream.skip(bytesToSkip);
this.mInputStreamPosition += skipped;
if(bytesToSkip != skipped) {
throw new AndEngineRuntimeException("Skipped: '" + skipped + "' instead of '" + bytesToSkip + "'.");
}
}
/* Read the requested data. */
final int bytesToRead = pStart + pByteCount - this.mInputStreamPosition;
StreamUtils.streamToBytes(this.mInputStream, bytesToRead, this.mData);
this.mInputStreamPosition += bytesToRead;
/* Return as a buffer. */
return ByteBuffer.wrap(this.mData, 0, pByteCount);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
}