summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 19:06:06 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 19:06:06 +0100
commitf67ee1ef7e3eff3cd746fc97be98195e68c1368d (patch)
tree529e2aa878da1c5e43d98e325efbe2178f57b6c9
parentChams: per-relationship, visible/invisible styles and viewmodel (diff)
downloadhl2h-f67ee1ef7e3eff3cd746fc97be98195e68c1368d.tar.gz
hl2h-f67ee1ef7e3eff3cd746fc97be98195e68c1368d.zip
Chams: fix the flat viewmodel, glow outline and fullbright styles
- Flat uses the solid model shader with the FLAT flag on the viewmodel; vgui/white does not draw skinned models and made the hands vanish. - Glow outline draws its wireframe contour with ZNEARER and a brightened colour, so the solid base no longer hides the contour. - Fullbright is now additive + self-illuminated with the colour lifted toward white, so it reads differently from Solid and Additive glow.
-rw-r--r--CONTEXT.md16
-rw-r--r--src/studio.cpp38
2 files changed, 39 insertions, 15 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index be526fc..f7fdecb 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -296,12 +296,16 @@ vocabulary / decisions.
296 (IMaterialVar slot 11, SetVecValue 3-float slot 11) and `ColorModulate` 296 (IMaterialVar slot 11, SetVecValue 3-float slot 11) and `ColorModulate`
297 (slot 28). Shared materials are restored after each draw. 297 (slot 28). Shared materials are restored after each draw.
298- Styles are built from the resident materials and material flags: 298- Styles are built from the resident materials and material flags:
299 0 Flat (`vgui/white` with FLAT), 1 Wireframe (`debug/debugwireframe`), 299 0 Flat (`vgui/white` with FLAT on NPCs; the solid model shader with FLAT on
300 2 Additive (`debug/debugtranslucentsinglecolor` + ADDITIVE), 3 Solid, 300 the viewmodel, because VGUI materials do not draw skinned models),
301 4 White (solid, colour forced white), 5 Fullbright (solid + FLAT|SELFILLUM), 301 1 Wireframe (`debug/debugwireframe`), 2 Additive
302 6 Glow outline (solid plus a `debug/debugwireframe` contour pass). 302 (`debug/debugtranslucentsinglecolor` + ADDITIVE), 3 Solid, 4 White (solid,
303 `models/debug/debugwhite` is EP2-only and the old VGUI additive material is 303 colour forced white), 5 Fullbright (solid + ADDITIVE|SELFILLUM with the
304 invisible on NPCs; the styles no longer depend on them. 304 colour lifted toward white), 6 Glow outline (solid plus a
305 `debug/debugwireframe` contour pass drawn with ZNEARER (1 << 10) and a
306 brightened colour so the base cannot bury it). `models/debug/debugwhite` is
307 EP2-only and the old VGUI additive material is invisible on NPCs; the styles
308 no longer depend on them.
305- Style materials are preloaded from `outer_draw` (throttled) and cached; the 309- Style materials are preloaded from `outer_draw` (throttled) and cached; the
306 render hook never calls FindMaterial itself. A missing style uses solid. 310 render hook never calls FindMaterial itself. A missing style uses solid.
307- Feature is off by default. Config sections: `[chams]` (active/bind), 311- Feature is off by default. Config sections: `[chams]` (active/bind),
diff --git a/src/studio.cpp b/src/studio.cpp
index 803b6b2..301e781 100644
--- a/src/studio.cpp
+++ b/src/studio.cpp
@@ -249,25 +249,28 @@ void chams_color(void *mat, float r, float g, float b) {
249} 249}
250 250
251void chams_apply(void *mat, bool ignorez, int style, bool force_white, 251void chams_apply(void *mat, bool ignorez, int style, bool force_white,
252 const int *rgb) { 252 const int *rgb, bool znearer) {
253 using FlagFn = void (*)(void *, int, bool); 253 using FlagFn = void (*)(void *, int, bool);
254 float r = force_white ? 1.0f : (float)rgb[0] / 255.0f; 254 float r = force_white ? 1.0f : (float)rgb[0] / 255.0f;
255 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f; 255 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f;
256 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f; 256 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f;
257 chams_color(mat, r, g, b); 257 chams_color(mat, r, g, b);
258 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright, 258 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright
259 // 6 Glow outline (solid base; the wireframe overlay is a second draw). 259 // (additive white glow), 6 Glow outline (solid base; the wireframe overlay
260 // is a second draw with ZNEARER so its contour is not hidden by the base).
260 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez); 261 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez);
262 vfunc<FlagFn>(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer);
261 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1); 263 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1);
262 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */, style == 2); 264 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */,
263 vfunc<FlagFn>(mat, 29)(mat, 1 << 12 /* FLAT */, 265 style == 2 || style == 5);
264 style == 0 || style == 5); 266 vfunc<FlagFn>(mat, 29)(mat, 1 << 12 /* FLAT */, style == 0);
265 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5); 267 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5);
266} 268}
267 269
268void chams_reset(void *mat) { 270void chams_reset(void *mat) {
269 using FlagFn = void (*)(void *, int, bool); 271 using FlagFn = void (*)(void *, int, bool);
270 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false); 272 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false);
273 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false);
271 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false); 274 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false);
272 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false); 275 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false);
273 vfunc<FlagFn>(mat, 29)(mat, 1 << 12, false); 276 vfunc<FlagFn>(mat, 29)(mat, 1 << 12, false);
@@ -297,17 +300,34 @@ void hkdModelExecute(void *self, const void *state, const void *info,
297 if (style < 0) style = 0; 300 if (style < 0) style = 0;
298 if (style > 6) style = 6; 301 if (style > 6) style = 6;
299 void *mat = style_material(style); 302 void *mat = style_material(style);
303 // vgui/white (Flat) does not draw skinned models, so the viewmodel
304 // uses the solid model shader with the same FLAT flag.
305 if (is_vm && style == 0)
306 mat = viewmodel_material();
300 if (!mat) 307 if (!mat)
301 return false; 308 return false;
302 bool white = style == 4; 309 bool white = style == 4;
303 chams_apply(mat, ignorez, style, white, rgb); 310 // Fullbright is an additive, self-illuminated version of the
311 // chosen colour: lift it toward white so it reads brighter than
312 // the plain additive style.
313 int brgb[3];
314 const int *use_rgb = rgb;
315 if (style == 5) {
316 for (int i = 0; i < 3; i++)
317 brgb[i] = rgb[i] + (255 - rgb[i]) / 2;
318 use_rgb = brgb;
319 }
320 chams_apply(mat, ignorez, style, white, use_rgb, false);
304 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */); 321 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */);
305 g_orig_model_exec(self, state, info, bone); 322 g_orig_model_exec(self, state, info, bone);
306 if (style == 6) { 323 if (style == 6) {
307 // Solid base plus a wireframe contour pass for depth. 324 // Solid base plus a wireframe contour pass for depth. Brighten
325 // the contour and bias it forward so the base cannot bury it.
308 void *wire = g_style_mats[1]; 326 void *wire = g_style_mats[1];
309 if (wire && wire != mat) { 327 if (wire && wire != mat) {
310 chams_apply(wire, ignorez, 1, false, rgb); 328 int wrgb[3] = {(rgb[0] + 255) / 2, (rgb[1] + 255) / 2,
329 (rgb[2] + 255) / 2};
330 chams_apply(wire, ignorez, 1, false, wrgb, true);
311 g_force_override(self, wire, 0); 331 g_force_override(self, wire, 0);
312 g_orig_model_exec(self, state, info, bone); 332 g_orig_model_exec(self, state, info, bone);
313 chams_reset(wire); 333 chams_reset(wire);