<commit_before>// ================================================================================
// == This file is a part of TinkerBell UI Toolkit. (C) 2011-2013, <NAME>  ==
// ==                   See tinkerbell.h for more information.                   ==
// ================================================================================

#include <assert.h>
#include <stdio.h>
#include "tb_renderer_gl.h"
#include "tb_bitmap_fragment.h"

namespace tinkerbell {

// == Utilities ===================================================================================

static void Ortho2D(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top)
{
#ifdef USE_GLES
	glOrthof(left, right, bottom, top, -1.0, 1.0);
#else
	glOrtho(left, right, bottom, top, -1.0, 1.0);
#endif
}

// == Batching ====================================================================================

#define VERTEX_BATCH_SIZE 6 * 2048

#define VER_COL(r, g, b, a) (((a)<<24) + ((b)<<16) + ((g)<<8) + r)
#define VER_COL_OPACITY(a) (0x00ffffff + (((uint32)a) << 24))

struct Vertex {
	float x, y;
	float u, v;
	union {
		unsigned char r, g, b, a;
		uint32 col;
	};
};

GLuint g_current_texture = (GLuint)-1;
class Batch *g_current_batch = 0;

void BindBitmap(TBBitmap *bitmap)
{
	GLuint texture = bitmap ? static_cast<TBBitmapGL*>(bitmap)->m_texture : 0;
	if (texture != g_current_texture)
	{
		g_current_texture = texture;
		glBindTexture(GL_TEXTURE_2D, g_current_texture);
	}
}

class Batch
{
public:
	Batch() : vertex_count(0), bitmap(nullptr), fragment(nullptr), is_flushing(false), batch_id(0) {}
	void Flush();
	void AddVertex(int x, int y, float u, float v, uint32 color);
//private:
	Vertex vertex[VERTEX_BATCH_SIZE];
	int vertex_count;

	TBBitmap *bitmap;
	TBBitmapFragment *fragment;
	bool is_flushing;
	uint32 batch_id;
};

void Batch::Flush()
{
	if (!vertex_count || is_flushing)
		return;

	// Prevent re-entrancy. Calling fragment->GetBitmap may end up calling TBBitmap::SetData
	// which will end up flushing any existing batch with that bitmap.
	is_flushing = true;

	if (fragment)
	{
		// Now it's time to ensure the bitmap data is up to date. A call to GetBitmap
		// with TB_VALIDATE_ALWAYS should guarantee that its data is validated.
		TBBitmap *frag_bitmap = fragment->GetBitmap(TB_VALIDATE_ALWAYS);
		assert(frag_bitmap == bitmap);
	}

	// Bind texture and array pointers
	BindBitmap(bitmap);
	if (g_current_batch != this)
	{
		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void *) &vertex[0].r);
		glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void *) &vertex[0].u);
		glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (void *) &vertex[0].x);
		g_current_batch = this;
	}

	// Flush
	glDrawArrays(GL_TRIANGLES, 0, vertex_count);
	vertex_count = 0;

	batch_id++; // Will overflow eventually, but that doesn't really matter.

	is_flushing = false;
}

void Batch::AddVertex(int x, int y, float u, float v, uint32 color)
{
	vertex[vertex_count].x = (float)x;
	vertex[vertex_count].y = (float)y;
	vertex[vertex_count].u = u;
	vertex[vertex_count].v = v;
	vertex[vertex_count].col = color;
	vertex_count++;

	if (vertex_count == VERTEX_BATCH_SIZE)
		Flush();
}

/** Extreemly simple batcher (only maintains one batch and flushes when texture changes) */
class BatchRenderer
{
public:
	float u, v, uu, vv; ///< Some temp variables

	void AddQuad(const TBRect &dst_rect, const TBRect &src_rect, uint32 color, TBBitmap *bitmap, TBBitmapFragment *fragment)
	{
		if (batch.bitmap != bitmap)
		{
			batch.Flush();
			batch.bitmap = bitmap;
		}
		batch.fragment = fragment;
		if (TBBitmapGL *b = static_cast<TBBitmapGL*>(bitmap))
		{
			u = (float)src_rect.x / b->m_w;
			v = (float)src_rect.y / b->m_h;
			uu = (float)(src_rect.x + src_rect.w) / b->m_w;
			vv = (float)(src_rect.y + src_rect.h) / b->m_h;
		}
		batch.AddVertex(dst_rect.x, dst_rect.y + dst_rect.h, u, vv, color);
		batch.AddVertex(dst_rect.x + dst_rect.w, dst_rect.y + dst_rect.h, uu, vv, color);
		batch.AddVertex(dst_rect.x, dst_rect.y, u, v, color);

		batch.AddVertex(dst_rect.x, dst_rect.y, u, v, color);
		batch.AddVertex(dst_rect.x + dst_rect.w, dst_rect.y + dst_rect.h, uu, vv, color);
		batch.AddVertex(dst_rect.x + dst_rect.w, dst_rect.y, uu, v, color);

		// Update fragments batch id (See FlushBitmapFragment)
		if (fragment)
			fragment->m_batch_id = batch.batch_id;
	}
	void Flush()
	{
		batch.Flush();
	}
	void FlushBitmap(TBBitmap *bitmap)
	{
		// Flush the batch if it's using this bitmap (that is about to change or be deleted)
		if (batch.vertex_count && bitmap == batch.bitmap)
			batch.Flush();
	}
	void FlushBitmapFragment(TBBitmapFragment *bitmap_fragment)
	{
		// Flush the batch if it is using this fragment (that is about to change or be deleted)
		// We know if it is in use in the current batch if its batch_id matches the current
		// batch_id in our (one and only) batch.
		// If we switch to a more advance batching system with multiple batches, we need to
		// solve this a bit differently.
		if (batch.vertex_count && bitmap_fragment->m_batch_id == batch.batch_id)
			batch.Flush();<commit_msg>Optimized triangle throughput slightly on some compilers.<commit_after>// ================================================================================
// == This file is a part of TinkerBell UI Toolkit. (C) 2011-2013, <NAME>  ==
// ==                   See tinkerbell.h for more information.                   ==
// ================================================================================

#include <assert.h>
#include <stdio.h>
#include "tb_renderer_gl.h"
#include "tb_bitmap_fragment.h"

namespace tinkerbell {

// == Utilities ===================================================================================

static void Ortho2D(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top)
{
#ifdef USE_GLES
	glOrthof(left, right, bottom, top, -1.0, 1.0);
#else
	glOrtho(left, right, bottom, top, -1.0, 1.0);
#endif
}

// == Batching ====================================================================================

#define VERTEX_BATCH_SIZE 6 * 2048

#define VER_COL(r, g, b, a) (((a)<<24) + ((b)<<16) + ((g)<<8) + r)
#define VER_COL_OPACITY(a) (0x00ffffff + (((uint32)a) << 24))

struct Vertex {
	float x, y;
	float u, v;
	union {
		unsigned char r, g, b, a;
		uint32 col;
	};
};

GLuint g_current_texture = (GLuint)-1;
class Batch *g_current_batch = 0;

void BindBitmap(TBBitmap *bitmap)
{
	GLuint texture = bitmap ? static_cast<TBBitmapGL*>(bitmap)->m_texture : 0;
	if (texture != g_current_texture)
	{
		g_current_texture = texture;
		glBindTexture(GL_TEXTURE_2D, g_current_texture);
	}
}

class Batch
{
public:
	Batch() : vertex_count(0), bitmap(nullptr), fragment(nullptr), is_flushing(false), batch_id(0) {}
	void Flush();
	Vertex *Reserve(int count);
//private:
	Vertex vertex[VERTEX_BATCH_SIZE];
	int vertex_count;

	TBBitmap *bitmap;
	TBBitmapFragment *fragment;
	bool is_flushing;
	uint32 batch_id;
};

void Batch::Flush()
{
	if (!vertex_count || is_flushing)
		return;

	// Prevent re-entrancy. Calling fragment->GetBitmap may end up calling TBBitmap::SetData
	// which will end up flushing any existing batch with that bitmap.
	is_flushing = true;

	if (fragment)
	{
		// Now it's time to ensure the bitmap data is up to date. A call to GetBitmap
		// with TB_VALIDATE_ALWAYS should guarantee that its data is validated.
		TBBitmap *frag_bitmap = fragment->GetBitmap(TB_VALIDATE_ALWAYS);
		assert(frag_bitmap == bitmap);
	}

	// Bind texture and array pointers
	BindBitmap(bitmap);
	if (g_current_batch != this)
	{
		glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(Vertex), (void *) &vertex[0].r);
		glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), (void *) &vertex[0].u);
		glVertexPointer(2, GL_FLOAT, sizeof(Vertex), (void *) &vertex[0].x);
		g_current_batch = this;
	}

	// Flush
	glDrawArrays(GL_TRIANGLES, 0, vertex_count);
	vertex_count = 0;

	batch_id++; // Will overflow eventually, but that doesn't really matter.

	is_flushing = false;
}

Vertex *Batch::Reserve(int count)
{
	assert(count < VERTEX_BATCH_SIZE);
	if (vertex_count + count > VERTEX_BATCH_SIZE)
		Flush();
	Vertex *ret = &vertex[vertex_count];
	vertex_count += count;
	return ret;
}

/** Extreemly simple batcher (only maintains one batch and flushes when texture changes) */
class BatchRenderer
{
public:
	float u, v, uu, vv; ///< Some temp variables

	void AddQuad(const TBRect &dst_rect, const TBRect &src_rect, uint32 color, TBBitmap *bitmap, TBBitmapFragment *fragment)
	{
		if (batch.bitmap != bitmap)
		{
			batch.Flush();
			batch.bitmap = bitmap;
		}
		batch.fragment = fragment;
		if (TBBitmapGL *b = static_cast<TBBitmapGL*>(bitmap))
		{
			u = (float)src_rect.x / b->m_w;
			v = (float)src_rect.y / b->m_h;
			uu = (float)(src_rect.x + src_rect.w) / b->m_w;
			vv = (float)(src_rect.y + src_rect.h) / b->m_h;
		}
		Vertex *ver = batch.Reserve(6);
		ver[0].x = dst_rect.x;
		ver[0].y = dst_rect.y + dst_rect.h;
		ver[0].u = u;
		ver[0].v = vv;
		ver[0].col = color;
		ver[1].x = dst_rect.x + dst_rect.w;
		ver[1].y = dst_rect.y + dst_rect.h;
		ver[1].u = uu;
		ver[1].v = vv;
		ver[1].col = color;
		ver[2].x = dst_rect.x;
		ver[2].y = dst_rect.y;
		ver[2].u = u;
		ver[2].v = v;
		ver[2].col = color;

		ver[3].x = dst_rect.x;
		ver[3].y = dst_rect.y;
		ver[3].u = u;
		ver[3].v = v;
		ver[3].col = color;
		ver[4].x = dst_rect.x + dst_rect.w;
		ver[4].y = dst_rect.y + dst_rect.h;
		ver[4].u = uu;
		ver[4].v = vv;
		ver[4].col = color;
		ver[5].x = dst_rect.x + dst_rect.w;
		ver[5].y = dst_rect.y;
		ver[5].u = uu;
		ver[5].v = v;
		ver[5].col = color;

		// Update fragments batch id (See FlushBitmapFragment)
		if (fragment)
			fragment->m_batch_id = batch.batch_id;
	}
	void Flush()
	{
		batch.Flush();
	}
	void FlushBitmap(TBBitmap *bitmap)
	{
		// Flush the batch if it's using this bitmap (that is about to change or be deleted)
		if (batch.vertex_count && bitmap == batch.bitmap)
			batch.Flush();
	}
	void FlushBitmapFragment(TBBitmapFragment *bitmap_fragment)
	{
		// Flush the batch if it is using this fragment (that is about to change or be deleted)
		// We know if it is in use in the current batch if its batch_id matches the current
		// batch_id in our (one and only) batch.
		// If we switch to a more advance batching system with multiple batches, we need to
		// solve this a bit differently.
		if (batch.vertex_count && bitmap_fragment->m_batch_id == batch.batch_id)
			batch.Flush();
{'fraction_non_alphanumeric': 0.19519461797212878, 'fraction_numerical': 0.013743392599711676, 'mean_word_length': 4.123584441161989, 'pattern_counts': {'":': 0, '<': 32, '<?xml version=': 0, '>': 32, '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': '5428584', 'n_tokens_mistral': 4016, 'n_tokens_neox': 3778, 'n_words': 983}