thunderbrew/src/gx/font/CGxFont.cpp
2023-03-27 17:46:26 -05:00

929 lines
26 KiB
C++

#include "gx/font/CGxFont.hpp"
#include "gx/font/FontFace.hpp"
#include "gx/Texture.hpp"
#include <cmath>
#include <cstring>
#include <storm/Error.hpp>
#include <storm/String.hpp>
#include <storm/Unicode.hpp>
uint16_t TEXTURECACHE::s_textureData[256 * 256];
GLYPHBITMAPDATA::~GLYPHBITMAPDATA() {
if (this->m_data) {
SMemFree(this->m_data, __FILE__, __LINE__, 0x0);
}
this->m_data = nullptr;
}
void GLYPHBITMAPDATA::CopyFrom(GLYPHBITMAPDATA* data) {
if (this->m_data) {
SMemFree(this->m_data, __FILE__, __LINE__, 0);
}
this->m_data = nullptr;
*this = *data;
data->m_data = nullptr;
}
uint32_t CHARCODEDESC::GapToNextTexture() {
CHARCODEDESC* next = this->textureRowLink.Next();
return next
? next->glyphStartPixel - this->glyphEndPixel - 1
: 255 - this->glyphEndPixel;
}
uint32_t CHARCODEDESC::GapToPreviousTexture() {
CHARCODEDESC* previous = this->textureRowLink.Prev();
return previous
? this->glyphStartPixel - previous->glyphEndPixel - 1
: this->glyphStartPixel;
}
void CHARCODEDESC::GenerateTextureCoords(uint32_t rowNumber, uint32_t glyphSide) {
this->bitmapData.m_textureCoords.minY = (glyphSide * rowNumber) / 256.0f;
this->bitmapData.m_textureCoords.minX = this->glyphStartPixel / 256.0f;
this->bitmapData.m_textureCoords.maxY = ((glyphSide * rowNumber) + glyphSide) / 256.0f;
this->bitmapData.m_textureCoords.maxX = (this->glyphStartPixel + this->bitmapData.m_glyphCellWidth) / 256.0f;
}
KERNINGHASHKEY& KERNINGHASHKEY::operator=(const KERNINGHASHKEY& rhs) {
if (this->code != rhs.code) {
this->code = rhs.code;
}
return *this;
}
bool KERNINGHASHKEY::operator==(const KERNINGHASHKEY& rhs) {
return this->code == rhs.code;
}
CHARCODEDESC* TEXTURECACHEROW::CreateNewDesc(GLYPHBITMAPDATA* data, uint32_t rowNumber, uint32_t glyphCellHeight) {
uint32_t glyphWidth = data->m_glyphCellWidth;
if (this->widestFreeSlot < glyphWidth) {
return nullptr;
}
if (!this->glyphList.Head()) {
CHARCODEDESC* newCode = this->glyphList.NewNode(2, 0, 0);
newCode->glyphStartPixel = 0;
newCode->glyphEndPixel = glyphWidth - 1;
newCode->rowNumber = rowNumber;
newCode->bitmapData.CopyFrom(data);
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
this->widestFreeSlot -= glyphWidth;
return newCode;
}
uint32_t gapToPrevious = this->glyphList.Head()->GapToPreviousTexture();
this->widestFreeSlot = gapToPrevious;
if (gapToPrevious >= glyphWidth) {
auto m = SMemAlloc(sizeof(CHARCODEDESC), __FILE__, __LINE__, 0x0);
auto newCode = new (m) CHARCODEDESC();
this->glyphList.LinkNode(newCode, 2, this->glyphList.Head());
newCode->glyphEndPixel = this->glyphList.Head()->glyphStartPixel - 1;
newCode->glyphStartPixel = newCode->glyphEndPixel - glyphWidth + 1;
newCode->rowNumber = rowNumber;
newCode->bitmapData.CopyFrom(data);
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
this->widestFreeSlot = this->glyphList.Head()
? this->glyphList.Head()->GapToPreviousTexture()
: 0;
for (auto code = this->glyphList.Head(); code; code = this->glyphList.Link(code)->Next()) {
uint32_t gapToNext = code->GapToNextTexture();
if (gapToNext > this->widestFreeSlot) {
this->widestFreeSlot = gapToNext;
}
}
return newCode;
}
int32_t inserted = 0;
CHARCODEDESC* newCode = nullptr;
for (auto code = this->glyphList.Head(); code; code = this->glyphList.Link(code)->Next()) {
uint32_t gapToNext = code->GapToNextTexture();
if (inserted) {
if (gapToNext > this->widestFreeSlot) {
this->widestFreeSlot = gapToNext;
}
continue;
}
if (gapToNext >= glyphWidth) {
auto m = SMemAlloc(sizeof(CHARCODEDESC), __FILE__, __LINE__, 0x0);
newCode = new (m) CHARCODEDESC();
this->glyphList.LinkNode(newCode, 1, code);
newCode->glyphStartPixel = code->glyphEndPixel + 1;
newCode->glyphEndPixel = code->glyphEndPixel + glyphWidth;
newCode->rowNumber = rowNumber;
newCode->bitmapData.CopyFrom(data);
newCode->GenerateTextureCoords(rowNumber, glyphCellHeight);
inserted = 1;
}
}
return newCode;
}
void TEXTURECACHEROW::EvictGlyph(CHARCODEDESC* desc) {
// TODO
}
void TEXTURECACHE::TextureCallback(EGxTexCommand cmd, uint32_t w, uint32_t h, uint32_t d, uint32_t mipLevel, void* userArg, uint32_t& texelStrideInBytes, const void*& texels) {
TEXTURECACHE* cache = static_cast<TEXTURECACHE*>(userArg);
switch (cmd) {
case GxTex_Latch: {
for (int32_t i = cache->m_textureRows.Count() - 1; i >= 0; i--) {
auto& cacheRow = cache->m_textureRows[i];
for (auto glyph = cacheRow.glyphList.Head(); glyph; glyph = cacheRow.glyphList.Next(glyph)) {
cache->WriteGlyphToTexture(glyph);
}
}
texelStrideInBytes = 512;
texels = TEXTURECACHE::s_textureData;
break;
};
}
}
CHARCODEDESC* TEXTURECACHE::AllocateNewGlyph(GLYPHBITMAPDATA* data) {
for (int32_t i = 0; i < this->m_textureRows.Count(); i++) {
auto& cacheRow = this->m_textureRows[i];
CHARCODEDESC* glyph = cacheRow.CreateNewDesc(data, i, this->m_theFace->m_cellHeight);
if (glyph) {
return glyph;
}
}
return nullptr;
}
void TEXTURECACHE::CreateTexture(int32_t filter) {
CGxTexFlags flags = CGxTexFlags(filter ? GxTex_Linear : GxTex_Nearest, 0, 0, 0, 0, 0, 1);
HTEXTURE texture = TextureCreate(
256,
256,
GxTex_Argb4444,
GxTex_Argb4444,
flags,
this,
TEXTURECACHE::TextureCallback,
"GxuFont",
0
);
this->m_texture = texture;
}
void TEXTURECACHE::Initialize(CGxFont* face, uint32_t pixelSize) {
this->m_theFace = face;
uint32_t rowCount = 256 / pixelSize;
this->m_textureRows.SetCount(rowCount);
for (int32_t i = 0; i < rowCount; i++) {
this->m_textureRows[i].widestFreeSlot = 256;
}
}
void TEXTURECACHE::PasteGlyph(const GLYPHBITMAPDATA& data, uint16_t* dst) {
if (this->m_theFace->m_flags & FONT_OUTLINE) {
if (this->m_theFace->m_flags & FONT_MONOCHROME) {
this->PasteGlyphOutlinedMonochrome(data, dst);
} else {
this->PasteGlyphOutlinedAA(data, dst);
}
} else if (this->m_theFace->m_flags & FONT_MONOCHROME) {
this->PasteGlyphNonOutlinedMonochrome(data, dst);
} else {
this->PasteGlyphNonOutlinedAA(data, dst);
}
}
void TEXTURECACHE::PasteGlyphNonOutlinedAA(const GLYPHBITMAPDATA& glyphData, uint16_t* dst) {
auto src = reinterpret_cast<uint8_t*>(glyphData.m_data);
auto pitch = glyphData.m_glyphPitch;
auto dstCellStride = glyphData.m_glyphCellWidth * 2;
for (int32_t y = 0; y < glyphData.m_yStart; y++) {
memset(dst, 0, dstCellStride);
dst += 256;
}
for (int32_t y = 0; y < glyphData.m_glyphHeight; y++) {
for (int32_t x = 0; x < glyphData.m_glyphWidth; x++) {
dst[x] = ((src[x] & 0xF0) << 8) | 0xFFF;
}
src += pitch;
dst += 256;
}
auto glyphHeight = glyphData.m_glyphHeight;
auto yStart = glyphData.m_yStart;
if (this->m_theFace->m_cellHeight - glyphHeight - yStart > 0 && this->m_theFace->m_cellHeight - glyphHeight != yStart) {
for (int32_t y = 0; y < this->m_theFace->m_cellHeight - glyphHeight - yStart; y++) {
memset(dst, 0, dstCellStride);
dst += 256;
}
}
}
void TEXTURECACHE::PasteGlyphNonOutlinedMonochrome(const GLYPHBITMAPDATA& data, uint16_t* dst) {
// TODO
}
void TEXTURECACHE::PasteGlyphOutlinedAA(const GLYPHBITMAPDATA& glyphData, uint16_t* dst) {
uint32_t v6;
uint32_t v7;
uint16_t* v8;
int32_t v9;
int32_t v15;
int32_t v16;
uint32_t v17;
uint32_t v18;
uint32_t v19;
uint32_t v20;
int32_t v21;
int32_t v22;
int32_t v23;
int32_t v24;
int32_t v25;
uint32_t v26;
uint32_t v27;
uint32_t v28;
bool v29;
bool v30;
int32_t v31;
int32_t v32;
int32_t v33;
int32_t v34;
int32_t v35;
int32_t v36;
bool v37;
int32_t v38;
int32_t v39;
int32_t v40;
uint32_t v41;
uint8_t v42;
bool v43;
uint16_t v44[9216];
uint16_t v45[9216];
uint16_t v46[9216];
uint32_t v49;
uint16_t* v52;
uint32_t v52_2;
uint32_t v52_3;
int32_t v53;
static uint8_t pixelsLitLevels[] = {
0, 1, 1, 3, 5, 7, 9, 0xB, 0xD, 0xF, 0, 0
};
const char* src = reinterpret_cast<char*>(glyphData.m_data);
uint32_t thick = this->m_theFace->m_flags & 0x8;
memset(v45, 0, sizeof(v45));
memset(v46, 0, sizeof(v46));
uint32_t ofs = thick
? 256 * glyphData.m_yStart + 258
: 256 * glyphData.m_yStart + 257;
for (int32_t y = 0; y < glyphData.m_glyphHeight; y++) {
for (int32_t x = 0; x < glyphData.m_glyphWidth; x++) {
uint8_t v10 = src[(y * glyphData.m_glyphPitch) + x];
if (v10) {
v45[ofs + (y * 256) + x] = v10;
v46[ofs + (y * 256) + x] = 1;
}
}
}
v52_2 = 0;
v15 = glyphData.m_yStart - 1;
for (int32_t i = 0; i < (thick != 0) + 1; i++) {
v49 = 2 * (i != 0) + 2;
v16 = 2 * (i != 0) + 1;
v17 = v15 < 0 ? 0 : v15;
v53 = v15 < 0 ? 0 : v15;
if (v17 >= this->m_theFace->m_cellHeight) {
continue;
}
do {
v18 = glyphData.m_glyphCellWidth;
v19 = v17 << 8;
v20 = 0;
if (!v18) {
goto LABEL_68;
}
do {
v21 = v19 + v20;
if (v46[v19 + v20] & v16) {
goto LABEL_66;
}
if (v53) {
if (v53 == this->m_theFace->m_cellHeight - 1) {
if (v20) {
if (v20 == v18 - 1) {
if (
v46[v21 - 1] & v16
|| v46[v19 + v20 - 257] & v16
) {
goto LABEL_65;
}
v22 = v46[v19 + v20 - 256];
} else {
if (
v46[v19 + v20 - 257] & v16
|| v46[v19 + v20 - 256] & v16
|| v46[v19 + v20 - 255] & v16
|| v46[v21 - 1] & v16
) {
goto LABEL_65;
}
v22 = v46[v21 + 1];
}
} else {
if (
v46[v19 - 256] & v16
|| v46[v19 - 255] & v16
) {
goto LABEL_65;
}
v22 = v46[v19 + 1];
}
} else if (v20) {
v24 = v19 + v20;
if (v20 == v18 - 1) {
if (
v46[v24 - 256] & v16
|| v46[v19 + v20 - 257] & v16
|| v46[v21 - 1] & v16
|| v46[v21 + 255] & v16
) {
goto LABEL_65;
}
v22 = v46[v21 + 256];
} else {
if (
v46[v24 - 257] & v16
|| v46[v19 + v20 - 256] & v16
|| v46[v19 + v20 - 255] & v16
|| v46[v21 - 1] & v16
|| v46[v21 + 1] & v16
|| v46[v21 + 255] & v16
|| v46[v21 + 256] & v16
) {
goto LABEL_65;
}
v22 = v46[v21 + 257];
}
} else {
if (
v46[v19 - 256] & v16
|| v46[v19 - 255] & v16
|| v46[v19 + 1] & v16
|| v46[v19 + 257] & v16
) {
goto LABEL_65;
}
v22 = v46[v19 + 256];
}
LABEL_64:
if (!(v22 & v16)) {
goto LABEL_66;
}
goto LABEL_65;
}
if (v20) {
v23 = v46[v20 - 1];
if (v20 == v18 - 1) {
if (!(v23 & v16) && !(v46[v20 + 255] & v16)) {
v22 = v46[v20 + 256];
goto LABEL_64;
}
} else if (!(v23 & v16) && !(v46[v20 + 1] & v16) && !(v46[v20 + 255] & v16) && !(v46[v20 + 256] & v16)) {
v22 = v46[v20 + 257];
goto LABEL_64;
}
} else if (!(v46[1] & v16) && !(v46[257] & v16)) {
v22 = v46[256];
goto LABEL_64;
}
LABEL_65:
v46[v21] = v49;
LABEL_66:
++v20;
} while (v20 < v18);
v17 = v53;
LABEL_68:
v53 = ++v17;
} while (v17 < this->m_theFace->m_cellHeight);
}
memset(v44, 0, sizeof(v44));
v26 = 0;
v53 = 0;
if (!this->m_theFace->m_cellHeight) {
goto LABEL_95;
}
while (2) {
v27 = glyphData.m_glyphCellWidth;
v28 = v26 << 8;
v25 = 0;
if (!v27) {
goto LABEL_94;
}
while (2) {
v37 = v46[v28 + v25] == 0;
v52 = &v46[v28 + v25];
v29 = !v37;
v30 = !v37;
if (v26) {
if (v53 == this->m_theFace->m_cellHeight - 1) {
if (!v25) {
v31 = v30 + (v46[v28 + 1] != 0) + (v46[v28 - 255] != 0) + (v46[v28 - 256] != 0);
goto LABEL_92;
}
v37 = v25 == v27 - 1;
v34 = v28 + v25;
if (v37) {
v31 = (v46[v28 + v25 - 256] != 0) + (v46[v34 - 257] != 0) + v30 + (*(v52 - 1) != 0);
goto LABEL_92;
}
v35 = (v46[v34 - 256] != 0) + (v46[v28 + v25 - 257] != 0);
v36 = 0;
v37 = v46[v28 + v25 - 255] == 0;
v38 = v28 + v25;
} else {
if (!v25) {
v31 = v30
+ (v46[v28 + 256] != 0)
+ (v46[v28 + 1] != 0)
+ (v46[v28 + 257] != 0)
+ (v46[v28 - 255] != 0)
+ (v46[v28 - 256] != 0);
goto LABEL_92;
}
v37 = v25 == v27 - 1;
v39 = v28 + v25;
if (v37) {
v31 = (v46[v28 + v25 + 256] != 0)
+ (v46[v28 + v25 + 255] != 0)
+ (v46[v28 + v25 - 256] != 0)
+ (v46[v39 - 257] != 0)
+ v30
+ (*(v52 - 1) != 0);
goto LABEL_92;
}
v37 = v46[v39 - 256] == 0;
v38 = v28 + v25;
v35 = (v46[v28 + v25 + 256] != 0)
+ (v46[v28 + v25 + 255] != 0)
+ (v46[v28 + v25 - 255] != 0)
+ !v37
+ (v46[v28 + v25 - 257] != 0);
v36 = 0;
v37 = v46[v28 + v25 + 257] == 0;
}
v36 = !v37;
v31 = (v46[v38 + 1] != 0) + v36 + v35 + v30 + (*(v52 - 1) != 0);
} else if (v25) {
if (v25 == v27 - 1) {
v32 = (v46[v25 + 255] != 0) + (v46[v25 - 1] != 0);
v33 = v29 + (v46[v25 + 256] != 0);
} else {
v32 = (v46[v25 + 257] != 0)
+ (v46[v25 + 256] != 0)
+ (v46[v25 + 255] != 0)
+ (v46[v25 - 1] != 0);
v33 = v29 + (v46[v25 + 1] != 0);
}
v31 = v33 + v32;
} else {
v31 = v29 + (v46[1] != 0) + (v46[257] != 0) + (v46[256] != 0);
}
LABEL_92:
v26 = v53;
v44[v28 + v25] = pixelsLitLevels[v31];
v27 = glyphData.m_glyphCellWidth;
if (++v25 < v27) {
continue;
}
break;
}
LABEL_94:
v53 = ++v26;
if (v26 < this->m_theFace->m_cellHeight) {
continue;
}
break;
}
LABEL_95:
v40 = 0;
for (int32_t y = 0; y < this->m_theFace->m_cellHeight; y++) {
for (int32_t x = 0; x < glyphData.m_glyphCellWidth; x++) {
if (v46[v40 + x]) {
if (v45[v40 + x]) {
v42 = (255 * v45[v40 + x]) >> 12;
dst[v40 + x] = v42 | (16 * (v42 | (16 * (v42 | (16 * v44[v40 + x])))));
} else {
dst[v40 + x] = v44[v40 + x] << 12;
}
} else {
dst[v40 + x] = 0;
}
}
v40 += 256;
}
}
void TEXTURECACHE::PasteGlyphOutlinedMonochrome(const GLYPHBITMAPDATA& data, uint16_t* dst) {
// TODO
}
void TEXTURECACHE::UpdateDirty() {
if (this->m_anyDirtyGlyphs && this->m_texture) {
CGxTex* gxTex = TextureGetGxTex(this->m_texture, 1, nullptr);
CiRect updateRect = { 0, 0, 256, 256 };
GxTexUpdate(gxTex, updateRect, 1);
this->m_anyDirtyGlyphs = 0;
}
}
void TEXTURECACHE::WriteGlyphToTexture(CHARCODEDESC* glyph) {
if (!this->m_texture || !this->m_theFace || !this->m_theFace->m_cellHeight) {
return;
}
uint32_t ofs = glyph->glyphStartPixel + (glyph->rowNumber * this->m_theFace->m_cellHeight << 8);
uint16_t* ptr = &TEXTURECACHE::s_textureData[ofs];
this->PasteGlyph(glyph->bitmapData, ptr);
}
CGxFont::~CGxFont() {
this->Clear();
}
int32_t CGxFont::CheckStringGlyphs(const char* string) {
if (!string || !*string) {
return 1;
}
while (*string) {
int32_t advance;
auto code = SUniSGetUTF8(reinterpret_cast<const uint8_t*>(string), &advance);
HASHKEY_NONE key = {};
if (code != '\r' && code != '\n' && !this->m_activeCharacters.Ptr(code, key)) {
return 0;
}
string += advance;
}
return 1;
}
void CGxFont::Clear() {
if (this->m_faceHandle) {
FontFaceCloseHandle(this->m_faceHandle);
}
this->m_faceHandle = nullptr;
this->ClearGlyphs();
}
void CGxFont::ClearGlyphs() {
for (int32_t i = 0; i < 8; i++) {
auto& cache = this->m_textureCache[i];
if (cache.m_texture) {
HandleClose(this->m_textureCache[i].m_texture);
}
cache.m_texture = nullptr;
// TODO
}
this->m_activeCharacters.Clear();
this->m_activeCharacterCache.Clear();
this->m_kernInfo.Clear();
}
float CGxFont::ComputeStep(uint32_t currentCode, uint32_t nextCode) {
KERNINGHASHKEY kernKey = { nextCode | (currentCode << 16) };
KERNNODE* kern = this->m_kernInfo.Ptr(currentCode, kernKey);
if (kern && kern->flags & 0x02) {
return kern->proporportionalSpacing;
}
auto face = FontFaceGetFace(this->m_faceHandle);
auto currentIndex = FT_Get_Char_Index(face, currentCode);
auto nextIndex = FT_Get_Char_Index(face, nextCode);
FT_Vector vector;
vector.x = 0;
if (face->face_flags & FT_FACE_FLAG_KERNING) {
FT_Get_Kerning(face, currentIndex, nextIndex, ft_kerning_unscaled, &vector);
vector.x &= (vector.x >= 0) - 1;
}
HASHKEY_NONE charKey = {};
auto activeChar = this->m_activeCharacters.Ptr(currentCode, charKey);
float advance = 0.0f;
if (activeChar) {
advance = this->m_flags & 0x08
? activeChar->bitmapData.m_glyphAdvance + 1.0f
: activeChar->bitmapData.m_glyphAdvance;
}
float spacing = (this->m_pixelsPerUnit * vector.x) + advance;
if (!kern) {
kern = this->m_kernInfo.New(currentCode, kernKey, 0, 0);
}
kern->flags |= 0x02;
kern->proporportionalSpacing = ceil(spacing);
return kern->proporportionalSpacing;
}
float CGxFont::ComputeStepFixedWidth(uint32_t currentCode, uint32_t nextCode) {
// TODO
return 0.0f;
}
float CGxFont::GetGlyphBearing(const CHARCODEDESC* glyph, bool billboarded, float height) {
if (billboarded) {
float v8 = ScreenToPixelHeight(1, height) / this->GetPixelSize();
return glyph->bitmapData.m_glyphBearing * v8;
}
return ceil(glyph->bitmapData.m_glyphBearing);
}
int32_t CGxFont::GetGlyphData(GLYPHBITMAPDATA* glyphData, uint32_t code) {
FT_Face face = FontFaceGetFace(this->m_faceHandle);
FT_Set_Pixel_Sizes(face, this->m_pixelSize, 0);
uint32_t v6 = 0;
if (this->m_flags & 0x8) {
v6 = 4;
} else if (this->m_flags & FONT_OUTLINE) {
v6 = 2;
}
return IGxuFontGlyphRenderGlyph(
face,
this->m_pixelSize,
code,
this->m_baseline,
glyphData,
this->m_flags & FONT_MONOCHROME,
v6
);
}
const char* CGxFont::GetName(void) const {
STORM_ASSERT(this->m_faceHandle);
return FontFaceGetFontName(this->m_faceHandle);
}
uint32_t CGxFont::GetPixelSize() {
return this->m_pixelSize;
}
int32_t CGxFont::Initialize(const char* name, uint32_t newFlags, float fontHeight) {
SStrPrintf(this->m_fontName, 260, "%s", name);
this->m_requestedFontHeight = fontHeight;
this->Clear();
this->m_flags = newFlags;
this->m_faceHandle = FontFaceGetHandle(name, GetFreeTypeLibrary());
if (this->m_faceHandle) {
return this->UpdateDimensions();
} else {
return 0;
}
}
const CHARCODEDESC* CGxFont::NewCodeDesc(uint32_t code) {
HASHKEY_NONE key = {};
CHARCODEDESC* charDesc = this->m_activeCharacters.Ptr(code, key);
if (charDesc) {
this->m_activeCharacterCache.LinkToHead(charDesc);
return charDesc;
}
GLYPHBITMAPDATA data;
if (!CGxFont::GetGlyphData(&data, code)) {
return nullptr;
}
// Attempt to allocate the character off of texture caches
for (uint32_t textureNumber = 0; textureNumber < 8; textureNumber++) {
TEXTURECACHE* textureCache = &this->m_textureCache[textureNumber];
if (textureCache->m_texture && TextureGetGxTex(reinterpret_cast<CTexture*>(textureCache->m_texture), 1, nullptr)) {
charDesc = textureCache->AllocateNewGlyph(&data);
if (charDesc) {
charDesc->textureNumber = textureNumber;
break;
}
} else {
textureCache->CreateTexture(this->m_flags & 0x4);
textureCache->Initialize(this, this->m_cellHeight);
charDesc = textureCache->AllocateNewGlyph(&data);
if (charDesc) {
charDesc->textureNumber = textureNumber;
}
break;
}
}
// No character was allocated from the texture caches, so evict the oldest character and
// attempt to allocate from that character's texture cache row
if (!charDesc) {
CHARCODEDESC* oldestDesc = this->m_activeCharacterCache.Tail();
if (oldestDesc) {
uint32_t textureNumber = oldestDesc->textureNumber;
uint32_t rowNumber = oldestDesc->rowNumber;
TEXTURECACHE* textureCache = &this->m_textureCache[textureNumber];
TEXTURECACHEROW* cacheRow = &textureCache->m_textureRows[rowNumber];
cacheRow->EvictGlyph(oldestDesc);
this->RegisterEvictNotice(textureNumber);
charDesc = cacheRow->CreateNewDesc(&data, rowNumber, this->m_cellHeight);
if (charDesc) {
charDesc->rowNumber = rowNumber;
charDesc->textureNumber = textureNumber;
}
}
}
if (charDesc) {
this->m_activeCharacters.Insert(charDesc, code, key);
this->m_activeCharacterCache.LinkToHead(charDesc);
this->m_textureCache[charDesc->textureNumber].m_anyDirtyGlyphs = 1;
}
return charDesc;
}
void CGxFont::RegisterEvictNotice(uint32_t a2) {
// TODO
}
int32_t CGxFont::UpdateDimensions() {
FT_Face theFace = FontFaceGetFace(this->m_faceHandle);
float v11 = Sub6C2280(theFace, this->m_requestedFontHeight);
float v3 = 2.0 / GetScreenPixelHeight();
if (v11 > v3) {
v3 = v11;
}
float height = v3;
uint32_t pixelSize = ScreenToPixelHeight(0, height);
if (pixelSize <= 32) {
if (!pixelSize) {
// TODO
// nullsub_3();
}
} else {
pixelSize = 32;
}
this->m_pixelSize = pixelSize;
uint32_t v10 = theFace->ascender + abs(theFace->descender);
if (!v10) {
return 0;
}
this->m_cellHeight = pixelSize;
float baseline = (double)(pixelSize * theFace->ascender) / (double)v10;
this->m_baseline = (int64_t)(baseline + 0.5);
uint32_t flags = this->m_flags;
if (flags & 0x8) {
this->m_cellHeight = pixelSize + 4;
} else if (flags & 0x1) {
this->m_cellHeight = pixelSize + 2;
}
int32_t result = FT_Set_Pixel_Sizes(theFace, pixelSize, 0) == FT_Err_Ok;
this->m_pixelsPerUnit = (double)theFace->size->metrics.x_ppem / (double)theFace->units_per_EM;
return result;
}