summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CONTEXT.md41
-rw-r--r--src/studio.cpp46
2 files changed, 37 insertions, 50 deletions
diff --git a/CONTEXT.md b/CONTEXT.md
index bfb0d8e..5b96c33 100644
--- a/CONTEXT.md
+++ b/CONTEXT.md
@@ -294,31 +294,38 @@ vocabulary / decisions.
294 alpha only. The through-wall pass uses `MATERIAL_VAR_IGNOREZ` (1 << 15) 294 alpha only. The through-wall pass uses `MATERIAL_VAR_IGNOREZ` (1 << 15)
295 through `IMaterial::SetMaterialVarFlag` (slot 29); colours use 295 through `IMaterial::SetMaterialVarFlag` (slot 29); colours use
296 `$color`/`$color2` (IMaterialVar slot 11, SetVecValue 3-float slot 11) and 296 `$color`/`$color2` (IMaterialVar slot 11, SetVecValue 3-float slot 11) and
297 `ColorModulate` (slot 28). Alpha uses `$alpha` (IMaterialVar slot 3, 297 `ColorModulate` (slot 28). `$alpha` is set through IMaterialVar slot 3
298 SetFloatValue) and `MATERIAL_VAR_TRANSLUCENT` (1 << 21) when alpha < 255. 298 (SetFloatValue). Shared materials are restored after each draw.
299 Shared materials are restored after each draw.
300- The GUI colour picker (`add_color_alpha`) has an alpha bar, checkerboard 299- The GUI colour picker (`add_color_alpha`) has an alpha bar, checkerboard
301 preview and `#RRGGBBAA` readout; plain `add_color` keeps the old opaque 300 preview and `#RRGGBBAA` readout; plain `add_color` keeps the old opaque
302 three-component behaviour. Chams colours are four ints (r, g, b, a). 301 three-component behaviour. Chams colours are four ints (r, g, b, a).
303- Styles are built from `debug/debugtranslucentsinglecolor` (UnlitGeneric, 302- **Alpha is stored but has no visual effect yet.** The usable model
304 `$color`) and material flags: 303 materials are opaque: `debug/debugtranslucentsinglecolor` has no
305 0 Flat (solid + FLAT), 1 Wireframe (`debug/debugwireframe`), 2 Additive 304 `$translucent`, and toggling `MATERIAL_VAR_TRANSLUCENT` (1 << 21) or
306 (+ ADDITIVE), 3 Solid, 4 White (colour forced white), 5 Fullbright 305 rebuilding the state snapshot does not change the static shader combo.
307 (ADDITIVE|SELFILLUM, colour forced white so it reads as a white-hot glow 306 `debug/debugtranslucentvertexcolor`/`debug/debughitbox` are translucent but
308 instead of matching Solid), 6 Glow outline 307 need vertex colours and render nothing on skinned models. A custom VMT with
309 (solid plus a `debug/debugwireframe` contour pass drawn with ZNEARER 308 `$model 1` + `$translucent 1` (or a white basetexture) is needed to make the
310 (1 << 10) and a brightened colour so the base cannot bury it). 309 alpha control real.
310- Styles: 0 Flat (`debug/debugtranslucentsinglecolor` + FLAT), 1 Wireframe
311 (`debug/debugwireframe`), 2 Additive
312 (`debug/debugtranslucentmodelhulls`, whose VMT has `$additive 1` + `$color`;
313 the ADDITIVE flag on the solid material did nothing), 3 Solid, 4 White
314 (solid, colour forced white), 5 Fullbright (the additive material, colour
315 forced white, giving a white-hot glow), 6 Glow outline (solid plus a
316 `debug/debugwireframe` contour pass drawn with ZNEARER (1 << 10) and a
317 brightened colour so the base cannot bury it).
311 `vgui/white` is vertex-colour based and has no `$model`/`$basetexture`, so it 318 `vgui/white` is vertex-colour based and has no `$model`/`$basetexture`, so it
312 is never used for chams; `models/debug/debugwhite` is EP2-only and the old 319 is never used for chams; `models/debug/debugwhite` is EP2-only and the old
313 VGUI additive material was invisible on NPCs. 320 VGUI additive material was invisible on NPCs.
314- Style materials are preloaded from `outer_draw` (throttled) and cached; the 321- Style materials are preloaded from `outer_draw` (throttled) and cached; the
315 render hook never calls FindMaterial itself. A missing style uses solid. 322 render hook never calls FindMaterial itself. A missing style uses solid.
316- Viewmodels are collated by the engine as `RENDER_GROUP_VIEW_MODEL_OPAQUE`, 323 `FindMaterial` can return an unreferenced material, so each cached material
317 so an additive forced material can wash out against a bright sky or wall 324 is addref'd (`IncrementReferenceCount`, IMaterial slot 12); without this the
318 (and the engine may not treat the draw as translucent). Additive styles on 325 engine warns "bad reference count 0 when being bound" and the material's
319 the viewmodel therefore draw a faint translucent base (alpha/8) first, then 326 `$color`/`ColorModulate` changes are ignored.
320 the additive pass, so the model keeps a silhouette on bright backgrounds 327- Additive styles still wash out against a bright sky or wall (inherent to
321 without becoming an opaque blob. 328 additive blending).
322- Feature is off by default. Config sections: `[chams]` (active/bind), 329- Feature is off by default. Config sections: `[chams]` (active/bind),
323 `[chams_hostile|neutral|friendly]` (`vis`, `vis_mat`, `vis_r/g/b/a`, `inv`, 330 `[chams_hostile|neutral|friendly]` (`vis`, `vis_mat`, `vis_r/g/b/a`, `inv`,
324 `inv_mat`, `inv_r/g/b/a`) and `[chams_vm]` (`on`, `mat`, `r/g/b/a`). The GUI 331 `inv_mat`, `inv_r/g/b/a`) and `[chams_vm]` (`on`, `mat`, `r/g/b/a`). The GUI
diff --git a/src/studio.cpp b/src/studio.cpp
index 086d213..cf145d1 100644
--- a/src/studio.cpp
+++ b/src/studio.cpp
@@ -199,20 +199,21 @@ ModelExecFn g_orig_model_exec = nullptr;
199ForceOverrideFn g_force_override = nullptr; 199ForceOverrideFn g_force_override = nullptr;
200void *g_style_mats[7] = {}; 200void *g_style_mats[7] = {};
201 201
202void *viewmodel_material();
203
204const char *chams_material_name(int idx) { 202const char *chams_material_name(int idx) {
205 switch (idx) { 203 switch (idx) {
206 case 1: return "debug/debugwireframe"; 204 case 1: return "debug/debugwireframe";
207 case 2: 205 case 2:
206 case 5: return "debug/debugtranslucentmodelhulls";
208 case 3: 207 case 3:
209 case 4: 208 case 4:
210 case 5:
211 case 6: 209 case 6:
212 default: return "debug/debugtranslucentsinglecolor"; 210 default: return "debug/debugtranslucentsinglecolor";
213 } 211 }
214} 212}
215 213
214// Never call FindMaterial here: this runs inside DrawModelExecute, where
215// loading a material can crash the material system. chams_preload fills the
216// cache from outer_draw instead.
216void *style_material(int idx) { 217void *style_material(int idx) {
217 if (idx < 0) idx = 0; 218 if (idx < 0) idx = 0;
218 if (idx > 6) idx = 6; 219 if (idx > 6) idx = 6;
@@ -220,17 +221,7 @@ void *style_material(int idx) {
220 return g_style_mats[idx]; 221 return g_style_mats[idx];
221 if (g_style_mats[3]) 222 if (g_style_mats[3])
222 return g_style_mats[3]; 223 return g_style_mats[3];
223 return viewmodel_material(); 224 return nullptr;
224}
225
226// Viewmodels need a model shader; vgui materials do not draw skinned models.
227void *viewmodel_material() {
228 if (g_style_mats[3])
229 return g_style_mats[3];
230 static void *mat = nullptr;
231 if (!mat)
232 mat = world_find_material("debug/debugtranslucentsinglecolor");
233 return mat;
234} 225}
235 226
236void chams_color(void *mat, float r, float g, float b) { 227void chams_color(void *mat, float r, float g, float b) {
@@ -260,6 +251,7 @@ void chams_alpha(void *mat, float a) {
260void chams_apply(void *mat, bool ignorez, int style, bool force_white, 251void chams_apply(void *mat, bool ignorez, int style, bool force_white,
261 const int *rgb, bool znearer) { 252 const int *rgb, bool znearer) {
262 using FlagFn = void (*)(void *, int, bool); 253 using FlagFn = void (*)(void *, int, bool);
254 bool additive = style == 2 || style == 5;
263 float r = force_white ? 1.0f : (float)rgb[0] / 255.0f; 255 float r = force_white ? 1.0f : (float)rgb[0] / 255.0f;
264 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f; 256 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f;
265 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f; 257 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f;
@@ -268,12 +260,12 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white,
268 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright 260 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright
269 // (additive white glow), 6 Glow outline (solid base; the wireframe overlay 261 // (additive white glow), 6 Glow outline (solid base; the wireframe overlay
270 // is a second draw with ZNEARER so its contour is not hidden by the base). 262 // is a second draw with ZNEARER so its contour is not hidden by the base).
263 // Styles 2/5 use debug/debugtranslucentmodelhulls, whose VMT already has
264 // $additive; ADDITIVE on debugtranslucentsinglecolor did nothing.
271 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez); 265 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez);
272 vfunc<FlagFn>(mat, 29)(mat, 1 << 21 /* TRANSLUCENT */, rgb[3] < 255);
273 vfunc<FlagFn>(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer); 266 vfunc<FlagFn>(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer);
274 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1); 267 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1);
275 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */, 268 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */, additive);
276 style == 2 || style == 5);
277 vfunc<FlagFn>(mat, 29)(mat, 1 << 12 /* FLAT */, style == 0); 269 vfunc<FlagFn>(mat, 29)(mat, 1 << 12 /* FLAT */, style == 0);
278 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5); 270 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5);
279} 271}
@@ -281,7 +273,6 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white,
281void chams_reset(void *mat) { 273void chams_reset(void *mat) {
282 using FlagFn = void (*)(void *, int, bool); 274 using FlagFn = void (*)(void *, int, bool);
283 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false); 275 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false);
284 vfunc<FlagFn>(mat, 29)(mat, 1 << 21, false);
285 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false); 276 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false);
286 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false); 277 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false);
287 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false); 278 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false);
@@ -317,21 +308,6 @@ void hkdModelExecute(void *self, const void *state, const void *info,
317 return false; 308 return false;
318 bool white = style == 4 || style == 5; 309 bool white = style == 4 || style == 5;
319 const int *use_rgb = rgb; 310 const int *use_rgb = rgb;
320 // Additive blending vanishes against bright backgrounds (sky,
321 // white walls, strong fog), which made the viewmodel disappear in
322 // some places. Lay down a faint translucent base so the first-person
323 // model keeps a silhouette on bright backgrounds without turning
324 // into an opaque blob; the additive pass still provides the glow.
325 if (is_vm && (style == 2 || style == 5) && rgb[3] > 0) {
326 int ba = rgb[3] / 8;
327 if (ba < 16)
328 ba = 16;
329 int drgb[4] = {rgb[0], rgb[1], rgb[2], ba};
330 chams_apply(mat, ignorez, 3, false, drgb, false);
331 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */);
332 g_orig_model_exec(self, state, info, bone);
333 chams_reset(mat);
334 }
335 chams_apply(mat, ignorez, style, white, use_rgb, false); 311 chams_apply(mat, ignorez, style, white, use_rgb, false);
336 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */); 312 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */);
337 g_orig_model_exec(self, state, info, bone); 313 g_orig_model_exec(self, state, info, bone);
@@ -391,6 +367,10 @@ void chams_preload() {
391 continue; 367 continue;
392 void *m = world_find_material(chams_material_name(i)); 368 void *m = world_find_material(chams_material_name(i));
393 if (m) { 369 if (m) {
370 // FindMaterial can hand back an unreferenced material; the engine warns
371 // ("bad reference count 0") and may reset its vars when it is bound.
372 using RefFn = void (*)(void *);
373 vfunc<RefFn>(m, 12)(m); // IMaterial::IncrementReferenceCount
394 g_style_mats[i] = m; 374 g_style_mats[i] = m;
395 logf("chams: preloaded style %d %s = %p", i, chams_material_name(i), m); 375 logf("chams: preloaded style %d %s = %p", i, chams_material_name(i), m);
396 } 376 }