Textbox progress

This commit is contained in:
robojumper
2025-04-02 17:47:19 +02:00
parent 4e88b4aec7
commit 010c0a9a3b
18 changed files with 553 additions and 90 deletions
+389
View File
@@ -0,0 +1,389 @@
#include "d/lyt/d_textbox.h"
#include "common.h"
#include "d/d_font_manager.h"
#include "d/d_tag_processor.h"
#include "d/d_textunk.h"
#include "libms/msgfile.h"
#include "nw4r/lyt/lyt_drawInfo.h"
#include "nw4r/lyt/lyt_textBox.h"
#include "nw4r/lyt/lyt_types.h"
#include "nw4r/ut/ut_Rect.h"
#include <cstring>
dTextBox_c::dTextBox_c(const nw4r::lyt::res::TextBox *pBlock, const nw4r::lyt::ResBlockSet &resBlockSet)
: nw4r::lyt::TextBox(pBlock, resBlockSet),
mMyFontSize(0.0f, 0.0f),
mMyTextScale(0.0f, 0.0f),
field_0x188(0.0f),
field_0x18C(0.0f),
field_0x190(0.0f),
field_0x194(0.0f) {
const nw4r::lyt::res::Font *fonts = nw4r::lyt::detail::ConvertOffsToPtr<nw4r::lyt::res::Font>(
resBlockSet.pFontList, sizeof(nw4r::lyt::res::FontList)
);
const char *fontName = nw4r::lyt::detail::ConvertOffsToPtr<char>(fonts, fonts[pBlock->fontIdx].nameStrOffset);
for (u32 i = 0; i < 5; i++) {
const char *name = dFontMng_c::getFontName(i);
if (!std::strcmp(fontName, name)) {
mFontIdx = i;
break;
}
}
init();
}
///////////////////////////////////////////////////////////////////////////
// Begin largely copied from nw4r::lyt::TextBox
///////////////////////////////////////////////////////////////////////////
inline u8 ClampColor(s16 colVal) {
// The CLAMP macro was reversed for this -_-
return colVal < 0 ? 0 : (colVal > 0xFF ? 0xFF : colVal);
}
nw4r::ut::Color GetColor(const GXColorS10 &src) {
GXColor dst;
dst.r = ClampColor(src.r);
dst.g = ClampColor(src.g);
dst.b = ClampColor(src.b);
dst.a = ClampColor(src.a);
return dst;
}
static void CalcStringRect(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> &textWriter, const wchar_t *str, int length,
bool *pbWideScreenUnk, f32 maxWidth
);
static void CalcStringRectImpl(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> *pTextWriter, const wchar_t *str, int length, f32 maxWidth,
bool *pbWideScreenUnk
);
static int CalcLineRectImpl(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> *pTextWriter, const wchar_t *str, int length, f32 maxWidth,
bool *pbOver, bool *pbWideScreenUnk
);
nw4r::ut::Rect dTextBox_c::GetMyTextDrawRect(nw4r::ut::TextWriterBase<wchar_t> *pWriter, bool *pbWideScreenUnk) const {
nw4r::ut::Rect textRect;
pWriter->SetCursor(0.0f, 0.0f);
pWriter->SetFont(*mpFont);
pWriter->SetFontSize(GetFontSize().width, GetFontSize().height);
pWriter->SetLineSpace(mLineSpace);
pWriter->SetCharSpace(mCharSpace);
if (mIsWidthFixed == true) {
pWriter->EnableFixedWidth(true);
pWriter->SetFixedWidth(mFixedWidth);
}
if (GetTagProcessor() != nullptr) {
pWriter->SetTagProcessor(GetTagProcessor());
}
CalcStringRect(&textRect, *pWriter, mTextBuf, mTextLen, pbWideScreenUnk, FLT_MAX);
nw4r::lyt::Size textSize(textRect.GetWidth(), textRect.GetHeight());
nw4r::math::VEC2 ltPos = GetVtxPos();
// Adjust for Alignment (left, center, right)
ltPos.x += (mSize.width - textSize.width) * GetTextMagH();
ltPos.y -= (mSize.height - textSize.height) * GetTextMagV();
// Apply the new pos
textRect.left = ltPos.x;
textRect.top = ltPos.y;
textRect.right = ltPos.x + textSize.width;
textRect.bottom = ltPos.y - textSize.height;
return textRect;
}
static void CalcStringRect(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> &textWriter, const wchar_t *str, int length,
bool *pbWideScreenUnk, f32 maxWidth
) {
nw4r::ut::TextWriterBase<wchar_t> writerCpy(textWriter);
CalcStringRectImpl(pRect, &writerCpy, str, length, maxWidth, pbWideScreenUnk);
}
static void CalcStringRectImpl(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> *pTextWriter, const wchar_t *str, int length, f32 maxWidth,
bool *pbWideScreenUnk
) {
pRect->left = 0.0f;
pRect->right = 0.0f;
pRect->top = 0.0f;
pRect->bottom = 0.0f;
pTextWriter->SetCursor(0.0f, 0.0f);
int remain = length;
const wchar_t *pos = str;
int i = 0;
do {
nw4r::ut::Rect rect;
bool bOver;
int read =
CalcLineRectImpl(&rect, pTextWriter, pos, remain, maxWidth, &bOver, i == 0 ? pbWideScreenUnk : nullptr);
pos += read;
remain -= read;
pRect->left = nw4r::ut::Min(pRect->left, rect.left);
pRect->top = nw4r::ut::Min(pRect->top, rect.top);
pRect->right = nw4r::ut::Max(pRect->right, rect.right);
pRect->bottom = nw4r::ut::Max(pRect->bottom, rect.bottom);
if (bOver) {
CalcLineRectImpl(&rect, pTextWriter, L"\n", 1, maxWidth, &bOver, nullptr);
pRect->left = nw4r::ut::Min(pRect->left, rect.left);
pRect->top = nw4r::ut::Min(pRect->top, rect.top);
pRect->right = nw4r::ut::Max(pRect->right, rect.right);
pRect->bottom = nw4r::ut::Max(pRect->bottom, rect.bottom);
}
i++;
} while (remain > 0);
}
extern "C" bool NeedsScreenAdjustment();
static int CalcLineRectImpl(
nw4r::ut::Rect *pRect, nw4r::ut::TextWriterBase<wchar_t> *pTextWriter, const wchar_t *str, int length, f32 maxWidth,
bool *pbOver, bool *pbWideScreenUnk
) {
nw4r::ut::PrintContext<wchar_t> context = {pTextWriter, str, 0.0f, 0.0f, 0};
f32 x = 0.0f;
const nw4r::ut::Font *font = pTextWriter->GetFont();
bool bCharSpace = false;
nw4r::ut::CharStrmReader reader = font->GetCharStrmReader();
const wchar_t *prStrPos = (const wchar_t *)reader.GetCurrentPos();
pRect->left = 0.0f;
pRect->right = 0.0f;
pRect->top = nw4r::ut::Min(0.0f, pTextWriter->GetLineHeight());
pRect->bottom = nw4r::ut::Max(0.0f, pTextWriter->GetLineHeight());
*pbOver = false;
reader.Set(str);
nw4r::ut::Rect prMaxRect = *pRect;
u16 code = reader.Next();
while (((const wchar_t *)reader.GetCurrentPos() - str) <= length) {
if (code < ' ') {
nw4r::ut::Operation operation;
nw4r::ut::Rect rect(x, 0.0f, 0.0f, 0.0f);
context.str = (const wchar_t *)reader.GetCurrentPos();
context.flags = !bCharSpace;
pTextWriter->SetCursorX(x);
// ??????????
if (pbWideScreenUnk != nullptr && ((u32 *)context.str)[0] == 0 && NeedsScreenAdjustment()) {
*pbWideScreenUnk = true;
}
operation = pTextWriter->GetTagProcessor()->CalcRect(&rect, code, &context);
reader.Set(context.str);
pRect->left = nw4r::ut::Min(pRect->left, rect.left);
pRect->top = nw4r::ut::Min(pRect->top, rect.top);
pRect->right = nw4r::ut::Max(pRect->right, rect.right);
pRect->bottom = nw4r::ut::Max(pRect->bottom, rect.bottom);
x = pTextWriter->GetCursorX();
if (pRect->GetWidth() > maxWidth) {
*pbOver = true;
break;
}
if (operation == nw4r::ut::OPERATION_END_DRAW) {
return length;
} else if (operation == nw4r::ut::OPERATION_NO_CHAR_SPACE) {
bCharSpace = false;
} else if (operation == nw4r::ut::OPERATION_CHAR_SPACE) {
bCharSpace = true;
} else if (operation == nw4r::ut::OPERATION_NEXT_LINE) {
break;
}
} else {
if (bCharSpace) {
x += pTextWriter->GetCharSpace();
}
bCharSpace = true;
if (pTextWriter->IsWidthFixed()) {
x += pTextWriter->GetFixedWidth();
} else {
x += pTextWriter->GetFont()->GetCharWidth(code) * pTextWriter->GetScaleH();
}
pRect->left = nw4r::ut::Min(pRect->left, x);
pRect->right = nw4r::ut::Max(pRect->right, x);
if (pRect->GetWidth() > maxWidth) {
*pbOver = true;
break;
}
}
prStrPos = (const wchar_t *)reader.GetCurrentPos();
code = reader.Next();
prMaxRect = *pRect;
}
if (*pbOver) {
if (prStrPos) {
*pRect = prMaxRect;
return (prStrPos - str);
}
}
return ((const wchar_t *)reader.GetCurrentPos() - str);
}
///////////////////////////////////////////////////////////////////////////
// End largely copied from nw4r::lyt::TextBox
///////////////////////////////////////////////////////////////////////////
void dTextBox_c::setTextWithGlobalTextProcessor(const wchar_t *str, void *unk, ...) {
va_list l;
va_start(l, str);
setTextWithGlobalTextProcessorV(str, unk, l);
va_end(l);
}
extern "C" dTagProcessor_c *GLOBAL_TEXT_MANAGER;
void dTextBox_c::setTextWithGlobalTextProcessorV(const wchar_t *str, void *unk, va_list list) {
SetFontSize(mMyTextScale);
mHasTextWriter = true;
mpMyTagProcessor = GLOBAL_TEXT_MANAGER;
u32 outLen = 0;
mWindowSubtype = mpMyTagProcessor->getMsgWindowSubtype();
mpMyTagProcessor->setField_0xEE1(field_0x1F6);
mpMyTagProcessor->setField_0xEE2(0);
mpMyTagProcessor->setField_0xEE3(1);
static wchar_t destBuffer[0x200];
mpMyTagProcessor->formatV(nullptr, str, destBuffer, ARRAY_LENGTH(destBuffer), &outLen, unk, list);
SetString(destBuffer, 0, outLen);
}
void dTextBox_c::setTextWithTextProcessor(const wchar_t *str, dTagProcessor_c *tagProcessor, void *unk, ...) {
va_list l;
va_start(l, str);
setTextWithTextProcessorV(str, tagProcessor, unk, l);
va_end(l);
}
void dTextBox_c::setTextWithTextProcessorV(const wchar_t *str, dTagProcessor_c *tagProcessor, void *unk, va_list list) {
SetFontSize(mMyTextScale);
mHasTextWriter = true;
u32 outLen = 0;
mpMyTagProcessor = tagProcessor;
mWindowSubtype = mpMyTagProcessor->getMsgWindowSubtype();
mpMyTagProcessor->setField_0xEE1(field_0x1F6);
mpMyTagProcessor->setField_0xEE2(0);
mpMyTagProcessor->setField_0xEE3(1);
static wchar_t destBuffer[0x200];
mpMyTagProcessor->formatV(nullptr, str, destBuffer, ARRAY_LENGTH(destBuffer), &outLen, unk, list);
SetString(destBuffer, 0, outLen);
}
s32 dTextBox_c::calcTextLines(const wchar_t *src, dTagProcessor_c *tagProcessor) {
static wchar_t destBuffer[0x200];
u32 outLen = 0;
tagProcessor->format(this, src, destBuffer, ARRAY_LENGTH(destBuffer), &outLen, nullptr);
return tagProcessor->getNumLinesMaybe();
}
extern "C" const wchar_t *getTextMessageByLabel(const char *labelId, int, int, int);
void dTextBox_c::setMessageWithGlobalTextProcessor(const char *labelId, void *unused, void *unk, ...) {
va_list l;
va_start(l, str);
setMessageWithGlobalTextProcessorV(labelId, unused, unk, l);
va_end(l);
}
void dTextBox_c::setMessageWithGlobalTextProcessorV(const char *labelId, void *unused, void *unk, va_list list) {
const wchar_t *text = getTextMessageByLabel(labelId, 1, 0, 0);
setTextWithGlobalTextProcessorV(text, unk, list);
if (GetFont() != nullptr) {
fn_800AFD60(GetSize().width);
}
}
void dTextBox_c::setMessageWithGlobalTextProcessorAndMsbtInfo(
const MsbtInfo *info, const char *labelId, wchar_t *destBuf, u32 maxLen
) {
const wchar_t *src = LMS_GetTextByLabel(info, labelId);
SetFontSize(mMyTextScale);
mHasTextWriter = true;
field_0x1FA = 1;
u32 outLen = 0;
mpMyTagProcessor = GLOBAL_TEXT_MANAGER;
mpMyTagProcessor->setMsgWindowSubtype(0x22);
mWindowSubtype = mpMyTagProcessor->getMsgWindowSubtype();
mpMyTagProcessor->setField_0xEE1(field_0x1F6);
mpMyTagProcessor->setField_0xEE2(0);
mpMyTagProcessor->setField_0xEE3(1);
mpMyTagProcessor->format(nullptr, src, destBuf, maxLen, &outLen, 0);
SetString(destBuf, 0, outLen);
}
void dTextBox_c::setTextWithGlobalTextProcessor(const wchar_t *str) {
setTextWithGlobalTextProcessor(str, nullptr);
if (GetFont() != nullptr) {
fn_800AFD60(GetSize().width);
}
}
void dTextBox_c::init() {
mpLytBase = nullptr;
mIsWidthFixed = false;
mFixedWidth = 0.0f;
mHasTextWriter = true;
field_0x1F6 = 0;
field_0x1F7 = 0;
field_0x1F9 = 0;
field_0x1FA = 0;
field_0x1F8 = 2;
mpMyTagProcessor = nullptr;
MySetFontSize(GetFontSize());
for (int i = 0; i < 10; i++) {
field_0x198[i] = 0;
field_0x1C4[i] = 0.0f;
field_0x1EC[i] = 0;
}
f32 f1 = 35.0f;
if (mFontIdx > 1 && mFontIdx < 4) {
f1 = 41.0f;
}
nw4r::lyt::Size sz = GetFontSize();
f32 scale = UnkTextThing::getFn800B1F70();
f32 height = sz.height / f1;
sz.width = GetFont()->GetWidth() * height * scale;
sz.height = GetFont()->GetHeight() * height * scale;
SetFontSize(sz);
mMyTextScale = sz;
mMyScale = 1.0f;
mWindowSubtype = 0x24;
field_0x201 = 1;
}
void dTextBox_c::DrawSelf(const nw4r::lyt::DrawInfo &drawInfo) {
if (!mTextBuf || !mpFont || !mpMaterial) {
return;
}
LoadMtx(drawInfo);
nw4r::ut::TextWriterBase<wchar_t> writer;
// TODO
}
void dTextBox_c::MySetFontSize(const nw4r::lyt::Size &value) {
mMyFontSize = value;
}
void dTextBox_c::MySetScale(const nw4r::lyt::Size &value) {
mMyTextScale = value;
}