summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTEXT.md8
-rw-r--r--src/hl2h.cpp4
-rw-r--r--src/menu.cpp1
-rw-r--r--src/world.cpp58
4 files changed, 69 insertions, 2 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index b07e407..5eca9f8 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -368,7 +368,9 @@ vocabulary / decisions.
368 the INI). Not `sv_skyname`: that did not take effect at runtime in this 368 the INI). Not `sv_skyname`: that did not take effect at runtime in this
369 build, so the skybox card now works on materials instead. 369 build, so the skybox card now works on materials instead.
370- The PNG is decoded by our own reader (`zlib`'s `uncompress` + PNG filters; 370- The PNG is decoded by our own reader (`zlib`'s `uncompress` + PNG filters;
371 8-bit non-interlaced RGB/RGBA/gray/palette). Do **not** use the system 371 8-bit non-interlaced RGB/RGBA/gray/palette) and scaled to the next power of
372 two, because the material system rejects textures whose dimensions are not
373 multiples of 4 ("Image dimensions must be multiple of 4!"). Do **not** use the system
372 libpng: `client.so`, `engine.so` and `vguimatsurface.so` each export their 374 libpng: `client.so`, `engine.so` and `vguimatsurface.so` each export their
373 own `png_create_read_struct`, so libpng16's internal PLT calls bind to the 375 own `png_create_read_struct`, so libpng16's internal PLT calls bind to the
374 game's older libpng with a different `png_struct` layout and crash in 376 game's older libpng with a different `png_struct` layout and crash in
@@ -394,6 +396,10 @@ vocabulary / decisions.
394 string as a fallback) and restored when the feature is disabled. Records 396 string as a fallback) and restored when the feature is disabled. Records
395 survive level changes so a reused sky material can still be restored; the 397 survive level changes so a reused sky material can still be restored; the
396 override is re-applied to the new map automatically. 398 override is re-applied to the new map automatically.
399- `skybox_update()` runs from the `FRAME_RENDER_START` FrameStageNotify hook,
400 not from the VGUI paint hook: `ITexture::Download` only regenerates texture
401 bits on a render-safe frame stage. Running it during paint skipped the
402 regenerator and left an empty VTF (upload warnings + crash).
397- The card shows the image path and has a Reload image button. A missing or 403- The card shows the image path and has a Reload image button. A missing or
398 unreadable PNG raises an error toast; the image is only re-read on Reload. 404 unreadable PNG raises an error toast; the image is only re-read on Reload.
399- Saved as `[skybox] active/bind`. 405- Saved as `[skybox] active/bind`.
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 *);