diff --git a/libs/JSystem/include/JSystem/JUtility/JUTFont.h b/libs/JSystem/include/JSystem/JUtility/JUTFont.h index d07e09a590..3c1cd0bf1f 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTFont.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTFont.h @@ -7,8 +7,7 @@ #if TARGET_PC struct FontDrawContext { - int loadedBlock = -1; - int loadedPage = -1; + bool isTextureLoaded = false; }; #define FONT_DRAW_CTX , FontDrawContext* context #define FONT_DRAW_CTX_ARG , context diff --git a/libs/JSystem/include/JSystem/JUtility/JUTResFont.h b/libs/JSystem/include/JSystem/JUtility/JUTResFont.h index 68fd798ba5..d9094f72a9 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTResFont.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTResFont.h @@ -18,10 +18,6 @@ struct BlockHeader { BE(u32) size; }; -#if TARGET_PC -struct GlyphTextures; -#endif - /** * @ingroup jsystem-jutility * @@ -91,6 +87,16 @@ public: /* 0x66 */ u16 field_0x66; /* 0x68 */ u16 mMaxCode; /* 0x6C */ const IsLeadByte_func* mIsLeadByte; + +#if TARGET_PC + // Dusk change: we use a single large texture for all characters. + // This enables better draw call merging, ideally enabling entire blocks of + // text to be one draw call. + TGXTexObj mJoinedTextureObject; + u16 mJoinedTextureHeight; + + void initJoinedTexture(); +#endif }; extern u8 const JUTResFONT_Ascfont_fix12[]; diff --git a/libs/JSystem/src/JUtility/JUTResFont.cpp b/libs/JSystem/src/JUtility/JUTResFont.cpp index 8583d42c58..3ef83b227e 100644 --- a/libs/JSystem/src/JUtility/JUTResFont.cpp +++ b/libs/JSystem/src/JUtility/JUTResFont.cpp @@ -6,26 +6,13 @@ #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTConsole.h" #include -#include "absl/container/node_hash_map.h" - -#if TARGET_PC -struct GlyphTextures { - absl::node_hash_map textures; -}; -#endif JUTResFont::JUTResFont() { -#if TARGET_PC - mGlyphTextures = new GlyphTextures(); -#endif initialize_state(); JUTFont::initialize_state(); } JUTResFont::JUTResFont(const ResFONT* pFont, JKRHeap* pHeap) { -#if TARGET_PC - mGlyphTextures = new GlyphTextures(); -#endif initialize_state(); JUTFont::initialize_state(); initiate(pFont, pHeap); @@ -33,10 +20,7 @@ JUTResFont::JUTResFont(const ResFONT* pFont, JKRHeap* pHeap) { JUTResFont::~JUTResFont() { #if TARGET_PC - for (auto& pair : mGlyphTextures->textures) { - pair.second.reset(); - } - delete mGlyphTextures; + mJoinedTextureObject.reset(); #endif if (mValid) { @@ -70,6 +54,33 @@ bool JUTResFont::initiate(const ResFONT* pFont, JKRHeap* pHeap) { return true; } +#if TARGET_PC +void JUTResFont::initJoinedTexture() { + if (mGly1BlockNum != 1) { + CRASH("mGly1BlockNum must be 1!"); + } + + const auto& block = *mpGlyphBlocks[0]; + if (block.textureWidth % 8 != 0 || block.textureHeight % 8 != 0) { + // Idk how the GameCube's tiling texture format works so this is a safety check. + CRASH("Texture size not divisible!"); + } + + int pageCount = 0; + u32 pageNumCells = block.numRows * block.numColumns; + for (u32 code = block.startCode; code < block.endCode; code += pageNumCells) { + pageCount += 1; + } + + mJoinedTextureHeight = block.textureHeight * pageCount; + GXInitTexObj(&mJoinedTextureObject, block.data, block.textureWidth, + mJoinedTextureHeight, static_cast(block.textureFormat.host()), + GX_CLAMP, GX_CLAMP, false); + + GXInitTexObjLOD(&mJoinedTextureObject, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0U, 0U, GX_ANISO_1); +} +#endif + bool JUTResFont::protected_initiate(const ResFONT* pFont, JKRHeap* pHeap) { void** p; delete_and_initialize(); @@ -100,8 +111,10 @@ bool JUTResFont::protected_initiate(const ResFONT* pFont, JKRHeap* pHeap) { mpMapBlocks = JKR_NEW_ARRAY_ARGS(ResFONT::MAP1*, mMap1BlockNum, p); } setBlock(); - return true; + IF_DUSK(initJoinedTexture()); + + return true; } void JUTResFont::countBlock() { @@ -258,8 +271,13 @@ f32 JUTResFont::drawChar_scale(f32 pos_x, f32 pos_y, f32 scale_x, f32 scale_y, i f32 y2 = getDescent() * (scale_y / getHeight()) + pos_y; u16 texW = mpGlyphBlocks[field_0x66]->textureWidth; +#if TARGET_PC + u16 texH = mJoinedTextureHeight; +#else u16 texH = mpGlyphBlocks[field_0x66]->textureHeight; +#endif u16 cellW = mpGlyphBlocks[field_0x66]->cellWidth; + u16 cellH = mpGlyphBlocks[field_0x66]->cellHeight; s32 u1 = (mWidth * 0x8000) / texW; s32 v1 = (mHeight * 0x8000) / texH; @@ -456,26 +474,12 @@ void JUTResFont::loadImage(int code, GXTexMapID id FONT_DRAW_CTX){ mHeight = cellRow * cellH; #if TARGET_PC - if (!context || context->loadedPage != pageIdx || context->loadedBlock != i) { - const auto found = mGlyphTextures->textures.find(pageIdx); - GXTexObj* texObj; - if (found == mGlyphTextures->textures.end()) { - texObj = &mGlyphTextures->textures[pageIdx]; - void* pImg = &mpGlyphBlocks[i]->data[pageIdx * mpGlyphBlocks[i]->textureSize]; - GXInitTexObj(texObj, pImg, mpGlyphBlocks[i]->textureWidth, - mpGlyphBlocks[i]->textureHeight, (GXTexFmt)(u16)mpGlyphBlocks[i]->textureFormat, - GX_CLAMP, GX_CLAMP, 0); - - GXInitTexObjLOD(texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0U, 0U, GX_ANISO_1); - } else { - texObj = &found->second; - } - - GXLoadTexObj(texObj, id); + mHeight += texH * pageIdx; + if (!context || !context->isTextureLoaded) { + GXLoadTexObj(&mJoinedTextureObject, id); if (context) { - context->loadedBlock = i; - context->loadedPage = pageIdx; + context->isTextureLoaded = true; } }