summaryrefslogtreecommitdiffstats
path: root/src/studio.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 21:35:44 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 21:35:44 +0100
commitc35fc21f345ac9ecf9017115c4481a1147d05206 (patch)
tree6907a027a097aec5af994b5bdcb20dddce6e984a /src/studio.cpp
parentChams: make Fullbright a white-hot additive glow (diff)
downloadhl2h-c35fc21f345ac9ecf9017115c4481a1147d05206.tar.gz
hl2h-c35fc21f345ac9ecf9017115c4481a1147d05206.zip
Chams: real additive material, addref cached materials
Testing on :99 showed ADDITIVE on debugtranslucentsinglecolor did nothing and alpha lost the colour, because that VMT has no $translucent and the engine bound an unreferenced material. Use debug/debugtranslucentmodelhulls (VMT has $additive 1 + $color) for Additive/Fullbright, and addref every preloaded material so the engine stops warning "bad reference count 0" and applies $color/ColorModulate. Verified: Solid is flat blue, Additive is a translucent coloured glow, Fullbright is a white additive glow, White is opaque white. Also drop the viewmodel additive base (the solid material is opaque, so it made an opaque blob) and never call FindMaterial inside DrawModelExecute. Document that the alpha control is stored but has no effect until a custom $translucent model VMT is added.
Diffstat (limited to '')
-rw-r--r--src/studio.cpp46
1 files changed, 13 insertions, 33 deletions
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 }