summaryrefslogtreecommitdiffstats
path: root/src/world.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-03 23:32:16 +0100
committersalmonik <salmonik@tuta.io>2026-11-03 23:32:16 +0100
commitedba65625dd5823705619a2e682a99d6ad91ae8b (patch)
treecae03d46267469d1076937ad22c7b2aec63b068e /src/world.cpp
parentGUI: add inline colour picker control (diff)
downloadhl2h-edba65625dd5823705619a2e682a99d6ad91ae8b.tar.gz
hl2h-edba65625dd5823705619a2e682a99d6ad91ae8b.zip
World: add prop tint and fog override
- World tint now also colours prop materials (models/props*) with their own colour, covering static props and prop_physics while leaving NPC, player and weapon materials untouched. - New Fog card: fog_override colour/start/end via ClientCmd, optional skybox fog, and a Remove fog mode. Restores the map fog (fog_override 0) when disabled and re-applies after level changes. - Config sections [worldtint] prop/colour keys and [fog].
Diffstat (limited to '')
-rw-r--r--src/world.cpp120
1 files changed, 107 insertions, 13 deletions
diff --git a/src/world.cpp b/src/world.cpp
index eeffb99..2333829 100644
--- a/src/world.cpp
+++ b/src/world.cpp
@@ -48,8 +48,16 @@ struct Tint {
48 bool valid; 48 bool valid;
49 int world_r, world_g, world_b; 49 int world_r, world_g, world_b;
50 int sky_r, sky_g, sky_b; 50 int sky_r, sky_g, sky_b;
51 int prop_r, prop_g, prop_b;
51}; 52};
52Tint g_applied{false, 255, 255, 255, 255, 255, 255}; 53Tint g_applied{false, 255, 255, 255, 255, 255, 255, 255, 255, 255};
54
55// Static props and prop_physics share their model materials; every stock HL2
56// map prop lives under models/props*, which keeps NPC/player/weapon materials
57// out of the prop pass.
58bool is_prop_material(const char *name) {
59 return name && strncmp(name, "models/props", 12) == 0;
60}
53 61
54struct MatCalls { 62struct MatCalls {
55 using FirstFn = unsigned short (*)(void *); 63 using FirstFn = unsigned short (*)(void *);
@@ -145,7 +153,7 @@ void *material_system() {
145// Push one colour pair over all materials. Groups that are off get white so a 153// Push one colour pair over all materials. Groups that are off get white so a
146// previously tinted world is restored. 154// previously tinted world is restored.
147bool apply_tint(int world_r, int world_g, int world_b, int sky_r, int sky_g, 155bool apply_tint(int world_r, int world_g, int world_b, int sky_r, int sky_g,
148 int sky_b) { 156 int sky_b, int prop_r, int prop_g, int prop_b) {
149 void *ms = material_system(); 157 void *ms = material_system();
150 if (!ms) 158 if (!ms)
151 return false; 159 return false;
@@ -166,9 +174,10 @@ bool apply_tint(int world_r, int world_g, int world_b, int sky_r, int sky_g,
166 174
167 float wr = world_r / 255.0f, wg = world_g / 255.0f, wb = world_b / 255.0f; 175 float wr = world_r / 255.0f, wg = world_g / 255.0f, wb = world_b / 255.0f;
168 float sr = sky_r / 255.0f, sg = sky_g / 255.0f, sb = sky_b / 255.0f; 176 float sr = sky_r / 255.0f, sg = sky_g / 255.0f, sb = sky_b / 255.0f;
177 float pr = prop_r / 255.0f, pg = prop_g / 255.0f, pb = prop_b / 255.0f;
169 178
170 unsigned short inv = invalid(ms); 179 unsigned short inv = invalid(ms);
171 int seen = 0, world_hits = 0, sky_hits = 0; 180 int seen = 0, world_hits = 0, sky_hits = 0, prop_hits = 0;
172 for (unsigned short h = first(ms); h != inv; h = next(ms, h)) { 181 for (unsigned short h = first(ms); h != inv; h = next(ms, h)) {
173 if (++seen > total + 16) { 182 if (++seen > total + 16) {
174 logf("tint: material walk runaway (%d > %d); stopped", seen, total); 183 logf("tint: material walk runaway (%d > %d); stopped", seen, total);
@@ -199,11 +208,15 @@ bool apply_tint(int world_r, int world_g, int world_b, int sky_r, int sky_g,
199 } else if (is_sky) { 208 } else if (is_sky) {
200 mod_fn(mat, sr, sg, sb); 209 mod_fn(mat, sr, sg, sb);
201 sky_hits++; 210 sky_hits++;
211 } else if (is_prop_material(name)) {
212 mod_fn(mat, pr, pg, pb);
213 prop_hits++;
202 } 214 }
203 } 215 }
204 logf("tint: applied world=%d(%d,%d,%d) sky=%d(%d,%d,%d) of %d materials", 216 logf("tint: applied world=%d(%d,%d,%d) sky=%d(%d,%d,%d) props=%d(%d,%d,%d) "
217 "of %d materials",
205 world_hits, world_r, world_g, world_b, sky_hits, sky_r, sky_g, sky_b, 218 world_hits, world_r, world_g, world_b, sky_hits, sky_r, sky_g, sky_b,
206 total); 219 prop_hits, prop_r, prop_g, prop_b, total);
207 return true; 220 return true;
208} 221}
209 222
@@ -215,6 +228,7 @@ void world_tint_update() {
215 bool on = feature_active(FEAT_WORLD_TINT); 228 bool on = feature_active(FEAT_WORLD_TINT);
216 bool world_on = on && g_tint_world_on; 229 bool world_on = on && g_tint_world_on;
217 bool sky_on = on && g_tint_sky_on; 230 bool sky_on = on && g_tint_sky_on;
231 bool prop_on = on && g_tint_prop_on;
218 232
219 int wr = world_on ? g_tint_world_rgb[0] : 255; 233 int wr = world_on ? g_tint_world_rgb[0] : 255;
220 int wg = world_on ? g_tint_world_rgb[1] : 255; 234 int wg = world_on ? g_tint_world_rgb[1] : 255;
@@ -222,27 +236,107 @@ void world_tint_update() {
222 int sr = sky_on ? g_tint_sky_rgb[0] : 255; 236 int sr = sky_on ? g_tint_sky_rgb[0] : 255;
223 int sg = sky_on ? g_tint_sky_rgb[1] : 255; 237 int sg = sky_on ? g_tint_sky_rgb[1] : 255;
224 int sb = sky_on ? g_tint_sky_rgb[2] : 255; 238 int sb = sky_on ? g_tint_sky_rgb[2] : 255;
239 int pr = prop_on ? g_tint_prop_rgb[0] : 255;
240 int pg = prop_on ? g_tint_prop_rgb[1] : 255;
241 int pb = prop_on ? g_tint_prop_rgb[2] : 255;
225 242
226 bool white = wr == 255 && wg == 255 && wb == 255 && sr == 255 && 243 bool white = wr == 255 && wg == 255 && wb == 255 && sr == 255 &&
227 sg == 255 && sb == 255; 244 sg == 255 && sb == 255 && pr == 255 && pg == 255 && pb == 255;
228 if (g_applied.valid && g_applied.world_r == wr && g_applied.world_g == wg && 245 if (g_applied.valid && g_applied.world_r == wr && g_applied.world_g == wg &&
229 g_applied.world_b == wb && g_applied.sky_r == sr && 246 g_applied.world_b == wb && g_applied.sky_r == sr &&
230 g_applied.sky_g == sg && g_applied.sky_b == sb) 247 g_applied.sky_g == sg && g_applied.sky_b == sb &&
248 g_applied.prop_r == pr && g_applied.prop_g == pg &&
249 g_applied.prop_b == pb)
231 return; 250 return;
232 // Nothing was ever tinted and nothing is requested: no need to walk the 251 // Nothing was ever tinted and nothing is requested: no need to walk the
233 // material list just to write white over white. 252 // material list just to write white over white.
234 if (!g_applied.valid && white) { 253 if (!g_applied.valid && white) {
235 g_applied = {true, wr, wg, wb, sr, sg, sb}; 254 g_applied = {true, wr, wg, wb, sr, sg, sb, pr, pg, pb};
236 return; 255 return;
237 } 256 }
238 if (g_matsys_failed && !world_on && !sky_on) { 257 if (g_matsys_failed && !world_on && !sky_on && !prop_on) {
239 g_applied = {true, wr, wg, wb, sr, sg, sb}; 258 g_applied = {true, wr, wg, wb, sr, sg, sb, pr, pg, pb};
240 return; 259 return;
241 } 260 }
242 if (!apply_tint(wr, wg, wb, sr, sg, sb)) { 261 if (!apply_tint(wr, wg, wb, sr, sg, sb, pr, pg, pb)) {
243 if (g_matsys_failed) 262 if (g_matsys_failed)
244 g_applied = {true, wr, wg, wb, sr, sg, sb}; 263 g_applied = {true, wr, wg, wb, sr, sg, sb, pr, pg, pb};
245 return; 264 return;
246 } 265 }
247 g_applied = {true, wr, wg, wb, sr, sg, sb}; 266 g_applied = {true, wr, wg, wb, sr, sg, sb, pr, pg, pb};
267}
268
269// ---------------------------------------------------------------------------
270// Fog override (engine console commands; no render hooks)
271// ---------------------------------------------------------------------------
272
273namespace {
274
275struct FogState {
276 bool valid;
277 bool on;
278 bool disable;
279 int r, g, b;
280 int start, end;
281 bool skybox;
282};
283FogState g_fog_applied{false, false, false, 0, 0, 0, 0, 0, false};
284
285} // namespace
286
287void fog_invalidate() { g_fog_applied.valid = false; }
288
289void fog_update() {
290 bool on = feature_active(FEAT_FOG);
291 bool disable = on && g_fog_disable;
292 int r = g_fog_rgb[0], g = g_fog_rgb[1], b = g_fog_rgb[2];
293 int start = g_fog_start;
294 int end = g_fog_end;
295 if (end <= start)
296 end = start + 1;
297 bool skybox = on && g_fog_skybox;
298
299 if (g_fog_applied.valid && g_fog_applied.on == on &&
300 g_fog_applied.disable == disable && g_fog_applied.r == r &&
301 g_fog_applied.g == g && g_fog_applied.b == b &&
302 g_fog_applied.start == start && g_fog_applied.end == end &&
303 g_fog_applied.skybox == skybox)
304 return;
305
306 if (!on) {
307 if (g_fog_applied.valid && g_fog_applied.on)
308 console_cmd("fog_override 0");
309 g_fog_applied = {true, false, false, 0, 0, 0, 0, 0, false};
310 return;
311 }
312
313 console_cmd("fog_override 1");
314 char cmd[128];
315 if (disable) {
316 console_cmd("fog_enable 0");
317 if (skybox)
318 console_cmd("fog_enableskybox 0");
319 } else {
320 console_cmd("fog_enable 1");
321 snprintf(cmd, sizeof(cmd), "fog_color %d %d %d", r, g, b);
322 console_cmd(cmd);
323 snprintf(cmd, sizeof(cmd), "fog_start %d", start);
324 console_cmd(cmd);
325 snprintf(cmd, sizeof(cmd), "fog_end %d", end);
326 console_cmd(cmd);
327 if (skybox) {
328 console_cmd("fog_enableskybox 1");
329 snprintf(cmd, sizeof(cmd), "fog_colorskybox %d %d %d", r, g, b);
330 console_cmd(cmd);
331 snprintf(cmd, sizeof(cmd), "fog_startskybox %d", start);
332 console_cmd(cmd);
333 snprintf(cmd, sizeof(cmd), "fog_endskybox %d", end);
334 console_cmd(cmd);
335 } else {
336 console_cmd("fog_enableskybox 0");
337 }
338 }
339 g_fog_applied = {true, on, disable, r, g, b, start, end, skybox};
340 logf("fog: %s colour=(%d,%d,%d) start=%d end=%d skybox=%d", disable ? "off"
341 : "on", r, g, b, start, end, (int)skybox);
248} 342}