<commit_before>package com.miviclin.droidengine2d.graphics.sprites;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;

import com.miviclin.droidengine2d.graphics.GLDebug;
import com.miviclin.droidengine2d.graphics.cameras.Camera;
import com.miviclin.droidengine2d.graphics.shaders.DynamicSpriteBatchShaderProgram;
import com.miviclin.droidengine2d.graphics.textures.Texture;
import com.miviclin.droidengine2d.util.TransformUtilities;
import com.miviclin.droidengine2d.util.math.Matrix4;

/**
 * SpriteBatch que permite renderizar en una llamada hasta 32 sprites con transformaciones (traslacion, rotacion y escala) distintas.
 * 
 * @author <NAME>
 * 
 */
public class DynamicSpriteBatch implements SpriteBatch {
	
	private static final int FLOAT_SIZE_BYTES = 4;
	private static final int SHORT_SIZE_BYTES = 4;
	
	private static final int VERTICES_DATA_STRIDE = 5;
	private static final int VERTICES_DATA_STRIDE_BYTES = VERTICES_DATA_STRIDE * FLOAT_SIZE_BYTES;
	private static final int VERTICES_DATA_POS_OFFSET = 0;
	private static final int VERTICES_DATA_UV_OFFSET = 3;
	
	private final float[] temp = new float[16];
	
	private float[] verticesData;
	private float[] mvpIndices;
	private float[] mvpMatrices;
	private short[] indices;
	
	private ShortBuffer indexBuffer;
	private FloatBuffer vertexBuffer;
	private FloatBuffer mvpIndexBuffer;
	
	private int batchCapacity;
	private int batchSize;
	
	private Matrix4 modelMatrix;
	private Texture texture;
	private Context context;
	private DynamicSpriteBatchShaderProgram shaderProgram;
	private boolean inBeginEndPair;
	private boolean requestTextureBind;
	
	/**
	 * Crea un DynamicSpriteBatch
	 * 
	 * @param context Context en el que se ejecuta el juego
	 * @param shaderProgram programa de shaders que se utilizara para renderizar los batches
	 */
	public DynamicSpriteBatch(Context context, DynamicSpriteBatchShaderProgram shaderProgram) {
		this.context = context;
		this.shaderProgram = shaderProgram;
		this.batchCapacity = 32;
		this.batchSize = 0;
		this.indices = new short[batchCapacity * 6];
		this.verticesData = new float[batchCapacity * 4 * VERTICES_DATA_STRIDE];
		this.mvpIndices = new float[batchCapacity * 4];
		this.mvpMatrices = new float[batchCapacity * 16];
		this.modelMatrix = new Matrix4();
		this.texture = null;
		this.inBeginEndPair = false;
		
		setupIndices();
		setupMVPIndices();
		setupVerticesData();
		
		indexBuffer = ByteBuffer.allocateDirect(indices.length * SHORT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asShortBuffer();
		indexBuffer.put(indices).flip();
		
		vertexBuffer = ByteBuffer.allocateDirect(verticesData.length * FLOAT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		vertexBuffer.put(verticesData).flip();
		
		mvpIndexBuffer = ByteBuffer.allocateDirect(mvpIndices.length * FLOAT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		mvpIndexBuffer.put(mvpIndices).flip();
	}
	
	/**
	 * Inicializa el array de indices de los vertices que definen la geometria de la malla de sprites
	 */
	private void setupIndices() {
		for (int i = 0, j = 0; i < indices.length; i += 6, j += 4) {
			indices[i + 0] = (short) (j + 0);
			indices[i + 1] = (short) (j + 1);
			indices[i + 2] = (short) (j + 2);
			indices[i + 3] = (short) (j + 2);
			indices[i + 4] = (short) (j + 3);
			indices[i + 5] = (short) (j + 0);
		}
	}
	
	/**
	 * Inicializa el array de indices que permiten acceder a las matrices MVP en el vertex shader.
	 */
	private void setupMVPIndices() {
		float value = 0.0f;
		for (int i = 0; i < mvpIndices.length; i++) {
			if ((i != 0) && (i % 4 == 0)) {
				value += 1.0f;
			}
			mvpIndices[i] = value;
		}
	}
	
	/**
	 * Inicializa el array de vertices que definen la geometria de la malla del batch
	 */
	private void setupVerticesData() {
		for (int i = 0; i < verticesData.length; i += 20) {
			// Bottom-Left
			verticesData[i + 0] = -0.5f;
			verticesData[i + 1] = -0.5f;
			verticesData[i + 2] = 0.0f;
			verticesData[i + 3] = 0.0f;
			verticesData[i + 4] = 1.0f;
			// Bottom-Right
			verticesData[i + 5] = 0.5f;
			verticesData[i + 6] = -0.5f;
			verticesData[i + 7] = 0.0f;
			verticesData[i + 8] = 1.0f;
			verticesData[i + 9] = 1.0f;
			// Top-Right
			verticesData[i + 10] = 0.5f;
			verticesData[i + 11] = 0.5f;
			verticesData[i + 12] = 0.0f;
			verticesData[i + 13] = 1.0f;
			verticesData[i + 14] = 0.0f;
			// Top-Left
			verticesData[i + 15] = -0.5f;
			verticesData[i + 16] = 0.5f;
			verticesData[i + 17] = 0.0f;
			verticesData[i + 18] = 0.0f;
			verticesData[i + 19] = 0.0f;
		}
	}
	
	@Override
	public void begin() {
		if (inBeginEndPair) {
			throw new RuntimeException("begin() can not be called more than once before calling end()");
		}
		if (!shaderProgram.isLinked()) {
			shaderProgram.link();
		}
		shaderProgram.use();
		inBeginEndPair = true;
		requestTextureBind = true;
	}
	
	@Override
	public void draw(Sprite sprite, Camera camera) {
		if (!inBeginEndPair) {
			throw new RuntimeException("begin() can not be called more than once before calling draw(Sprite, Camera)");
		}
		drawSprite(sprite, camera);
	}
	
	@Override
	public void end() {
		if (!inBeginEndPair) {
			throw new RuntimeException("begin() must be called once before calling end()");
		}
		if (batchSize > 0) {
			drawBatch();
		}
		inBeginEndPair = false;
	}
	
	/**
	 * Prepara los datos de la geometria para ser enviados a los shaders
	 */
	public void setupVertexShaderVariables() {<commit_msg>Fix the exception message of DynamicSpriteBatch.draw(...)<commit_after>package com.miviclin.droidengine2d.graphics.sprites;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;

import android.content.Context;
import android.opengl.GLES20;
import android.opengl.Matrix;

import com.miviclin.droidengine2d.graphics.GLDebug;
import com.miviclin.droidengine2d.graphics.cameras.Camera;
import com.miviclin.droidengine2d.graphics.shaders.DynamicSpriteBatchShaderProgram;
import com.miviclin.droidengine2d.graphics.textures.Texture;
import com.miviclin.droidengine2d.util.TransformUtilities;
import com.miviclin.droidengine2d.util.math.Matrix4;

/**
 * SpriteBatch que permite renderizar en una llamada hasta 32 sprites con transformaciones (traslacion, rotacion y escala) distintas.
 * 
 * @author <NAME>
 * 
 */
public class DynamicSpriteBatch implements SpriteBatch {
	
	private static final int FLOAT_SIZE_BYTES = 4;
	private static final int SHORT_SIZE_BYTES = 4;
	
	private static final int VERTICES_DATA_STRIDE = 5;
	private static final int VERTICES_DATA_STRIDE_BYTES = VERTICES_DATA_STRIDE * FLOAT_SIZE_BYTES;
	private static final int VERTICES_DATA_POS_OFFSET = 0;
	private static final int VERTICES_DATA_UV_OFFSET = 3;
	
	private final float[] temp = new float[16];
	
	private float[] verticesData;
	private float[] mvpIndices;
	private float[] mvpMatrices;
	private short[] indices;
	
	private ShortBuffer indexBuffer;
	private FloatBuffer vertexBuffer;
	private FloatBuffer mvpIndexBuffer;
	
	private int batchCapacity;
	private int batchSize;
	
	private Matrix4 modelMatrix;
	private Texture texture;
	private Context context;
	private DynamicSpriteBatchShaderProgram shaderProgram;
	private boolean inBeginEndPair;
	private boolean requestTextureBind;
	
	/**
	 * Crea un DynamicSpriteBatch
	 * 
	 * @param context Context en el que se ejecuta el juego
	 * @param shaderProgram programa de shaders que se utilizara para renderizar los batches
	 */
	public DynamicSpriteBatch(Context context, DynamicSpriteBatchShaderProgram shaderProgram) {
		this.context = context;
		this.shaderProgram = shaderProgram;
		this.batchCapacity = 32;
		this.batchSize = 0;
		this.indices = new short[batchCapacity * 6];
		this.verticesData = new float[batchCapacity * 4 * VERTICES_DATA_STRIDE];
		this.mvpIndices = new float[batchCapacity * 4];
		this.mvpMatrices = new float[batchCapacity * 16];
		this.modelMatrix = new Matrix4();
		this.texture = null;
		this.inBeginEndPair = false;
		
		setupIndices();
		setupMVPIndices();
		setupVerticesData();
		
		indexBuffer = ByteBuffer.allocateDirect(indices.length * SHORT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asShortBuffer();
		indexBuffer.put(indices).flip();
		
		vertexBuffer = ByteBuffer.allocateDirect(verticesData.length * FLOAT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		vertexBuffer.put(verticesData).flip();
		
		mvpIndexBuffer = ByteBuffer.allocateDirect(mvpIndices.length * FLOAT_SIZE_BYTES)
				.order(ByteOrder.nativeOrder())
				.asFloatBuffer();
		mvpIndexBuffer.put(mvpIndices).flip();
	}
	
	/**
	 * Inicializa el array de indices de los vertices que definen la geometria de la malla de sprites
	 */
	private void setupIndices() {
		for (int i = 0, j = 0; i < indices.length; i += 6, j += 4) {
			indices[i + 0] = (short) (j + 0);
			indices[i + 1] = (short) (j + 1);
			indices[i + 2] = (short) (j + 2);
			indices[i + 3] = (short) (j + 2);
			indices[i + 4] = (short) (j + 3);
			indices[i + 5] = (short) (j + 0);
		}
	}
	
	/**
	 * Inicializa el array de indices que permiten acceder a las matrices MVP en el vertex shader.
	 */
	private void setupMVPIndices() {
		float value = 0.0f;
		for (int i = 0; i < mvpIndices.length; i++) {
			if ((i != 0) && (i % 4 == 0)) {
				value += 1.0f;
			}
			mvpIndices[i] = value;
		}
	}
	
	/**
	 * Inicializa el array de vertices que definen la geometria de la malla del batch
	 */
	private void setupVerticesData() {
		for (int i = 0; i < verticesData.length; i += 20) {
			// Bottom-Left
			verticesData[i + 0] = -0.5f;
			verticesData[i + 1] = -0.5f;
			verticesData[i + 2] = 0.0f;
			verticesData[i + 3] = 0.0f;
			verticesData[i + 4] = 1.0f;
			// Bottom-Right
			verticesData[i + 5] = 0.5f;
			verticesData[i + 6] = -0.5f;
			verticesData[i + 7] = 0.0f;
			verticesData[i + 8] = 1.0f;
			verticesData[i + 9] = 1.0f;
			// Top-Right
			verticesData[i + 10] = 0.5f;
			verticesData[i + 11] = 0.5f;
			verticesData[i + 12] = 0.0f;
			verticesData[i + 13] = 1.0f;
			verticesData[i + 14] = 0.0f;
			// Top-Left
			verticesData[i + 15] = -0.5f;
			verticesData[i + 16] = 0.5f;
			verticesData[i + 17] = 0.0f;
			verticesData[i + 18] = 0.0f;
			verticesData[i + 19] = 0.0f;
		}
	}
	
	@Override
	public void begin() {
		if (inBeginEndPair) {
			throw new RuntimeException("begin() can not be called more than once before calling end()");
		}
		if (!shaderProgram.isLinked()) {
			shaderProgram.link();
		}
		shaderProgram.use();
		inBeginEndPair = true;
		requestTextureBind = true;
	}
	
	@Override
	public void draw(Sprite sprite, Camera camera) {
		if (!inBeginEndPair) {
			throw new RuntimeException("begin() must be called once before calling draw(Sprite, Camera)");
		}
		drawSprite(sprite, camera);
	}
	
	@Override
	public void end() {
		if (!inBeginEndPair) {
			throw new RuntimeException("begin() must be called once before calling end()");
		}
		if (batchSize > 0) {
			drawBatch();
		}
		inBeginEndPair = false;
	}
	
	/**
	 * Prepara los datos de la geometria para ser enviados a los shaders
	 */
	public void setupVertexShaderVariables() {
{'fraction_non_alphanumeric': 0.11695802644422752, 'fraction_numerical': 0.02253971071079954, 'mean_word_length': 3.847311827956989, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '18059', 'n_tokens_mistral': 4464, 'n_tokens_neox': 3891, 'n_words': 1006}