summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 00:29:24 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 00:29:24 +0100
commit4632788c4bef265e58630473eed5559bf125a726 (patch)
tree9264d8f59c8914e118adfafc4592ee77377eaf9e /src
parentSkybox image: fix HDR sky binding; clip checkbox/arrow drawing (diff)
downloadhl2h-4632788c4bef265e58630473eed5559bf125a726.tar.gz
hl2h-4632788c4bef265e58630473eed5559bf125a726.zip
Skybox image: power-of-two resize; upload at FRAME_RENDER_START
- The material system rejects textures whose dimensions are not multiples of 4 ("Image dimensions must be multiple of 4!"), so scale the decoded image to the next power of two (bilinear). 798x798 -> 1024x1024. The invalid VTF also crashed the renderer after the apply. - Move skybox_update() out of the VGUI paint hook into the FRAME_RENDER_START FrameStageNotify stage. ITexture::Download only regenerates bits when the material system considers the frame render-safe; during paint it returned early, the regenerator never ran (no pixels), and a later upload of the empty VTF crashed. - Log the regenerator entry so the log shows whether the upload path ran.
Diffstat (limited to '')
-rw-r--r--src/hl2h.cpp4
-rw-r--r--src/menu.cpp1
-rw-r--r--src/world.cpp58
3 files changed, 62 insertions, 1 deletions
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index 4ba1af3..28b2995 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -770,6 +770,10 @@ static void hkdFrameStageNotify(void *self, int stage) {
770 if (oFrameStageNotify) 770 if (oFrameStageNotify)
771 oFrameStageNotify(self, stage); 771 oFrameStageNotify(self, stage);
772 if (stage == 5) { 772 if (stage == 5) {
773 // Skybox texture uploads happen here, not in the VGUI paint hook: the
774 // material system only downloads procedural textures on a render-safe
775 // frame stage.
776 skybox_update();
773 if (g_silent_restore_pending) { 777 if (g_silent_restore_pending) {
774 g_silent_restore_pending = false; 778 g_silent_restore_pending = false;
775 if (g_iface.engine) { 779 if (g_iface.engine) {
diff --git a/src/menu.cpp b/src/menu.cpp
index 92131d4..7ffc84a 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -816,7 +816,6 @@ void outer_draw() {
816 fullbright_update(); 816 fullbright_update();
817 world_tint_update(); 817 world_tint_update();
818 fog_update(); 818 fog_update();
819 skybox_update();
820 gui_handle_input(); 819 gui_handle_input();
821 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open 820 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open
822 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; 821 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr;
diff --git a/src/world.cpp b/src/world.cpp
index aaee058..1228c7a 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -557,6 +557,58 @@ bool load_png_rgba(const char *path, std::vector<unsigned char> &pixels,
557 } 557 }
558 } 558 }
559 559
560 // The material system rejects textures whose dimensions are not multiples of
561 // 4 ("Image dimensions must be multiple of 4!" / "LoadTextureFromVTF: VTF
562 // dimensions do not match texture"). Scale to the next power of two; that is
563 // also what the old skybox code expects.
564 {
565 int tw = 1, th = 1;
566 while (tw < (int)w)
567 tw <<= 1;
568 while (th < (int)h)
569 th <<= 1;
570 if (tw > 4096) tw = 4096;
571 if (th > 4096) th = 4096;
572 if (tw != (int)w || th != (int)h) {
573 std::vector<unsigned char> scaled((size_t)tw * (size_t)th * 4);
574 for (int y = 0; y < th; y++) {
575 float sy = ((float)y + 0.5f) * (float)h / (float)th - 0.5f;
576 int y0 = (int)sy;
577 float fy = sy - (float)y0;
578 if (y0 < 0) { y0 = 0; fy = 0.0f; }
579 int y1 = y0 + 1 < (int)h ? y0 + 1 : y0;
580 for (int x = 0; x < tw; x++) {
581 float sx = ((float)x + 0.5f) * (float)w / (float)tw - 0.5f;
582 int x0 = (int)sx;
583 float fx = sx - (float)x0;
584 if (x0 < 0) { x0 = 0; fx = 0.0f; }
585 int x1 = x0 + 1 < (int)w ? x0 + 1 : x0;
586 const unsigned char *p00 = pixels.data() +
587 ((size_t)y0 * (size_t)w + (size_t)x0) * 4;
588 const unsigned char *p10 = pixels.data() +
589 ((size_t)y0 * (size_t)w + (size_t)x1) * 4;
590 const unsigned char *p01 = pixels.data() +
591 ((size_t)y1 * (size_t)w + (size_t)x0) * 4;
592 const unsigned char *p11 = pixels.data() +
593 ((size_t)y1 * (size_t)w + (size_t)x1) * 4;
594 unsigned char *o = scaled.data() +
595 ((size_t)y * (size_t)tw + (size_t)x) * 4;
596 for (int c = 0; c < 4; c++) {
597 float v = (1.0f - fy) *
598 ((1.0f - fx) * p00[c] + fx * p10[c]) +
599 fy * ((1.0f - fx) * p01[c] + fx * p11[c]);
600 o[c] = (unsigned char)(v + 0.5f);
601 }
602 }
603 }
604 logf("skybox: resized %dx%d -> %dx%d for the material system",
605 (int)w, (int)h, tw, th);
606 pixels.swap(scaled);
607 w = (uint32_t)tw;
608 h = (uint32_t)th;
609 }
610 }
611
560 out_w = (int)w; 612 out_w = (int)w;
561 out_h = (int)h; 613 out_h = (int)h;
562 return true; 614 return true;
@@ -574,6 +626,12 @@ public:
574 virtual void RegenerateTextureBits(void *texture, void *vtf, void *rect) { 626 virtual void RegenerateTextureBits(void *texture, void *vtf, void *rect) {
575 (void)texture; 627 (void)texture;
576 (void)rect; 628 (void)rect;
629 static bool entered = false;
630 if (!entered) {
631 entered = true;
632 logf("skybox: regenerator entered (vtf=%p, %zu pixels)", vtf,
633 g_sky_pixels.size());
634 }
577 if (!vtf || g_sky_pixels.empty()) 635 if (!vtf || g_sky_pixels.empty())
578 return; 636 return;
579 using IntFn = int (*)(void *); 637 using IntFn = int (*)(void *);