summaryrefslogtreecommitdiffstats
path: root/src/studio.cpp
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-04 19:36:24 +0100
committersalmonik <salmonik@tuta.io>2026-11-04 19:36:24 +0100
commitb661a8dfd2c02bea54d8581ebb35d0fb3267867c (patch)
tree817760a933a14cc0e6446299424a017a9a1c88cf /src/studio.cpp
parentChams: keep additive viewmodel visible on bright backgrounds (diff)
downloadhl2h-b661a8dfd2c02bea54d8581ebb35d0fb3267867c.tar.gz
hl2h-b661a8dfd2c02bea54d8581ebb35d0fb3267867c.zip
Chams: per-colour alpha and a softer viewmodel additive base
- Colour picker gains an optional alpha bar (checkerboard preview, #RRGGBBAA readout); add_color_alpha is used for the chams colours. Chams colours are now r,g,b,a and chams_apply sets $alpha plus MATERIAL_VAR_TRANSLUCENT when alpha < 255. Config stores vis_a / inv_a / vm a. - The additive viewmodel base is now a faint translucent tint (alpha/8) instead of an opaque fill, so additive/Fullbright stay see-through and the viewmodel no longer becomes a solid blob. Fullbright whitening reduced to 25% so blue stays blue instead of turning lavender.
Diffstat (limited to 'src/studio.cpp')
-rw-r--r--src/studio.cpp35
1 files changed, 26 insertions, 9 deletions
diff --git a/src/studio.cpp b/src/studio.cpp
index bee6db5..07ebec3 100644
--- a/src/studio.cpp
+++ b/src/studio.cpp
@@ -248,6 +248,15 @@ void chams_color(void *mat, float r, float g, float b) {
248 vfunc<ColorFn>(mat, 28)(mat, r, g, b); 248 vfunc<ColorFn>(mat, 28)(mat, r, g, b);
249} 249}
250 250
251void chams_alpha(void *mat, float a) {
252 using FindVarFn = void *(*)(void *, const char *, bool *, bool);
253 using SetFloatFn = void (*)(void *, float);
254 bool found = false;
255 void *var = vfunc<FindVarFn>(mat, 11)(mat, "$alpha", &found, false);
256 if (var)
257 vfunc<SetFloatFn>(var, 3)(var, a);
258}
259
251void chams_apply(void *mat, bool ignorez, int style, bool force_white, 260void chams_apply(void *mat, bool ignorez, int style, bool force_white,
252 const int *rgb, bool znearer) { 261 const int *rgb, bool znearer) {
253 using FlagFn = void (*)(void *, int, bool); 262 using FlagFn = void (*)(void *, int, bool);
@@ -255,10 +264,12 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white,
255 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f; 264 float g = force_white ? 1.0f : (float)rgb[1] / 255.0f;
256 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f; 265 float b = force_white ? 1.0f : (float)rgb[2] / 255.0f;
257 chams_color(mat, r, g, b); 266 chams_color(mat, r, g, b);
267 chams_alpha(mat, (float)rgb[3] / 255.0f);
258 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright 268 // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright
259 // (additive white glow), 6 Glow outline (solid base; the wireframe overlay 269 // (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). 270 // is a second draw with ZNEARER so its contour is not hidden by the base).
261 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez); 271 vfunc<FlagFn>(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez);
272 vfunc<FlagFn>(mat, 29)(mat, 1 << 21 /* TRANSLUCENT */, rgb[3] < 255);
262 vfunc<FlagFn>(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer); 273 vfunc<FlagFn>(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer);
263 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1); 274 vfunc<FlagFn>(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1);
264 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */, 275 vfunc<FlagFn>(mat, 29)(mat, 1 << 7 /* ADDITIVE */,
@@ -270,12 +281,14 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white,
270void chams_reset(void *mat) { 281void chams_reset(void *mat) {
271 using FlagFn = void (*)(void *, int, bool); 282 using FlagFn = void (*)(void *, int, bool);
272 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false); 283 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false);
284 vfunc<FlagFn>(mat, 29)(mat, 1 << 21, false);
273 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false); 285 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false);
274 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false); 286 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false);
275 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false); 287 vfunc<FlagFn>(mat, 29)(mat, 1 << 7, false);
276 vfunc<FlagFn>(mat, 29)(mat, 1 << 12, false); 288 vfunc<FlagFn>(mat, 29)(mat, 1 << 12, false);
277 vfunc<FlagFn>(mat, 29)(mat, 1 << 6, false); 289 vfunc<FlagFn>(mat, 29)(mat, 1 << 6, false);
278 chams_color(mat, 1.0f, 1.0f, 1.0f); 290 chams_color(mat, 1.0f, 1.0f, 1.0f);
291 chams_alpha(mat, 1.0f);
279} 292}
280 293
281void hkdModelExecute(void *self, const void *state, const void *info, 294void hkdModelExecute(void *self, const void *state, const void *info,
@@ -306,20 +319,24 @@ void hkdModelExecute(void *self, const void *state, const void *info,
306 // Fullbright is an additive, self-illuminated version of the 319 // Fullbright is an additive, self-illuminated version of the
307 // chosen colour: lift it toward white so it reads brighter than 320 // chosen colour: lift it toward white so it reads brighter than
308 // the plain additive style. 321 // the plain additive style.
309 int brgb[3]; 322 int brgb[4];
310 const int *use_rgb = rgb; 323 const int *use_rgb = rgb;
311 if (style == 5) { 324 if (style == 5) {
312 for (int i = 0; i < 3; i++) 325 for (int i = 0; i < 3; i++)
313 brgb[i] = rgb[i] + (255 - rgb[i]) / 2; 326 brgb[i] = rgb[i] + (255 - rgb[i]) / 4;
327 brgb[3] = rgb[3];
314 use_rgb = brgb; 328 use_rgb = brgb;
315 } 329 }
316 // Additive blending vanishes against bright backgrounds (sky, 330 // Additive blending vanishes against bright backgrounds (sky,
317 // white walls, strong fog), which made the viewmodel disappear in 331 // white walls, strong fog), which made the viewmodel disappear in
318 // some places. Lay down a dim opaque base first so the first-person 332 // some places. Lay down a faint translucent base so the first-person
319 // model always has a visible silhouette; the additive pass still 333 // model keeps a silhouette on bright backgrounds without turning
320 // adds the glow on top. 334 // into an opaque blob; the additive pass still provides the glow.
321 if (is_vm && (style == 2 || style == 5)) { 335 if (is_vm && (style == 2 || style == 5) && rgb[3] > 0) {
322 int drgb[3] = {rgb[0] / 2, rgb[1] / 2, rgb[2] / 2}; 336 int ba = rgb[3] / 8;
337 if (ba < 16)
338 ba = 16;
339 int drgb[4] = {rgb[0], rgb[1], rgb[2], ba};
323 chams_apply(mat, ignorez, 3, false, drgb, false); 340 chams_apply(mat, ignorez, 3, false, drgb, false);
324 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */); 341 g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */);
325 g_orig_model_exec(self, state, info, bone); 342 g_orig_model_exec(self, state, info, bone);
@@ -333,8 +350,8 @@ void hkdModelExecute(void *self, const void *state, const void *info,
333 // the contour and bias it forward so the base cannot bury it. 350 // the contour and bias it forward so the base cannot bury it.
334 void *wire = g_style_mats[1]; 351 void *wire = g_style_mats[1];
335 if (wire && wire != mat) { 352 if (wire && wire != mat) {
336 int wrgb[3] = {(rgb[0] + 255) / 2, (rgb[1] + 255) / 2, 353 int wrgb[4] = {(rgb[0] + 255) / 2, (rgb[1] + 255) / 2,
337 (rgb[2] + 255) / 2}; 354 (rgb[2] + 255) / 2, rgb[3]};
338 chams_apply(wire, ignorez, 1, false, wrgb, true); 355 chams_apply(wire, ignorez, 1, false, wrgb, true);
339 g_force_override(self, wire, 0); 356 g_force_override(self, wire, 0);
340 g_orig_model_exec(self, state, info, bone); 357 g_orig_model_exec(self, state, info, bone);