From 771c72324cfffcb29b8727348e8f0db62f09eaee Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 27 Sep 2026 23:13:45 +0300 Subject: [PATCH 1/8] update advanced shading --- res/shaders/effects/deferred_lighting.glsl | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/res/shaders/effects/deferred_lighting.glsl b/res/shaders/effects/deferred_lighting.glsl index 55e267bf3..8df2dd0d7 100644 --- a/res/shaders/effects/deferred_lighting.glsl +++ b/res/shaders/effects/deferred_lighting.glsl @@ -26,8 +26,12 @@ vec4 effect() { float emission = texture(u_emission, v_uv).r; + float rg = 1.0; #ifdef ENABLE_SHADOWS - light *= calc_shadow(modelpos, normal, length(pos)); + float shadow_mul = calc_shadow(modelpos, normal, length(pos)); + light *= shadow_mul; + rg *= min(1.0, shadow_mul + emission); + light *= 2.0; #endif light = max(light, emission); @@ -40,5 +44,5 @@ vec4 effect() { mix(1.0, CLOUDS_FOG_FACTOR_MUL, emission), mix(1.0, CLOUDS_FOG_CURVE_MUL, emission) ); - return vec4(mix(texture(u_screen, v_uv).rgb * mix(1.0, light, 1.0), fogColor, fog), 1.0); + return vec4(mix(texture(u_screen, v_uv).rgb * mix(1.0, light, 1.0) * vec3(rg, 0.5 + rg * 0.5, 1.0), fogColor, fog), 1.0); } From 2b8d97a2cacd6e37999d5230f5cb5aed4b446f3c Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 27 Sep 2026 23:21:45 +0300 Subject: [PATCH 2/8] feat: color temperature compensation --- res/shaders/effects/deferred_lighting.glsl | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/res/shaders/effects/deferred_lighting.glsl b/res/shaders/effects/deferred_lighting.glsl index 8df2dd0d7..274ceae56 100644 --- a/res/shaders/effects/deferred_lighting.glsl +++ b/res/shaders/effects/deferred_lighting.glsl @@ -3,6 +3,7 @@ #define CLOUDS_FOG_FACTOR_MUL 0.3f #define CLOUDS_FOG_CURVE_MUL 0.4f +#define COLOR_TEMPERATURE_COMPENSATION 1.12f vec4 effect() { vec4 pos = texture(u_position, v_uv); @@ -30,7 +31,7 @@ vec4 effect() { #ifdef ENABLE_SHADOWS float shadow_mul = calc_shadow(modelpos, normal, length(pos)); light *= shadow_mul; - rg *= min(1.0, shadow_mul + emission); + rg *= min(1.0, shadow_mul + emission) + COLOR_TEMPERATURE_COMPENSATION; light *= 2.0; #endif From 8726a95a9bbf15ef211420b5b0934c2ca4ff867e Mon Sep 17 00:00:00 2001 From: MihailRis Date: Sun, 27 Sep 2026 23:23:21 +0300 Subject: [PATCH 3/8] fix --- res/shaders/effects/deferred_lighting.glsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/shaders/effects/deferred_lighting.glsl b/res/shaders/effects/deferred_lighting.glsl index 274ceae56..ebcf138aa 100644 --- a/res/shaders/effects/deferred_lighting.glsl +++ b/res/shaders/effects/deferred_lighting.glsl @@ -31,7 +31,7 @@ vec4 effect() { #ifdef ENABLE_SHADOWS float shadow_mul = calc_shadow(modelpos, normal, length(pos)); light *= shadow_mul; - rg *= min(1.0, shadow_mul + emission) + COLOR_TEMPERATURE_COMPENSATION; + rg *= min(1.0, shadow_mul + emission) * COLOR_TEMPERATURE_COMPENSATION; light *= 2.0; #endif From ffba11e87fd1268208def134fa32412b075b8154 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 28 Sep 2026 01:40:48 +0300 Subject: [PATCH 4/8] update clouds shader --- res/shaders/clouds.glslv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/shaders/clouds.glslv b/res/shaders/clouds.glslv index 0b9c17774..e1576f633 100644 --- a/res/shaders/clouds.glslv +++ b/res/shaders/clouds.glslv @@ -22,7 +22,7 @@ void main() { vec3 pos3d = a_modelpos.xyz - u_cameraPos; - a_realnormal = v_normal.xyz * 2.0 - 1.0; + a_realnormal = vec3(0.0, 1.0, 0.0); a_normal = calc_screen_normal(a_realnormal); a_torchLight = vec4(calc_torch_light( From 19a952a3bec85a26365a544c031acac1e8b265bf Mon Sep 17 00:00:00 2001 From: MihailRis Date: Mon, 28 Sep 2026 01:47:23 +0300 Subject: [PATCH 5/8] update shadows.glsl --- res/shaders/lib/shadows.glsl | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/res/shaders/lib/shadows.glsl b/res/shaders/lib/shadows.glsl index 658e9a699..a686683f2 100644 --- a/res/shaders/lib/shadows.glsl +++ b/res/shaders/lib/shadows.glsl @@ -25,18 +25,14 @@ float calc_shadow( projCoords.z -= 0.00001 / u_shadowsRes + bias; float shadow = 0.0; - if (dot(realnormal, u_sunDir) < 0.0) { - // 3x3 kernel - for (int y = -1; y <= 1; y++) { - for (int x = -1; x <= 1; x++) { - vec3 offset = vec3(x, y, -(abs(x) + abs(y)) * 0.8) * step * 1.0 * u_shadowsSoftness; - shadow += texture(shadowsMap, projCoords + offset); - } + // 3x3 kernel + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + vec3 offset = vec3(x, y, -(abs(x) + abs(y)) * 0.8) * step * 1.0 * u_shadowsSoftness; + shadow += texture(shadowsMap, projCoords + offset); } - shadow /= 9.0; - } else { - shadow = 0.0; } + shadow /= 9.0; return shadow; } From 3378001b9bff52120725234afe2e625798871625 Mon Sep 17 00:00:00 2001 From: nogitsune-youkai Date: Mon, 28 Sep 2026 22:02:08 +0300 Subject: [PATCH 6/8] Fix: Add asserts to prevent undefined behavior on empty containers --- src/util/stack_vector.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/util/stack_vector.hpp b/src/util/stack_vector.hpp index 87749396b..3c506f160 100644 --- a/src/util/stack_vector.hpp +++ b/src/util/stack_vector.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -74,6 +75,7 @@ namespace util { } void pop_back() noexcept { + assert(!empty() && "pop_back() called on empty stack_vector"); if (size_ > 0) { data_.ptr()[size_ - 1].~T(); --size_; @@ -110,18 +112,22 @@ namespace util { } T& front() { + assert(!empty() && "front() called on empty stack_vector"); return data_.ptr()[0]; } T& back() { + assert(!empty() && "back() called on empty stack_vector"); return data_.ptr()[size_ - 1]; } const T& front() const { + assert(!empty() && "front() called on empty stack_vector"); return data_.ptr()[0]; } const T& back() const { + assert(!empty() && "back() called on empty stack_vector"); return data_.ptr()[size_ - 1]; } From ca68ddc03aad65bb365e6263bf68485b1d85e245 Mon Sep 17 00:00:00 2001 From: nogitsune-youkai Date: Tue, 29 Sep 2026 01:20:54 +0300 Subject: [PATCH 7/8] Improve Windows presets --- CMakePresets.json | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 508719628..86a6fd075 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -2,19 +2,36 @@ "version": 6, "configurePresets": [ { - "name": "default-vs-msvc-windows", + "name": "windows-msvc-base", + "hidden": true, "condition": { "type": "equals", "rhs": "${hostSystemName}", "lhs": "Windows" }, - "generator": "Visual Studio 17 2022", "binaryDir": "${sourceDir}/build", "cacheVariables": { "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake", "VOXELENGINE_BUILD_TESTS": "ON" } }, + { + "name": "default-vs-msvc-windows", + "displayName": "Visual Studio (auto: latest installed)", + "inherits": "windows-msvc-base" + }, + { + "name": "vs2022", + "displayName": "Visual Studio 2022", + "inherits": "windows-msvc-base", + "generator": "Visual Studio 17 2022" + }, + { + "name": "vs2026", + "displayName": "Visual Studio 2026", + "inherits": "windows-msvc-base", + "generator": "Visual Studio 18 2026" + }, { "name": "default-ninja-mingw-windows", "condition": { From 7211e99bc87b3ed69c690fca0a3cd64fc49b8fd1 Mon Sep 17 00:00:00 2001 From: boolean-false Date: Tue, 29 Sep 2026 20:31:14 +0700 Subject: [PATCH 8/8] fix text width and caret positioning in text boxes --- src/graphics/core/Font.cpp | 46 ++++++++++++++++++---------- src/graphics/core/Font.hpp | 10 ++++-- src/graphics/ui/elements/TextBox.cpp | 38 ++++++++++++++++------- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/src/graphics/core/Font.cpp b/src/graphics/core/Font.cpp index e94881adc..fde3e0c17 100644 --- a/src/graphics/core/Font.cpp +++ b/src/graphics/core/Font.cpp @@ -29,6 +29,10 @@ Font::Font( if (this->fontFile.has_value()) { if (auto fontPtr = this->fontFile->lock()) { monospace = fontPtr->isMonospace(); + if (monospace && this->glyphs.size() > '0' && + this->glyphs['0'].xAdvance > 0) { + glyphInterval = this->glyphs['0'].xAdvance; + } } } } @@ -62,21 +66,13 @@ bool Font::isPrintableChar(uint codepoint) const { int FontMetrics::calcWidth(std::wstring_view text, size_t offset, size_t length) const { auto font = this->font.has_value() ? this->font->lock() : nullptr; - if (font == nullptr || font->isMonospace()) { - return std::min(text.length() - offset, length) * _glyphInterval; + if (font != nullptr) { + return font->calcWidth(text, offset, length); } - int totalWidth = 0; - for (int i = offset; i < offset + length && i < text.length(); i++) { - auto codepoint = text[i]; - if (!font->isPrintableChar(codepoint)) { - totalWidth += _glyphInterval; - } else if (auto glyph = font->getGlyph(codepoint)) { - totalWidth += glyph->xAdvance; - } else { - totalWidth += _glyphInterval; - } + if (offset >= text.length()) { + return 0; } - return totalWidth; + return std::min(text.length() - offset, length) * _glyphInterval; } int Font::calcWidth(std::wstring_view text, size_t length) const { @@ -84,7 +80,24 @@ int Font::calcWidth(std::wstring_view text, size_t length) const { } int Font::calcWidth(std::wstring_view text, size_t offset, size_t length) const { - return std::min(text.length()-offset, length) * glyphInterval; + if (offset >= text.length()) { + return 0; + } + size_t end = offset + std::min(text.length() - offset, length); + int width = 0; + for (size_t i = offset; i < end; i++) { + width += getAdvance(text[i]); + } + return width; +} + +int Font::getAdvance(uint codepoint) const { + if (isPrintableChar(codepoint)) { + if (auto glyph = getGlyph(codepoint)) { + return glyph->xAdvance; + } + } + return glyphInterval; } static inline void draw_glyph( @@ -194,11 +207,10 @@ static inline void draw_text( } int yOffset = 0; int xOffset = 0; - float advance = 1.0f; + float advance = font.getAdvance(c) / cellAdvance; if (auto glyph = font.getGlyph(c)) { yOffset = glyph->yOffset; xOffset = glyph->xOffset; - advance = glyph->xAdvance / cellAdvance; } uint charpage = c >> 8; if (charpage == page){ @@ -325,7 +337,7 @@ std::unique_ptr Font::createBitmapFont( return std::make_unique(std::move(textures), std::move(glyphs), res, 4); } -const Glyph* Font::getGlyph(int codepoint) { +const Glyph* Font::getGlyph(int codepoint) const { if (codepoint < 0) { return nullptr; } diff --git a/src/graphics/core/Font.hpp b/src/graphics/core/Font.hpp index 19e77ef83..b20b5e530 100644 --- a/src/graphics/core/Font.hpp +++ b/src/graphics/core/Font.hpp @@ -57,6 +57,10 @@ public: /// @return pixel width of the substring int calcWidth(std::wstring_view text, size_t offset, size_t length) const; + /// @brief Get the horizontal advance of a character in pixels + /// @param codepoint character unicode codepoint + int getAdvance(uint codepoint) const; + /// @brief Check if character is visible (non-whitespace) /// @param codepoint character unicode codepoint bool isPrintableChar(uint codepoint) const; @@ -87,7 +91,7 @@ public: return {std::nullopt, lineHeight, yoffset, glyphInterval}; } - const Glyph* getGlyph(int codepoint); + const Glyph* getGlyph(int codepoint) const; static std::unique_ptr createBitmapFont( std::vector> pages @@ -97,7 +101,7 @@ private: int yoffset; int glyphInterval; bool monospace = true; - std::vector> pages; - std::vector glyphs; + mutable std::vector> pages; + mutable std::vector glyphs; std::optional> fontFile; }; diff --git a/src/graphics/ui/elements/TextBox.cpp b/src/graphics/ui/elements/TextBox.cpp index d60b09142..2f6a20301 100644 --- a/src/graphics/ui/elements/TextBox.cpp +++ b/src/graphics/ui/elements/TextBox.cpp @@ -255,9 +255,9 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { // drawing caret here if (isFocused() && editable && static_cast((time - caretLastMove) * 2) % 2 == 0) { uint line = label->getLineByTextIndex(caret); - auto linestart = label->getTextLineOffset(line); - uint lcaret = caret - label->getTextLineOffset(line); - int width = rawTextCache.metrics.calcWidth(input.substr(linestart), 0, lcaret); + size_t lineStart = label->getTextLineOffset(line); + size_t lineCaret = caret - lineStart; + int width = rawTextCache.metrics.calcWidth(input, lineStart, lineCaret); batch->rect( lcoord.x + width, @@ -275,11 +275,13 @@ 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)); + size_t startLineOffset = label->getTextLineOffset(startLine); + size_t endLineOffset = label->getTextLineOffset(endLine); int start = rawTextCache.metrics.calcWidth( - labelText, 0, selectionStart - label->getTextLineOffset(startLine) + labelText, startLineOffset, selectionStart - startLineOffset ); int end = rawTextCache.metrics.calcWidth( - labelText, 0, selectionEnd - label->getTextLineOffset(endLine) + labelText, endLineOffset, selectionEnd - endLineOffset ); int lineY = label->getLineYOffset(startLine); @@ -352,6 +354,11 @@ void TextBox::draw(const DrawContext& pctx, const Assets& assets) { } void TextBox::drawBackground(const DrawContext& pctx, const Assets& assets) { + if (lineNumbersLabel->getFontName() != label->getFontName()) { + lineNumbersLabel->setFontName(label->getFontName()); + } + lineNumbersLabel->setLineInterval(label->getLineInterval()); + auto font = assets.getShared(label->getFontName()); if (font != nullptr) { rawTextCache.prepare(font, font->getMetrics(), label->getSize().x); @@ -681,13 +688,19 @@ int TextBox::calcIndexAt(int x, int y) const { uint line = label->getLineByYOffset(y - lcoord.y); line = std::min(line, label->getLinesNumber() - 1); size_t lineLength = getLineLength(line); + size_t lineStart = label->getTextLineOffset(line); uint offset = 0; - while (lcoord.x + rawTextCache.metrics.calcWidth(labelText, 0, offset) < x && - offset < lineLength - 1) { + while (offset < lineLength - 1) { + int width = rawTextCache.metrics.calcWidth( + labelText, lineStart, offset + ); + if (lcoord.x + width >= x) { + break; + } offset++; } return std::min( - offset + label->getTextLineOffset(line), labelText.length() + offset + lineStart, labelText.length() ); } @@ -1224,9 +1237,12 @@ void TextBox::setCaret(size_t position) { offset -= getSize().y; scrolled(-glm::ceil(offset / static_cast(scrollStep) + 0.5f)); } - int lcaret = caret - rawTextCache.getTextLineOffset(line); - int realoffset = rawTextCache.metrics.calcWidth(labelText, 0, lcaret) - - static_cast(textOffset); + size_t lineStart = rawTextCache.getTextLineOffset(line); + size_t lineCaret = caret - lineStart; + int caretWidth = rawTextCache.metrics.calcWidth( + labelText, lineStart, lineCaret + ); + int realoffset = caretWidth - static_cast(textOffset); if (realoffset - width > 0) { setTextOffset(textOffset + realoffset - width);