mirror of
https://github.com/zeldaret/ss
synced 2026-05-30 08:56:34 -04:00
262 lines
8.2 KiB
C++
262 lines
8.2 KiB
C++
// ported from https://github.com/kiwi515/ogws/blob/master/src/nw4r/ut/ut_CharWriter.cpp
|
|
|
|
#include <nw4r/ut.h>
|
|
|
|
namespace {
|
|
|
|
static void SetupGXCommon() {
|
|
static const nw4r::ut::Color fog = 0;
|
|
|
|
GXSetFog(GX_FOG_NONE, fog, 0.0f, 0.0f, 0.0f, 0.0f);
|
|
GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA);
|
|
GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0);
|
|
GXSetNumChans(1);
|
|
GXSetChanCtrl(GX_COLOR0A0, FALSE, GX_SRC_REG, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
|
|
GXSetChanCtrl(GX_COLOR1A1, FALSE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE);
|
|
GXSetNumTexGens(1);
|
|
GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX_IDENT, FALSE, GX_DUALMTX_IDENT);
|
|
GXSetNumIndStages(0);
|
|
GXSetBlendMode(GX_BM_BLEND, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_SET);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
namespace nw4r {
|
|
namespace ut {
|
|
|
|
CharWriter::CharWriter() : mAlpha(255), mIsWidthFixed(false), mFixedWidth(0.0f), mFont(NULL) {
|
|
mLoadingTexture.Reset();
|
|
ResetColorMapping();
|
|
SetGradationMode(GRADMODE_NONE);
|
|
SetTextColor(Color(0xFFFFFFFF));
|
|
SetScale(1.0f, 1.0f);
|
|
SetCursor(0.0f, 0.0f, 0.0f);
|
|
EnableLinearFilter(true, true);
|
|
}
|
|
|
|
CharWriter::~CharWriter() {}
|
|
|
|
void CharWriter::SetupGX() {
|
|
ResetTextureCache();
|
|
|
|
if (mColorMapping.min != 0x00000000 || mColorMapping.max != 0xFFFFFFFF) {
|
|
SetupGXWithColorMapping(mColorMapping.min, mColorMapping.max);
|
|
} else if (mFont != NULL) {
|
|
switch (mFont->GetTextureFormat()) {
|
|
case GX_TF_I4:
|
|
case GX_TF_I8:
|
|
SetupGXForI();
|
|
break;
|
|
case GX_TF_IA4:
|
|
case GX_TF_IA8:
|
|
SetupGXDefault();
|
|
break;
|
|
case GX_TF_RGB565:
|
|
case GX_TF_RGB5A3:
|
|
case GX_TF_RGBA8:
|
|
SetupGXForRGBA();
|
|
break;
|
|
default:
|
|
SetupGXDefault();
|
|
break;
|
|
}
|
|
} else {
|
|
SetupGXDefault();
|
|
}
|
|
}
|
|
|
|
void CharWriter::SetFontSize(f32 width, f32 height) {
|
|
SetScale(width / mFont->GetWidth(), height / mFont->GetHeight());
|
|
}
|
|
|
|
void CharWriter::SetFontSize(f32 height) {
|
|
f32 scale = height / mFont->GetHeight();
|
|
SetScale(scale, scale);
|
|
}
|
|
|
|
f32 CharWriter::GetFontWidth() const {
|
|
return mScale.x * mFont->GetWidth();
|
|
}
|
|
|
|
f32 CharWriter::GetFontHeight() const {
|
|
return mScale.y * mFont->GetHeight();
|
|
}
|
|
|
|
f32 CharWriter::GetFontAscent() const {
|
|
return mScale.y * mFont->GetAscent();
|
|
}
|
|
|
|
f32 CharWriter::GetFontDescent() const {
|
|
return mScale.y * mFont->GetDescent();
|
|
}
|
|
|
|
void CharWriter::EnableLinearFilter(bool atSmall, bool atLarge) {
|
|
mFilter.atSmall = atSmall ? GX_LINEAR : GX_NEAR;
|
|
mFilter.atLarge = atLarge ? GX_LINEAR : GX_NEAR;
|
|
}
|
|
|
|
f32 CharWriter::Print(u16 ch) {
|
|
f32 width;
|
|
f32 left;
|
|
|
|
Glyph glyph;
|
|
mFont->GetGlyph(&glyph, ch);
|
|
|
|
if (mIsWidthFixed) {
|
|
width = mFixedWidth;
|
|
left = (width - glyph.widths.charWidth * mScale.x) / 2 + (glyph.widths.leftSpacing * mScale.x);
|
|
} else {
|
|
width = glyph.widths.charWidth * mScale.x;
|
|
left = glyph.widths.leftSpacing * mScale.x;
|
|
}
|
|
|
|
PrintGlyph(mCursorPos.x + left, mCursorPos.y, mCursorPos.z, glyph);
|
|
mCursorPos.x += width;
|
|
|
|
return width;
|
|
}
|
|
|
|
void CharWriter::PrintGlyph(f32 x, f32 y, f32 z, const Glyph &glyph) {
|
|
f32 x2 = x + (glyph.widths.glyphWidth * mScale.x);
|
|
f32 y2 = y + (glyph.height * mScale.y);
|
|
|
|
u32 posLeft = glyph.cellX;
|
|
u16 texLeft = 0x8000 * posLeft / glyph.texWidth;
|
|
|
|
u32 posTop = glyph.cellY;
|
|
u16 texTop = 0x8000 * posTop / glyph.texHeight;
|
|
|
|
u32 posRight = posLeft + glyph.widths.glyphWidth;
|
|
u16 texRight = 0x8000 * posRight / glyph.texWidth;
|
|
|
|
u32 posBottom = posTop + glyph.height;
|
|
u16 texBottom = 0x8000 * posBottom / glyph.texHeight;
|
|
|
|
LoadTexture(glyph, GX_TEXMAP0);
|
|
|
|
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
|
{
|
|
GXPosition3f32(x, y, z);
|
|
GXColor1u32(mVertexColor.tl);
|
|
GXTexCoord2s16(texLeft, texTop);
|
|
|
|
GXPosition3f32(x2, y, z);
|
|
GXColor1u32(mVertexColor.tr);
|
|
GXTexCoord2s16(texRight, texTop);
|
|
|
|
GXPosition3f32(x2, y2, z);
|
|
GXColor1u32(mVertexColor.br);
|
|
GXTexCoord2s16(texRight, texBottom);
|
|
|
|
GXPosition3f32(x, y2, z);
|
|
GXColor1u32(mVertexColor.bl);
|
|
GXTexCoord2s16(texLeft, texBottom);
|
|
}
|
|
// GXEnd();
|
|
}
|
|
|
|
void CharWriter::LoadTexture(const Glyph &glyph, GXTexMapID slot) {
|
|
LoadingTexture loadingTexture;
|
|
|
|
loadingTexture.slot = slot;
|
|
loadingTexture.texture = glyph.texture;
|
|
loadingTexture.filter = mFilter;
|
|
|
|
if (loadingTexture != mLoadingTexture) {
|
|
GXTexObj texObj;
|
|
GXInitTexObj(&texObj, glyph.texture, glyph.texWidth, glyph.texHeight, glyph.format, GX_CLAMP, GX_CLAMP, FALSE);
|
|
GXInitTexObjLOD(&texObj, mFilter.atSmall, mFilter.atLarge, 0.0f, 0.0f, 0.0f, FALSE, FALSE, GX_ANISO_1);
|
|
GXLoadTexObj(&texObj, slot);
|
|
|
|
mLoadingTexture = loadingTexture;
|
|
}
|
|
}
|
|
|
|
void CharWriter::UpdateVertexColor() {
|
|
// clang-format off
|
|
mVertexColor.tl = mTextColor.start;
|
|
mVertexColor.tr = mTextColor.gradMode != GRADMODE_H ? mTextColor.start : mTextColor.end;
|
|
mVertexColor.bl = mTextColor.gradMode != GRADMODE_V ? mTextColor.start : mTextColor.end;
|
|
mVertexColor.br = mTextColor.gradMode == GRADMODE_NONE ? mTextColor.start : mTextColor.end;
|
|
// clang-format on
|
|
|
|
mVertexColor.tl.a = (mVertexColor.tl.a * mAlpha) / 255, mVertexColor.tr.a = (mVertexColor.tr.a * mAlpha) / 255;
|
|
mVertexColor.bl.a = (mVertexColor.bl.a * mAlpha) / 255;
|
|
mVertexColor.br.a = (mVertexColor.br.a * mAlpha) / 255;
|
|
}
|
|
|
|
void CharWriter::SetupVertexFormat() {
|
|
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
|
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0);
|
|
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U16, 15);
|
|
|
|
GXClearVtxDesc();
|
|
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
|
GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT);
|
|
GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
|
|
}
|
|
|
|
void CharWriter::SetupGXDefault() {
|
|
SetupGXCommon();
|
|
|
|
GXSetNumTevStages(1);
|
|
GXSetTevDirect(GX_TEVSTAGE0);
|
|
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
|
GXSetTevOp(GX_TEVSTAGE0, GX_MODULATE);
|
|
|
|
SetupVertexFormat();
|
|
}
|
|
|
|
void CharWriter::SetupGXWithColorMapping(Color min, Color max) {
|
|
SetupGXCommon();
|
|
|
|
GXSetNumTevStages(2);
|
|
GXSetTevDirect(GX_TEVSTAGE0);
|
|
GXSetTevDirect(GX_TEVSTAGE1);
|
|
|
|
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
|
|
|
|
GXSetTevColor(GX_TEVREG0, min);
|
|
GXSetTevColor(GX_TEVREG1, max);
|
|
|
|
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_C0, GX_CC_C1, GX_CC_TEXC, GX_CC_ZERO);
|
|
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_A0, GX_CA_A1, GX_CA_TEXA, GX_CA_ZERO);
|
|
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
|
|
GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
|
|
GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_CPREV, GX_CC_RASC, GX_CC_ZERO);
|
|
GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_APREV, GX_CA_RASA, GX_CA_ZERO);
|
|
GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
|
|
SetupVertexFormat();
|
|
}
|
|
|
|
void CharWriter::SetupGXForI() {
|
|
SetupGXCommon();
|
|
|
|
GXSetNumTevStages(1);
|
|
GXSetTevDirect(GX_TEVSTAGE0);
|
|
GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0);
|
|
GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR0A0);
|
|
GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO, GX_CC_RASC);
|
|
GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_TEXA, GX_CA_RASA, GX_CA_ZERO);
|
|
GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, TRUE, GX_TEVPREV);
|
|
|
|
SetupVertexFormat();
|
|
}
|
|
|
|
void CharWriter::SetupGXForRGBA() {
|
|
SetupGXDefault();
|
|
}
|
|
|
|
CharWriter::LoadingTexture CharWriter::mLoadingTexture;
|
|
|
|
} // namespace ut
|
|
} // namespace nw4r
|