summaryrefslogtreecommitdiffstats
path: root/src/gui.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-03 23:58:59 +0100
committersalmonik <salmonik@tuta.io>2026-11-03 23:58:59 +0100
commit9c4455af43da34127864b09ad2a3d3e996c9dce1 (patch)
treeeb3754763db7c00fe664b900f9a560057bcb9955 /src/gui.cpp
parentWorld: add skybox changer (diff)
downloadhl2h-9c4455af43da34127864b09ad2a3d3e996c9dce1.tar.gz
hl2h-9c4455af43da34127864b09ad2a3d3e996c9dce1.zip
World: replace skybox changer with a PNG skybox image
sv_skyname did not take effect at runtime in this build, so the Skybox card now replaces the skybox materials' textures with <config dir>/skybox.png. The PNG is decoded through libpng16's simplified API (dlopen'ed, so no new link dependency) and uploaded with IMaterialSystem::CreateTextureFromBits as an RGBA8888 texture. IMaterialVar::SetTextureValue assigns it to $basetexture and the HDR variants for every material in the SkyBox textures group (all six faces get the same image). Original textures are recorded per material/var (texture pointer plus string fallback) and restored when the feature is off. Records survive level changes so a reused sky material is still restorable; the override is re-applied to a new map automatically. The card shows the image path and has a Reload image button; a missing/unreadable PNG raises an error toast.
Diffstat (limited to '')
-rw-r--r--src/gui.cpp77
1 files changed, 16 insertions, 61 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index 5fb8fa7..eb53dff 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -183,11 +183,10 @@ enum CtrlKind {
183 CK_SECTION, 183 CK_SECTION,
184 CK_INFO, 184 CK_INFO,
185 CK_BUTTON, 185 CK_BUTTON,
186 CK_COLOR, 186 CK_COLOR
187 CK_CHOICE
188}; 187};
189 188
190enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET }; 189enum CtrlAction { ACT_NONE = 0, ACT_RELOAD, ACT_RESET, ACT_SKY_RELOAD };
191 190
192struct Ctrl { 191struct Ctrl {
193 int kind; 192 int kind;
@@ -196,8 +195,6 @@ struct Ctrl {
196 bool *bval; // CK_TOGGLE 195 bool *bval; // CK_TOGGLE
197 int *ival; // CK_SLIDER 196 int *ival; // CK_SLIDER
198 int *rgb; // CK_COLOR: three ints, 0..255 197 int *rgb; // CK_COLOR: three ints, 0..255
199 const char *const *opts; // CK_CHOICE: option labels
200 int nopts;
201 int min, max; 198 int min, max;
202 int action; // CK_BUTTON 199 int action; // CK_BUTTON
203 bool zero_unlimited; // slider: value 0 displays as "All" 200 bool zero_unlimited; // slider: value 0 displays as "All"
@@ -256,8 +253,6 @@ static void add_ctrl(int card, int kind, const char *label, const char *desc,
256 c.action = action; 253 c.action = action;
257 c.zero_unlimited = false; 254 c.zero_unlimited = false;
258 c.rgb = nullptr; 255 c.rgb = nullptr;
259 c.opts = nullptr;
260 c.nopts = 0;
261 c.hue = 0.0f; 256 c.hue = 0.0f;
262 c.sat = 0.0f; 257 c.sat = 0.0f;
263 c.val = 1.0f; 258 c.val = 1.0f;
@@ -287,19 +282,11 @@ static void add_color(int card, const char *label, const char *desc,
287 add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); 282 add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE);
288 g_ctrls[i].rgb = rgb; 283 g_ctrls[i].rgb = rgb;
289} 284}
290static void add_choice(int card, const char *label, const char *desc,
291 const char *const *opts, int nopts, int *value) {
292 int i = g_nctrl;
293 add_ctrl(card, CK_CHOICE, label, desc, 0, nopts > 0 ? nopts - 1 : 0,
294 nullptr, value, ACT_NONE);
295 g_ctrls[i].opts = opts;
296 g_ctrls[i].nopts = nopts;
297}
298 285
299static int ctrl_val(const Ctrl &c) { 286static int ctrl_val(const Ctrl &c) {
300 if (c.kind == CK_TOGGLE && c.bval) 287 if (c.kind == CK_TOGGLE && c.bval)
301 return *c.bval ? 1 : 0; 288 return *c.bval ? 1 : 0;
302 if ((c.kind == CK_SLIDER || c.kind == CK_CHOICE) && c.ival) 289 if (c.kind == CK_SLIDER && c.ival)
303 return *c.ival; 290 return *c.ival;
304 return 0; 291 return 0;
305} 292}
@@ -307,7 +294,7 @@ static void ctrl_set(Ctrl &c, int v) {
307 if (c.kind == CK_TOGGLE && c.bval) { 294 if (c.kind == CK_TOGGLE && c.bval) {
308 *c.bval = v != 0; 295 *c.bval = v != 0;
309 config_save(); 296 config_save();
310 } else if ((c.kind == CK_SLIDER || c.kind == CK_CHOICE) && c.ival) { 297 } else if (c.kind == CK_SLIDER && c.ival) {
311 if (v < c.min) v = c.min; 298 if (v < c.min) v = c.min;
312 if (v > c.max) v = c.max; 299 if (v > c.max) v = c.max;
313 if (*c.ival != v) { 300 if (*c.ival != v) {
@@ -433,12 +420,17 @@ static void build_cards() {
433 add_toggle(fog, "Remove fog", 420 add_toggle(fog, "Remove fog",
434 "Disable fog entirely instead of recolouring it.", &g_fog_disable); 421 "Disable fog entirely instead of recolouring it.", &g_fog_disable);
435 422
423 static char sky_label[512];
424 snprintf(sky_label, sizeof(sky_label), "Image: %s",
425 config_file_cstr("skybox.png"));
436 int sky = add_card(2, &g_skybox, "Skybox", 426 int sky = add_card(2, &g_skybox, "Skybox",
437 "Swap the skybox at runtime through sv_skyname. The " 427 "Replace the map skybox with a PNG image from the "
438 "map's own sky comes back on level change.", 428 "config directory (all six faces).",
439 true); 429 true);
440 add_choice(sky, "Sky", "Pick a skybox from the HL2 set.", skybox_options(), 430 add_info(sky, sky_label);
441 skybox_option_count(), &g_skybox_choice); 431 add_info(sky, "Edit skybox.png, then Reload image. Off restores the map sky.");
432 add_button(sky, "Reload image", "Re-read the PNG and apply it again.",
433 ACT_SKY_RELOAD);
442 434
443 int spread = add_card(3, &g_spread, "Spread control", 435 int spread = add_card(3, &g_spread, "Spread control",
444 "Choose a server shot seed that tightens the cone.", 436 "Choose a server shot seed that tightens the cone.",
@@ -855,8 +847,6 @@ static int header_h(const Card &c) {
855static int label_max_w(const Ctrl &c) { 847static int label_max_w(const Ctrl &c) {
856 if (c.kind == CK_SLIDER) 848 if (c.kind == CK_SLIDER)
857 return S(214.0f); 849 return S(214.0f);
858 if (c.kind == CK_CHOICE)
859 return card_content_w() - S(16.0f) - S(250.0f);
860 return card_content_w() - S(16.0f) - S(110.0f); 850 return card_content_w() - S(16.0f) - S(110.0f);
861} 851}
862 852
@@ -1431,25 +1421,6 @@ static void handle_mouse_click() {
1431 } 1421 }
1432 return; 1422 return;
1433 } 1423 }
1434 if (ct.kind == CK_CHOICE) {
1435 int base = label_row_h(ct);
1436 Rect box{cr.x + cr.w - S(238.0f),
1437 by + (base - S(24.0f)) / 2, S(222.0f), S(24.0f)};
1438 if (box.has(mx, my)) {
1439 int v = ctrl_val(ct);
1440 if (mx < box.x + S(36.0f))
1441 v--;
1442 else if (mx >= box.x + box.w - S(36.0f))
1443 v++;
1444 if (v < 0) v = 0;
1445 if (ct.nopts > 0 && v >= ct.nopts) v = ct.nopts - 1;
1446 if (v != ctrl_val(ct)) {
1447 *ct.ival = v;
1448 config_save();
1449 }
1450 }
1451 return;
1452 }
1453 if (ct.kind == CK_BUTTON) { 1424 if (ct.kind == CK_BUTTON) {
1454 int bw = button_w(ct.label); 1425 int bw = button_w(ct.label);
1455 Rect b{cr.x + cr.w - S(16.0f) - bw, 1426 Rect b{cr.x + cr.w - S(16.0f) - bw,
@@ -1469,6 +1440,9 @@ static void handle_mouse_click() {
1469 g_reset_armed = true; 1440 g_reset_armed = true;
1470 g_reset_armed_at = now; 1441 g_reset_armed_at = now;
1471 } 1442 }
1443 } else if (ct.action == ACT_SKY_RELOAD) {
1444 skybox_reload_image();
1445 toastf(TOAST_INFO, "Reloading skybox.png");
1472 } 1446 }
1473 return; 1447 return;
1474 } 1448 }
@@ -1840,25 +1814,6 @@ static void draw_card(const Rect &clip, int index, int y) {
1840 outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip); 1814 outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip);
1841 if (picker_open_for(ct)) 1815 if (picker_open_for(ct))
1842 draw_picker(clip, cr, ct, by); 1816 draw_picker(clip, cr, ct, by);
1843 } else if (ct.kind == CK_CHOICE) {
1844 int v = ctrl_val(ct);
1845 const char *name = (ct.opts && v >= 0 && v < ct.nopts)
1846 ? ct.opts[v]
1847 : "?";
1848 Rect box{cr.x + cr.w - S(238.0f),
1849 by + (base_h - S(24.0f)) / 2, S(222.0f), S(24.0f)};
1850 fill(box, Col{45, 50, 60, 255}, &clip);
1851 outline(box, C_BORDER, &clip);
1852 int ty = box.y + (box.h - g_body_h) / 2;
1853 text_in(clip, box.x + S(8.0f), ty, "<", g_font_body, g_body_h, 0,
1854 C_DIM);
1855 text_in(clip, box.x + box.w - S(16.0f), ty, ">", g_font_body, g_body_h,
1856 0, C_DIM);
1857 int w = text_w(name, g_body_h);
1858 int tx = box.x + (box.w - w) / 2;
1859 if (tx < box.x + S(24.0f))
1860 tx = box.x + S(24.0f);
1861 text_in(clip, tx, ty, name, g_font_body, g_body_h, 0, C_TEXT);
1862 } 1817 }
1863 } 1818 }
1864 by += rh; 1819 by += rh;