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/world.cpp | |
| 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/world.cpp | 58 |
1 files changed, 58 insertions, 0 deletions
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 *); |
