2023-01-02 13:17:18 -06:00
|
|
|
#include "gx/font/CGxString.hpp"
|
|
|
|
|
#include "gx/Buffer.hpp"
|
|
|
|
|
#include "gx/font/CGxFont.hpp"
|
|
|
|
|
#include "gx/font/Wrap.hpp"
|
|
|
|
|
#include "gx/Font.hpp"
|
|
|
|
|
#include "gx/Gx.hpp"
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <cmath>
|
2025-03-31 23:52:37 -04:00
|
|
|
#include <bc/Memory.hpp>
|
2023-01-02 13:17:18 -06:00
|
|
|
#include <storm/String.hpp>
|
|
|
|
|
#include <tempest/Math.hpp>
|
|
|
|
|
|
|
|
|
|
TEXTLINETEXTURE* TEXTLINETEXTURE::NewTextLineTexture() {
|
|
|
|
|
// TODO
|
|
|
|
|
// Allocate off of TEXTLINETEXTURE::s_freeTextLineTextures
|
|
|
|
|
|
2025-03-31 23:52:37 -04:00
|
|
|
return NEW(TEXTLINETEXTURE);
|
2023-01-02 13:17:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TEXTLINETEXTURE::Recycle(TEXTLINETEXTURE* ptr) {
|
|
|
|
|
// TODO if (TEXTLINETEXTURE::s_recycledBytes <= 0x80000)
|
|
|
|
|
|
2025-03-31 23:52:37 -04:00
|
|
|
DEL(ptr);
|
2023-01-02 13:17:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TEXTLINETEXTURE::WriteGeometry(CGxVertexPCT* buf, const CImVector& fontColor, const C2Vector& shadowOffset, const CImVector& shadowColor, const C3Vector& viewTranslation, bool a7, bool a8, int32_t ofs, int32_t size) {
|
|
|
|
|
if (!size || !this->m_vert.Count()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t colorCount = this->m_vert.Count() == this->m_colors.Count()
|
|
|
|
|
? this->m_colors.Count()
|
|
|
|
|
: 0;
|
|
|
|
|
|
|
|
|
|
if (ofs >= this->m_vert.Count()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t v24 = this->m_vert.Count() - ofs;
|
|
|
|
|
|
|
|
|
|
if (size >= v24) {
|
|
|
|
|
size = v24;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (a7) {
|
|
|
|
|
C3Vector shadowTranslation = {
|
2024-07-21 18:30:33 -04:00
|
|
|
viewTranslation.x + std::floor(ScreenToPixelWidth(0, shadowOffset.x)),
|
|
|
|
|
viewTranslation.y + std::floor(ScreenToPixelHeight(0, shadowOffset.y)),
|
2023-01-02 13:17:18 -06:00
|
|
|
viewTranslation.z
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto color = colorCount ? this->m_colors[ofs] : fontColor;
|
|
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < size; i++) {
|
|
|
|
|
auto& vert = this->m_vert[i + ofs];
|
|
|
|
|
|
|
|
|
|
C3Vector p = {
|
|
|
|
|
vert.vc.x + shadowTranslation.x,
|
|
|
|
|
vert.vc.y + shadowTranslation.y,
|
|
|
|
|
vert.vc.z + shadowTranslation.z
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buf->p = p;
|
|
|
|
|
buf->tc[0] = vert.tc;
|
|
|
|
|
|
|
|
|
|
auto formattedShadowColor = shadowColor;
|
|
|
|
|
if (a8 && colorCount) {
|
|
|
|
|
formattedShadowColor.a = static_cast<uint8_t>(
|
|
|
|
|
(static_cast<float>(formattedShadowColor.a) * static_cast<float>(color.a)) / 65536.0f
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
GxFormatColor(formattedShadowColor);
|
|
|
|
|
buf->c = formattedShadowColor;
|
|
|
|
|
|
|
|
|
|
buf++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// if (BATCHEDRENDERFONTDESC::s_billboarded) {
|
|
|
|
|
// // TODO
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < size; i++) {
|
|
|
|
|
auto& vert = this->m_vert[i + ofs];
|
|
|
|
|
|
|
|
|
|
auto color = colorCount ? this->m_colors[i + ofs] : fontColor;
|
|
|
|
|
GxFormatColor(color);
|
|
|
|
|
|
|
|
|
|
// if (BATCHEDRENDERFONTDESC::s_billboarded) {
|
|
|
|
|
// // TODO
|
|
|
|
|
// continue;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
C3Vector p = {
|
|
|
|
|
vert.vc.x + viewTranslation.x,
|
|
|
|
|
vert.vc.y + viewTranslation.y,
|
|
|
|
|
vert.vc.z + viewTranslation.z
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
buf->p = p;
|
|
|
|
|
buf->tc[0] = vert.tc;
|
|
|
|
|
|
|
|
|
|
buf->c = color;
|
|
|
|
|
|
|
|
|
|
buf++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CGxString* CGxString::GetNewString(int32_t linkOnList) {
|
|
|
|
|
CGxString* string = g_freeStrings.Head();
|
|
|
|
|
|
|
|
|
|
if (string) {
|
|
|
|
|
g_strings.LinkToTail(string);
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-31 23:52:37 -04:00
|
|
|
string = NEW_ZERO(CGxString);
|
2023-01-02 13:17:18 -06:00
|
|
|
|
|
|
|
|
if (linkOnList) {
|
|
|
|
|
g_strings.LinkToTail(string);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CGxString::~CGxString() {
|
|
|
|
|
// TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::AddShadow(const C2Vector& offset, const CImVector& color) {
|
|
|
|
|
this->m_shadowColor = color;
|
|
|
|
|
this->m_shadowColor.a = std::min(this->m_shadowColor.a, this->m_fontColor.a);
|
|
|
|
|
this->m_shadowOffset = offset;
|
|
|
|
|
|
|
|
|
|
this->m_flags |= 0x1;
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x20) {
|
|
|
|
|
this->ClearInstanceData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t CGxString::CalculateVertsNeeded(int32_t line) {
|
|
|
|
|
if (this->m_flags & 0x01) {
|
|
|
|
|
return 2 * this->m_textLines[line]->m_vert.Count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this->m_textLines[line]->m_vert.Count();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CGxString::CheckGeometry() {
|
|
|
|
|
if (this->m_textureEvicted) {
|
|
|
|
|
if (!this->m_currentFace->CheckStringGlyphs(this->m_text)) {
|
|
|
|
|
this->ClearInstanceData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->m_textureEvicted = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->CreateGeometry();
|
|
|
|
|
this->m_intD4 = 0;
|
|
|
|
|
|
|
|
|
|
return this->m_intB0 != 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::ClearInstanceData() {
|
|
|
|
|
// TODO this->m_hyperlinkInfo->SetCount(0);
|
|
|
|
|
// TODO this->m_textureInfo->SetCount(0);
|
|
|
|
|
|
|
|
|
|
// TODO this->dwordA4 = 0;
|
|
|
|
|
this->m_lastGradientStart = -1;
|
|
|
|
|
this->m_lastGradientLength = -1;
|
|
|
|
|
this->m_intB0 = 0;
|
|
|
|
|
|
|
|
|
|
for (int32_t i = 0; i < 8; i++) {
|
|
|
|
|
if (this->m_textLines[i]) {
|
|
|
|
|
TEXTLINETEXTURE::Recycle(this->m_textLines[i]);
|
|
|
|
|
this->m_textLines[i] = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::CreateGeometry() {
|
|
|
|
|
if (this->m_intB0 || !this->m_text || !*this->m_text) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EMBEDDEDPARSEINFO info;
|
|
|
|
|
uint32_t flags = this->m_flags;
|
|
|
|
|
uint32_t numBytes = 0;
|
|
|
|
|
const char* currentText = this->m_text;
|
|
|
|
|
const char* nextText = nullptr;
|
|
|
|
|
int32_t advance = 0;
|
|
|
|
|
uint32_t wide = 0;
|
|
|
|
|
int32_t gStart = this->m_lastGradientStart;
|
|
|
|
|
int32_t gLength = this->m_lastGradientLength;
|
|
|
|
|
CImVector lineColor = this->m_fontColor;
|
|
|
|
|
float height = -this->m_currentFontHeight;
|
|
|
|
|
C3Vector linePos = {
|
|
|
|
|
0.0f,
|
|
|
|
|
this->m_flags & 0x80 ? 0.0f : ScreenToPixelHeight(0, -this->m_currentFontHeight),
|
|
|
|
|
0.0f
|
|
|
|
|
};
|
|
|
|
|
bool a10 = true;
|
|
|
|
|
float blockWidth = this->m_blockWidth;
|
|
|
|
|
|
|
|
|
|
auto v611 = static_cast<float>(CMath::fuint_pi(GetScreenPixelHeight() * this->m_spacing));
|
|
|
|
|
auto v51 = ScreenToPixelHeight(0, this->m_currentFontHeight);
|
|
|
|
|
auto spacing = this->m_flags & 0x80 ? this->m_spacing : v611 / static_cast<float>(GetScreenPixelHeight());
|
|
|
|
|
auto v59 = this->m_flags & 0x80 ? this->m_currentFontHeight + this->m_spacing : v611 + v51;
|
|
|
|
|
|
|
|
|
|
float v49 = 0.0f;
|
|
|
|
|
|
|
|
|
|
while (*currentText) {
|
|
|
|
|
if (this->m_blockHeight <= v49) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x2000 && this->m_intB0 == 1) {
|
|
|
|
|
blockWidth -= GetIndentNormWidth();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v49 += this->m_currentFontHeight + spacing;
|
|
|
|
|
|
|
|
|
|
QUOTEDCODE code = GxuDetermineQuotedCode(currentText, advance, 0, flags, wide);
|
|
|
|
|
|
|
|
|
|
if (code == CODE_NEWLINE) {
|
|
|
|
|
currentText += advance;
|
|
|
|
|
this->m_intB0++;
|
|
|
|
|
linePos.y -= v59;
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// info.dword0C -= v59;
|
|
|
|
|
// info.dword04 -= v59;
|
|
|
|
|
// info.dword34 -= v59;
|
|
|
|
|
// info.dword2C -= v59;
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float extent = 0.0f;
|
|
|
|
|
float a8 = 0.0f;
|
|
|
|
|
float a11 = 0.0f;
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x1) {
|
|
|
|
|
a8 = this->m_shadowOffset.x;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CalcWrapPoint(
|
|
|
|
|
this->m_currentFace,
|
|
|
|
|
currentText,
|
|
|
|
|
this->m_currentFontHeight,
|
|
|
|
|
blockWidth,
|
|
|
|
|
&numBytes,
|
|
|
|
|
&extent,
|
|
|
|
|
&nextText,
|
|
|
|
|
a8,
|
|
|
|
|
this->m_flags,
|
|
|
|
|
&a10,
|
|
|
|
|
&a11,
|
|
|
|
|
this->m_scale
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (nextText == currentText || !nextText || (!numBytes && !*nextText)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->m_horzJust == GxHJ_Right) {
|
|
|
|
|
float indent = this->m_flags & 0x2000 && this->m_intB0 ? GetIndentPixelWidth() : 0.0f;
|
|
|
|
|
linePos.x = ScreenToPixelWidth(this->m_flags & 0x80, -extent) - indent;
|
|
|
|
|
} else if (this->m_horzJust == GxHJ_Center) {
|
|
|
|
|
linePos.x = ScreenToPixelWidth(this->m_flags & 0x80, -(extent * 0.5f));
|
|
|
|
|
} else if (this->m_flags & 0x2000 && this->m_intB0) {
|
|
|
|
|
linePos.x = GetIndentPixelWidth();
|
|
|
|
|
} else {
|
|
|
|
|
linePos.x = 0.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float offsetY = 0.0f;
|
|
|
|
|
if (v51 < a11) {
|
|
|
|
|
if (this->m_vertJust == GxVJ_Bottom) {
|
|
|
|
|
offsetY = a11 - v51;
|
|
|
|
|
} else if (this->m_vertJust == GxVJ_Middle) {
|
|
|
|
|
offsetY = floor((a11 - v51) * 0.5);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
linePos.y -= offsetY;
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// info.dword0C -= v62;
|
|
|
|
|
// info.dword04 -= v62;
|
|
|
|
|
// info.dword34 = linePos.y;
|
|
|
|
|
// info.dword2C = linePos.y + v59;
|
|
|
|
|
// if (info.dword00) {
|
|
|
|
|
// info.dword08 = linePos.x;
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
uint32_t texturePagesUsedFlag = 0;
|
|
|
|
|
|
|
|
|
|
this->InitializeTextLine(currentText, numBytes, lineColor, linePos, &texturePagesUsedFlag, info);
|
|
|
|
|
this->m_intB0++;
|
|
|
|
|
|
|
|
|
|
this->m_texturePagesUsed |= texturePagesUsedFlag;
|
|
|
|
|
|
|
|
|
|
currentText = nextText;
|
|
|
|
|
|
|
|
|
|
linePos.y -= offsetY + v59;
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x2) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// info.dword0C -= offsetY + v59;
|
|
|
|
|
// info.dword04 -= offsetY + v59;
|
|
|
|
|
// info.dword34 = linePos.y;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
this->InitializeViewTranslation();
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x20 && (gStart != -1 || gLength != -1)) {
|
|
|
|
|
this->SetGradient(gStart, gLength);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t CGxString::Initialize(float fontHeight, const C3Vector& position, float blockWidth, float blockHeight, CGxFont* face, const char* text, EGxFontVJusts vertJust, EGxFontHJusts horzJust, float spacing, uint32_t flags, const CImVector& color, float scale) {
|
|
|
|
|
uint32_t textLen = SStrLen(text) + 1;
|
|
|
|
|
if (textLen > this->m_textLen) {
|
|
|
|
|
if (this->m_text) {
|
2025-03-31 23:52:37 -04:00
|
|
|
FREE(this->m_text);
|
2023-01-02 13:17:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->m_textLen = textLen;
|
2025-03-31 23:52:37 -04:00
|
|
|
this->m_text = static_cast<char*>(ALLOC(textLen));
|
2023-01-02 13:17:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SStrCopy(this->m_text, text, this->m_textLen);
|
|
|
|
|
|
|
|
|
|
this->m_blockWidth = blockWidth;
|
|
|
|
|
this->m_blockHeight = blockHeight;
|
|
|
|
|
this->m_spacing = spacing;
|
|
|
|
|
this->m_position = position;
|
|
|
|
|
this->m_horzJust = horzJust;
|
|
|
|
|
this->m_vertJust = vertJust;
|
|
|
|
|
this->m_flags = flags;
|
|
|
|
|
this->m_fontColor = color;
|
|
|
|
|
this->m_scale = scale;
|
|
|
|
|
this->m_currentFace = face;
|
|
|
|
|
|
|
|
|
|
face->m_strings.LinkToTail(this);
|
|
|
|
|
|
2025-04-17 01:32:37 +04:00
|
|
|
float requestedFontHeight = ((this->m_flags & 0x4) && !(this->m_flags & 0x80))
|
2023-01-02 13:17:18 -06:00
|
|
|
? GxuFontGetOneToOneHeight(face)
|
|
|
|
|
: fontHeight;
|
|
|
|
|
this->m_requestedFontHeight = requestedFontHeight;
|
|
|
|
|
|
|
|
|
|
this->m_currentFontHeight = std::max(this->m_requestedFontHeight, 2.0f / GetScreenPixelHeight());
|
|
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::InitializeTextLine(const char* currentText, uint32_t numBytes, CImVector& workingColor, const C3Vector& position, uint32_t* texturePagesUsedFlag, EMBEDDEDPARSEINFO& info) {
|
|
|
|
|
if (this->m_flags & 0x08) {
|
|
|
|
|
// TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
C3Vector curPos = position;
|
|
|
|
|
|
|
|
|
|
float screenPixelHeight = ScreenToPixelHeight(this->m_flags & 0x80, this->m_currentFontHeight);
|
|
|
|
|
float glyphToScreenPixels = screenPixelHeight / this->m_currentFace->GetPixelSize();
|
|
|
|
|
float glyphPixelHeight = ScreenToPixelHeight(this->m_flags & 0x80, this->m_currentFontHeight);
|
|
|
|
|
|
|
|
|
|
if (this->m_currentFace->m_flags & 0x08) {
|
|
|
|
|
glyphPixelHeight += 4.0f;
|
|
|
|
|
} else if (this->m_currentFace->m_flags & 0x01) {
|
|
|
|
|
glyphPixelHeight += 2.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// - billboard adjustment table init
|
|
|
|
|
// - EMBEDDEDPARSEINFO update
|
|
|
|
|
|
|
|
|
|
float stepGlyph = 0.0f;
|
|
|
|
|
float stepScreen = 0.0f;
|
|
|
|
|
uint32_t prevCode = 0;
|
2025-04-17 01:32:37 +04:00
|
|
|
CImVector color = this->m_fontColor;
|
2023-01-02 13:17:18 -06:00
|
|
|
|
|
|
|
|
while (numBytes && *currentText) {
|
|
|
|
|
int32_t advance;
|
|
|
|
|
uint32_t code;
|
|
|
|
|
CImVector quotedColor;
|
|
|
|
|
|
|
|
|
|
QUOTEDCODE quotedCode = GxuDetermineQuotedCode(currentText, advance, "edColor, this->m_flags, code);
|
|
|
|
|
|
|
|
|
|
currentText += advance;
|
|
|
|
|
numBytes -= advance;
|
|
|
|
|
|
|
|
|
|
if (prevCode) {
|
|
|
|
|
if (this->m_flags & 0x10) {
|
|
|
|
|
// TODO
|
|
|
|
|
// stepGlyph = this->m_currentFace->ComputeStepFixedWidth(prevCode, code);
|
|
|
|
|
} else {
|
|
|
|
|
stepGlyph = this->m_currentFace->ComputeStep(prevCode, code);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stepScreen = stepGlyph * glyphToScreenPixels;
|
|
|
|
|
|
|
|
|
|
switch (quotedCode) {
|
|
|
|
|
case CODE_COLORON:
|
|
|
|
|
if (!(this->m_flags & 0x08)) {
|
|
|
|
|
color = quotedColor;
|
|
|
|
|
color.a = this->m_fontColor.a;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// EMBEDDEDPARSEINFO update
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_COLORRESTORE:
|
|
|
|
|
color = this->m_fontColor;
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_NEWLINE:
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_HYPERLINKSTART:
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_HYPERLINKSTOP:
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_TEXTURESTART:
|
|
|
|
|
// TODO
|
|
|
|
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
case CODE_TEXTURESTOP:
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
default: {
|
|
|
|
|
auto glyph = this->m_currentFace->NewCodeDesc(code);
|
|
|
|
|
|
|
|
|
|
if (!glyph) {
|
|
|
|
|
glyph = this->m_currentFace->NewCodeDesc('?');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!glyph) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*texturePagesUsedFlag |= 1 << glyph->textureNumber;
|
|
|
|
|
|
|
|
|
|
if (!this->m_textLines[glyph->textureNumber]) {
|
|
|
|
|
this->m_textLines[glyph->textureNumber] = TEXTLINETEXTURE::NewTextLineTexture();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto line = this->m_textLines[glyph->textureNumber];
|
|
|
|
|
|
|
|
|
|
if (!(this->m_flags & 0x08)) {
|
|
|
|
|
uint32_t index = line->m_colors.Add(4, 0, &color);
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x20) {
|
|
|
|
|
// TODO
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!(this->m_flags & 0x80)) {
|
|
|
|
|
stepScreen = floor(stepScreen + 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
curPos.x += stepScreen;
|
|
|
|
|
|
|
|
|
|
VERT vert;
|
|
|
|
|
vert.vc = { curPos.x, curPos.y, curPos.z };
|
|
|
|
|
vert.tc = { 0.0f, 0.0f };
|
|
|
|
|
|
|
|
|
|
vert.vc.x += this->m_currentFace->GetGlyphBearing(
|
|
|
|
|
glyph,
|
|
|
|
|
this->m_flags & 0x80,
|
|
|
|
|
this->m_currentFontHeight
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (this->m_currentFace->m_flags & 0x08) {
|
|
|
|
|
vert.vc.y -= 2.0f;
|
|
|
|
|
} else if (this->m_currentFace->m_flags & 0x01) {
|
|
|
|
|
vert.vc.y -= 1.0f;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vert.vc.y += (glyph->bitmapData.m_yOffset * glyphToScreenPixels);
|
|
|
|
|
|
|
|
|
|
uint32_t index = line->m_vert.Add(4, 0, &vert);
|
|
|
|
|
VERT* verts = &line->m_vert[index];
|
|
|
|
|
|
|
|
|
|
float width = this->m_flags & 0x80
|
|
|
|
|
? glyph->bitmapData.m_glyphCellWidth * glyphToScreenPixels
|
|
|
|
|
: floor(glyph->bitmapData.m_glyphCellWidth * glyphToScreenPixels);
|
|
|
|
|
float height = this->m_flags & 0x80
|
|
|
|
|
? screenPixelHeight
|
|
|
|
|
: glyphPixelHeight;
|
|
|
|
|
|
|
|
|
|
verts[0].vc.x = verts[1].vc.x;
|
|
|
|
|
verts[3].vc.x = verts[3].vc.x + width;
|
|
|
|
|
verts[2].vc.x = verts[3].vc.x;
|
|
|
|
|
verts[3].vc.y = verts[3].vc.y + height;
|
|
|
|
|
verts[1].vc.y = verts[3].vc.y;
|
|
|
|
|
verts[0].vc.y = verts[2].vc.y;
|
|
|
|
|
|
|
|
|
|
verts[2].tc.y = glyph->bitmapData.m_textureCoords.maxY;
|
|
|
|
|
verts[0].tc.y = verts[2].tc.y;
|
|
|
|
|
verts[3].tc.y = glyph->bitmapData.m_textureCoords.minY;
|
|
|
|
|
verts[1].tc.y = verts[3].tc.y;
|
|
|
|
|
verts[1].tc.x = glyph->bitmapData.m_textureCoords.minX;
|
|
|
|
|
verts[0].tc.x = verts[1].tc.x;
|
|
|
|
|
verts[3].tc.x = glyph->bitmapData.m_textureCoords.maxX;
|
|
|
|
|
verts[2].tc.x = verts[3].tc.x;
|
|
|
|
|
|
|
|
|
|
if (this->m_flags & 0x80) {
|
|
|
|
|
// TODO
|
|
|
|
|
// verts[3].tc.y += flt_C7D2E8;
|
|
|
|
|
// verts[1].tc.y += flt_C7D2E8;
|
|
|
|
|
// verts[1].tc.x += flt_C7D2EC;
|
|
|
|
|
// verts[0].tc.x += flt_C7D2EC;
|
|
|
|
|
// verts[2].tc.y += flt_C7D2F0;
|
|
|
|
|
// verts[0].tc.y += flt_C7D2F0;
|
|
|
|
|
// verts[3].tc.x += flt_C7D2F4;
|
|
|
|
|
// verts[2].tc.x += flt_C7D2F4;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
prevCode = code;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// info.dword10 = curPos.x + stepScreen;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::InitializeViewTranslation() {
|
|
|
|
|
this->m_viewTranslation = this->m_position;
|
|
|
|
|
|
|
|
|
|
if (!this->m_intB0 || this->m_flags & 0x80) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->m_horzJust == GxHJ_Right) {
|
|
|
|
|
this->m_viewTranslation.x += this->m_blockWidth;
|
|
|
|
|
} else if (this->m_horzJust == GxHJ_Center) {
|
|
|
|
|
this->m_viewTranslation.x += (this->m_blockWidth * 0.5f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
float v13 = ((this->m_spacing * (float)GetScreenPixelHeight()) + 0.9999499917030334f) / (float)GetScreenPixelHeight();
|
|
|
|
|
float v24 = v13 * (float)(this->m_intB0 - 1) + (float)this->m_intB0 * this->m_currentFontHeight;
|
|
|
|
|
|
|
|
|
|
if (this->m_intD4 >= 4) {
|
|
|
|
|
// TODO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO
|
|
|
|
|
// - current font height logic
|
|
|
|
|
|
|
|
|
|
if (this->m_vertJust == GxVJ_Bottom) {
|
|
|
|
|
this->m_viewTranslation.y += v24;
|
|
|
|
|
} else if (this->m_vertJust == GxVJ_Middle) {
|
|
|
|
|
this->m_viewTranslation.y += 0.5f * (this->m_blockHeight - v24) + v24;
|
|
|
|
|
} else {
|
|
|
|
|
this->m_viewTranslation.y += this->m_blockHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->m_viewTranslation.x = floor((float)GetScreenPixelWidth() * this->m_viewTranslation.x);
|
|
|
|
|
this->m_viewTranslation.y = floor((float)GetScreenPixelHeight() * this->m_viewTranslation.y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::Recycle() {
|
|
|
|
|
this->m_batchedStringLink.Unlink();
|
|
|
|
|
g_freeStrings.LinkToTail(this);
|
|
|
|
|
this->ClearInstanceData();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::SetColor(const CImVector& color) {
|
|
|
|
|
if (this->m_fontColor == color) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->m_fontColor = color;
|
|
|
|
|
this->m_shadowColor.a = std::min(color.a, this->m_shadowColor.a);
|
|
|
|
|
|
|
|
|
|
if (!(this->m_flags & 0x8) || this->m_flags & 0x20 || this->m_intD4) {
|
|
|
|
|
this->ClearInstanceData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int32_t CGxString::SetGradient(int32_t startCharacter, int32_t length) {
|
|
|
|
|
// TODO
|
2023-01-03 00:45:25 -06:00
|
|
|
return 0;
|
2023-01-02 13:17:18 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::SetStringPosition(const C3Vector& position) {
|
|
|
|
|
this->m_position = position;
|
|
|
|
|
this->InitializeViewTranslation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::Tick() {
|
|
|
|
|
if (this->m_intB0) {
|
|
|
|
|
this->m_intD4++;
|
|
|
|
|
|
|
|
|
|
if (this->m_intD4 - 1 > 30) {
|
|
|
|
|
this->ClearInstanceData();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CGxString::WriteGeometry(CGxVertexPCT* buf, int32_t line, int32_t ofs, int32_t size) {
|
|
|
|
|
auto textLine = this->m_textLines[line];
|
|
|
|
|
|
|
|
|
|
if (textLine) {
|
|
|
|
|
textLine->WriteGeometry(
|
|
|
|
|
buf,
|
|
|
|
|
this->m_fontColor,
|
|
|
|
|
this->m_shadowOffset,
|
|
|
|
|
this->m_shadowColor,
|
|
|
|
|
this->m_viewTranslation,
|
|
|
|
|
this->m_flags & 0x01,
|
|
|
|
|
this->m_flags & 0x20,
|
|
|
|
|
ofs,
|
|
|
|
|
size
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|