<commit_before>#include "dtex2/CacheGlyph.h"
#include "dtex2/TextureMid.h"
#include "dtex2/DebugDraw.h"
#include "dtex2/RenderAPI.h"
#include "dtex2/DrawTexture.h"
#include "dtex2/ResourceAPI.h"

#include <cu/cu_stl.h>
#include <texpack.h>
#include <unirender/PixelBuffer.h>

#include <algorithm>

#include <string.h>

namespace dtex
{

static const int MAX_NODE_SIZE = 512;

static const int PADDING = 1;

CacheGlyph::CacheGlyph(int width, int height, const Callback& cb)
	: m_width(width)
	, m_height(height)
	, m_cb(cb)
{
	m_pbuf = ur::PixelBuffer::Create(RenderAPI::GetRenderContext(), width, height, ur::TEXTURE_RGBA8, true);
	m_pbuf->Clear();
	m_tex = new TextureMid(width, height, 4, true);
	m_tp  = texpack_create(width, height, MAX_NODE_SIZE);

	InitDirtyRect();

	if (!m_tex || !m_tp) {
		ResourceAPI::ErrorReload();
	}
}

CacheGlyph::~CacheGlyph()
{
	delete m_tex;
	texpack_release(m_tp);
}

void CacheGlyph::DebugDraw() const
{
	DebugDraw::Draw(m_tex->GetID(), 2);
}

void CacheGlyph::Clear()
{
	m_pbuf->Clear();
	DrawTexture::ClearAllTex(m_tex);
	texpack_clear(m_tp);

	m_all_nodes.clear();
	m_new_nodes.clear();

	InitDirtyRect();
}

void CacheGlyph::Load(uint32_t* bitmap, int width, int height, uint64_t key)
{
	if (!bitmap) {
		return;
	}
	if (Exist(key)) {
		return;
	}

	texpack_pos* pos = texpack_add(m_tp, width + PADDING * 2, height + PADDING * 2, false);
	if (!pos) 
	{
		Flush();
		RenderAPI::Flush();
		Clear();
		pos = texpack_add(m_tp, width + PADDING * 2, height + PADDING * 2, false);
		if (!pos) {
			return;
		}
	}

	Rect r;
	r.xmin = pos->r.xmin + PADDING;
	r.ymin = pos->r.ymin + PADDING;
	r.xmax = pos->r.xmax - PADDING;
	r.ymax = pos->r.ymax - PADDING;
	auto node = std::make_pair(key, r);
	m_all_nodes.insert(node);
	m_new_nodes.push_back(node);

	uint32_t* bmp_buf = (uint32_t*)m_pbuf->Map(ur::WRITE_ONLY);
	int src_ptr = 0;
	for (int y = 0; y < height; ++y) {
		for (int x = 0; x < width; ++x) {
			uint32_t src = bitmap[src_ptr++];
			uint8_t r = (src >> 24) & 0xff;
			uint8_t g = (src >> 16) & 0xff;
			uint8_t b = (src >> 8) & 0xff;
			uint8_t a = src & 0xff;

			int dst_ptr = (pos->r.ymin + PADDING + y) * m_width + pos->r.xmin + PADDING + x;
			bmp_buf[dst_ptr] = a << 24 | b << 16 | g << 8 | r;
		}
	}

	UpdateDirtyRect(pos);
}

void CacheGlyph::Flush()
{
	if (m_new_nodes.empty()) {
		return;
	}

	UpdateTexture();

	m_cb.load_start();
	for (int i = 0, n = m_new_nodes.size(); i < n; ++i) {
		m_cb.load(m_tex->GetID(), m_tex->GetWidth(), m_tex->GetHeight(), 
			m_new_nodes[i].second, m_new_nodes[i].first);
	}
	m_new_nodes.clear();
	m_cb.load_finish();

	InitDirtyRect();
}

bool CacheGlyph::QueryAndInsert(uint64_t key, float* texcoords, int& tex_id) const
{
	auto itr = m_all_nodes.find(key);
	if (itr == m_all_nodes.end()) {
		return false;
	}

	m_new_nodes.push_back(*itr);

	tex_id = m_tex->GetID();

	const Rect& r = itr->second;
	float xmin = r.xmin / static_cast<float>(m_width),
		  ymin = r.ymin / static_cast<float>(m_height),
		  xmax = r.xmax / static_cast<float>(m_width),
		  ymax = r.ymax / static_cast<float>(m_height);
	texcoords[0] = xmin; texcoords[1] = ymin;
	texcoords[2] = xmax; texcoords[3] = ymin;
	texcoords[4] = xmax; texcoords[5] = ymax;
	texcoords[6] = xmin; texcoords[7] = ymax;
	
	return true;
}

void CacheGlyph::InitDirtyRect()
{
	m_dirty_rect.xmax = m_dirty_rect.ymax = 0;
	m_dirty_rect.xmin = m_width;
	m_dirty_rect.ymin = m_height;
}

void CacheGlyph::UpdateDirtyRect(const texpack_pos* pos)
{<commit_msg>[FIXED] unbind fbo<commit_after>#include "dtex2/CacheGlyph.h"
#include "dtex2/TextureMid.h"
#include "dtex2/DebugDraw.h"
#include "dtex2/RenderAPI.h"
#include "dtex2/DrawTexture.h"
#include "dtex2/ResourceAPI.h"

#include <cu/cu_stl.h>
#include <texpack.h>
#include <unirender/PixelBuffer.h>
#include <unirender/RenderContext.h>

#include <algorithm>

#include <string.h>

namespace dtex
{

static const int MAX_NODE_SIZE = 512;

static const int PADDING = 1;

CacheGlyph::CacheGlyph(int width, int height, const Callback& cb)
	: m_width(width)
	, m_height(height)
	, m_cb(cb)
{
	m_pbuf = ur::PixelBuffer::Create(RenderAPI::GetRenderContext(), width, height, ur::TEXTURE_RGBA8, true);
	m_pbuf->Clear();
	m_tex = new TextureMid(width, height, 4, true);
	m_tp  = texpack_create(width, height, MAX_NODE_SIZE);

	InitDirtyRect();

	if (!m_tex || !m_tp) {
		ResourceAPI::ErrorReload();
	}
}

CacheGlyph::~CacheGlyph()
{
	delete m_tex;
	texpack_release(m_tp);
}

void CacheGlyph::DebugDraw() const
{
	DebugDraw::Draw(m_tex->GetID(), 2);
}

void CacheGlyph::Clear()
{
	m_pbuf->Clear();
	DrawTexture::ClearAllTex(m_tex);
	texpack_clear(m_tp);

	m_all_nodes.clear();
	m_new_nodes.clear();

	InitDirtyRect();
}

void CacheGlyph::Load(uint32_t* bitmap, int width, int height, uint64_t key)
{
	if (!bitmap) {
		return;
	}
	if (Exist(key)) {
		return;
	}

	texpack_pos* pos = texpack_add(m_tp, width + PADDING * 2, height + PADDING * 2, false);
	if (!pos)
	{
		Flush();
		RenderAPI::Flush();
		Clear();
		pos = texpack_add(m_tp, width + PADDING * 2, height + PADDING * 2, false);
		if (!pos) {
			return;
		}
	}

	Rect r;
	r.xmin = pos->r.xmin + PADDING;
	r.ymin = pos->r.ymin + PADDING;
	r.xmax = pos->r.xmax - PADDING;
	r.ymax = pos->r.ymax - PADDING;
	auto node = std::make_pair(key, r);
	m_all_nodes.insert(node);
	m_new_nodes.push_back(node);

	uint32_t* bmp_buf = (uint32_t*)m_pbuf->Map(ur::WRITE_ONLY);
	int src_ptr = 0;
	for (int y = 0; y < height; ++y) {
		for (int x = 0; x < width; ++x) {
			uint32_t src = bitmap[src_ptr++];
			uint8_t r = (src >> 24) & 0xff;
			uint8_t g = (src >> 16) & 0xff;
			uint8_t b = (src >> 8) & 0xff;
			uint8_t a = src & 0xff;

			int dst_ptr = (pos->r.ymin + PADDING + y) * m_width + pos->r.xmin + PADDING + x;
			bmp_buf[dst_ptr] = a << 24 | b << 16 | g << 8 | r;
		}
	}

	UpdateDirtyRect(pos);
}

void CacheGlyph::Flush()
{
	if (m_new_nodes.empty()) {
		return;
	}

	UpdateTexture();

	m_cb.load_start();
	for (int i = 0, n = m_new_nodes.size(); i < n; ++i) {
		m_cb.load(m_tex->GetID(), m_tex->GetWidth(), m_tex->GetHeight(),
			m_new_nodes[i].second, m_new_nodes[i].first);
	}
	m_new_nodes.clear();
	m_cb.load_finish();

	InitDirtyRect();

	// unbind fbo
	RenderAPI::GetRenderContext()->UnbindPixelBuffer();
}

bool CacheGlyph::QueryAndInsert(uint64_t key, float* texcoords, int& tex_id) const
{
	auto itr = m_all_nodes.find(key);
	if (itr == m_all_nodes.end()) {
		return false;
	}

	m_new_nodes.push_back(*itr);

	tex_id = m_tex->GetID();

	const Rect& r = itr->second;
	float xmin = r.xmin / static_cast<float>(m_width),
		  ymin = r.ymin / static_cast<float>(m_height),
		  xmax = r.xmax / static_cast<float>(m_width),
		  ymax = r.ymax / static_cast<float>(m_height);
	texcoords[0] = xmin; texcoords[1] = ymin;
	texcoords[2] = xmax; texcoords[3] = ymin;
	texcoords[4] = xmax; texcoords[5] = ymax;
	texcoords[6] = xmin; texcoords[7] = ymax;

	return true;
}

void CacheGlyph::InitDirtyRect()
{
	m_dirty_rect.xmax = m_dirty_rect.ymax = 0;
	m_dirty_rect.xmin = m_width;
	m_dirty_rect.ymin = m_height;
}

void CacheGlyph::UpdateDirtyRect(const texpack_pos* pos)
{
{'fraction_non_alphanumeric': 0.17075924357888794, 'fraction_numerical': 0.01693480101608806, 'mean_word_length': 4.328571428571428, 'pattern_counts': {'":': 0, '<': 40, '<?xml version=': 0, '>': 65, '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': '5964628', 'n_tokens_mistral': 3296, 'n_tokens_neox': 3112, 'n_words': 599}