diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 00:29:24 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 00:29:24 +0100 |
| commit | 4632788c4bef265e58630473eed5559bf125a726 (patch) | |
| tree | 9264d8f59c8914e118adfafc4592ee77377eaf9e /src | |
| parent | Skybox image: fix HDR sky binding; clip checkbox/arrow drawing (diff) | |
| download | hl2h-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.cpp | 4 | ||||
| -rw-r--r-- | src/menu.cpp | 1 | ||||
| -rw-r--r-- | src/world.cpp | 58 |
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 *); |
