From b3ab0371155163a98a2564259d99ed5ef6dde18f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 03:14:59 +0300 Subject: [PATCH] add 3D text render (WIP) --- src/graphics/core/Batch3D.cpp | 16 +++ src/graphics/core/Batch3D.hpp | 10 ++ src/graphics/core/Font.cpp | 114 ++++++++++++++++++--- src/graphics/core/Font.hpp | 19 +++- src/graphics/render/WorldRenderer.cpp | 25 +++++ src/graphics/render/WorldRenderer.hpp | 7 ++ src/graphics/ui/elements/InventoryView.cpp | 4 +- src/graphics/ui/elements/Label.cpp | 4 +- src/graphics/ui/elements/Plotter.cpp | 2 +- 9 files changed, 176 insertions(+), 25 deletions(-) diff --git a/src/graphics/core/Batch3D.cpp b/src/graphics/core/Batch3D.cpp index 41db4294..c2db0eee 100644 --- a/src/graphics/core/Batch3D.cpp +++ b/src/graphics/core/Batch3D.cpp @@ -117,6 +117,22 @@ void Batch3D::texture(const Texture* new_texture){ new_texture->bind(); } +void Batch3D::sprite( + const glm::vec3& pos, + const glm::vec3& up, + const glm::vec3& right, + float w, + float h, + int atlasRes, + int index, + glm::vec4 tint +) { + float scale = 1.0f / static_cast(atlasRes); + float u = (index % atlasRes) * scale; + float v = 1.0f - ((index / atlasRes) * scale) - scale; + sprite(pos, up, right, w, h, UVRegion(u, v, u+scale, v+scale), tint); +} + void Batch3D::sprite( const glm::vec3& pos, const glm::vec3& up, diff --git a/src/graphics/core/Batch3D.hpp b/src/graphics/core/Batch3D.hpp index 672021fd..cf787935 100644 --- a/src/graphics/core/Batch3D.hpp +++ b/src/graphics/core/Batch3D.hpp @@ -57,6 +57,16 @@ public: const UVRegion& uv, const glm::vec4& tint ); + void sprite( + const glm::vec3& pos, + const glm::vec3& up, + const glm::vec3& right, + float w, + float h, + int atlasRes, + int index, + glm::vec4 tint + ); void xSprite( float w, float h, diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 30db7d3e..db3b3593 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -3,6 +3,8 @@ #include #include "Texture.hpp" #include "Batch2D.hpp" +#include "Batch3D.hpp" +#include "window/Camera.hpp" inline constexpr uint GLYPH_SIZE = 16; inline constexpr uint MAX_CODEPAGES = 10000; // idk ho many codepages unicode has @@ -35,41 +37,76 @@ bool Font::isPrintableChar(uint codepoint) const { } } -int Font::calcWidth(const std::wstring& text, size_t length) { +int Font::calcWidth(const std::wstring& text, size_t length) const { return calcWidth(text, 0, length); } -int Font::calcWidth(const std::wstring& text, size_t offset, size_t length) { +int Font::calcWidth(const std::wstring& text, size_t offset, size_t length) const { return std::min(text.length()-offset, length) * glyphInterval; } static inline void drawGlyph( - Batch2D* batch, int x, int y, uint c, int glyphSize + Batch2D& batch, + const glm::vec3& pos, + const glm::vec2& offset, + uint c, + int glyphSize, + const Camera* ) { - batch->sprite(x, y, glyphSize, glyphSize, 16, c, batch->getColor()); + batch.sprite( + pos.x + offset.x, + pos.y + offset.y, + glyphSize, + glyphSize, + 16, + c, + batch.getColor() + ); } -void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y) { +static inline void drawGlyph( + Batch3D& batch, + const glm::vec3& pos, + const glm::vec2& offset, + uint c, + int glyphSize, + const Camera* camera +) { + batch.sprite( + pos + camera->right * offset.x + camera->up * offset.y, + camera->up, camera->right, + glyphSize * 0.5f, + glyphSize * 0.5f, + 16, + c, + glm::vec4(1.0f) + ); +} + +template +static inline void draw_text( + const Font& font, + Batch& batch, + std::wstring_view text, + const glm::vec3& pos, + float glyphInterval, + float lineHeight, + const Camera* camera +) { uint page = 0; uint next = MAX_CODEPAGES; - int init_x = x; + float x = 0; + float y = 0; do { for (uint c : text){ - if (!isPrintableChar(c)) { + if (!font.isPrintableChar(c)) { x += glyphInterval; continue; } uint charpage = c >> 8; if (charpage == page){ - Texture* texture = nullptr; - if (charpage < pages.size()) { - texture = pages[charpage].get(); - } - if (texture == nullptr){ - texture = pages[0].get(); - } - batch->texture(texture); - drawGlyph(batch, x, y, c, lineHeight); + batch.texture(font.getPage(charpage)); + drawGlyph(batch, pos, glm::vec2(x, y), c, lineHeight, camera); } else if (charpage > page && charpage < next){ next = charpage; @@ -78,6 +115,49 @@ void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y) { } page = next; next = MAX_CODEPAGES; - x = init_x; + x = 0.0f; } while (page < MAX_CODEPAGES); } + +const Texture* Font::getPage(int charpage) const { + Texture* texture = nullptr; + if (charpage < pages.size()) { + texture = pages[charpage].get(); + } + if (texture == nullptr){ + texture = pages[0].get(); + } + return texture; +} + +void Font::draw( + Batch2D& batch, std::wstring_view text, int x, int y, float scale +) const { + draw_text( + *this, + batch, + text, + glm::vec3(x, y, 0), + glyphInterval * scale, + lineHeight * scale, + nullptr + ); +} + +void Font::draw( + Batch3D& batch, + const Camera& camera, + std::wstring_view text, + const glm::vec3& pos, + float scale +) const { + draw_text( + *this, + batch, + text, + pos, + glyphInterval * scale, + lineHeight * scale, + &camera + ); +} diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index b5f0c533..1a778cfc 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -3,10 +3,13 @@ #include #include #include +#include #include "typedefs.hpp" class Texture; class Batch2D; +class Batch3D; +class Camera; enum class FontStyle { none, @@ -30,18 +33,28 @@ public: /// @param text selected text /// @param length max substring length (default: no limit) /// @return pixel width of the substring - int calcWidth(const std::wstring& text, size_t length=-1); + int calcWidth(const std::wstring& text, size_t length=-1) const; /// @brief Calculate text width in pixels /// @param text selected text /// @param offset start of the substring /// @param length max substring length /// @return pixel width of the substring - int calcWidth(const std::wstring& text, size_t offset, size_t length); + int calcWidth(const std::wstring& text, size_t offset, size_t length) const; /// @brief Check if character is visible (non-whitespace) /// @param codepoint character unicode codepoint bool isPrintableChar(uint codepoint) const; - void draw(Batch2D* batch, std::wstring_view text, int x, int y); + void draw(Batch2D& batch, std::wstring_view text, int x, int y, float scale=1) const; + + void draw( + Batch3D& batch, + const Camera& camera, + std::wstring_view text, + const glm::vec3& pos, + float scale = 1 + ) const; + + const Texture* getPage(int page) const; }; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 033b8124..cfbb8373 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -40,6 +40,7 @@ #include "graphics/core/PostProcessing.hpp" #include "graphics/core/Shader.hpp" #include "graphics/core/Texture.hpp" +#include "graphics/core/Font.hpp" #include "ParticlesRenderer.hpp" #include "ChunksRenderer.hpp" #include "ModelBatch.hpp" @@ -405,6 +406,29 @@ void WorldRenderer::renderHands( skybox->unbind(); } +void WorldRenderer::renderTexts( + const DrawContext& context, + const Camera& camera, + const EngineSettings& settings, + bool hudVisible +) { + const auto& assets = *engine->getAssets(); + auto& shader = assets.require("ui3d"); + auto& font = assets.require("normal"); + shader.uniformMatrix("u_projview", camera.getProjView()); + shader.uniformMatrix("u_apply", glm::mat4(1.0f)); + batch3d->begin(); + std::wstring string = L"Segmentation fault (core dumped)"; + font.draw( + *batch3d, + camera, + string, + glm::vec3(0, 100, 0) - + camera.right * (font.calcWidth(string, string.length()) * 0.5f) + ); + batch3d->flush(); +} + void WorldRenderer::draw( const DrawContext& pctx, Camera& camera, @@ -441,6 +465,7 @@ void WorldRenderer::draw( DrawContext ctx = wctx.sub(); ctx.setDepthTest(true); ctx.setCullFace(true); + renderTexts(ctx, camera, settings, hudVisible); renderLevel(ctx, camera, settings, delta, pause); // Debug lines if (hudVisible) { diff --git a/src/graphics/render/WorldRenderer.hpp b/src/graphics/render/WorldRenderer.hpp index a1023b2d..f30acf83 100644 --- a/src/graphics/render/WorldRenderer.hpp +++ b/src/graphics/render/WorldRenderer.hpp @@ -80,6 +80,13 @@ class WorldRenderer { const EngineSettings& settings, float fogFactor ); + + void renderTexts( + const DrawContext& context, + const Camera& camera, + const EngineSettings& settings, + bool hudVisible + ); public: std::unique_ptr particles; diff --git a/src/graphics/ui/elements/InventoryView.cpp b/src/graphics/ui/elements/InventoryView.cpp index fa3d836c..9d07441d 100644 --- a/src/graphics/ui/elements/InventoryView.cpp +++ b/src/graphics/ui/elements/InventoryView.cpp @@ -194,9 +194,9 @@ void SlotView::draw(const DrawContext* pctx, Assets* assets) { int y = pos.y+slotSize-16; batch->setColor({0, 0, 0, 1.0f}); - font->draw(batch, text, x+1, y+1); + font->draw(*batch, text, x+1, y+1); batch->setColor(glm::vec4(1.0f)); - font->draw(batch, text, x, y); + font->draw(*batch, text, x, y); } } diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index 5e02b31a..c356f13b 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -201,10 +201,10 @@ void Label::draw(const DrawContext* pctx, Assets* assets) { if (i < cache.lines.size()-1) { view = std::wstring_view(text.c_str()+offset, cache.lines.at(i+1).offset-offset); } - font->draw(batch, view, pos.x, pos.y + i * totalLineHeight); + font->draw(*batch, view, pos.x, pos.y + i * totalLineHeight); } } else { - font->draw(batch, text, pos.x, pos.y); + font->draw(*batch, text, pos.x, pos.y); } } diff --git a/src/graphics/ui/elements/Plotter.cpp b/src/graphics/ui/elements/Plotter.cpp index 86e159bf..293d84b5 100644 --- a/src/graphics/ui/elements/Plotter.cpp +++ b/src/graphics/ui/elements/Plotter.cpp @@ -47,6 +47,6 @@ void Plotter::draw(const DrawContext* pctx, Assets* assets) { batch->setColor({1,1,1,0.2f}); string = util::to_wstring(y / multiplier, 3); } - font->draw(batch, string, pos.x+dmwidth+2, pos.y+dmheight-y-labelsInterval); + font->draw(*batch, string, pos.x+dmwidth+2, pos.y+dmheight-y-labelsInterval); } }