From 2d1c69ee7e7248d8e86e00c4a2f5cead490cd278 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Sep 2025 21:44:04 +0300 Subject: [PATCH 1/9] fix: Bytearray expected, got function --- res/modules/internal/events.lua | 2 +- src/logic/scripting/lua/lua_util.hpp | 7 +++++-- src/network/Network.cpp | 1 - 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/res/modules/internal/events.lua b/res/modules/internal/events.lua index 4820ddd5..7635af25 100644 --- a/res/modules/internal/events.lua +++ b/res/modules/internal/events.lua @@ -39,7 +39,7 @@ function events.emit(event, ...) local status, newres = xpcall(func, __vc__error, ...) if not status then debug.error("error in event ("..event..") handler: "..newres) - else + else result = result or newres end end diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 75f30b54..280857e5 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -768,9 +768,12 @@ namespace lua { } inline std::string_view bytearray_as_string(lua::State* L, int idx) { - lua::requireglobal(L, "Bytearray_as_string"); lua::pushvalue(L, idx); + lua::requireglobal(L, "Bytearray_as_string"); + lua::pushvalue(L, -2); lua::call(L, 1, 1); - return lua::tolstring(L, -1); + auto view = lua::tolstring(L, -1); + lua::pop(L); + return view; } } diff --git a/src/network/Network.cpp b/src/network/Network.cpp index b3ff07cf..d8dc6185 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -379,7 +379,6 @@ public: } totalDownload += size; } - logger.debug() << "read " << size << " bytes from " << to_string(addr); } } From 6eda8190112b5cec437e2163518191ed11d67efc Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 28 Sep 2025 22:22:59 +0300 Subject: [PATCH 2/9] fix --- src/logic/scripting/lua/libs/libutf8.cpp | 3 +-- src/logic/scripting/lua/lua_util.hpp | 2 +- src/network/Network.cpp | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/logic/scripting/lua/libs/libutf8.cpp b/src/logic/scripting/lua/libs/libutf8.cpp index c0801b4d..d9164784 100644 --- a/src/logic/scripting/lua/libs/libutf8.cpp +++ b/src/logic/scripting/lua/libs/libutf8.cpp @@ -33,8 +33,7 @@ static int l_tostring(lua::State* L) { lua::pop(L); return lua::pushlstring(L, buffer.data(), size); } else { - lua::bytearray_as_string(L, 1); - return 1; + return lua::pushlstring(L, lua::bytearray_as_string(L, 1)); } } diff --git a/src/logic/scripting/lua/lua_util.hpp b/src/logic/scripting/lua/lua_util.hpp index 280857e5..d7aed664 100644 --- a/src/logic/scripting/lua/lua_util.hpp +++ b/src/logic/scripting/lua/lua_util.hpp @@ -773,7 +773,7 @@ namespace lua { lua::pushvalue(L, -2); lua::call(L, 1, 1); auto view = lua::tolstring(L, -1); - lua::pop(L); + lua::pop(L, 2); return view; } } diff --git a/src/network/Network.cpp b/src/network/Network.cpp index d8dc6185..2a1aacc8 100644 --- a/src/network/Network.cpp +++ b/src/network/Network.cpp @@ -696,7 +696,8 @@ public: while (open) { int size = recv(descriptor, buffer.data(), buffer.size(), 0); if (size <= 0) { - logger.error() < Date: Sun, 28 Sep 2025 22:27:50 +0300 Subject: [PATCH 3/9] fix lua::tovalue --- src/logic/scripting/lua/lua_util.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/logic/scripting/lua/lua_util.cpp b/src/logic/scripting/lua/lua_util.cpp index 77937aef..401255c7 100644 --- a/src/logic/scripting/lua/lua_util.cpp +++ b/src/logic/scripting/lua/lua_util.cpp @@ -133,7 +133,6 @@ dv::value lua::tovalue(State* L, int idx) { auto bytes = std::make_shared( reinterpret_cast(data.data()), data.size() ); - pop(L); return bytes; } } From e9222976efa67e2fe541962aabb6485363a12354 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 29 Sep 2025 12:18:24 +0300 Subject: [PATCH 4/9] fix zero frames texture animation fatal error --- src/graphics/core/TextureAnimation.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/graphics/core/TextureAnimation.cpp b/src/graphics/core/TextureAnimation.cpp index 73af95a2..fdc36c1a 100644 --- a/src/graphics/core/TextureAnimation.cpp +++ b/src/graphics/core/TextureAnimation.cpp @@ -25,6 +25,9 @@ void TextureAnimator::update(float delta) { std::unordered_set changedTextures; for (auto& elem : animations) { + if (elem.frames.empty()) { + continue; + } elem.timer += delta; size_t frameNum = elem.currentFrame; Frame frame = elem.frames[elem.currentFrame]; From 75ef603df0b1958e0c9eb95c2474dc7f3ec34057 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 29 Sep 2025 22:21:14 +0300 Subject: [PATCH 5/9] fix non-local players interpolation and head direction --- res/scripts/components/player.lua | 10 ++++---- src/graphics/render/HandsRenderer.cpp | 3 +-- src/objects/Entities.cpp | 2 +- src/objects/rigging.cpp | 35 +++++++++++++++------------ src/objects/rigging.hpp | 4 +-- 5 files changed, 29 insertions(+), 25 deletions(-) diff --git a/res/scripts/components/player.lua b/res/scripts/components/player.lua index f3f37584..2fc25b7e 100644 --- a/res/scripts/components/player.lua +++ b/res/scripts/components/player.lua @@ -67,12 +67,12 @@ function on_physics_update(delta) mob.set_flight(player.is_flight(pid)) body:set_body_type(player.is_noclip(pid) and "kinematic" or "dynamic") - if hud and pid == hud.get_player() then - local pos = tsf:get_pos() - local rot = get_player_rotation(pid) - local front = mat4.mul(rot, {0, 0, -1}) + local rot = get_player_rotation(pid) + local front = mat4.mul(rot, {0, 0, -1}) + local pos = tsf:get_pos() + if hud and pid == hud.get_player() then process_player_inputs(pid, rot, delta) - mob.look_at(vec3.add(pos, front)) end + mob.look_at(vec3.add(pos, front)) end diff --git a/src/graphics/render/HandsRenderer.cpp b/src/graphics/render/HandsRenderer.cpp index db598a43..c1891ccf 100644 --- a/src/graphics/render/HandsRenderer.cpp +++ b/src/graphics/render/HandsRenderer.cpp @@ -27,8 +27,7 @@ void HandsRenderer::renderHands( auto& skeleton = *this->skeleton; const auto& config = *skeleton.config; - // render modelBatch.setLightsOffset(camera.position); config.update(skeleton, glm::mat4(1.0f), glm::vec3()); - config.render(assets, modelBatch, skeleton, glm::mat4(1.0f), glm::vec3()); + config.render(assets, modelBatch, skeleton, glm::mat3(1.0f), glm::vec3()); } diff --git a/src/objects/Entities.cpp b/src/objects/Entities.cpp index a95f2ad1..8cd0f5f7 100644 --- a/src/objects/Entities.cpp +++ b/src/objects/Entities.cpp @@ -412,7 +412,7 @@ void Entities::render( const auto& size = transform.size; if (!frustum || frustum->isBoxVisible(pos - size, pos + size)) { const auto* rigConfig = skeleton.config; - rigConfig->render(assets, batch, skeleton, transform.combined, pos); + rigConfig->render(assets, batch, skeleton, transform.rot, pos); } } } diff --git a/src/objects/rigging.cpp b/src/objects/rigging.cpp index 1da11f8c..3f50e905 100644 --- a/src/objects/rigging.cpp +++ b/src/objects/rigging.cpp @@ -1,14 +1,14 @@ #include "rigging.hpp" +#include +#include + #include "assets/Assets.hpp" #include "coders/json.hpp" #include "data/dv_util.hpp" #include "graphics/commons/Model.hpp" #include "graphics/render/ModelBatch.hpp" -#include -#include - using namespace rigging; void ModelReference::refresh(const Assets& assets) { @@ -122,21 +122,26 @@ size_t SkeletonConfig::update( return count; } +static glm::mat4 build_matrix(const glm::mat3& rot, const glm::vec3& pos) { + glm::mat4 combined(1.0f); + combined = glm::translate(combined, pos); + combined = combined * glm::mat4(rot); + return combined; +} + void SkeletonConfig::update( - Skeleton& skeleton, const glm::mat4& matrix, const glm::vec3& position + Skeleton& skeleton, const glm::mat3& rotation, const glm::vec3& position ) const { if (skeleton.interpolation.isEnabled()) { const auto& interpolation = skeleton.interpolation; - glm::vec3 scale, translation, skew; - glm::quat rotation; - glm::vec4 perspective; - glm::decompose(matrix, scale, rotation, translation, skew, perspective); - - auto delta = interpolation.getCurrent() - position; - auto interpolatedMatrix = glm::translate(matrix, delta); - update(0, skeleton, root.get(), interpolatedMatrix); + update( + 0, + skeleton, + root.get(), + build_matrix(rotation, interpolation.getCurrent()) + ); } else { - update(0, skeleton, root.get(), matrix); + update(0, skeleton, root.get(), rotation); } } @@ -144,10 +149,10 @@ void SkeletonConfig::render( const Assets& assets, ModelBatch& batch, Skeleton& skeleton, - const glm::mat4& matrix, + const glm::mat3& rotation, const glm::vec3& position ) const { - update(skeleton, matrix, position); + update(skeleton, rotation, position); if (!skeleton.visible) { return; diff --git a/src/objects/rigging.hpp b/src/objects/rigging.hpp index 76ee764b..46019065 100644 --- a/src/objects/rigging.hpp +++ b/src/objects/rigging.hpp @@ -120,7 +120,7 @@ namespace rigging { void update( Skeleton& skeleton, - const glm::mat4& matrix, + const glm::mat3& rotation, const glm::vec3& position ) const; @@ -128,7 +128,7 @@ namespace rigging { const Assets& assets, ModelBatch& batch, Skeleton& skeleton, - const glm::mat4& matrix, + const glm::mat3& rotation, const glm::vec3& position ) const; From 47cdc0213723c74be3e41b39702b656a2db0448d Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 30 Sep 2025 00:28:51 +0300 Subject: [PATCH 6/9] fix std::bad_alloc caused by corrupted regions --- src/world/files/RegionsLayer.cpp | 37 ++++++++++++++++++++++---------- src/world/files/WorldRegions.cpp | 6 ++++-- src/world/files/WorldRegions.hpp | 1 + 3 files changed, 31 insertions(+), 13 deletions(-) diff --git a/src/world/files/RegionsLayer.cpp b/src/world/files/RegionsLayer.cpp index f5c5b696..2da2bd01 100644 --- a/src/world/files/RegionsLayer.cpp +++ b/src/world/files/RegionsLayer.cpp @@ -1,9 +1,11 @@ -#include "WorldRegions.hpp" - #include +#include "WorldRegions.hpp" +#include "debug/Logger.hpp" #include "util/data_io.hpp" +static debug::Logger logger("regions-layer"); + #define REGION_FORMAT_MAGIC ".VOXREG" static io::path get_region_filename(int x, int z) { @@ -20,31 +22,39 @@ static void fetch_chunks(WorldRegion* region, int x, int z, regfile* file) { int chunk_z = (i / REGION_SIZE) + z * REGION_SIZE; if (chunks[i] == nullptr) { chunks[i] = RegionsLayer::readChunkData( - chunk_x, chunk_z, sizes[i][0], sizes[i][1], file); + chunk_x, chunk_z, sizes[i][0], sizes[i][1], file + ); } } } -regfile::regfile(io::path filename) : file(std::move(filename)) { +regfile::regfile(io::path filename) : file(filename), filename(filename) { if (file.length() < REGION_HEADER_SIZE) - throw std::runtime_error("incomplete region file header"); + throw std::runtime_error( + "incomplete region file header in " + filename.string() + ); char header[REGION_HEADER_SIZE]; file.read(header, REGION_HEADER_SIZE); // avoid of use strcmp_s if (std::string(header, std::strlen(REGION_FORMAT_MAGIC)) != REGION_FORMAT_MAGIC) { - throw std::runtime_error("invalid region file magic number"); + throw std::runtime_error( + "invalid region file magic number in " + filename.string() + ); } version = header[8]; if (static_cast(version) > REGION_FORMAT_VERSION) { throw illegal_region_format( - "region format " + std::to_string(version) + " is not supported" + "region format " + std::to_string(version) + + " is not supported in " + filename.string() ); } } -std::unique_ptr regfile::read(int index, uint32_t& size, uint32_t& srcSize) { +std::unique_ptr regfile::read( + int index, uint32_t& size, uint32_t& srcSize +) { size_t file_size = file.length(); size_t table_offset = file_size - REGION_CHUNKS_COUNT * 4; @@ -62,12 +72,17 @@ std::unique_ptr regfile::read(int index, uint32_t& size, uint32_t& srcS file.read(reinterpret_cast(&buff32), 4); srcSize = dataio::le2h(buff32); + if (offset + size > file_size) { + logger.error() << "corrupted region " << filename.string() + << " chunk offset detected at " + << (table_offset + index * 4); + return nullptr; + } auto data = std::make_unique(size); file.read(reinterpret_cast(data.get()), size); return data; } - void RegionsLayer::closeRegFile(glm::ivec2 coord) { openRegFiles.erase(coord); regFilesCv.notify_one(); @@ -192,7 +207,7 @@ void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) { char header[REGION_HEADER_SIZE] = REGION_FORMAT_MAGIC; header[8] = REGION_FORMAT_VERSION; - header[9] = static_cast(compression); // FIXME + header[9] = static_cast(compression); // FIXME std::ofstream file(io::resolve(filename), std::ios::out | std::ios::binary); file.write(header, REGION_HEADER_SIZE); @@ -213,7 +228,7 @@ void RegionsLayer::writeRegion(int x, int z, WorldRegion* entry) { auto sizevec = sizes[i]; uint32_t compressedSize = sizevec[0]; uint32_t srcSize = sizevec[1]; - + intbuf = dataio::h2le(compressedSize); file.write(reinterpret_cast(&intbuf), 4); offset += 4; diff --git a/src/world/files/WorldRegions.cpp b/src/world/files/WorldRegions.cpp index 7c1ab08c..62817ee6 100644 --- a/src/world/files/WorldRegions.cpp +++ b/src/world/files/WorldRegions.cpp @@ -238,8 +238,10 @@ std::unique_ptr WorldRegions::getLights(int x, int z) { auto data = compression::decompress( bytes, size, srcSize, layer.compression ); - assert(srcSize == LIGHTMAP_DATA_LEN); - return Lightmap::decode(data.get()); + if (srcSize == LIGHTMAP_DATA_LEN) { + return Lightmap::decode(data.get()); + } + return nullptr; } ChunkInventoriesMap WorldRegions::fetchInventories(int x, int z) { diff --git a/src/world/files/WorldRegions.hpp b/src/world/files/WorldRegions.hpp index a50fc819..8bc10ba2 100644 --- a/src/world/files/WorldRegions.hpp +++ b/src/world/files/WorldRegions.hpp @@ -52,6 +52,7 @@ public: struct regfile { io::rafile file; + io::path filename; int version; bool inUse = false; From c8ba5b5dbb7980a6576444fed9f7ea66ae1ed32a Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 30 Sep 2025 12:15:53 +0300 Subject: [PATCH 7/9] fix 'align' ui property reading --- src/graphics/ui/gui_xml.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp index 49adcc6a..930aef34 100644 --- a/src/graphics/ui/gui_xml.cpp +++ b/src/graphics/ui/gui_xml.cpp @@ -152,8 +152,9 @@ static void read_uinode( if (element.has("pressed-color")) { node.setPressedColor(element.attr("pressed-color").asColor()); } - const auto& alignName = element.attr("align", "").getText(); - node.setAlign(align_from_string(alignName, node.getAlign())); + node.setAlign( + align_from_string(element.attr("align", "").getText(), node.getAlign()) + ); if (element.has("gravity")) { node.setGravity(gravity_from_string(element.attr("gravity").getText())); From edc681028331cd6b43e612e1c5d48c84d67470cd Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 30 Sep 2025 18:22:39 +0300 Subject: [PATCH 8/9] fix label font cache --- src/graphics/core/Font.cpp | 4 +++ src/graphics/core/Font.hpp | 6 ++++ src/graphics/core/FontMetics.hpp | 11 +++++++ src/graphics/ui/elements/Label.cpp | 35 ++++++++++++--------- src/graphics/ui/elements/Label.hpp | 8 +++-- src/graphics/ui/elements/TextBox.cpp | 46 +++++++++++++++++----------- src/graphics/ui/elements/TextBox.hpp | 1 - 7 files changed, 75 insertions(+), 36 deletions(-) create mode 100644 src/graphics/core/FontMetics.hpp diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index 19abb9f0..73718b4f 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -38,6 +38,10 @@ bool Font::isPrintableChar(uint codepoint) const { } } +int FontMetrics::calcWidth(std::wstring_view text, size_t offset, size_t length) const { + return std::min(text.length() - offset, length) * glyphInterval; +} + int Font::calcWidth(std::wstring_view text, size_t length) const { return calcWidth(text, 0, length); } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index eabfbcc6..12371595 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -4,7 +4,9 @@ #include #include #include + #include "typedefs.hpp" +#include "FontMetics.hpp" class Texture; class Batch2D; @@ -90,4 +92,8 @@ public: ) const; const Texture* getPage(int page) const; + + FontMetrics getMetrics() const { + return {lineHeight, yoffset, glyphInterval}; + } }; diff --git a/src/graphics/core/FontMetics.hpp b/src/graphics/core/FontMetics.hpp new file mode 100644 index 00000000..d58a4fd9 --- /dev/null +++ b/src/graphics/core/FontMetics.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +struct FontMetrics { + int lineHeight; + int yoffset; + int glyphInterval = 8; + + int calcWidth(std::wstring_view text, size_t offset=0, size_t length=-1) const; +}; diff --git a/src/graphics/ui/elements/Label.cpp b/src/graphics/ui/elements/Label.cpp index c11f119c..80b28fc2 100644 --- a/src/graphics/ui/elements/Label.cpp +++ b/src/graphics/ui/elements/Label.cpp @@ -11,10 +11,11 @@ using namespace gui; -void LabelCache::prepare(Font* font, size_t wrapWidth) { - if (font != this->font) { +void LabelCache::prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth) { + if (fontId != this->fontId) { resetFlag = true; - this->font = font; + this->fontId = fontId; + this->metrics = metrics; } if (wrapWidth != this->wrapWidth) { resetFlag = true; @@ -41,7 +42,7 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) { lines.clear(); lines.push_back(LineScheme {0, false}); - if (font == nullptr) { + if (fontId == 0) { wrap = false; } @@ -52,7 +53,7 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) { lines.push_back(LineScheme {i+1, false}); len = 0; } else if (i > 0 && i+1 < text.length() && wrap && text[i+1] != L'\n') { - size_t width = font->calcWidth(text, i-len-1, i-(i-len)+2); + size_t width = metrics.calcWidth(text, i-len-1, i-(i-len)+2); if (width >= wrapWidth) { // starting a fake line lines.push_back(LineScheme {i+1, true}); @@ -60,20 +61,20 @@ void LabelCache::update(std::wstring_view text, bool multiline, bool wrap) { } } } - if (font != nullptr) { + if (fontId != 0) { int maxWidth = 0; for (int i = 0; i < lines.size() - 1; i++) { const auto& next = lines[i + 1]; const auto& cur = lines[i]; maxWidth = std::max( - font->calcWidth( + metrics.calcWidth( text.substr(cur.offset, next.offset - cur.offset) ), maxWidth ); } maxWidth = std::max( - font->calcWidth( + metrics.calcWidth( text.substr(lines[lines.size() - 1].offset) ), maxWidth @@ -105,8 +106,8 @@ Label::Label(GUI& gui, const std::wstring& text, std::string fontName) Label::~Label() = default; glm::vec2 Label::calcSize() { - auto font = cache.font; - uint lineHeight = font->getLineHeight(); + auto& metrics = cache.metrics; + uint lineHeight = metrics.lineHeight; if (cache.lines.size() > 1) { lineHeight *= lineInterval; } @@ -114,12 +115,12 @@ glm::vec2 Label::calcSize() { if (multiline) { return glm::vec2( cache.multilineWidth, - lineHeight * cache.lines.size() + font->getYOffset() + lineHeight * cache.lines.size() + metrics.yoffset ); } return glm::vec2 ( - cache.font->calcWidth(view), - lineHeight * cache.lines.size() + font->getYOffset() + cache.metrics.calcWidth(view), + lineHeight * cache.lines.size() + metrics.yoffset ); } @@ -135,7 +136,7 @@ void Label::setText(std::wstring text) { this->text = std::move(text); cache.update(this->text, multiline, textWrap); - if (cache.font && autoresize) { + if (cache.fontId != 0 && autoresize) { setSize(calcSize()); } } @@ -203,7 +204,11 @@ uint Label::getLinesNumber() const { void Label::draw(const DrawContext& pctx, const Assets& assets) { auto batch = pctx.getBatch2D(); auto font = assets.get(fontName); - cache.prepare(font, static_cast(glm::abs(getSize().x))); + cache.prepare( + reinterpret_cast(font), + font->getMetrics(), + static_cast(glm::abs(getSize().x)) + ); if (supplier) { setText(supplier()); diff --git a/src/graphics/ui/elements/Label.hpp b/src/graphics/ui/elements/Label.hpp index 7e682757..df6e4c6a 100644 --- a/src/graphics/ui/elements/Label.hpp +++ b/src/graphics/ui/elements/Label.hpp @@ -3,6 +3,8 @@ #include "UINode.hpp" #include "constants.hpp" +#include "graphics/core/FontMetics.hpp" + class Font; struct FontStylesScheme; @@ -13,14 +15,16 @@ namespace gui { }; struct LabelCache { - Font* font = nullptr; + ptrdiff_t fontId = 0; + FontMetrics metrics; + std::vector lines; /// @brief Reset cache flag bool resetFlag = true; size_t wrapWidth = -1; int multilineWidth = 0; - void prepare(Font* font, size_t wrapWidth); + void prepare(std::ptrdiff_t fontId, FontMetrics metrics, size_t wrapWidth); void update(std::wstring_view text, bool multiline, bool wrap); size_t getTextLineOffset(size_t line) const; diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index 1755b6b9..a05ba5df 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -231,8 +231,6 @@ TextBox::~TextBox() = default; void TextBox::draw(const DrawContext& pctx, const Assets& assets) { Container::draw(pctx, assets); - font = assets.get(label->getFontName()); - if (!isFocused()) { return; } @@ -244,7 +242,8 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { auto subctx = pctx.sub(); subctx.setScissors(glm::vec4(pos.x, pos.y, size.x, size.y)); - const int lineHeight = font->getLineHeight() * label->getLineInterval(); + const int lineHeight = + rawTextCache.metrics.lineHeight * label->getLineInterval(); glm::vec2 lcoord = label->calcPos(); lcoord.y -= 2; auto batch = pctx.getBatch2D(); @@ -256,7 +255,7 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { if (editable && static_cast((time - caretLastMove) * 2) % 2 == 0) { uint line = rawTextCache.getLineByTextIndex(caret); uint lcaret = caret - rawTextCache.getTextLineOffset(line); - int width = font->calcWidth(input, lcaret); + int width = rawTextCache.metrics.calcWidth(input, 0, lcaret); batch->rect( lcoord.x + width, lcoord.y + label->getLineYOffset(line), @@ -272,10 +271,10 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { uint endLine = label->getLineByTextIndex(selectionEnd); batch->setColor(glm::vec4(0.8f, 0.9f, 1.0f, 0.25f)); - int start = font->calcWidth( + int start = rawTextCache.metrics.calcWidth( labelText, selectionStart - label->getTextLineOffset(startLine) ); - int end = font->calcWidth( + int end = rawTextCache.metrics.calcWidth( labelText, selectionEnd - label->getTextLineOffset(endLine) ); int lineY = label->getLineYOffset(startLine); @@ -346,7 +345,14 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { } } -void TextBox::drawBackground(const DrawContext& pctx, const Assets&) { +void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) { + auto font = assets.get(label->getFontName()); + rawTextCache.prepare( + reinterpret_cast(font), + font->getMetrics(), + label->getSize().x + ); + glm::vec2 pos = calcPos(); auto batch = pctx.getBatch2D(); @@ -375,7 +381,11 @@ void TextBox::drawBackground(const DrawContext& pctx, const Assets&) { } void TextBox::refreshLabel() { - rawTextCache.prepare(font, static_cast(getSize().x)); + rawTextCache.prepare( + rawTextCache.fontId, + rawTextCache.metrics, + static_cast(getSize().x) + ); rawTextCache.update(input, multiline, false); label->setColor(textColor * glm::vec4(input.empty() ? 0.5f : 1.0f)); @@ -412,13 +422,13 @@ void TextBox::refreshLabel() { lineNumbersLabel->setColor(glm::vec4(1, 1, 1, 0.25f)); } - if (autoresize && font) { + if (autoresize && rawTextCache.fontId) { auto size = getSize(); int newy = glm::min( static_cast(parent->getSize().y), static_cast( label->getLinesNumber() * label->getLineInterval() * - font->getLineHeight() + rawTextCache.metrics.lineHeight ) + 1 ); if (newy != static_cast(size.y)) { @@ -430,9 +440,9 @@ void TextBox::refreshLabel() { } } - if (multiline && font) { + if (multiline && rawTextCache.fontId) { setScrollable(true); - uint height = label->getLinesNumber() * font->getLineHeight() * + uint height = label->getLinesNumber() * rawTextCache.metrics.lineHeight * label->getLineInterval(); label->setSize(glm::vec2(label->getSize().x, height)); actualLength = height; @@ -644,14 +654,14 @@ size_t TextBox::normalizeIndex(int index) { /// @param y screen Y position /// @return non-normalized character index int TextBox::calcIndexAt(int x, int y) const { - if (font == nullptr) return 0; + if (rawTextCache.fontId == 0) return 0; const auto& labelText = label->getText(); glm::vec2 lcoord = label->calcPos(); uint line = label->getLineByYOffset(y - lcoord.y); line = std::min(line, label->getLinesNumber() - 1); size_t lineLength = getLineLength(line); uint offset = 0; - while (lcoord.x + font->calcWidth(labelText, offset) < x && + while (lcoord.x + rawTextCache.metrics.calcWidth(labelText, offset) < x && offset < lineLength - 1) { offset++; } @@ -1177,19 +1187,19 @@ size_t TextBox::getCaret() const { void TextBox::setCaret(size_t position) { const auto& labelText = label->getText(); caret = std::min(static_cast(position), input.length()); - if (font == nullptr) { + if (rawTextCache.fontId == 0) { return; } int width = label->getSize().x; - rawTextCache.prepare(font, width); + rawTextCache.prepare(rawTextCache.fontId, rawTextCache.metrics, width); rawTextCache.update(input, multiline, label->isTextWrapping()); caretLastMove = gui.getWindow().time(); uint line = rawTextCache.getLineByTextIndex(caret); int offset = label->getLineYOffset(line) + getContentOffset().y; - uint lineHeight = font->getLineHeight() * label->getLineInterval(); + uint lineHeight = rawTextCache.metrics.lineHeight * label->getLineInterval(); if (scrollStep == 0) { scrollStep = lineHeight; } @@ -1201,7 +1211,7 @@ void TextBox::setCaret(size_t position) { } int lcaret = caret - rawTextCache.getTextLineOffset(line); int realoffset = - font->calcWidth(labelText, lcaret) - static_cast(textOffset) + 2; + rawTextCache.metrics.calcWidth(labelText, lcaret) - static_cast(textOffset) + 2; if (realoffset - width > 0) { setTextOffset(textOffset + realoffset - width); diff --git a/src/graphics/ui/elements/TextBox.hpp b/src/graphics/ui/elements/TextBox.hpp index 9bbfac39..c4b88f90 100644 --- a/src/graphics/ui/elements/TextBox.hpp +++ b/src/graphics/ui/elements/TextBox.hpp @@ -52,7 +52,6 @@ namespace gui { int textInitX = 0; /// @brief Last time of the caret was moved (used for blink animation) double caretLastMove = 0.0; - Font* font = nullptr; // Note: selection does not include markup size_t selectionStart = 0; From acb46253ffdd18a884fd5855abd91a537a2b6edb Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 30 Sep 2025 18:43:51 +0300 Subject: [PATCH 9/9] update udp test --- dev/tests/network_udp.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/dev/tests/network_udp.lua b/dev/tests/network_udp.lua index 975321a4..043f5d24 100644 --- a/dev/tests/network_udp.lua +++ b/dev/tests/network_udp.lua @@ -1,5 +1,4 @@ -math.randomseed(43172) -for i = 1, 15 do +for i = 1, 3 do debug.log(string.format("iteration %s", i)) local complete = false @@ -30,6 +29,7 @@ for i = 1, 15 do end, "udp-data-sender") end) - app.sleep_until(function () return complete end, nil, 5) + app.sleep_until(function () return complete end, nil, 1) + assert(complete, "timeout at iteration #"..i) server:close() end