From b661a8dfd2c02bea54d8581ebb35d0fb3267867c Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Nov 2026 19:36:24 +0100 Subject: 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. --- src/studio.cpp | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) (limited to 'src/studio.cpp') 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) { vfunc(mat, 28)(mat, r, g, b); } +void chams_alpha(void *mat, float a) { + using FindVarFn = void *(*)(void *, const char *, bool *, bool); + using SetFloatFn = void (*)(void *, float); + bool found = false; + void *var = vfunc(mat, 11)(mat, "$alpha", &found, false); + if (var) + vfunc(var, 3)(var, a); +} + void chams_apply(void *mat, bool ignorez, int style, bool force_white, const int *rgb, bool znearer) { using FlagFn = void (*)(void *, int, bool); @@ -255,10 +264,12 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white, float g = force_white ? 1.0f : (float)rgb[1] / 255.0f; float b = force_white ? 1.0f : (float)rgb[2] / 255.0f; chams_color(mat, r, g, b); + chams_alpha(mat, (float)rgb[3] / 255.0f); // 0 Flat, 1 Wireframe, 2 Additive, 3 Solid, 4 White, 5 Fullbright // (additive white glow), 6 Glow outline (solid base; the wireframe overlay // is a second draw with ZNEARER so its contour is not hidden by the base). vfunc(mat, 29)(mat, 1 << 15 /* IGNOREZ */, ignorez); + vfunc(mat, 29)(mat, 1 << 21 /* TRANSLUCENT */, rgb[3] < 255); vfunc(mat, 29)(mat, 1 << 10 /* ZNEARER */, znearer); vfunc(mat, 29)(mat, 1 << 28 /* WIREFRAME */, style == 1); vfunc(mat, 29)(mat, 1 << 7 /* ADDITIVE */, @@ -270,12 +281,14 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white, void chams_reset(void *mat) { using FlagFn = void (*)(void *, int, bool); vfunc(mat, 29)(mat, 1 << 15, false); + vfunc(mat, 29)(mat, 1 << 21, false); vfunc(mat, 29)(mat, 1 << 10, false); vfunc(mat, 29)(mat, 1 << 28, false); vfunc(mat, 29)(mat, 1 << 7, false); vfunc(mat, 29)(mat, 1 << 12, false); vfunc(mat, 29)(mat, 1 << 6, false); chams_color(mat, 1.0f, 1.0f, 1.0f); + chams_alpha(mat, 1.0f); } void hkdModelExecute(void *self, const void *state, const void *info, @@ -306,20 +319,24 @@ void hkdModelExecute(void *self, const void *state, const void *info, // Fullbright is an additive, self-illuminated version of the // chosen colour: lift it toward white so it reads brighter than // the plain additive style. - int brgb[3]; + int brgb[4]; const int *use_rgb = rgb; if (style == 5) { for (int i = 0; i < 3; i++) - brgb[i] = rgb[i] + (255 - rgb[i]) / 2; + brgb[i] = rgb[i] + (255 - rgb[i]) / 4; + brgb[3] = rgb[3]; use_rgb = brgb; } // Additive blending vanishes against bright backgrounds (sky, // white walls, strong fog), which made the viewmodel disappear in - // some places. Lay down a dim opaque base first so the first-person - // model always has a visible silhouette; the additive pass still - // adds the glow on top. - if (is_vm && (style == 2 || style == 5)) { - int drgb[3] = {rgb[0] / 2, rgb[1] / 2, rgb[2] / 2}; + // some places. Lay down a faint translucent base so the first-person + // model keeps a silhouette on bright backgrounds without turning + // into an opaque blob; the additive pass still provides the glow. + if (is_vm && (style == 2 || style == 5) && rgb[3] > 0) { + int ba = rgb[3] / 8; + if (ba < 16) + ba = 16; + int drgb[4] = {rgb[0], rgb[1], rgb[2], ba}; chams_apply(mat, ignorez, 3, false, drgb, false); g_force_override(self, mat, 0 /* OVERRIDE_NORMAL */); g_orig_model_exec(self, state, info, bone); @@ -333,8 +350,8 @@ void hkdModelExecute(void *self, const void *state, const void *info, // the contour and bias it forward so the base cannot bury it. void *wire = g_style_mats[1]; if (wire && wire != mat) { - int wrgb[3] = {(rgb[0] + 255) / 2, (rgb[1] + 255) / 2, - (rgb[2] + 255) / 2}; + int wrgb[4] = {(rgb[0] + 255) / 2, (rgb[1] + 255) / 2, + (rgb[2] + 255) / 2, rgb[3]}; chams_apply(wire, ignorez, 1, false, wrgb, true); g_force_override(self, wire, 0); g_orig_model_exec(self, state, info, bone); -- cgit v1.2.3