diff --git a/Runtime/Graphics/CGraphicsPalette.hpp b/Runtime/Graphics/CGraphicsPalette.hpp index a039f560c..3a61c13f9 100644 --- a/Runtime/Graphics/CGraphicsPalette.hpp +++ b/Runtime/Graphics/CGraphicsPalette.hpp @@ -16,6 +16,7 @@ enum class EPaletteFormat class CGraphicsPalette { + friend class CTextRenderBuffer; EPaletteFormat x0_fmt; int x4_entryCount; std::unique_ptr x8_entries; diff --git a/Runtime/GuiSys/CFontImageDef.cpp b/Runtime/GuiSys/CFontImageDef.cpp index b5c328a4f..32e5008db 100644 --- a/Runtime/GuiSys/CFontImageDef.cpp +++ b/Runtime/GuiSys/CFontImageDef.cpp @@ -5,14 +5,14 @@ namespace urde CFontImageDef::CFontImageDef(std::vector>&& texs, float interval, const zeus::CVector2f& vec) -: x0_interval(interval), x4_texs(std::move(texs)), x14_pointsPerTexel(vec) +: x0_fps(interval), x4_texs(std::move(texs)), x14_pointsPerTexel(vec) { for (TToken& tok : x4_texs) tok.Lock(); } CFontImageDef::CFontImageDef(TToken&& tex, const zeus::CVector2f& vec) -: x0_interval(0.f), x4_texs({std::move(tex)}), x14_pointsPerTexel(vec) +: x0_fps(0.f), x4_texs({std::move(tex)}), x14_pointsPerTexel(vec) { x4_texs[0].Lock(); } diff --git a/Runtime/GuiSys/CFontImageDef.hpp b/Runtime/GuiSys/CFontImageDef.hpp index 170ddd86a..b84227f8c 100644 --- a/Runtime/GuiSys/CFontImageDef.hpp +++ b/Runtime/GuiSys/CFontImageDef.hpp @@ -12,11 +12,11 @@ class CTexture; class CFontImageDef { public: - float x0_interval; + float x0_fps; std::vector> x4_texs; zeus::CVector2f x14_pointsPerTexel; - CFontImageDef(std::vector>&& texs, float interval, + CFontImageDef(std::vector>&& texs, float fps, const zeus::CVector2f& vec); CFontImageDef(TToken&& tex, const zeus::CVector2f& vec); bool IsLoaded() const; diff --git a/Runtime/GuiSys/CGuiTextPane.cpp b/Runtime/GuiSys/CGuiTextPane.cpp index 7474bd6a2..4fc61d838 100644 --- a/Runtime/GuiSys/CGuiTextPane.cpp +++ b/Runtime/GuiSys/CGuiTextPane.cpp @@ -58,8 +58,9 @@ void CGuiTextPane::Draw(const CGuiWidgetDrawParms& parms) const else dims.y = 0.f; - zeus::CTransform local = zeus::CTransform::Translate(x100_verts.front().m_pos + x108_scaleCenter) * - zeus::CTransform::Scale(dims.x, 1.f, dims.y); + zeus::CTransform local = + zeus::CTransform::Translate(x100_verts.front().m_pos + x108_scaleCenter) * + zeus::CTransform::Scale(dims.x, 1.f, dims.y); CGraphics::SetModelMatrix(x34_worldXF * local); zeus::CColor geomCol = xb4_; @@ -118,7 +119,8 @@ CGuiTextPane* CGuiTextPane::Create(CGuiFrame* frame, CInputStream& in, bool flag outlineCol.readRGBABig(in); int extentX = in.readFloatBig(); int extentY = in.readFloatBig(); - return new CGuiTextPane(parms, xDim, zDim, vec, fontId, props, fontCol, outlineCol, extentX, extentY); + return new CGuiTextPane(parms, xDim, zDim, vec, fontId, props, + fontCol, outlineCol, extentX, extentY); } } diff --git a/Runtime/GuiSys/CGuiTextSupport.cpp b/Runtime/GuiSys/CGuiTextSupport.cpp index ca46b09dc..9bef6ff0d 100644 --- a/Runtime/GuiSys/CGuiTextSupport.cpp +++ b/Runtime/GuiSys/CGuiTextSupport.cpp @@ -26,13 +26,13 @@ float CGuiTextSupport::GetCurrentAnimationOverAge() const if (x34_primStartTimes.size()) { - float val = (x54_renderBuf->x24_primOffsets.size() - x34_primStartTimes.back().second) / + float val = (x54_renderBuf->GetPrimitiveCount() - x34_primStartTimes.back().second) / x4c_chRate + x34_primStartTimes.back().first; return std::max(0.f, val); } else { - float val = x54_renderBuf->x24_primOffsets.size() / x4c_chRate; + float val = x54_renderBuf->GetPrimitiveCount() / x4c_chRate; return std::max(0.f, val); } } @@ -40,7 +40,7 @@ float CGuiTextSupport::GetCurrentAnimationOverAge() const float CGuiTextSupport::GetNumCharsPrinted() const { if (x2ac_active) - return std::min(x30_curTime * x4c_chRate, float(x54_renderBuf->x24_primOffsets.size())); + return std::min(x30_curTime * x4c_chRate, float(x54_renderBuf->GetPrimitiveCount())); return 0.f; } @@ -49,7 +49,7 @@ float CGuiTextSupport::GetTotalAnimationTime() const if (!x2ac_active || !x44_typeEnable) return 0.f; - return x54_renderBuf->x24_primOffsets.size() / x4c_chRate; + return x54_renderBuf->GetPrimitiveCount() / x4c_chRate; } void CGuiTextSupport::SetTypeWriteEffectOptions(bool enable, float chFadeTime, float chRate) @@ -66,7 +66,7 @@ void CGuiTextSupport::Update(float dt) if (x44_typeEnable) { - for (int i=0 ; ix24_primOffsets.size() ; ++i) + for (int i=0 ; iGetPrimitiveCount() ; ++i) { float chStartTime = 0.f; for (const std::pair& p : x34_primStartTimes) @@ -79,9 +79,14 @@ void CGuiTextSupport::Update(float dt) break; } +#if 0 CTextRenderBuffer::Primitive prim = x54_renderBuf->GetPrimitive(i); prim.x0_color1.a = std::min(std::max(0.f, (x30_curTime - chStartTime) / x48_chFadeTime), 1.f); x54_renderBuf->SetPrimitive(prim, i); +#else + x54_renderBuf->SetPrimitiveOpacity(i, + std::min(std::max(0.f, (x30_curTime - chStartTime) / x48_chFadeTime), 1.f)); +#endif } } @@ -164,7 +169,7 @@ void CGuiTextSupport::AddText(const std::wstring& str) { float t = GetCurrentAnimationOverAge(); x34_primStartTimes.push_back(std::make_pair(std::max(t, x30_curTime), - x54_renderBuf->x24_primOffsets.size())); + x54_renderBuf->GetPrimitiveCount())); } x0_string += str; ClearBuffer(); diff --git a/Runtime/GuiSys/CRasterFont.hpp b/Runtime/GuiSys/CRasterFont.hpp index fb3b86442..b5a273222 100644 --- a/Runtime/GuiSys/CRasterFont.hpp +++ b/Runtime/GuiSys/CRasterFont.hpp @@ -148,6 +148,7 @@ public: } void GetSize(const CDrawStringOptions& opts, int& width, int& height, const wchar_t* str, int len) const; + TToken& GetTexture() { return x80_texture; } }; std::unique_ptr FRasterFontFactory(const SObjectTag& tag, CInputStream& in, const CVParamTransfer& vparms); diff --git a/Runtime/GuiSys/CTextExecuteBuffer.cpp b/Runtime/GuiSys/CTextExecuteBuffer.cpp index 5b25a096d..880a2bbb1 100644 --- a/Runtime/GuiSys/CTextExecuteBuffer.cpp +++ b/Runtime/GuiSys/CTextExecuteBuffer.cpp @@ -13,7 +13,7 @@ namespace urde CTextRenderBuffer CTextExecuteBuffer::CreateTextRenderBuffer() const { - CTextRenderBuffer ret(CTextRenderBuffer::EMode::Zero); + CTextRenderBuffer ret(CTextRenderBuffer::EMode::AllocTally); { CFontRenderState rendState; @@ -21,7 +21,7 @@ CTextRenderBuffer CTextExecuteBuffer::CreateTextRenderBuffer() const inst->Invoke(rendState, &ret); } - ret.SetMode(CTextRenderBuffer::EMode::One); + ret.SetMode(CTextRenderBuffer::EMode::BufferFill); { CFontRenderState rendState; diff --git a/Runtime/GuiSys/CTextRenderBuffer.cpp b/Runtime/GuiSys/CTextRenderBuffer.cpp index 345d5456f..72491ca64 100644 --- a/Runtime/GuiSys/CTextRenderBuffer.cpp +++ b/Runtime/GuiSys/CTextRenderBuffer.cpp @@ -1,67 +1,233 @@ #include "CTextRenderBuffer.hpp" #include "CFontImageDef.hpp" #include "Graphics/CGraphicsPalette.hpp" +#include "Graphics/CGraphics.hpp" +#include "CRasterFont.hpp" +#include "Graphics/CTexture.hpp" namespace urde { +boo::IShaderPipeline* g_TextShaderPipeline = nullptr; +boo::IVertexFormat* g_TextVtxFmt = nullptr; + +boo::IShaderPipeline* g_TextImageShaderPipeline = nullptr; +boo::IVertexFormat* g_TextImageVtxFmt = nullptr; + CTextRenderBuffer::CTextRenderBuffer(EMode mode) -: x0_mode(mode) +: x0_mode(mode) {} + +void CTextRenderBuffer::BooCharacterInstance::SetMetrics(const CGlyph& glyph, + const zeus::CVector2i& offset) { - for (int i=0 ; i<64 ; ++i) + m_pos[0].assign(offset.x, 0.f, offset.y); + m_uv[0].assign(glyph.GetStartU(), glyph.GetStartV()); + + m_pos[1].assign(offset.x + glyph.GetCellWidth(), 0.f, offset.y); + m_uv[1].assign(glyph.GetEndU(), glyph.GetStartV()); + + m_pos[2].assign(offset.x, 0.f, offset.y + glyph.GetCellHeight()); + m_uv[2].assign(glyph.GetStartU(), glyph.GetEndV()); + + m_pos[3].assign(offset.x + glyph.GetCellWidth(), 0.f, offset.y + glyph.GetCellHeight()); + m_uv[3].assign(glyph.GetEndU(), glyph.GetEndV()); +} + +void CTextRenderBuffer::BooPrimitiveMark::SetOpacity(CTextRenderBuffer& rb, float opacity) +{ + switch (m_cmd) { - x54_palettes[i].reset(new CGraphicsPalette(EPaletteFormat::RGB5A3, 4)); - ++x50_paletteCount; + case Command::CharacterRender: + { + BooFontCharacters& fc = rb.m_fontCharacters[m_bindIdx]; + BooCharacterInstance& inst = fc.m_charData[m_instIdx]; + inst.m_fontColor.a = opacity; + inst.m_outlineColor.a = opacity; + fc.m_dirty = true; + break; + } + case Command::ImageRender: + { + BooImage& img = rb.m_images[m_bindIdx]; + img.m_imageData.m_color.a = opacity; + img.m_dirty = true; + break; + } + default: break; } } -void CTextRenderBuffer::SetPrimitive(const Primitive&, int) +void CTextRenderBuffer::CommitResources() { + if (m_committed) + return; + m_committed = true; + + m_uniBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Uniform, + sizeof(BooUniform), 1); + + for (BooFontCharacters& chs : m_fontCharacters) + { + chs.m_instBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Vertex, + sizeof(BooCharacterInstance), + chs.m_charCount); + boo::IVertexFormat* vFmt = g_TextVtxFmt; + if (CGraphics::g_BooFactory->bindingNeedsVertexFormat()) + { + boo::VertexElementDescriptor elems[] = + { + {chs.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 0}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 1}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 2}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 3}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 0}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 1}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 2}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 3}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced, 0}, + {chs.m_instBuf, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced, 1}, + }; + vFmt = CGraphics::g_BooFactory->newVertexFormat(10, elems); + } + + boo::IGraphicsBuffer* uniforms[] = {m_uniBuf}; + boo::ITexture* texs[] = {chs.m_font.GetObj()->GetTexture()->GetBooTexture()}; + chs.m_dataBinding = CGraphics::g_BooFactory->newShaderDataBinding(g_TextShaderPipeline, vFmt, + nullptr, chs.m_instBuf, nullptr, + 1, uniforms, 1, texs); + } + + for (BooImage& img : m_images) + { + img.m_instBuf = CGraphics::NewDynamicGPUBuffer(boo::BufferUse::Vertex, + sizeof(BooImageInstance), 1); + boo::IVertexFormat* vFmt = g_TextImageVtxFmt; + if (CGraphics::g_BooFactory->bindingNeedsVertexFormat()) + { + boo::VertexElementDescriptor elems[] = + { + {img.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 0}, + {img.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 1}, + {img.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 2}, + {img.m_instBuf, nullptr, boo::VertexSemantic::Position4 | boo::VertexSemantic::Instanced, 3}, + {img.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 0}, + {img.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 1}, + {img.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 2}, + {img.m_instBuf, nullptr, boo::VertexSemantic::UV4 | boo::VertexSemantic::Instanced, 3}, + {img.m_instBuf, nullptr, boo::VertexSemantic::Color | boo::VertexSemantic::Instanced, 0}, + }; + vFmt = CGraphics::g_BooFactory->newVertexFormat(9, elems); + } + + boo::IGraphicsBuffer* uniforms[] = {m_uniBuf}; + img.m_dataBinding.reserve(img.m_imageDef.x4_texs.size()); + for (TToken& tex : img.m_imageDef.x4_texs) + { + boo::ITexture* texs[] = {tex->GetBooTexture()}; + img.m_dataBinding.push_back(CGraphics::g_BooFactory->newShaderDataBinding(g_TextImageShaderPipeline, vFmt, + nullptr, img.m_instBuf, nullptr, + 1, uniforms, 1, texs)); + } + } + + m_booToken = CGraphics::CommitResources(); } -CTextRenderBuffer::Primitive CTextRenderBuffer::GetPrimitive(int) const +void CTextRenderBuffer::SetMode(EMode mode) { + if (mode == EMode::BufferFill) + { + m_images.reserve(m_imagesCount); + for (BooFontCharacters& fc : m_fontCharacters) + fc.m_charData.reserve(fc.m_charCount); + } + m_activeFontCh = -1; } -void CTextRenderBuffer::GetOutStream() +void CTextRenderBuffer::SetPrimitiveOpacity(int idx, float opacity) { + m_primitiveMarks[idx].SetOpacity(*this, opacity); } -void CTextRenderBuffer::VerifyBuffer() +void CTextRenderBuffer::Render(const zeus::CColor& col, float time) const { - if (x34_blob.empty()) - x34_blob.resize(x44_blobSize); + ((CTextRenderBuffer*)this)->CommitResources(); + + BooUniform uniforms = {CGraphics::GetPerspectiveProjectionMatrix() * + CGraphics::g_GXModelView.toMatrix4f(), col}; + m_uniBuf->load(&uniforms, sizeof(uniforms)); + + for (const BooFontCharacters& chs : m_fontCharacters) + { + if (chs.m_dirty) + { + chs.m_instBuf->load(chs.m_charData.data(), sizeof(BooCharacterInstance) * chs.m_charData.size()); + ((BooFontCharacters&)chs).m_dirty = false; + } + CGraphics::SetShaderDataBinding(chs.m_dataBinding); + CGraphics::DrawInstances(0, 4, chs.m_charData.size()); + } + + for (const BooImage& img : m_images) + { + if (img.m_dirty) + { + img.m_instBuf->load(&img.m_imageData, sizeof(BooImageInstance)); + ((BooImage&)img).m_dirty = false; + } + int idx = int(img.m_imageDef.x0_fps * time) % img.m_dataBinding.size(); + CGraphics::SetShaderDataBinding(img.m_dataBinding[idx]); + CGraphics::DrawInstances(0, 4, 1); + } } -void CTextRenderBuffer::Render(const zeus::CColor& col, float) const +void CTextRenderBuffer::AddImage(const zeus::CVector2i& offset, const CFontImageDef& image) { + if (x0_mode == EMode::AllocTally) + m_primitiveMarks.push_back({Command::ImageRender, m_imagesCount++, 0}); + else + m_images.push_back({image}); } -void CTextRenderBuffer::AddImage(const zeus::CVector2i& vec, const CFontImageDef&) +void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& offset, wchar_t ch, + const zeus::CColor& color) { + if (m_activeFontCh == -1) + return; + BooFontCharacters& chs = m_fontCharacters[m_activeFontCh]; + if (x0_mode == EMode::AllocTally) + m_primitiveMarks.push_back({Command::CharacterRender, m_activeFontCh, chs.m_charCount++}); + else + { + const CGlyph* glyph = chs.m_font.GetObj()->GetGlyph(ch); + chs.m_charData.emplace_back(); + BooCharacterInstance& inst = chs.m_charData.back(); + inst.SetMetrics(*glyph, offset); + inst.m_fontColor = m_main * color; + inst.m_outlineColor = m_outline * color; + } } -void CTextRenderBuffer::AddCharacter(const zeus::CVector2i& vec, s16, const zeus::CColor&) -{ -} - -void CTextRenderBuffer::AddPaletteChange(const CGraphicsPalette& palette) +void CTextRenderBuffer::AddPaletteChange(const zeus::CColor& main, const zeus::CColor& outline) { + m_main = main; + m_outline = outline; } void CTextRenderBuffer::AddFontChange(const TToken& font) { -} + for (int i=0 ; i= 64) - x254_nextPalette = 0; - return x54_palettes[x254_nextPalette++].get(); + m_activeFontCh = m_fontCharacters.size(); + m_fontCharacters.push_back({font}); } } diff --git a/Runtime/GuiSys/CTextRenderBuffer.hpp b/Runtime/GuiSys/CTextRenderBuffer.hpp index 8017c3e7b..841b68d4b 100644 --- a/Runtime/GuiSys/CTextRenderBuffer.hpp +++ b/Runtime/GuiSys/CTextRenderBuffer.hpp @@ -3,14 +3,19 @@ #include "zeus/CColor.hpp" #include "zeus/CVector2i.hpp" +#include "zeus/CVector2f.hpp" +#include "zeus/CMatrix4f.hpp" #include "CToken.hpp" +#include "CFontImageDef.hpp" #include "RetroTypes.hpp" +#include "boo/graphicsdev/IGraphicsDataFactory.hpp" + namespace urde { -class CFontImageDef; class CGraphicsPalette; class CRasterFont; +class CGlyph; using CTextColor = zeus::CColor; @@ -18,44 +23,127 @@ class CTextRenderBuffer { friend class CGuiTextSupport; public: + enum class Command + { + CharacterRender, + ImageRender, + FontChange, + PaletteChange + }; struct Primitive { CTextColor x0_color1; - u32 x4_; - u16 x8_; - u16 xa_; - u16 xc_; - u8 xe_; + Command x4_command; + u16 x8_xPos; + u16 xa_zPos; + wchar_t xc_glyph; + u8 xe_imageIndex; }; enum class EMode { - Zero, - One + AllocTally, + BufferFill }; + private: EMode x0_mode; +#if 0 std::vector> x4_fonts; std::vector x14_images; std::vector x24_primOffsets; - std::vector x34_blob; + std::vector x34_bytecode; u32 x44_blobSize = 0; + u32 x48_curBytecodeOffset = 0; u32 x50_paletteCount = 0; - std::unique_ptr x54_palettes[64]; + std::array, 64> x54_palettes; u32 x254_nextPalette = 0; + +#else + /* Boo-specific text-rendering functionality */ + struct BooUniform + { + zeus::CMatrix4f m_mvp; + zeus::CColor m_uniformColor; + }; + boo::IGraphicsBufferD* m_uniBuf; + + struct BooCharacterInstance + { + zeus::CVector3f m_pos[4]; + zeus::CVector2f m_uv[4]; + zeus::CColor m_fontColor; + zeus::CColor m_outlineColor; + void SetMetrics(const CGlyph& glyph, const zeus::CVector2i& offset); + }; + + struct BooImageInstance + { + zeus::CVector3f m_pos[4]; + zeus::CVector2f m_uv[4]; + zeus::CColor m_color; + }; + + struct BooFontCharacters + { + TToken m_font; + boo::IGraphicsBufferD* m_instBuf; + boo::IShaderDataBinding* m_dataBinding; + std::vector m_charData; + u32 m_charCount = 0; + bool m_dirty = true; + }; + std::vector m_fontCharacters; + + struct BooImage + { + CFontImageDef m_imageDef; + boo::IGraphicsBufferD* m_instBuf; + std::vector m_dataBinding; + BooImageInstance m_imageData; + bool m_dirty = true; + }; + std::vector m_images; + + boo::GraphicsDataToken m_booToken; + + struct BooPrimitiveMark + { + Command m_cmd; + u32 m_bindIdx; + u32 m_instIdx; + void SetOpacity(CTextRenderBuffer& rb, float opacity); + }; + std::vector m_primitiveMarks; + u32 m_imagesCount = 0; + u32 m_activeFontCh = -1; + + zeus::CColor m_main; + zeus::CColor m_outline; + + bool m_committed = false; + void CommitResources(); +#endif + public: CTextRenderBuffer(EMode mode); +#if 0 void SetPrimitive(const Primitive&, int); Primitive GetPrimitive(int) const; void GetOutStream(); - void SetMode(EMode mode) {x0_mode = mode;} void VerifyBuffer(); - void Render(const zeus::CColor& col, float) const; - void AddImage(const zeus::CVector2i& vec, const CFontImageDef&); - void AddCharacter(const zeus::CVector2i& vec, s16, const zeus::CColor&); - void AddPaletteChange(const CGraphicsPalette& palette); - void AddFontChange(const TToken& font); int GetMatchingPaletteIndex(const CGraphicsPalette& palette); CGraphicsPalette* GetNextAvailablePalette(); + void AddPaletteChange(const CGraphicsPalette& palette); +#else + void SetPrimitiveOpacity(int idx, float opacity); + u32 GetPrimitiveCount() const {return m_primitiveMarks.size();} +#endif + void SetMode(EMode mode); + void Render(const zeus::CColor& col, float) const; + void AddImage(const zeus::CVector2i& offset, const CFontImageDef& image); + void AddCharacter(const zeus::CVector2i& offset, wchar_t ch, const zeus::CColor& color); + void AddPaletteChange(const zeus::CColor& main, const zeus::CColor& outline); + void AddFontChange(const TToken& font); }; }