Start working on getting PAL/JP/Trilogy multilayered fonts implemented

This commit is contained in:
Phillip Stephens 2022-05-30 15:49:46 -07:00
parent fe65258d91
commit eff44ad56a
Signed by: Antidote
GPG Key ID: F8BEE4C83DACA60D
14 changed files with 185 additions and 104 deletions

View File

@ -34,16 +34,6 @@ public:
enum class EBlackKey { Zero, One };
enum class EFontType {
None = -1,
OneLayer = 0, /* Fill bit0 */
OneLayerOutline = 1, /* Fill bit0, Outline bit1 */
FourLayers = 2,
TwoLayersOutlines = 3, /* Fill bit0/2, Outline bit1/3 */
TwoLayers = 4, /* Fill bit0/1 and copied to bit2/3 */
TwoLayersOutlines2 = 8 /* Fill bit2/3, Outline bit0/1 */
};
private:
static bool sMangleMips;
static u32 sCurrentFrameCount;

View File

@ -43,41 +43,25 @@ void CFontRenderState::RefreshPalette() {
RefreshColor(EColorType::Background);
}
void CFontRenderState::RefreshColor(EColorType tp) {
switch (tp) {
case EColorType::Main:
if (!x48_font)
return;
switch (x48_font->GetMode()) {
case EColorType::Main:
case EColorType::Outline:
if (!x64_colorOverrides[0]) {
x0_drawStrOpts.x4_colors[0] = ConvertToTextureSpace(x54_colors[0]);
}
break;
default:
break;
void CFontRenderState::RefreshColor(EColorType color) {
if (color == EColorType::Geometry && !x64_colorOverrides[2]) {
x0_drawStrOpts.x4_colors[2] = ConvertToTextureSpace(x54_colors[2]);
} else if (color == EColorType::Main && IsFinishedLoading() && !x48_font.IsNull()) {
const auto mode = x48_font->GetMode();
if (mode == EFontMode::OneLayerOutline && !x64_colorOverrides[0]) {
x0_drawStrOpts.x4_colors[0] = ConvertToTextureSpace(x54_colors[0]);
} else if (mode == EFontMode::OneLayer && !x64_colorOverrides[0]) {
x0_drawStrOpts.x4_colors[0] = ConvertToTextureSpace(x54_colors[0]);
}
break;
case EColorType::Outline:
if (!x48_font)
return;
if (x64_colorOverrides[1])
return;
if (x48_font->GetMode() == EColorType::Outline)
} else if (color == EColorType::Outline && IsFinishedLoading() && !x48_font.IsNull() && !x64_colorOverrides[1]) {
if (x48_font->GetMode() == EFontMode::OneLayerOutline) {
x0_drawStrOpts.x4_colors[1] = ConvertToTextureSpace(x54_colors[1]);
break;
case EColorType::Geometry:
if (!x64_colorOverrides[2])
x0_drawStrOpts.x4_colors[2] = ConvertToTextureSpace(x54_colors[2]);
break;
case EColorType::Foreground:
}
} else if (color == EColorType::Background) {
RefreshColor(EColorType::Outline);
} else if (color == EColorType::Foreground) {
RefreshColor(EColorType::Main);
RefreshColor(EColorType::Geometry);
break;
case EColorType::Background:
RefreshColor(EColorType::Outline);
break;
}
}

View File

@ -175,6 +175,8 @@ void CGuiTextSupport::CheckAndRebuildTextBuffer() {
x14_props.x8_vertJustification);
g_TextExecuteBuf->AddColor(EColorType::Main, x24_fontColor);
g_TextExecuteBuf->AddColor(EColorType::Outline, x28_outlineColor);
g_TextExecuteBuf->AddCharacterExtraSpace(x34_characterExtraSpace);
g_TextExecuteBuf->AddLineExtraSpace(x38_lineExtraSpace);
std::u16string initStr;
if (x5c_fontId.IsValid())

View File

@ -78,8 +78,9 @@ class CGuiTextSupport {
zeus::CColor x28_outlineColor;
zeus::CColor x2c_geometryColor;
bool x30_imageBaseline = false;
s32 x30_; // new in PAL/JP
s32 x34_; // ""
s32 x30_; // new in PAL/JP
s32 x34_characterExtraSpace; // ""
s32 x38_lineExtraSpace; // ""
s32 x34_extentX;
s32 x38_extentY;
float x3c_curTime = 0.f;

View File

@ -49,12 +49,22 @@ void CLineExtraSpaceInstruction::PageInvoke(CFontRenderState& state, CTextRender
Invoke(state, buf);
}
void CLineInstruction::TestLargestFont(s32 w, s32 h, s32 b) {
if (!x18_largestMonoBaseline)
x18_largestMonoBaseline = b;
void CCharacterExtraSpaceInstruction::Invoke(CFontRenderState& state, CTextRenderBuffer* buf) const {
state.x48_extraCharacterSpace = x4_extraSpace;
}
if (x14_largestMonoWidth < w)
void CCharacterExtraSpaceInstruction::PageInvoke(CFontRenderState& state, CTextRenderBuffer* buf) const {
Invoke(state, buf);
}
void CLineInstruction::TestLargestFont(s32 w, s32 h, s32 b) {
if (!x18_largestMonoBaseline) {
x18_largestMonoBaseline = b;
}
if (x14_largestMonoWidth < w) {
x14_largestMonoWidth = w;
}
if (x10_largestMonoHeight < h) {
x10_largestMonoHeight = h;

View File

@ -60,6 +60,13 @@ public:
void PageInvoke(CFontRenderState& state, CTextRenderBuffer* buf) const override;
};
class CCharacterExtraSpaceInstruction : public CInstruction {
s32 x4_extraSpace;
public:
explicit CCharacterExtraSpaceInstruction(s32 extraSpace) : x4_extraSpace(extraSpace) {}
void Invoke(CFontRenderState& state, CTextRenderBuffer* buf) const override;
void PageInvoke(CFontRenderState& state, CTextRenderBuffer* buf) const override;
};
class CLineInstruction : public CInstruction {
friend class CTextExecuteBuffer;
friend class CTextInstruction;

View File

@ -36,7 +36,7 @@ CRasterFont::CRasterFont(metaforce::CInputStream& in, metaforce::IObjectStore& s
u32 txtrId = (version == 5 ? in.ReadLongLong() : in.ReadLong());
x30_fontInfo = CFontInfo(tmp1, tmp2, tmp3, tmp4, name.c_str());
x80_texture = store.GetObj({FOURCC('TXTR'), txtrId});
x2c_mode = CTexture::EFontType(in.ReadLong());
x2c_mode = EFontMode(in.ReadLong());
u32 glyphCount = in.ReadLong();
xc_glyphs.reserve(glyphCount);
@ -160,7 +160,7 @@ void CRasterFont::DrawString(const CDrawStringOptions& opts, int x, int y, int&
data[2] = bswap16(opts.x4_colors[1].toRGB5A3());
data[3] = bswap16(zeus::CColor(0.f, 0.f, 0.f, 0.f).toRGB5A3());
pal.UnLock();
renderBuf->AddPaletteChange(pal);
renderBuf->AddPaletteChange(pal, GetMode());
}
SinglePassDrawString(opts, x, y, xout, yout, renderBuf, str, len);

View File

@ -16,7 +16,23 @@ class CDrawStringOptions;
class CTextRenderBuffer;
class IObjectStore;
enum class EColorType { Main, Outline, Geometry, Foreground, Background };
enum class EFontMode {
None = -1,
OneLayer = 0, /* Fill bit0 */
OneLayerOutline = 1, /* Fill bit0, Outline bit1 */
FourLayers = 2,
TwoLayersOutlines = 3, /* Fill bit0/2, Outline bit1/3 */
TwoLayers = 4, /* Fill bit0/1 and copied to bit2/3 */
TwoLayersOutlines2 = 8 /* Fill bit2/3, Outline bit0/1 */
};
enum class EColorType {
Main,
Outline,
Geometry,
Foreground,
Background,
};
/* NOTE: Is this a good place for CGlyph and CKernPair? */
class CGlyph {
@ -100,7 +116,7 @@ class CRasterFont {
s32 x8_monoHeight = 16;
std::vector<std::pair<char16_t, CGlyph>> xc_glyphs;
std::vector<CKernPair> x1c_kerning;
CTexture::EFontType x2c_mode = CTexture::EFontType::OneLayer;
EFontMode x2c_mode = EFontMode::OneLayer;
CFontInfo x30_fontInfo;
TLockedToken<CTexture> x80_texture;
s32 x8c_baseline;
@ -113,20 +129,8 @@ public:
s32 GetMonoWidth() const { return x4_monoWidth; }
s32 GetMonoHeight() const { return x8_monoHeight; }
EColorType GetMode() const {
switch (x2c_mode) {
case CTexture::EFontType::OneLayer:
case CTexture::EFontType::TwoLayers:
case CTexture::EFontType::FourLayers:
return EColorType::Main;
case CTexture::EFontType::OneLayerOutline:
case CTexture::EFontType::TwoLayersOutlines:
case CTexture::EFontType::TwoLayersOutlines2:
return EColorType::Outline;
default:
return EColorType::Main;
}
}
EFontMode GetMode() const { return x2c_mode; }
s32 GetLineMargin() const { return x90_lineMargin; }
s32 GetCarriageAdvance() const { return GetLineMargin() + GetMonoHeight(); }

View File

@ -16,6 +16,7 @@ class CSaveableState {
friend class CFontInstruction;
friend class CGuiTextSupport;
friend class CLineExtraSpaceInstruction;
friend class CCharacterExtraSpaceInstruction;
friend class CLineSpacingInstruction;
friend class CRemoveColorOverrideInstruction;
friend class CTextExecuteBuffer;
@ -24,6 +25,7 @@ class CSaveableState {
protected:
CDrawStringOptions x0_drawStrOpts;
s32 x48_extraCharacterSpace;
TLockedToken<CRasterFont> x48_font;
std::vector<CTextColor> x54_colors;
std::vector<bool> x64_colorOverrides;

View File

@ -314,6 +314,11 @@ void CTextExecuteBuffer::AddLineExtraSpace(s32 space) {
x18_textState.x78_extraLineSpace = space;
}
void CTextExecuteBuffer::AddCharacterExtraSpace(s32 space) {
x0_instList.emplace(x0_instList.cend(), std::make_shared<CCharacterExtraSpaceInstruction>(space));
x18_textState.x48_extraCharacterSpace = space;
}
void CTextExecuteBuffer::AddLineSpacing(float spacing) {
x0_instList.emplace(x0_instList.cend(), std::make_shared<CLineSpacingInstruction>(spacing));
x18_textState.x74_lineSpacing = spacing;

View File

@ -58,6 +58,7 @@ public:
void AddVerticalJustification(EVerticalJustification vjust);
void AddJustification(EJustification just);
void AddLineExtraSpace(s32 space);
void AddCharacterExtraSpace(s32 space);
void AddLineSpacing(float spacing);
void AddRemoveColorOverride(int idx);
void AddColorOverride(int idx, const CTextColor& color);

View File

@ -117,6 +117,8 @@ void CTextParser::ParseTag(CTextExecuteBuffer& out, const char16_t* str, int len
out.AddLineSpacing(ParseInt(str + 13, len - 13, true) / 100.0f);
} else if (BeginsWith(str, len, u"line-extra-space=")) {
out.AddLineExtraSpace(ParseInt(str + 17, len - 17, true));
} else if (BeginsWith(str, len, u"character-extra-space")) {
out.AddCharacterExtraSpace(ParseInt(str + 22, len - 22, true));
} else if (BeginsWith(str, len, u"just=")) {
if (Equals(str + 5, len - 5, u"left"))
out.AddJustification(EJustification::Left);

View File

@ -78,7 +78,7 @@ void CTextRenderBuffer::SetMode(EMode mode) { x0_mode = mode; }
int CTextRenderBuffer::GetMatchingPaletteIndex(const CGraphicsPalette& palette) {
for (int i = 0; i < x50_palettes.size(); ++i) {
if (memcmp(x50_palettes[i]->GetPaletteData(), palette.GetPaletteData(), 8) == 0) {
if (memcmp(x50_palettes[i].x4_colorPal.data(), palette.GetPaletteData(), 8) == 0) {
return i;
}
}
@ -86,14 +86,17 @@ int CTextRenderBuffer::GetMatchingPaletteIndex(const CGraphicsPalette& palette)
return -1;
}
CGraphicsPalette* CTextRenderBuffer::GetNextAvailablePalette() {
CTextRenderBuffer::SFontPalette* CTextRenderBuffer::GetNextAvailablePalette() {
if (x254_nextPalette < 64) {
x50_palettes.push_back(std::make_unique<CGraphicsPalette>(EPaletteFormat::RGB5A3, 4));
x50_palettes.emplace_back(EFontMode::None, std::make_unique<CGraphicsPalette>(EPaletteFormat::RGB5A3, 16),
std::make_unique<CGraphicsPalette>(EPaletteFormat::RGB5A3, 16),
std::make_unique<CGraphicsPalette>(EPaletteFormat::RGB5A3, 16),
std::make_unique<CGraphicsPalette>(EPaletteFormat::RGB5A3, 16));
} else {
x254_nextPalette = 0;
}
++x254_nextPalette;
return x50_palettes[x254_nextPalette - 1].get();
return &x50_palettes[x254_nextPalette - 1];
}
u32 CTextRenderBuffer::GetCurLen() {
@ -102,6 +105,12 @@ u32 CTextRenderBuffer::GetCurLen() {
}
void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
constexpr std::array skVtxDesc{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
x4c_activeFont = -1;
x4d_activePalette = -1;
CMemoryInStream in(x34_bytecode.data(), x44_blobSize);
@ -117,20 +126,41 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
x4e_queuedFont = -1;
}
}
if (x4f_queuedPalette != -1) {
x50_palettes[x4f_queuedPalette]->Load();
x4f_queuedPalette = -1;
}
s16 offX = in.ReadShort();
s16 offY = in.ReadShort();
char16_t chr = in.ReadShort();
zeus::CColor chrColor(static_cast<zeus::Comp32>(in.ReadLong()));
if (x4c_activeFont != -1) {
auto font = x4_fonts[x4c_activeFont];
if (font && font->GetGlyph(chr) != nullptr) {
if (font) {
const auto* glyph = font->GetGlyph(chr);
if (glyph == nullptr) {
continue;
}
const auto layer = glyph->GetLayer();
s32 paletteIdx = x4f_queuedPalette;
if (paletteIdx != -1 || layer != -1) {
if (paletteIdx == -1) {
paletteIdx = x4d_activePalette;
}
if (paletteIdx != -1) {
if (layer == 0) {
x50_palettes[paletteIdx].xc_layer1Pal->Load();
} else if (glyph->GetLayer() == 1) {
x50_palettes[paletteIdx].x14_layer2Pal->Load();
} else if (glyph->GetLayer() == 2) {
x50_palettes[paletteIdx].x1c_layer3Pal->Load();
} else if (glyph->GetLayer() == 3) {
x50_palettes[paletteIdx].x24_layer4Pal->Load();
}
x4f_queuedPalette = -1;
}
}
CGX::SetTevKColor(GX::KCOLOR0, chrColor * color);
CGX::SetVtxDescv(skVtxDesc.data());
CGX::SetNumChans(0);
CGX::SetNumTexGens(1);
CGX::Begin(GX::TRIANGLESTRIP, GX::VTXFMT0, 4);
{
GXPosition3f32(offX, 0.f, offY);
@ -164,11 +194,6 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
CGX::SetTevColorIn(GX::TEVSTAGE0, GX::CC_ZERO, GX::CC_TEXC, GX::CC_KONST, GX::CC_ZERO);
CGX::SetTevAlphaIn(GX::TEVSTAGE0, GX::CA_ZERO, GX::CA_TEXA, GX::CA_KONST, GX::CA_ZERO);
CGX::SetStandardTevColorAlphaOp(GX::TEVSTAGE0);
constexpr std::array skVtxDesc{
GX::VtxDescList{GX::VA_POS, GX::DIRECT},
GX::VtxDescList{GX::VA_TEX0, GX::DIRECT},
GX::VtxDescList{},
};
CGX::SetVtxDescv(skVtxDesc.data());
CGX::SetNumChans(0);
CGX::SetNumTexGens(1);
@ -197,24 +222,57 @@ void CTextRenderBuffer::Render(const zeus::CColor& color, float time) {
}
}
void CTextRenderBuffer::AddPaletteChange(const CGraphicsPalette& palette) {
if (x0_mode == EMode::BufferFill) {
{
u8* buf = GetOutStream();
CMemoryStreamOut out(buf, GetCurLen());
s32 paletteIndex = GetMatchingPaletteIndex(palette);
if (paletteIndex == -1) {
GetNextAvailablePalette();
paletteIndex = x254_nextPalette - 1;
CGraphicsPalette* destPalette = x50_palettes[x254_nextPalette - 1].get();
u16* data = destPalette->Lock();
memcpy(data, palette.GetPaletteData(), 8);
destPalette->UnLock();
void SetFontPalette(EFontMode mode, u32 layer, CGraphicsPalette& layerPal, const CGraphicsPalette& colorPal) {
u16* layerLut = layerPal.Lock();
const u16* colorLut = colorPal.GetPaletteData();
if (mode == EFontMode::OneLayer || mode == EFontMode::OneLayerOutline) {
memcpy(layerLut, colorLut, 8);
} else {
u32 layerOffset = layer * 2;
for (u32 i = 0; i < 16; ++i) {
if (mode == EFontMode::TwoLayersOutlines) {
u32 uVar1 = (i & 2) << layerOffset;
if ((i & 1) << layerOffset == 0) {
if ((-uVar1 | uVar1) < 0) {
*layerLut = colorLut[2];
} else {
*layerLut = colorLut[0];
}
} else {
*layerLut = colorLut[1];
}
} else if (mode == EFontMode::FourLayers) {
if ((i >> (layer & 0x3f) & 1) == 0) {
*layerLut = colorLut[0];
} else {
*layerLut = colorLut[1];
}
}
out.WriteUint8(static_cast<u8>(Command::PaletteChange));
out.WriteUint8(paletteIndex);
x48_curBytecodeOffset += out.GetNumWrites();
++layerLut;
}
}
layerPal.UnLock();
}
void CTextRenderBuffer::AddPaletteChange(const CGraphicsPalette& palette, EFontMode mode) {
if (x0_mode == EMode::BufferFill) {
CMemoryStreamOut out(GetOutStream(), GetCurLen(), CMemoryStreamOut::EOwnerShip::NotOwned, 64);
s32 paletteIndex = GetMatchingPaletteIndex(palette);
if (paletteIndex == -1) {
GetNextAvailablePalette();
paletteIndex = x254_nextPalette - 1;
x50_palettes[paletteIndex].x0_mode = mode;
auto& destPalette = x50_palettes[x254_nextPalette - 1];
memcpy(destPalette.x4_colorPal.data(), palette.GetPaletteData(), 8);
SetFontPalette(mode, 0, *destPalette.xc_layer1Pal, palette);
SetFontPalette(mode, 1, *destPalette.x14_layer2Pal, palette);
SetFontPalette(mode, 2, *destPalette.x1c_layer3Pal, palette);
SetFontPalette(mode, 3, *destPalette.x24_layer4Pal, palette);
}
out.WriteUint8(static_cast<u8>(Command::PaletteChange));
out.WriteUint8(paletteIndex);
x48_curBytecodeOffset += out.GetNumWrites();
} else {
x44_blobSize += 2;
}
@ -245,7 +303,7 @@ void CTextRenderBuffer::AddImage(const zeus::CVector2i& offset, const CFontImage
void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, char16_t ch, const CTextColor& color) {
if (x0_mode == EMode::BufferFill) {
CMemoryStreamOut out(GetOutStream(), GetCurLen());
CMemoryStreamOut out(GetOutStream(), GetCurLen(), CMemoryStreamOut::EOwnerShip::NotOwned, 64);
x24_primOffsets.reserve(x24_primOffsets.size() + 1);
u32 primCap = x24_primOffsets.capacity();
if (x24_primOffsets.capacity() <= x24_primOffsets.size()) {
@ -265,7 +323,7 @@ void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, char16_t ch,
void CTextRenderBuffer::AddFontChange(const TToken<CRasterFont>& font) {
if (x0_mode == EMode::BufferFill) {
CMemoryStreamOut out(GetOutStream(), GetCurLen());
CMemoryStreamOut out(GetOutStream(), GetCurLen(), CMemoryStreamOut::EOwnerShip::NotOwned, 64);
u32 fontCount = x4_fonts.size();
bool found = false;
u8 fontIndex = 0;

View File

@ -5,9 +5,9 @@
#include "Runtime/CToken.hpp"
#include "Runtime/RetroTypes.hpp"
#include "Runtime/Graphics/Shaders/CTextSupportShader.hpp"
#include "Runtime/GuiSys/CFontImageDef.hpp"
#include "Runtime/GuiSys/CGuiWidget.hpp"
#include "Runtime/GuiSys/CRasterFont.hpp"
#include <zeus/CColor.hpp>
#include <zeus/CMatrix4f.hpp>
@ -15,9 +15,7 @@
#include <zeus/CVector2i.hpp>
namespace metaforce {
class CGlyph;
class CGraphicsPalette;
class CRasterFont;
class CTextExecuteBuffer;
using CTextColor = zeus::CColor;
@ -38,6 +36,23 @@ public:
};
enum class EMode { AllocTally, BufferFill };
struct SFontPalette {
EFontMode x0_mode;
std::array<u8, 8> x4_colorPal;
std::unique_ptr<CGraphicsPalette> xc_layer1Pal;
std::unique_ptr<CGraphicsPalette> x14_layer2Pal;
std::unique_ptr<CGraphicsPalette> x1c_layer3Pal;
std::unique_ptr<CGraphicsPalette> x24_layer4Pal;
SFontPalette(EFontMode mode, std::unique_ptr<CGraphicsPalette>&& pal1, std::unique_ptr<CGraphicsPalette>&& pal2,
std::unique_ptr<CGraphicsPalette>&& pal3, std::unique_ptr<CGraphicsPalette>&& pal4)
: x0_mode(mode)
, xc_layer1Pal(std::move(pal1))
, x14_layer2Pal(std::move(pal2))
, x1c_layer3Pal(std::move(pal3))
, x24_layer4Pal(std::move(pal4)) {}
};
private:
EMode x0_mode;
std::vector<TToken<CRasterFont>> x4_fonts;
@ -50,7 +65,7 @@ private:
s8 x4d_activePalette = -1;
s8 x4e_queuedFont = -1;
s8 x4f_queuedPalette = -1;
rstl::reserved_vector<std::unique_ptr<CGraphicsPalette>, 64> x50_palettes;
rstl::reserved_vector<SFontPalette, 64> x50_palettes;
s32 x254_nextPalette = 0;
public:
@ -67,8 +82,8 @@ public:
[[nodiscard]] u32 GetCurLen();
void VerifyBuffer();
int GetMatchingPaletteIndex(const CGraphicsPalette& palette);
[[nodiscard]] CGraphicsPalette* GetNextAvailablePalette();
void AddPaletteChange(const CGraphicsPalette& palette);
[[nodiscard]] SFontPalette* GetNextAvailablePalette();
void AddPaletteChange(const CGraphicsPalette& palette, EFontMode mode);
void SetMode(EMode mode);
void Render(const CTextColor& col, float time);
void AddImage(const zeus::CVector2i& offset, const CFontImageDef& image);