public static class

SmartPVRTexturePixelBufferStrategy.SmartPVRTexturePixelBufferStrategyBufferManager

extends Object
implements IPVRTexturePixelBufferStrategy.IPVRTexturePixelBufferStrategyBufferManager
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
		// ===========================================================
	}
}