diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 19:06:06 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 19:06:06 +0100 |
| commit | f67ee1ef7e3eff3cd746fc97be98195e68c1368d (patch) | |
| tree | 529e2aa878da1c5e43d98e325efbe2178f57b6c9 | |
| parent | Chams: per-relationship, visible/invisible styles and viewmodel (diff) | |
| download | hl2h-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.md | 16 | ||||
| -rw-r--r-- | src/studio.cpp | 38 |
2 files changed, 39 insertions, 15 deletions
| @@ -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 | ||
| 251 | void chams_apply(void *mat, bool ignorez, int style, bool force_white, | 251 | void 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 | ||
| 268 | void chams_reset(void *mat) { | 270 | void 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); |
