From 8e549fe806553a7412da61029ce5addea439ec7a Mon Sep 17 00:00:00 2001 From: opchik98 Date: Thu, 7 Nov 2024 18:38:24 +0200 Subject: [PATCH 001/105] Feature #152 and potential fix #320 - Added Lua scripts hud.open, inventory.create and inventory.remove - Window now resizes even if it is not focused --- doc/en/scripting/builtins/libhud.md | 6 +++- doc/en/scripting/builtins/libinventory.md | 6 ++++ doc/ru/scripting/builtins/libhud.md | 6 +++- doc/ru/scripting/builtins/libinventory.md | 12 ++++--- src/frontend/hud.cpp | 33 +++++++++++++++++++ src/frontend/hud.hpp | 12 +++++++ src/logic/scripting/lua/libs/libhud.cpp | 21 ++++++++++++ src/logic/scripting/lua/libs/libinventory.cpp | 22 +++++++++++++ src/voxels/Chunk.cpp | 2 +- src/voxels/Chunk.hpp | 2 +- src/window/Window.cpp | 8 ++--- 11 files changed, 117 insertions(+), 13 deletions(-) diff --git a/doc/en/scripting/builtins/libhud.md b/doc/en/scripting/builtins/libhud.md index b823ab50..4beb5d93 100644 --- a/doc/en/scripting/builtins/libhud.md +++ b/doc/en/scripting/builtins/libhud.md @@ -7,7 +7,11 @@ hud.open_inventory() -- Close inventory. hud.close_inventory() --- Open block UI and inventory. +-- Open UI and inventory. +-- Throws an exception if has no UI layout. +hud.open(invid: int, layoutid: str) + +-- Open block UI and inventory. -- Throws an exception if block has no UI layout. -- Returns block inventory ID (if *"inventory-size"=0* a virtual -- inventory will be created), and UI layout ID. diff --git a/doc/en/scripting/builtins/libinventory.md b/doc/en/scripting/builtins/libinventory.md index a719878a..344840f1 100644 --- a/doc/en/scripting/builtins/libinventory.md +++ b/doc/en/scripting/builtins/libinventory.md @@ -40,12 +40,18 @@ inventory.bind_block(invid: int, x: int, y: int, z: int) -- Unbind inventory from the specified block. inventory.unbind_block(x: int, y: int, z: int) + +-- Remove inventory. +inventory.remove(invid: int) ``` > [!WARNING] > Unbound inventories will be deleted on world close. ```lua +-- Create inventory. Returns the created ID. +inventory.create(size: int) -> int + -- Create inventory copy. Returns the created copy ID. inventory.clone(invid: int) -> int diff --git a/doc/ru/scripting/builtins/libhud.md b/doc/ru/scripting/builtins/libhud.md index cba34dee..ae5a69c3 100644 --- a/doc/ru/scripting/builtins/libhud.md +++ b/doc/ru/scripting/builtins/libhud.md @@ -7,7 +7,11 @@ hud.open_inventory() -- Закрывает инвентарь. hud.close_inventory() --- Открывает инвентарь и UI блока. +-- Открывает инвентарь и UI. +-- Если не имеет макета UI - бросается исключение. +hud.open(invid: int, layoutid: str) + +-- Открывает инвентарь и UI блока. -- Если блок не имеет макета UI - бросается исключение. -- Возвращает id инвентаря блока -- (при *"inventory-size"=0* создаётся виртуальный инвентарь, diff --git a/doc/ru/scripting/builtins/libinventory.md b/doc/ru/scripting/builtins/libinventory.md index 4d937358..01ecc5cc 100644 --- a/doc/ru/scripting/builtins/libinventory.md +++ b/doc/ru/scripting/builtins/libinventory.md @@ -23,7 +23,7 @@ inventory.set( count: int ) --- Возращает размер инвентаря (число слотов). +-- Возвращает размер инвентаря (число слотов). -- Если указанного инвентаря не существует, бросает исключение. inventory.size(invid: int) -> int @@ -47,13 +47,19 @@ inventory.bind_block(invid: int, x: int, y: int, z: int) -- Отвязывает инвентарь от блока. inventory.unbind_block(x: int, y: int, z: int) + +-- Удаляет инвентарь. +inventory.remove(invid: int) ``` > [!WARNING] > Инвентари, не привязанные ни к одному из блоков, удаляются при выходе из мира. ```lua --- Создает копию инвентаря и возвращает id копии. +-- Создаёт инвентарь и возвращает id. +inventory.create(size: int) -> int + +-- Создает копию инвентаря и возвращает id копии. -- Если копируемого инвентаря не существует, возвращает 0. inventory.clone(invid: int) -> int @@ -62,5 +68,3 @@ inventory.clone(invid: int) -> int -- slotB будет выбран автоматически, если не указывать явно. inventory.move(invA: int, slotA: int, invB: int, slotB: int) ``` - - diff --git a/src/frontend/hud.cpp b/src/frontend/hud.cpp index 0063fd46..fd418d0f 100644 --- a/src/frontend/hud.cpp +++ b/src/frontend/hud.cpp @@ -388,6 +388,39 @@ void Hud::openInventory() { add(HudElement(hud_element_mode::inventory_bound, nullptr, exchangeSlot, false)); } +void Hud::openInventory( + UiDocument* doc, + std::shared_ptr inv, + bool playerInventory +) { + if (inv == nullptr) { + // why try to open nox-existent inventory?? + return; + } + + if (isInventoryOpen()) { + closeInventory(); + } + auto level = frontend->getLevel(); + auto content = level->content; + secondInvView = std::dynamic_pointer_cast(doc->getRoot()); + if (secondInvView == nullptr) { + throw std::runtime_error("secondary UI root element must be 'inventory'"); + } + secondUI = secondInvView; + + if (playerInventory) { + openInventory(); + } else { + inventoryOpen = true; + } + if (inv == nullptr) { + inv = level->inventories->createVirtual(secondInvView->getSlotsCount()); + } + secondInvView->bind(inv, content); + add(HudElement(hud_element_mode::inventory_bound, doc, secondUI, false)); +} + void Hud::openInventory( glm::ivec3 block, UiDocument* doc, diff --git a/src/frontend/hud.hpp b/src/frontend/hud.hpp index 775681af..b184ddfc 100644 --- a/src/frontend/hud.hpp +++ b/src/frontend/hud.hpp @@ -102,6 +102,8 @@ class Hud : public util::ObjectsKeeper { std::shared_ptr inventoryView = nullptr; /// @brief Block inventory view std::shared_ptr blockUI = nullptr; + /// @brief Secondary inventory view + std::shared_ptr secondInvView = nullptr; /// @brief Position of the block open glm::ivec3 blockPos {}; /// @brief Id of the block open (used to detect block destruction or replacement) @@ -145,6 +147,16 @@ public: /// @brief Show player inventory in inventory-mode void openInventory(); + + /// @brief Show inventory in inventory-mode + /// @param doc ui layout + /// @param inv inventory + /// @param playerInventory show player inventory too + void openInventory( + UiDocument* doc, + std::shared_ptr inv, + bool playerInventory + ); /// @brief Show block inventory in inventory-mode /// @param block block position diff --git a/src/logic/scripting/lua/libs/libhud.cpp b/src/logic/scripting/lua/libs/libhud.cpp index 5df2e08c..17e1211a 100644 --- a/src/logic/scripting/lua/libs/libhud.cpp +++ b/src/logic/scripting/lua/libs/libhud.cpp @@ -36,6 +36,26 @@ static int l_close_inventory(lua::State*) { return 0; } +static int l_open(lua::State* L) { + auto invid = lua::tointeger(L, 1); + auto layoutid = lua::require_string(L, 2); + bool playerInventory = !lua::toboolean(L, 3); + + auto assets = engine->getAssets(); + auto layout = assets->get(layoutid); + if (layout == nullptr) { + throw std::runtime_error("there is no ui layout " + util::quote(layoutid)); + } + + hud->openInventory( + layout, + level->inventories->get(invid), + playerInventory + ); + + return 0; +} + static int l_open_block(lua::State* L) { auto x = lua::tointeger(L, 1); auto y = lua::tointeger(L, 2); @@ -154,6 +174,7 @@ static int l_set_debug_cheats(lua::State* L) { const luaL_Reg hudlib[] = { {"open_inventory", lua::wrap}, {"close_inventory", lua::wrap}, + {"open", lua::wrap}, {"open_block", lua::wrap}, {"open_permanent", lua::wrap}, {"show_overlay", lua::wrap}, diff --git a/src/logic/scripting/lua/libs/libinventory.cpp b/src/logic/scripting/lua/libs/libinventory.cpp index bc5abd47..a705c48b 100644 --- a/src/logic/scripting/lua/libs/libinventory.cpp +++ b/src/logic/scripting/lua/libs/libinventory.cpp @@ -109,6 +109,26 @@ static int l_inventory_unbind_block(lua::State* L) { return 0; } +static int l_inventory_create(lua::State* L) { + auto invsize = lua::tointeger(L, 1); + auto inv = level->inventories->create(invsize); + if (inv == nullptr) { + return lua::pushinteger(L, 0); + } + return lua::pushinteger(L, inv->getId()); +} + +static int l_inventory_remove(lua::State* L) { + auto invid = lua::tointeger(L, 1); + auto inv = get_inventory(invid); + if (inv == nullptr) { + return 0; + } + + level->inventories->remove(invid); + return 0; +} + static int l_inventory_clone(lua::State* L) { auto id = lua::tointeger(L, 1); auto clone = level->inventories->clone(id); @@ -145,5 +165,7 @@ const luaL_Reg inventorylib[] = { {"get_block", lua::wrap}, {"bind_block", lua::wrap}, {"unbind_block", lua::wrap}, + {"create", lua::wrap}, + {"remove", lua::wrap}, {"clone", lua::wrap}, {NULL, NULL}}; diff --git a/src/voxels/Chunk.cpp b/src/voxels/Chunk.cpp index 6cbab94c..a32fc8ba 100644 --- a/src/voxels/Chunk.cpp +++ b/src/voxels/Chunk.cpp @@ -13,7 +13,7 @@ Chunk::Chunk(int xpos, int zpos) : x(xpos), z(zpos) { top = CHUNK_H; } -bool Chunk::isEmpty() { +bool Chunk::isEmpty() const { int id = -1; for (uint i = 0; i < CHUNK_VOL; i++) { if (voxels[i].id != id) { diff --git a/src/voxels/Chunk.hpp b/src/voxels/Chunk.hpp index 1b426c37..94011d40 100644 --- a/src/voxels/Chunk.hpp +++ b/src/voxels/Chunk.hpp @@ -44,7 +44,7 @@ public: Chunk(int x, int z); - bool isEmpty(); + bool isEmpty() const; void updateHeights(); diff --git a/src/window/Window.cpp b/src/window/Window.cpp index 2de948a3..d095778b 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -72,11 +72,9 @@ bool Window::isFocused() { void window_size_callback(GLFWwindow*, int width, int height) { if (width && height) { - if (Window::isFocused()) { - glViewport(0, 0, width, height); - Window::width = width; - Window::height = height; - } + glViewport(0, 0, width, height); + Window::width = width; + Window::height = height; if (!Window::isFullscreen() && !Window::isMaximized()) { Window::getSettings()->width.set(width); From 82733d38011b52a426cb74560521949c1cd43cc1 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 9 Nov 2024 21:27:52 +0300 Subject: [PATCH 002/105] fix old custom models render --- src/graphics/render/ModelsGenerator.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/graphics/render/ModelsGenerator.cpp b/src/graphics/render/ModelsGenerator.cpp index a1283bac..c629661d 100644 --- a/src/graphics/render/ModelsGenerator.cpp +++ b/src/graphics/render/ModelsGenerator.cpp @@ -60,43 +60,42 @@ model::Model ModelsGenerator::fromCustom( auto& mesh = model.addMesh("blocks:" + modelTextures[i * 6]); mesh.lighting = lighting; const UVRegion boxtexfaces[6] = { - get_region_for(modelTextures[i * 6], assets), - get_region_for(modelTextures[i * 6 + 1], assets), - get_region_for(modelTextures[i * 6 + 2], assets), - get_region_for(modelTextures[i * 6 + 3], assets), + get_region_for(modelTextures[i * 6 + 5], assets), get_region_for(modelTextures[i * 6 + 4], assets), - get_region_for(modelTextures[i * 6 + 5], assets) + get_region_for(modelTextures[i * 6 + 3], assets), + get_region_for(modelTextures[i * 6 + 2], assets), + get_region_for(modelTextures[i * 6 + 1], assets), + get_region_for(modelTextures[i * 6 + 0], assets) }; mesh.addBox( modelBoxes[i].center(), modelBoxes[i].size() * 0.5f, boxtexfaces ); } - glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 norm {0, 1, 0}; for (size_t i = 0; i < points.size() / 4; i++) { - auto texture = "blocks:" + modelTextures[modelBoxes.size() * 6 + i]; + auto texture = modelTextures[modelBoxes.size() * 6 + i]; auto& mesh = model.addMesh(texture); mesh.lighting = lighting; auto reg = get_region_for(texture, assets); mesh.vertices.push_back( - {points[i * 4 + 0] - poff, glm::vec2(reg.u1, reg.v1), norm} + {points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm} ); mesh.vertices.push_back( - {points[i * 4 + 1] - poff, glm::vec2(reg.u2, reg.v1), norm} + {points[i * 4 + 1], glm::vec2(reg.u2, reg.v1), norm} ); mesh.vertices.push_back( - {points[i * 4 + 2] - poff, glm::vec2(reg.u2, reg.v2), norm} + {points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm} ); mesh.vertices.push_back( - {points[i * 4 + 3] - poff, glm::vec2(reg.u1, reg.v1), norm} + {points[i * 4 + 0], glm::vec2(reg.u1, reg.v1), norm} ); mesh.vertices.push_back( - {points[i * 4 + 4] - poff, glm::vec2(reg.u2, reg.v2), norm} + {points[i * 4 + 2], glm::vec2(reg.u2, reg.v2), norm} ); mesh.vertices.push_back( - {points[i * 4 + 0] - poff, glm::vec2(reg.u1, reg.v2), norm} + {points[i * 4 + 3], glm::vec2(reg.u1, reg.v2), norm} ); } return model; From 983e516fb4ebc1f2def592f2b7f3195d968deed2 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 9 Nov 2024 21:54:30 +0300 Subject: [PATCH 003/105] fix: emitter does not skip particles --- src/graphics/render/Emitter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/graphics/render/Emitter.cpp b/src/graphics/render/Emitter.cpp index 582410db..82848a63 100644 --- a/src/graphics/render/Emitter.cpp +++ b/src/graphics/render/Emitter.cpp @@ -64,6 +64,7 @@ void Emitter::update( return; } } + timer += delta; const float maxDistance = preset.maxDistance; if (glm::distance2(position, cameraPosition) > maxDistance * maxDistance) { if (count > 0) { @@ -77,7 +78,6 @@ void Emitter::update( } return; } - timer += delta; while (count && timer > spawnInterval) { // spawn particle Particle particle = prototype; From a333cadfcaeb485a30833343d55faf01b28a5c5f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sat, 9 Nov 2024 23:54:19 +0300 Subject: [PATCH 004/105] fix custom model lighting --- src/graphics/render/BlocksRenderer.cpp | 40 +++++++++++++++----------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index f2fa5c6d..b1d8d135 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -292,23 +292,29 @@ void BlocksRenderer::blockCustomModel( overflow = true; return; } - int i = 0; - for (const auto& vertex : mesh.vertices) { - auto n = - vertex.normal.x * X + vertex.normal.y * Y + vertex.normal.z * Z; - float d = glm::dot(glm::normalize(n), SUN_VECTOR); - d = 0.8f + d * 0.2f; - const auto& vcoord = vertex.coord - 0.5f; - vertexAO( - coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, - vertex.uv.x, - vertex.uv.y, - glm::vec4(1, 1, 1, 1), - glm::vec3(1, 0, 0), - glm::vec3(0, 1, 0), - n - ); - indexBuffer[indexSize++] = indexOffset++; + for (int triangle = 0; triangle < mesh.vertices.size() / 3; triangle++) { + auto r = mesh.vertices[triangle * 3 + (triangle % 2) * 2].coord - + mesh.vertices[triangle * 3 + 1].coord; + r = glm::normalize(r); + + for (int i = 0; i < 3; i++) { + const auto& vertex = mesh.vertices[triangle * 3 + i]; + auto n = vertex.normal.x * X + vertex.normal.y * Y + + vertex.normal.z * Z; + float d = glm::dot(n, SUN_VECTOR); + d = 0.8f + d * 0.2f; + const auto& vcoord = vertex.coord - 0.5f; + vertexAO( + coord + vcoord.x * X + vcoord.y * Y + vcoord.z * Z, + vertex.uv.x, + vertex.uv.y, + glm::vec4(d, d, d, d), + glm::cross(r, n), + r, + n + ); + indexBuffer[indexSize++] = indexOffset++; + } } } } From 354e67087c939e032c2afa0bdec69207885b8694 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 10 Nov 2024 19:41:08 +0300 Subject: [PATCH 005/105] add 'creators' property --- doc/en/main-page.md | 4 +++- doc/ru/content-packs.md | 2 ++ doc/ru/main-page.md | 4 +++- src/content/ContentPack.cpp | 12 +++++++++++- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/doc/en/main-page.md b/doc/en/main-page.md index 06636ea0..4d487f5a 100644 --- a/doc/en/main-page.md +++ b/doc/en/main-page.md @@ -1,6 +1,8 @@ # Documentation -Documentation for the engine of version 0.24. +Documentation for the engine of in-development version 0.25. + +[Documentation for stable release 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/en/main-page.md) ## Sections diff --git a/doc/ru/content-packs.md b/doc/ru/content-packs.md index 33d46ffb..77a78636 100644 --- a/doc/ru/content-packs.md +++ b/doc/ru/content-packs.md @@ -22,6 +22,8 @@ } ``` +Вместо `creator` можно указать массив `creators` + Уровни зависимостей указываются с помощью префиксов в имени: - '!' - обязательная зависимость - '?' - опциональная зависимость diff --git a/doc/ru/main-page.md b/doc/ru/main-page.md index 30445fb6..800415c6 100644 --- a/doc/ru/main-page.md +++ b/doc/ru/main-page.md @@ -1,6 +1,8 @@ # Документация -Документация движка версии 0.24. +Документация движка разрабатываемой версии 0.25. + +[Документация стабильной версии 0.24.x.](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.24/doc/ru/main-page.md) ## Разделы diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 777e8ae1..1dae138c 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -76,7 +76,17 @@ ContentPack ContentPack::read(const fs::path& folder) { root.at("id").get(pack.id); root.at("title").get(pack.title); root.at("version").get(pack.version); - root.at("creator").get(pack.creator); + if (root.has("creators")) { + const auto& creators = root["creators"]; + for (int i = 0; i < creators.size(); i++) { + if (i > 0) { + pack.creator += ", "; + } + pack.creator += creators[i].asString(); + } + } else { + root.at("creator").get(pack.creator); + } root.at("description").get(pack.description); pack.folder = folder; From 3fa5369c7c0af82c09fcacd345279d6ad5e7258b Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 10 Nov 2024 20:09:07 +0300 Subject: [PATCH 006/105] add 'source' property --- src/content/ContentPack.cpp | 1 + src/content/ContentPack.hpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/content/ContentPack.cpp b/src/content/ContentPack.cpp index 1dae138c..166400c6 100644 --- a/src/content/ContentPack.cpp +++ b/src/content/ContentPack.cpp @@ -88,6 +88,7 @@ ContentPack ContentPack::read(const fs::path& folder) { root.at("creator").get(pack.creator); } root.at("description").get(pack.description); + root.at("source").get(pack.source); pack.folder = folder; if (auto found = root.at("dependencies")) { diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index 5aa1a22b..292400a5 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -42,6 +42,7 @@ struct ContentPack { std::string version = "0.0"; std::string creator = ""; std::string description = "no description"; + std::string source = ""; fs::path folder; std::vector dependencies; From af4edee06313948d13b585856a232db3bafc3a8e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 10 Nov 2024 21:02:48 +0300 Subject: [PATCH 007/105] fix --- src/content/ContentPack.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/ContentPack.hpp b/src/content/ContentPack.hpp index 292400a5..9d25d752 100644 --- a/src/content/ContentPack.hpp +++ b/src/content/ContentPack.hpp @@ -42,9 +42,9 @@ struct ContentPack { std::string version = "0.0"; std::string creator = ""; std::string description = "no description"; - std::string source = ""; fs::path folder; std::vector dependencies; + std::string source = ""; fs::path getContentFile() const; From 79693580e0dabd6ad616d175bd74e9f4396bca0e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 11 Nov 2024 20:30:10 +0300 Subject: [PATCH 008/105] refactor Font --- src/graphics/core/Font.cpp | 40 +++++++----------------------- src/graphics/core/Font.hpp | 8 +++--- src/graphics/ui/elements/Label.cpp | 4 +-- 3 files changed, 15 insertions(+), 37 deletions(-) diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index c12cd923..30db7d3e 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -40,45 +40,23 @@ int Font::calcWidth(const std::wstring& text, size_t length) { } int Font::calcWidth(const std::wstring& text, size_t offset, size_t length) { - return std::min(text.length()-offset, length) * 8; + return std::min(text.length()-offset, length) * glyphInterval; } -void Font::draw(Batch2D* batch, std::wstring text, int x, int y) { - draw(batch, std::move(text), x, y, FontStyle::none); +static inline void drawGlyph( + Batch2D* batch, int x, int y, uint c, int glyphSize +) { + batch->sprite(x, y, glyphSize, glyphSize, 16, c, batch->getColor()); } -static inline void drawGlyph(Batch2D* batch, int x, int y, uint c, FontStyle style) { - switch (style){ - case FontStyle::none: - break; - case FontStyle::shadow: - batch->sprite(x+1, y+1, GLYPH_SIZE, GLYPH_SIZE, 16, c, SHADOW_TINT); - break; - case FontStyle::outline: - for (int oy = -1; oy <= 1; oy++){ - for (int ox = -1; ox <= 1; ox++){ - if (ox || oy) { - batch->sprite(x+ox, y+oy, GLYPH_SIZE, GLYPH_SIZE, 16, c, SHADOW_TINT); - } - } - } - break; - } - batch->sprite(x, y, GLYPH_SIZE, GLYPH_SIZE, 16, c, batch->getColor()); -} - -void Font::draw(Batch2D* batch, const std::wstring& text, int x, int y, FontStyle style) { - draw(batch, std::wstring_view(text.c_str(), text.length()), x, y, style); -} - -void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y, FontStyle style) { +void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y) { uint page = 0; uint next = MAX_CODEPAGES; int init_x = x; do { for (uint c : text){ if (!isPrintableChar(c)) { - x += 8; + x += glyphInterval; continue; } uint charpage = c >> 8; @@ -91,12 +69,12 @@ void Font::draw(Batch2D* batch, std::wstring_view text, int x, int y, FontStyle texture = pages[0].get(); } batch->texture(texture); - drawGlyph(batch, x, y, c, style); + drawGlyph(batch, x, y, c, lineHeight); } else if (charpage > page && charpage < next){ next = charpage; } - x += 8;//getGlyphWidth(c); + x += glyphInterval; } page = next; next = MAX_CODEPAGES; diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index ecda77a5..b5f0c533 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -17,8 +17,9 @@ enum class FontStyle { class Font { int lineHeight; int yoffset; -public: + int glyphInterval = 8; std::vector> pages; +public: Font(std::vector> pages, int lineHeight, int yoffset); ~Font(); @@ -41,7 +42,6 @@ public: /// @brief Check if character is visible (non-whitespace) /// @param codepoint character unicode codepoint bool isPrintableChar(uint codepoint) const; - void draw(Batch2D* batch, std::wstring text, int x, int y); - void draw(Batch2D* batch, const std::wstring& text, int x, int y, FontStyle style); - void draw(Batch2D* batch, std::wstring_view text, int x, int y, FontStyle style); + + void draw(Batch2D* batch, std::wstring_view text, int x, int y); }; diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index a0d356b3..5e02b31a 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, FontStyle::none); + font->draw(batch, view, pos.x, pos.y + i * totalLineHeight); } } else { - font->draw(batch, text, pos.x, pos.y, FontStyle::none); + font->draw(batch, text, pos.x, pos.y); } } From c5ca9128e9990e52090310da2a890892e9f4a2de Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 11 Nov 2024 22:30:42 +0300 Subject: [PATCH 009/105] move getVoxels from ChunksStorage to Chunks --- src/graphics/render/BlocksRenderer.cpp | 6 +- src/graphics/render/BlocksRenderer.hpp | 6 +- src/graphics/render/ChunksRenderer.cpp | 4 +- src/voxels/Chunks.cpp | 94 +++++++++++++++++++++++++- src/voxels/Chunks.hpp | 7 +- src/voxels/ChunksStorage.cpp | 91 ------------------------- src/voxels/ChunksStorage.hpp | 2 - src/world/generator/VoxelFragment.cpp | 4 +- 8 files changed, 107 insertions(+), 107 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index b1d8d135..cd20249d 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -5,7 +5,7 @@ #include "maths/UVRegion.hpp" #include "constants.hpp" #include "content/Content.hpp" -#include "voxels/ChunksStorage.hpp" +#include "voxels/Chunks.hpp" #include "lighting/Lightmap.hpp" #include "frontend/ContentGfxCache.hpp" #include "settings.hpp" @@ -486,7 +486,7 @@ void BlocksRenderer::render(const voxel* voxels) { } } -void BlocksRenderer::build(const Chunk* chunk, const ChunksStorage* chunks) { +void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) { this->chunk = chunk; voxelsBuffer->setPosition( chunk->x * CHUNK_W - voxelBufferPadding, 0, @@ -515,7 +515,7 @@ MeshData BlocksRenderer::createMesh() { ); } -std::shared_ptr BlocksRenderer::render(const Chunk* chunk, const ChunksStorage* chunks) { +std::shared_ptr BlocksRenderer::render(const Chunk* chunk, const Chunks* chunks) { build(chunk, chunks); const vattr attrs[]{ {3}, {2}, {1}, {0} }; diff --git a/src/graphics/render/BlocksRenderer.hpp b/src/graphics/render/BlocksRenderer.hpp index 3890349a..15d68905 100644 --- a/src/graphics/render/BlocksRenderer.hpp +++ b/src/graphics/render/BlocksRenderer.hpp @@ -19,7 +19,7 @@ class Block; class Chunk; class Chunks; class VoxelsVolume; -class ChunksStorage; +class Chunks; class ContentGfxCache; struct EngineSettings; struct UVRegion; @@ -140,8 +140,8 @@ public: BlocksRenderer(size_t capacity, const Content* content, const ContentGfxCache* cache, const EngineSettings* settings); virtual ~BlocksRenderer(); - void build(const Chunk* chunk, const ChunksStorage* chunks); - std::shared_ptr render(const Chunk* chunk, const ChunksStorage* chunks); + void build(const Chunk* chunk, const Chunks* chunks); + std::shared_ptr render(const Chunk* chunk, const Chunks* chunks); MeshData createMesh(); VoxelsVolume* getVoxelsBuffer() const; diff --git a/src/graphics/render/ChunksRenderer.cpp b/src/graphics/render/ChunksRenderer.cpp index f5fb7f89..656124da 100644 --- a/src/graphics/render/ChunksRenderer.cpp +++ b/src/graphics/render/ChunksRenderer.cpp @@ -26,7 +26,7 @@ public: {} RendererResult operator()(const std::shared_ptr& chunk) override { - renderer.build(chunk.get(), level->chunksStorage.get()); + renderer.build(chunk.get(), level->chunks.get()); if (renderer.isCancelled()) { return RendererResult { glm::ivec2(chunk->x, chunk->z), true, MeshData()}; @@ -66,7 +66,7 @@ ChunksRenderer::~ChunksRenderer() { std::shared_ptr ChunksRenderer::render(const std::shared_ptr& chunk, bool important) { chunk->flags.modified = false; if (important) { - auto mesh = renderer->render(chunk.get(), level->chunksStorage.get()); + auto mesh = renderer->render(chunk.get(), level->chunks.get()); meshes[glm::ivec2(chunk->x, chunk->z)] = mesh; return mesh; } diff --git a/src/voxels/Chunks.cpp b/src/voxels/Chunks.cpp index 5937a38e..0ce0e5c1 100644 --- a/src/voxels/Chunks.cpp +++ b/src/voxels/Chunks.cpp @@ -20,6 +20,7 @@ #include "objects/Entities.hpp" #include "world/Level.hpp" #include "world/LevelEvents.hpp" +#include "VoxelsVolume.hpp" #include "Block.hpp" #include "Chunk.hpp" #include "voxel.hpp" @@ -161,7 +162,7 @@ light_t Chunks::getLight(int32_t x, int32_t y, int32_t z) const { return chunk->lightmap.get(lx, y, lz); } -Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) { +Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) const { if (y < 0 || y >= CHUNK_H) { return nullptr; } @@ -173,7 +174,7 @@ Chunk* Chunks::getChunkByVoxel(int32_t x, int32_t y, int32_t z) { return nullptr; } -Chunk* Chunks::getChunk(int x, int z) { +Chunk* Chunks::getChunk(int x, int z) const { if (auto ptr = areaMap.getIf(x, z)) { return ptr->get(); } @@ -675,6 +676,95 @@ bool Chunks::putChunk(const std::shared_ptr& chunk) { return areaMap.set(chunk->x, chunk->z, chunk); } +// reduce nesting on next modification +// 25.06.2024: not now +// 11.11.2024: not now +void Chunks::getVoxels(VoxelsVolume* volume, bool backlight) const { + const Content* content = level->content; + auto indices = content->getIndices(); + voxel* voxels = volume->getVoxels(); + light_t* lights = volume->getLights(); + int x = volume->getX(); + int y = volume->getY(); + int z = volume->getZ(); + + int w = volume->getW(); + int h = volume->getH(); + int d = volume->getD(); + + int scx = floordiv(x, CHUNK_W); + int scz = floordiv(z, CHUNK_D); + + int ecx = floordiv(x + w, CHUNK_W); + int ecz = floordiv(z + d, CHUNK_D); + + int cw = ecx - scx + 1; + int cd = ecz - scz + 1; + + // cw*cd chunks will be scanned + for (int cz = scz; cz < scz + cd; cz++) { + for (int cx = scx; cx < scx + cw; cx++) { + const auto chunk = getChunk(cx, cz); + if (chunk == nullptr) { + // no chunk loaded -> filling with BLOCK_VOID + for (int ly = y; ly < y + h; ly++) { + for (int lz = std::max(z, cz * CHUNK_D); + lz < std::min(z + d, (cz + 1) * CHUNK_D); + lz++) { + for (int lx = std::max(x, cx * CHUNK_W); + lx < std::min(x + w, (cx + 1) * CHUNK_W); + lx++) { + uint idx = vox_index(lx - x, ly - y, lz - z, w, d); + voxels[idx].id = BLOCK_VOID; + lights[idx] = 0; + } + } + } + } else { + const voxel* cvoxels = chunk->voxels; + const light_t* clights = chunk->lightmap.getLights(); + for (int ly = y; ly < y + h; ly++) { + for (int lz = std::max(z, cz * CHUNK_D); + lz < std::min(z + d, (cz + 1) * CHUNK_D); + lz++) { + for (int lx = std::max(x, cx * CHUNK_W); + lx < std::min(x + w, (cx + 1) * CHUNK_W); + lx++) { + uint vidx = vox_index(lx - x, ly - y, lz - z, w, d); + uint cidx = vox_index( + lx - cx * CHUNK_W, + ly, + lz - cz * CHUNK_D, + CHUNK_W, + CHUNK_D + ); + voxels[vidx] = cvoxels[cidx]; + light_t light = clights[cidx]; + if (backlight) { + const auto block = + indices->blocks.get(voxels[vidx].id); + if (block && block->lightPassing) { + light = Lightmap::combine( + std::min(15, + Lightmap::extract(light, 0) + 1), + std::min(15, + Lightmap::extract(light, 1) + 1), + std::min(15, + Lightmap::extract(light, 2) + 1), + std::min(15, + static_cast(Lightmap::extract(light, 3))) + ); + } + } + lights[vidx] = light; + } + } + } + } + } + } +} + void Chunks::saveAndClear() { areaMap.clear(); } diff --git a/src/voxels/Chunks.hpp b/src/voxels/Chunks.hpp index fed09f1d..d2440210 100644 --- a/src/voxels/Chunks.hpp +++ b/src/voxels/Chunks.hpp @@ -21,6 +21,7 @@ class WorldFiles; class LevelEvents; class Block; class Level; +class VoxelsVolume; /// Player-centred chunks matrix class Chunks { @@ -55,8 +56,8 @@ public: bool putChunk(const std::shared_ptr& chunk); - Chunk* getChunk(int32_t x, int32_t z); - Chunk* getChunkByVoxel(int32_t x, int32_t y, int32_t z); + Chunk* getChunk(int32_t x, int32_t z) const; + Chunk* getChunkByVoxel(int32_t x, int32_t y, int32_t z) const; voxel* get(int32_t x, int32_t y, int32_t z) const; voxel& require(int32_t x, int32_t y, int32_t z) const; @@ -119,6 +120,8 @@ public: bool isReplaceableBlock(int32_t x, int32_t y, int32_t z); bool isObstacleBlock(int32_t x, int32_t y, int32_t z); + void getVoxels(VoxelsVolume* volume, bool backlight = false) const; + void setCenter(int32_t x, int32_t z); void resize(uint32_t newW, uint32_t newD); diff --git a/src/voxels/ChunksStorage.cpp b/src/voxels/ChunksStorage.cpp index 75b37b9e..596c4b78 100644 --- a/src/voxels/ChunksStorage.cpp +++ b/src/voxels/ChunksStorage.cpp @@ -14,7 +14,6 @@ #include "world/World.hpp" #include "Block.hpp" #include "Chunk.hpp" -#include "VoxelsVolume.hpp" static debug::Logger logger("chunks-storage"); @@ -84,93 +83,3 @@ std::shared_ptr ChunksStorage::create(int x, int z) { chunk->blocksMetadata = regions.getBlocksData(chunk->x, chunk->z); return chunk; } - -// reduce nesting on next modification -// 25.06.2024: not now -// TODO: move to Chunks for performance improvement -void ChunksStorage::getVoxels(VoxelsVolume* volume, bool backlight) const { - const Content* content = level->content; - auto indices = content->getIndices(); - voxel* voxels = volume->getVoxels(); - light_t* lights = volume->getLights(); - int x = volume->getX(); - int y = volume->getY(); - int z = volume->getZ(); - - int w = volume->getW(); - int h = volume->getH(); - int d = volume->getD(); - - int scx = floordiv(x, CHUNK_W); - int scz = floordiv(z, CHUNK_D); - - int ecx = floordiv(x + w, CHUNK_W); - int ecz = floordiv(z + d, CHUNK_D); - - int cw = ecx - scx + 1; - int cd = ecz - scz + 1; - - // cw*cd chunks will be scanned - for (int cz = scz; cz < scz + cd; cz++) { - for (int cx = scx; cx < scx + cw; cx++) { - const auto& found = chunksMap.find(glm::ivec2(cx, cz)); - if (found == chunksMap.end()) { - // no chunk loaded -> filling with BLOCK_VOID - for (int ly = y; ly < y + h; ly++) { - for (int lz = std::max(z, cz * CHUNK_D); - lz < std::min(z + d, (cz + 1) * CHUNK_D); - lz++) { - for (int lx = std::max(x, cx * CHUNK_W); - lx < std::min(x + w, (cx + 1) * CHUNK_W); - lx++) { - uint idx = vox_index(lx - x, ly - y, lz - z, w, d); - voxels[idx].id = BLOCK_VOID; - lights[idx] = 0; - } - } - } - } else { - auto& chunk = found->second; - const voxel* cvoxels = chunk->voxels; - const light_t* clights = chunk->lightmap.getLights(); - for (int ly = y; ly < y + h; ly++) { - for (int lz = std::max(z, cz * CHUNK_D); - lz < std::min(z + d, (cz + 1) * CHUNK_D); - lz++) { - for (int lx = std::max(x, cx * CHUNK_W); - lx < std::min(x + w, (cx + 1) * CHUNK_W); - lx++) { - uint vidx = vox_index(lx - x, ly - y, lz - z, w, d); - uint cidx = vox_index( - lx - cx * CHUNK_W, - ly, - lz - cz * CHUNK_D, - CHUNK_W, - CHUNK_D - ); - voxels[vidx] = cvoxels[cidx]; - light_t light = clights[cidx]; - if (backlight) { - const auto block = - indices->blocks.get(voxels[vidx].id); - if (block && block->lightPassing) { - light = Lightmap::combine( - std::min(15, - Lightmap::extract(light, 0) + 1), - std::min(15, - Lightmap::extract(light, 1) + 1), - std::min(15, - Lightmap::extract(light, 2) + 1), - std::min(15, - static_cast(Lightmap::extract(light, 3))) - ); - } - } - lights[vidx] = light; - } - } - } - } - } - } -} diff --git a/src/voxels/ChunksStorage.hpp b/src/voxels/ChunksStorage.hpp index 887af1ca..35fff6c1 100644 --- a/src/voxels/ChunksStorage.hpp +++ b/src/voxels/ChunksStorage.hpp @@ -11,7 +11,6 @@ class Chunk; class Level; -class VoxelsVolume; class ChunksStorage { Level* level; @@ -23,6 +22,5 @@ public: std::shared_ptr get(int x, int z) const; void store(const std::shared_ptr& chunk); void remove(int x, int y); - void getVoxels(VoxelsVolume* volume, bool backlight = false) const; std::shared_ptr create(int x, int z); }; diff --git a/src/world/generator/VoxelFragment.cpp b/src/world/generator/VoxelFragment.cpp index 2d287b0b..f36824b0 100644 --- a/src/world/generator/VoxelFragment.cpp +++ b/src/world/generator/VoxelFragment.cpp @@ -26,7 +26,7 @@ std::unique_ptr VoxelFragment::create( if (crop) { VoxelsVolume volume(size.x, size.y, size.z); volume.setPosition(start.x, start.y, start.z); - level->chunksStorage->getVoxels(&volume); + level->chunks->getVoxels(&volume); auto end = start + size; @@ -51,7 +51,7 @@ std::unique_ptr VoxelFragment::create( VoxelsVolume volume(size.x, size.y, size.z); volume.setPosition(start.x, start.y, start.z); - level->chunksStorage->getVoxels(&volume); + level->chunks->getVoxels(&volume); auto volVoxels = volume.getVoxels(); std::vector voxels(size.x * size.y * size.z); From b3ab0371155163a98a2564259d99ed5ef6dde18f Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 03:14:59 +0300 Subject: [PATCH 010/105] 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); } } From edbd851d11665e0e19700d21d226a89a0cee5983 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 05:58:16 +0300 Subject: [PATCH 011/105] update font rendering --- src/graphics/core/Font.cpp | 76 ++++++++++++++++----------- src/graphics/core/Font.hpp | 4 +- src/graphics/render/WorldRenderer.cpp | 13 +++-- 3 files changed, 58 insertions(+), 35 deletions(-) diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index db3b3593..3f63065e 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -45,38 +45,42 @@ int Font::calcWidth(const std::wstring& text, size_t offset, size_t length) cons return std::min(text.length()-offset, length) * glyphInterval; } -static inline void drawGlyph( +static inline void draw_glyph( Batch2D& batch, const glm::vec3& pos, const glm::vec2& offset, uint c, - int glyphSize, - const Camera* + const glm::vec3& right, + const glm::vec3& up, + float glyphInterval, + float lineHeight ) { batch.sprite( - pos.x + offset.x, - pos.y + offset.y, - glyphSize, - glyphSize, + pos.x + offset.x * right.x, + pos.y + offset.y * right.y, + right.x / glyphInterval, + up.y, 16, c, batch.getColor() ); } -static inline void drawGlyph( +static inline void draw_glyph( Batch3D& batch, const glm::vec3& pos, const glm::vec2& offset, uint c, - int glyphSize, - const Camera* camera + const glm::vec3& right, + const glm::vec3& up, + float glyphInterval, + float lineHeight ) { batch.sprite( - pos + camera->right * offset.x + camera->up * offset.y, - camera->up, camera->right, - glyphSize * 0.5f, - glyphSize * 0.5f, + pos + right * offset.x + up * offset.y, + up, right / glyphInterval, + 0.5f, + 0.5f, 16, c, glm::vec4(1.0f) @@ -89,33 +93,43 @@ static inline void draw_text( Batch& batch, std::wstring_view text, const glm::vec3& pos, + const glm::vec3& right, + const glm::vec3& up, float glyphInterval, - float lineHeight, - const Camera* camera + float lineHeight ) { uint page = 0; uint next = MAX_CODEPAGES; - float x = 0; - float y = 0; + int x = 0; + int y = 0; do { for (uint c : text){ if (!font.isPrintableChar(c)) { - x += glyphInterval; + x++; continue; } uint charpage = c >> 8; if (charpage == page){ batch.texture(font.getPage(charpage)); - drawGlyph(batch, pos, glm::vec2(x, y), c, lineHeight, camera); + draw_glyph( + batch, + pos, + glm::vec2(x, y), + c, + right, + up, + glyphInterval, + lineHeight + ); } else if (charpage > page && charpage < next){ next = charpage; } - x += glyphInterval; + x++; } page = next; next = MAX_CODEPAGES; - x = 0.0f; + x = 0; } while (page < MAX_CODEPAGES); } @@ -138,26 +152,28 @@ void Font::draw( batch, text, glm::vec3(x, y, 0), - glyphInterval * scale, - lineHeight * scale, - nullptr + glm::vec3(glyphInterval*scale, 0, 0), + glm::vec3(0, lineHeight*scale, 0), + glyphInterval/static_cast(lineHeight), + lineHeight ); } void Font::draw( Batch3D& batch, - const Camera& camera, std::wstring_view text, const glm::vec3& pos, - float scale + const glm::vec3& right, + const glm::vec3& up ) const { draw_text( *this, batch, text, pos, - glyphInterval * scale, - lineHeight * scale, - &camera + right * static_cast(glyphInterval), + up * static_cast(lineHeight), + glyphInterval/static_cast(lineHeight), + lineHeight ); } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index 1a778cfc..deb07534 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -50,10 +50,10 @@ public: void draw( Batch3D& batch, - const Camera& camera, std::wstring_view text, const glm::vec3& pos, - float scale = 1 + const glm::vec3& right={1, 0, 0}, + const glm::vec3& up={0, 1, 0} ) const; const Texture* getPage(int page) const; diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index cfbb8373..41e368a6 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -419,12 +419,19 @@ void WorldRenderer::renderTexts( shader.uniformMatrix("u_apply", glm::mat4(1.0f)); batch3d->begin(); std::wstring string = L"Segmentation fault (core dumped)"; + glm::vec3 pos(0, 100, 0); + auto zvec = camera.position - pos; + zvec.y = 0; + std::swap(zvec.x, zvec.z); + zvec.z *= -1; + zvec = glm::normalize(zvec); + font.draw( *batch3d, - camera, string, - glm::vec3(0, 100, 0) - - camera.right * (font.calcWidth(string, string.length()) * 0.5f) + pos - zvec * (font.calcWidth(string, string.length()) * 0.5f), + zvec, + camera.up ); batch3d->flush(); } From 7734d403ea8145e88804c0490bab8e67743c023e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 06:01:53 +0300 Subject: [PATCH 012/105] cleanup --- src/graphics/core/Font.cpp | 33 ++++++++------------------------- 1 file changed, 8 insertions(+), 25 deletions(-) diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 3f63065e..31fe60c0 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -52,8 +52,7 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval, - float lineHeight + float glyphInterval ) { batch.sprite( pos.x + offset.x * right.x, @@ -73,8 +72,7 @@ static inline void draw_glyph( uint c, const glm::vec3& right, const glm::vec3& up, - float glyphInterval, - float lineHeight + float glyphInterval ) { batch.sprite( pos + right * offset.x + up * offset.y, @@ -95,8 +93,7 @@ static inline void draw_text( const glm::vec3& pos, const glm::vec3& right, const glm::vec3& up, - float glyphInterval, - float lineHeight + float glyphInterval ) { uint page = 0; uint next = MAX_CODEPAGES; @@ -112,14 +109,7 @@ static inline void draw_text( if (charpage == page){ batch.texture(font.getPage(charpage)); draw_glyph( - batch, - pos, - glm::vec2(x, y), - c, - right, - up, - glyphInterval, - lineHeight + batch, pos, glm::vec2(x, y), c, right, up, glyphInterval ); } else if (charpage > page && charpage < next){ @@ -148,14 +138,11 @@ void Font::draw( Batch2D& batch, std::wstring_view text, int x, int y, float scale ) const { draw_text( - *this, - batch, - text, + *this, batch, text, glm::vec3(x, y, 0), glm::vec3(glyphInterval*scale, 0, 0), glm::vec3(0, lineHeight*scale, 0), - glyphInterval/static_cast(lineHeight), - lineHeight + glyphInterval/static_cast(lineHeight) ); } @@ -167,13 +154,9 @@ void Font::draw( const glm::vec3& up ) const { draw_text( - *this, - batch, - text, - pos, + *this, batch, text, pos, right * static_cast(glyphInterval), up * static_cast(lineHeight), - glyphInterval/static_cast(lineHeight), - lineHeight + glyphInterval/static_cast(lineHeight) ); } From 283ac854a47e4b38b3f9ab01fbc5819cfaab8068 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 07:42:48 +0300 Subject: [PATCH 013/105] Development-related additions (#365) --- src/window/Window.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/window/Window.cpp b/src/window/Window.cpp index d095778b..fdfde141 100644 --- a/src/window/Window.cpp +++ b/src/window/Window.cpp @@ -211,9 +211,12 @@ int Window::initialize(DisplaySettings* settings) { setFramerate(settings->framerate.get()); const GLubyte* vendor = glGetString(GL_VENDOR); const GLubyte* renderer = glGetString(GL_RENDERER); - logger.info() << "GL Vendor: " << (char*)vendor; - logger.info() << "GL Renderer: " << (char*)renderer; + logger.info() << "GL Vendor: " << reinterpret_cast(vendor); + logger.info() << "GL Renderer: " << reinterpret_cast(renderer); logger.info() << "GLFW: " << glfwGetVersionString(); + glm::vec2 scale; + glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &scale.x, &scale.y); + logger.info() << "monitor content scale: " << scale.x << "x" << scale.y; input_util::initialize(); return 0; From 01c568e032b4faea5ccc016aebaea437d7d92553 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 07:51:15 +0300 Subject: [PATCH 014/105] set version to 0.25 --- res/content/base/package.json | 2 +- src/constants.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/res/content/base/package.json b/res/content/base/package.json index 0ed25d38..7645a6e0 100644 --- a/res/content/base/package.json +++ b/res/content/base/package.json @@ -1,6 +1,6 @@ { "id": "base", "title": "Base", - "version": "0.24", + "version": "0.25", "description": "basic content package" } diff --git a/src/constants.hpp b/src/constants.hpp index 53be95d2..12e12c75 100644 --- a/src/constants.hpp +++ b/src/constants.hpp @@ -6,7 +6,7 @@ #include inline constexpr int ENGINE_VERSION_MAJOR = 0; -inline constexpr int ENGINE_VERSION_MINOR = 24; +inline constexpr int ENGINE_VERSION_MINOR = 25; #ifdef NDEBUG inline constexpr bool ENGINE_DEBUG_BUILD = false; @@ -14,7 +14,7 @@ inline constexpr bool ENGINE_DEBUG_BUILD = false; inline constexpr bool ENGINE_DEBUG_BUILD = true; #endif // NDEBUG -inline const std::string ENGINE_VERSION_STRING = "0.24"; +inline const std::string ENGINE_VERSION_STRING = "0.25"; /// @brief world regions format version inline constexpr uint REGION_FORMAT_VERSION = 3; From aadb04c41eb4caae8f611da3cf1a895d38550403 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 20:07:45 +0300 Subject: [PATCH 015/105] minor optimize BlocksRenderer --- src/graphics/render/BlocksRenderer.cpp | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/graphics/render/BlocksRenderer.cpp b/src/graphics/render/BlocksRenderer.cpp index cd20249d..745e96ec 100644 --- a/src/graphics/render/BlocksRenderer.cpp +++ b/src/graphics/render/BlocksRenderer.cpp @@ -434,10 +434,27 @@ glm::vec4 BlocksRenderer::pickSoftLight( } void BlocksRenderer::render(const voxel* voxels) { - int begin = chunk->bottom * (CHUNK_W * CHUNK_D); - int end = chunk->top * (CHUNK_W * CHUNK_D); + int totalBegin = chunk->bottom * (CHUNK_W * CHUNK_D); + int totalEnd = chunk->top * (CHUNK_W * CHUNK_D); + + int beginEnds[256][2] {}; + for (int i = totalBegin; i < totalEnd; i++) { + const voxel& vox = voxels[i]; + blockid_t id = vox.id; + const auto& def = *blockDefsCache[id]; + + if (beginEnds[def.drawGroup][0] == 0) { + beginEnds[def.drawGroup][0] = i+1; + } + beginEnds[def.drawGroup][1] = i; + } for (const auto drawGroup : *content->drawGroups) { - for (int i = begin; i < end; i++) { + int begin = beginEnds[drawGroup][0]; + if (begin == 0) { + continue; + } + int end = beginEnds[drawGroup][1]; + for (int i = begin-1; i <= end; i++) { const voxel& vox = voxels[i]; blockid_t id = vox.id; blockstate state = vox.state; From 866f6e99517904c97da6655b1723b14ba2ba7c2d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 22:53:45 +0300 Subject: [PATCH 016/105] add NotePreset --- src/graphics/render/WorldRenderer.cpp | 8 ++++-- src/presets/NotePreset.cpp | 40 +++++++++++++++++++++++++++ src/presets/NotePreset.hpp | 23 +++++++++++++++ 3 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/presets/NotePreset.cpp create mode 100644 src/presets/NotePreset.hpp diff --git a/src/graphics/render/WorldRenderer.cpp b/src/graphics/render/WorldRenderer.cpp index 41e368a6..54f2d447 100644 --- a/src/graphics/render/WorldRenderer.cpp +++ b/src/graphics/render/WorldRenderer.cpp @@ -426,12 +426,14 @@ void WorldRenderer::renderTexts( zvec.z *= -1; zvec = glm::normalize(zvec); + float ppbx = 100; + float ppby = 100; font.draw( *batch3d, string, - pos - zvec * (font.calcWidth(string, string.length()) * 0.5f), - zvec, - camera.up + pos - zvec * (font.calcWidth(string, string.length()) * 0.5f) / ppbx, + zvec / ppbx, + camera.up / ppby ); batch3d->flush(); } diff --git a/src/presets/NotePreset.cpp b/src/presets/NotePreset.cpp new file mode 100644 index 00000000..e8601ab7 --- /dev/null +++ b/src/presets/NotePreset.cpp @@ -0,0 +1,40 @@ +#include "NotePreset.hpp" + +#include +#include + +std::string to_string(NoteDisplayMode mode) { + static std::vector names = { + "static_billboard", + "y_free_billboard", + "xy_free_billboard", + "projected" + }; + return names.at(static_cast(mode)); +} + +std::optional NoteDisplayMode_from(std::string_view s) { + static std::map> map { + {"static_billboard", NoteDisplayMode::STATIC_BILLBOARD}, + {"y_free_billboard", NoteDisplayMode::Y_FREE_BILLBOARD}, + {"xy_free_billboard", NoteDisplayMode::XY_FREE_BILLBOARD}, + {"projected", NoteDisplayMode::PROJECTED} + }; + const auto& found = map.find(s); + if (found == map.end()) { + return std::nullopt; + } + return found->second; +} + +dv::value NotePreset::serialize() const { + return dv::object({ + {"display", to_string(displayMode)} + }); +} + +void NotePreset::deserialize(const dv::value& src) { + if (src.has("display")) { + displayMode = NoteDisplayMode_from(src["display"].asString()).value(); + } +} diff --git a/src/presets/NotePreset.hpp b/src/presets/NotePreset.hpp new file mode 100644 index 00000000..cf8aa15f --- /dev/null +++ b/src/presets/NotePreset.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "interfaces/Serializable.hpp" + +enum class NoteDisplayMode { + STATIC_BILLBOARD, + Y_FREE_BILLBOARD, + XY_FREE_BILLBOARD, + PROJECTED +}; + +std::string to_string(NoteDisplayMode mode); +std::optional NoteDisplayMode_from(std::string_view s); + +struct NotePreset : public Serializable { + NoteDisplayMode displayMode = NoteDisplayMode::STATIC_BILLBOARD; + + dv::value serialize() const override; + void deserialize(const dv::value& src) override; +}; From d72f758dc58ff95d6b26340cdf0f02d8f965b1d0 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 12 Nov 2024 23:20:43 +0300 Subject: [PATCH 017/105] add 'hint' property to TextBox --- doc/en/scripting/ui.md | 1 + doc/ru/scripting/ui.md | 1 + src/graphics/ui/elements/TextBox.cpp | 17 +++++++++++---- src/graphics/ui/elements/TextBox.hpp | 29 ++++++++++++++++++++----- src/graphics/ui/gui_xml.cpp | 13 +++++++++-- src/logic/scripting/lua/libs/libgui.cpp | 14 ++++++++++++ 6 files changed, 64 insertions(+), 11 deletions(-) diff --git a/doc/en/scripting/ui.md b/doc/en/scripting/ui.md index e209c267..0a6ad4c3 100644 --- a/doc/en/scripting/ui.md +++ b/doc/en/scripting/ui.md @@ -74,6 +74,7 @@ Properties: | ----------- | ------ | ---- | ----- | ------------------------------------------------------------------------------------ | | text | string | yes | yes | entered text or placeholder | | placeholder | string | yes | yes | placeholder (used if nothing has been entered) | +| hint | string | yes | yes | text to display when nothing is entered | | caret | int | yes | yes | carriage position. `textbox.caret = -1` will set the position to the end of the text | | editable | bool | yes | yes | text mutability | | multiline | bool | yes | yes | multiline support | diff --git a/doc/ru/scripting/ui.md b/doc/ru/scripting/ui.md index 6d39c6c7..0a955947 100644 --- a/doc/ru/scripting/ui.md +++ b/doc/ru/scripting/ui.md @@ -74,6 +74,7 @@ document["worlds-panel"]:clear() | ----------- | ------ | ------ | ------ | ---------------------------------------------------------------------- | | text | string | да | да | введенный текст или заполнитель | | placeholder | string | да | да | заполнитель (используется если ничего не было введено) | +| hint | string | да | да | текст, отображаемый, когда ничего не введено | | caret | int | да | да | позиция каретки. `textbox.caret = -1` установит позицию в конец текста | | editable | bool | да | да | изменяемость текста | | multiline | bool | да | да | поддержка многострочности | diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 7477d2f3..9fe44327 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -127,7 +127,7 @@ void TextBox::drawBackground(const DrawContext* pctx, Assets*) { void TextBox::refreshLabel() { label->setColor(glm::vec4(input.empty() ? 0.5f : 1.0f)); - label->setText(getText()); + label->setText(input.empty() && !hint.empty() ? hint : getText()); if (autoresize && font) { auto size = getSize(); @@ -505,7 +505,7 @@ void TextBox::performEditingKeyboardEvents(keycode key) { } else { defocus(); if (validate() && consumer) { - consumer(label->getText()); + consumer(getText()); } } } else if (key == keycode::TAB) { @@ -627,7 +627,7 @@ glm::vec4 TextBox::getErrorColor() const { return invalidColor; } -std::wstring TextBox::getText() const { +const std::wstring& TextBox::getText() const { if (input.empty()) return placeholder; return input; @@ -638,7 +638,7 @@ void TextBox::setText(const std::wstring& value) { input.erase(std::remove(input.begin(), input.end(), '\r'), input.end()); } -std::wstring TextBox::getPlaceholder() const { +const std::wstring& TextBox::getPlaceholder() const { return placeholder; } @@ -646,6 +646,15 @@ void TextBox::setPlaceholder(const std::wstring& placeholder) { this->placeholder = placeholder; } + +const std::wstring& TextBox::getHint() const { + return hint; +} + +void TextBox::setHint(const std::wstring& text) { + this->hint = text; +} + std::wstring TextBox::getSelection() const { return input.substr(selectionStart, selectionEnd-selectionStart); } diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index c7898307..834f7a64 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -13,23 +13,35 @@ namespace gui { glm::vec4 focusedColor {0.0f, 0.0f, 0.0f, 1.0f}; glm::vec4 invalidColor {0.1f, 0.05f, 0.03f, 1.0f}; std::shared_ptr