diff options
| author | salmonik <salmonik@tuta.io> | 2026-11-04 19:36:24 +0100 |
|---|---|---|
| committer | salmonik <salmonik@tuta.io> | 2026-11-04 19:36:24 +0100 |
| commit | b661a8dfd2c02bea54d8581ebb35d0fb3267867c (patch) | |
| tree | 817760a933a14cc0e6446299424a017a9a1c88cf | |
| parent | Chams: keep additive viewmodel visible on bright backgrounds (diff) | |
| download | hl2h-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.
| -rw-r--r-- | CONTEXT.md | 26 | ||||
| -rw-r--r-- | src/gui.cpp | 126 | ||||
| -rw-r--r-- | src/hl2h.h | 7 | ||||
| -rw-r--r-- | src/menu.cpp | 50 | ||||
| -rw-r--r-- | src/studio.cpp | 35 |
5 files changed, 178 insertions, 66 deletions
| @@ -290,11 +290,16 @@ vocabulary / decisions. | |||
| 290 | viewmodel entities (class contains `viewmodel` or model path `.../v_...`) | 290 | viewmodel entities (class contains `viewmodel` or model path `.../v_...`) |
| 291 | are a fourth group. | 291 | are a fourth group. |
| 292 | - Each relationship has independent **visible** and **through-wall** settings: | 292 | - Each relationship has independent **visible** and **through-wall** settings: |
| 293 | on/off, style, and colour. The viewmodel has on/off, style and colour only. | 293 | on/off, style, colour and alpha. The viewmodel has on/off, style, colour and |
| 294 | The through-wall pass uses `MATERIAL_VAR_IGNOREZ` (1 << 15) through | 294 | alpha only. The through-wall pass uses `MATERIAL_VAR_IGNOREZ` (1 << 15) |
| 295 | `IMaterial::SetMaterialVarFlag` (slot 29); colours use `$color`/`$color2` | 295 | through `IMaterial::SetMaterialVarFlag` (slot 29); colours use |
| 296 | (IMaterialVar slot 11, SetVecValue 3-float slot 11) and `ColorModulate` | 296 | `$color`/`$color2` (IMaterialVar slot 11, SetVecValue 3-float slot 11) and |
| 297 | (slot 28). Shared materials are restored after each draw. | 297 | `ColorModulate` (slot 28). Alpha uses `$alpha` (IMaterialVar slot 3, |
| 298 | SetFloatValue) and `MATERIAL_VAR_TRANSLUCENT` (1 << 21) when alpha < 255. | ||
| 299 | Shared materials are restored after each draw. | ||
| 300 | - The GUI colour picker (`add_color_alpha`) has an alpha bar, checkerboard | ||
| 301 | preview and `#RRGGBBAA` readout; plain `add_color` keeps the old opaque | ||
| 302 | three-component behaviour. Chams colours are four ints (r, g, b, a). | ||
| 298 | - Styles are built from `debug/debugtranslucentsinglecolor` (UnlitGeneric, | 303 | - Styles are built from `debug/debugtranslucentsinglecolor` (UnlitGeneric, |
| 299 | `$color`) and material flags: | 304 | `$color`) and material flags: |
| 300 | 0 Flat (solid + FLAT), 1 Wireframe (`debug/debugwireframe`), 2 Additive | 305 | 0 Flat (solid + FLAT), 1 Wireframe (`debug/debugwireframe`), 2 Additive |
| @@ -310,12 +315,13 @@ vocabulary / decisions. | |||
| 310 | - Viewmodels are collated by the engine as `RENDER_GROUP_VIEW_MODEL_OPAQUE`, | 315 | - Viewmodels are collated by the engine as `RENDER_GROUP_VIEW_MODEL_OPAQUE`, |
| 311 | so an additive forced material can wash out against a bright sky or wall | 316 | so an additive forced material can wash out against a bright sky or wall |
| 312 | (and the engine may not treat the draw as translucent). Additive styles on | 317 | (and the engine may not treat the draw as translucent). Additive styles on |
| 313 | the viewmodel therefore draw a dim opaque solid base first, then the | 318 | the viewmodel therefore draw a faint translucent base (alpha/8) first, then |
| 314 | additive pass; the first-person model never disappears. | 319 | the additive pass, so the model keeps a silhouette on bright backgrounds |
| 320 | without becoming an opaque blob. | ||
| 315 | - Feature is off by default. Config sections: `[chams]` (active/bind), | 321 | - Feature is off by default. Config sections: `[chams]` (active/bind), |
| 316 | `[chams_hostile|neutral|friendly]` (`vis`, `vis_mat`, `vis_r/g/b`, `inv`, | 322 | `[chams_hostile|neutral|friendly]` (`vis`, `vis_mat`, `vis_r/g/b/a`, `inv`, |
| 317 | `inv_mat`, `inv_r/g/b`) and `[chams_vm]` (`on`, `mat`, `r/g/b`). The GUI has | 323 | `inv_mat`, `inv_r/g/b/a`) and `[chams_vm]` (`on`, `mat`, `r/g/b/a`). The GUI |
| 318 | a Hostile/Neutral/Friendly section each, plus Viewmodel. | 324 | has a Hostile/Neutral/Friendly section each, plus Viewmodel. |
| 319 | - This is a material override, not stencil outlines. | 325 | - This is a material override, not stencil outlines. |
| 320 | 326 | ||
| 321 | ## Bones / ESP | 327 | ## Bones / ESP |
diff --git a/src/gui.cpp b/src/gui.cpp index 3cbb40a..89888da 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -195,7 +195,8 @@ struct Ctrl { | |||
| 195 | const char *desc; | 195 | const char *desc; |
| 196 | bool *bval; // CK_TOGGLE | 196 | bool *bval; // CK_TOGGLE |
| 197 | int *ival; // CK_SLIDER | 197 | int *ival; // CK_SLIDER |
| 198 | int *rgb; // CK_COLOR: three ints, 0..255 | 198 | int *rgb; // CK_COLOR: three or four ints, 0..255 (see has_alpha) |
| 199 | bool has_alpha; // CK_COLOR: rgb[3] is an editable alpha channel | ||
| 199 | const char *const *opts; // CK_DROPDOWN | 200 | const char *const *opts; // CK_DROPDOWN |
| 200 | int nopts; // CK_DROPDOWN | 201 | int nopts; // CK_DROPDOWN |
| 201 | int min, max; | 202 | int min, max; |
| @@ -256,6 +257,7 @@ static void add_ctrl(int card, int kind, const char *label, const char *desc, | |||
| 256 | c.action = action; | 257 | c.action = action; |
| 257 | c.zero_unlimited = false; | 258 | c.zero_unlimited = false; |
| 258 | c.rgb = nullptr; | 259 | c.rgb = nullptr; |
| 260 | c.has_alpha = false; | ||
| 259 | c.opts = nullptr; | 261 | c.opts = nullptr; |
| 260 | c.nopts = 0; | 262 | c.nopts = 0; |
| 261 | c.hue = 0.0f; | 263 | c.hue = 0.0f; |
| @@ -287,6 +289,14 @@ static void add_color(int card, const char *label, const char *desc, | |||
| 287 | add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); | 289 | add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); |
| 288 | g_ctrls[i].rgb = rgb; | 290 | g_ctrls[i].rgb = rgb; |
| 289 | } | 291 | } |
| 292 | // Same picker, plus an editable alpha bar; rgb must hold four ints. | ||
| 293 | static void add_color_alpha(int card, const char *label, const char *desc, | ||
| 294 | int *rgba) { | ||
| 295 | int i = g_nctrl; | ||
| 296 | add_ctrl(card, CK_COLOR, label, desc, 0, 255, nullptr, nullptr, ACT_NONE); | ||
| 297 | g_ctrls[i].rgb = rgba; | ||
| 298 | g_ctrls[i].has_alpha = true; | ||
| 299 | } | ||
| 290 | static void add_dropdown(int card, const char *label, const char *desc, | 300 | static void add_dropdown(int card, const char *label, const char *desc, |
| 291 | const char *const *opts, int nopts, int *value) { | 301 | const char *const *opts, int nopts, int *value) { |
| 292 | int i = g_nctrl; | 302 | int i = g_nctrl; |
| @@ -456,15 +466,15 @@ static void build_cards() { | |||
| 456 | &g.vis_on); | 466 | &g.vis_on); |
| 457 | add_dropdown(chams, "Visible material", "Material for the visible pass.", | 467 | add_dropdown(chams, "Visible material", "Material for the visible pass.", |
| 458 | chams_mat_names, 7, &g.vis_mat); | 468 | chams_mat_names, 7, &g.vis_mat); |
| 459 | add_color(chams, "Visible colour", "Colour for the visible pass.", | 469 | add_color_alpha(chams, "Visible colour", "Colour and alpha for the visible pass.", |
| 460 | g.vis_rgb); | 470 | g.vis_rgb); |
| 461 | add_toggle(chams, "Through walls", "Draw a pass with the depth test off.", | 471 | add_toggle(chams, "Through walls", "Draw a pass with the depth test off.", |
| 462 | &g.inv_on); | 472 | &g.inv_on); |
| 463 | add_dropdown(chams, "Invisible material", | 473 | add_dropdown(chams, "Invisible material", |
| 464 | "Material for the through-wall pass.", chams_mat_names, 7, | 474 | "Material for the through-wall pass.", chams_mat_names, 7, |
| 465 | &g.inv_mat); | 475 | &g.inv_mat); |
| 466 | add_color(chams, "Invisible colour", | 476 | add_color_alpha(chams, "Invisible colour", |
| 467 | "Colour for the through-wall pass.", g.inv_rgb); | 477 | "Colour and alpha for the through-wall pass.", g.inv_rgb); |
| 468 | }; | 478 | }; |
| 469 | add_chams_group("Hostile", g_chams_hostile); | 479 | add_chams_group("Hostile", g_chams_hostile); |
| 470 | add_chams_group("Neutral", g_chams_neutral); | 480 | add_chams_group("Neutral", g_chams_neutral); |
| @@ -475,8 +485,8 @@ static void build_cards() { | |||
| 475 | &g_chams_viewmodel); | 485 | &g_chams_viewmodel); |
| 476 | add_dropdown(chams, "Viewmodel material", "Material for the viewmodel.", | 486 | add_dropdown(chams, "Viewmodel material", "Material for the viewmodel.", |
| 477 | chams_mat_names, 7, &g_chams_vm_mat); | 487 | chams_mat_names, 7, &g_chams_vm_mat); |
| 478 | add_color(chams, "Viewmodel colour", "Colour for the viewmodel.", | 488 | add_color_alpha(chams, "Viewmodel colour", "Colour and alpha for the viewmodel.", |
| 479 | g_chams_vm_rgb); | 489 | g_chams_vm_rgb); |
| 480 | int view = add_card(2, nullptr, "Camera / display", | 490 | int view = add_card(2, nullptr, "Camera / display", |
| 481 | "Camera FOV, viewmodel FOV and HDR brightness.", true); | 491 | "Camera FOV, viewmodel FOV and HDR brightness.", true); |
| 482 | add_slider(view, "Camera FOV", | 492 | add_slider(view, "Camera FOV", |
| @@ -970,7 +980,7 @@ static int button_w(const char *label) { | |||
| 970 | 980 | ||
| 971 | static int label_row_h(const Ctrl &c); | 981 | static int label_row_h(const Ctrl &c); |
| 972 | static bool picker_open_for(const Ctrl &c); | 982 | static bool picker_open_for(const Ctrl &c); |
| 973 | static int picker_panel_h(); | 983 | static int picker_panel_h(bool with_alpha); |
| 974 | static bool card_in_category(int i); | 984 | static bool card_in_category(int i); |
| 975 | static Rect card_rect(int index, int y); | 985 | static Rect card_rect(int index, int y); |
| 976 | static int card_h(const Card &c); | 986 | static int card_h(const Card &c); |
| @@ -978,7 +988,7 @@ static int card_h(const Card &c); | |||
| 978 | static int row_h(const Ctrl &c) { | 988 | static int row_h(const Ctrl &c) { |
| 979 | int h = label_row_h(c); | 989 | int h = label_row_h(c); |
| 980 | if (picker_open_for(c)) | 990 | if (picker_open_for(c)) |
| 981 | h += picker_panel_h(); | 991 | h += picker_panel_h(c.has_alpha); |
| 982 | return h; | 992 | return h; |
| 983 | } | 993 | } |
| 984 | 994 | ||
| @@ -989,6 +999,7 @@ static int row_h(const Ctrl &c) { | |||
| 989 | static constexpr int PICKER_SV_W = 180; | 999 | static constexpr int PICKER_SV_W = 180; |
| 990 | static constexpr int PICKER_SV_H = 110; | 1000 | static constexpr int PICKER_SV_H = 110; |
| 991 | static constexpr int PICKER_HUE_H = 12; | 1001 | static constexpr int PICKER_HUE_H = 12; |
| 1002 | static constexpr int PICKER_ALPHA_H = 12; | ||
| 992 | static constexpr int PICKER_GAP = 8; | 1003 | static constexpr int PICKER_GAP = 8; |
| 993 | 1004 | ||
| 994 | static bool picker_open_for(const Ctrl &c) { | 1005 | static bool picker_open_for(const Ctrl &c) { |
| @@ -996,9 +1007,11 @@ static bool picker_open_for(const Ctrl &c) { | |||
| 996 | &c == &g_ctrls[g_picker_ctrl]; | 1007 | &c == &g_ctrls[g_picker_ctrl]; |
| 997 | } | 1008 | } |
| 998 | 1009 | ||
| 999 | static int picker_panel_h() { | 1010 | static int picker_panel_h(bool with_alpha) { |
| 1000 | return S((float)(PICKER_GAP + PICKER_SV_H + PICKER_GAP + PICKER_HUE_H + | 1011 | int h = PICKER_GAP + PICKER_SV_H + PICKER_GAP + PICKER_HUE_H + PICKER_GAP; |
| 1001 | PICKER_GAP)); | 1012 | if (with_alpha) |
| 1013 | h += PICKER_ALPHA_H + PICKER_GAP; | ||
| 1014 | return S((float)h); | ||
| 1002 | } | 1015 | } |
| 1003 | 1016 | ||
| 1004 | static int label_row_h(const Ctrl &c) { | 1017 | static int label_row_h(const Ctrl &c) { |
| @@ -1069,16 +1082,17 @@ static void rgb_to_hsv(int r, int g, int b, float &h, float &s, float &v) { | |||
| 1069 | } | 1082 | } |
| 1070 | 1083 | ||
| 1071 | struct PickerRects { | 1084 | struct PickerRects { |
| 1072 | Rect panel, sv, hue, preview; | 1085 | Rect panel, sv, hue, alpha, preview; |
| 1073 | }; | 1086 | }; |
| 1074 | 1087 | ||
| 1075 | static PickerRects picker_rects(const Rect &cr, int row_y, int base_h) { | 1088 | static PickerRects picker_rects(const Rect &cr, int row_y, int base_h, |
| 1089 | bool with_alpha) { | ||
| 1076 | PickerRects p{}; | 1090 | PickerRects p{}; |
| 1077 | int px = cr.x + S(16.0f); | 1091 | int px = cr.x + S(16.0f); |
| 1078 | int py = row_y + base_h; | 1092 | int py = row_y + base_h; |
| 1079 | int pw = card_content_w() - S(32.0f); | 1093 | int pw = card_content_w() - S(32.0f); |
| 1080 | if (pw > S(340.0f)) pw = S(340.0f); | 1094 | if (pw > S(340.0f)) pw = S(340.0f); |
| 1081 | p.panel = Rect{px, py, pw, picker_panel_h()}; | 1095 | p.panel = Rect{px, py, pw, picker_panel_h(with_alpha)}; |
| 1082 | int preview_w = S(84.0f); | 1096 | int preview_w = S(84.0f); |
| 1083 | int svw = S((float)PICKER_SV_W); | 1097 | int svw = S((float)PICKER_SV_W); |
| 1084 | if (svw + preview_w + S(16.0f) > pw) | 1098 | if (svw + preview_w + S(16.0f) > pw) |
| @@ -1089,6 +1103,8 @@ static PickerRects picker_rects(const Rect &cr, int row_y, int base_h) { | |||
| 1089 | S((float)PICKER_SV_H)}; | 1103 | S((float)PICKER_SV_H)}; |
| 1090 | p.hue = Rect{p.sv.x, p.sv.y + p.sv.h + S(PICKER_GAP), svw, | 1104 | p.hue = Rect{p.sv.x, p.sv.y + p.sv.h + S(PICKER_GAP), svw, |
| 1091 | S((float)PICKER_HUE_H)}; | 1105 | S((float)PICKER_HUE_H)}; |
| 1106 | p.alpha = Rect{p.hue.x, p.hue.y + p.hue.h + S(PICKER_GAP), svw, | ||
| 1107 | S((float)PICKER_ALPHA_H)}; | ||
| 1092 | p.preview = Rect{p.sv.x + p.sv.w + S(12.0f), p.sv.y, preview_w, S(52.0f)}; | 1108 | p.preview = Rect{p.sv.x + p.sv.w + S(12.0f), p.sv.y, preview_w, S(52.0f)}; |
| 1093 | return p; | 1109 | return p; |
| 1094 | } | 1110 | } |
| @@ -1175,7 +1191,7 @@ static bool picker_rects_for(int ctrl_index, PickerRects &out) { | |||
| 1175 | if (!control_rect(ctrl_index, card, row)) | 1191 | if (!control_rect(ctrl_index, card, row)) |
| 1176 | return false; | 1192 | return false; |
| 1177 | Ctrl &ct = g_ctrls[ctrl_index]; | 1193 | Ctrl &ct = g_ctrls[ctrl_index]; |
| 1178 | out = picker_rects(card, row.y, label_row_h(ct)); | 1194 | out = picker_rects(card, row.y, label_row_h(ct), ct.has_alpha); |
| 1179 | return true; | 1195 | return true; |
| 1180 | } | 1196 | } |
| 1181 | 1197 | ||
| @@ -1191,18 +1207,47 @@ static void picker_apply(Ctrl &ct, const PickerRects &p) { | |||
| 1191 | if (v > 1.0f) v = 1.0f; | 1207 | if (v > 1.0f) v = 1.0f; |
| 1192 | ct.sat = s; | 1208 | ct.sat = s; |
| 1193 | ct.val = v; | 1209 | ct.val = v; |
| 1210 | hsv_to_rgb(ct.hue, ct.sat, ct.val, ct.rgb[0], ct.rgb[1], ct.rgb[2]); | ||
| 1194 | } else if (g_picker_drag == 2) { | 1211 | } else if (g_picker_drag == 2) { |
| 1195 | float h = 360.0f * (float)(g_mouse_x - p.hue.x) / (float)p.hue.w; | 1212 | float h = 360.0f * (float)(g_mouse_x - p.hue.x) / (float)p.hue.w; |
| 1196 | if (h < 0.0f) h = 0.0f; | 1213 | if (h < 0.0f) h = 0.0f; |
| 1197 | if (h >= 360.0f) h = 359.9f; | 1214 | if (h >= 360.0f) h = 359.9f; |
| 1198 | ct.hue = h; | 1215 | ct.hue = h; |
| 1216 | hsv_to_rgb(ct.hue, ct.sat, ct.val, ct.rgb[0], ct.rgb[1], ct.rgb[2]); | ||
| 1217 | } else if (g_picker_drag == 3 && ct.has_alpha) { | ||
| 1218 | if (p.alpha.w <= 0) | ||
| 1219 | return; | ||
| 1220 | int a = (int)(255.0f * (float)(g_mouse_x - p.alpha.x) / | ||
| 1221 | (float)p.alpha.w + | ||
| 1222 | 0.5f); | ||
| 1223 | if (a < 0) a = 0; | ||
| 1224 | if (a > 255) a = 255; | ||
| 1225 | ct.rgb[3] = a; | ||
| 1226 | } | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | static void draw_checker(const Rect &r, const Rect *clip) { | ||
| 1230 | int sq = S(6.0f); | ||
| 1231 | if (sq < 4) | ||
| 1232 | sq = 4; | ||
| 1233 | for (int yy = 0; yy < r.h; yy += sq) { | ||
| 1234 | for (int xx = 0; xx < r.w; xx += sq) { | ||
| 1235 | int w = sq < r.w - xx ? sq : r.w - xx; | ||
| 1236 | int h = sq < r.h - yy ? sq : r.h - yy; | ||
| 1237 | bool odd = ((xx / sq) + (yy / sq)) & 1; | ||
| 1238 | fill(Rect{r.x + xx, r.y + yy, w, h}, | ||
| 1239 | odd ? Col{62, 66, 74, 255} : Col{38, 41, 47, 255}, clip); | ||
| 1240 | } | ||
| 1199 | } | 1241 | } |
| 1200 | hsv_to_rgb(ct.hue, ct.sat, ct.val, ct.rgb[0], ct.rgb[1], ct.rgb[2]); | ||
| 1201 | } | 1242 | } |
| 1202 | 1243 | ||
| 1203 | static void draw_picker(const Rect &clip, const Rect &cr, const Ctrl &ct, | 1244 | static void draw_picker(const Rect &clip, const Rect &cr, const Ctrl &ct, |
| 1204 | int row_y) { | 1245 | int row_y) { |
| 1205 | PickerRects p = picker_rects(cr, row_y, label_row_h(ct)); | 1246 | PickerRects p = picker_rects(cr, row_y, label_row_h(ct), ct.has_alpha); |
| 1247 | int pr = ct.rgb ? ct.rgb[0] : 255; | ||
| 1248 | int pg = ct.rgb ? ct.rgb[1] : 255; | ||
| 1249 | int pb = ct.rgb ? ct.rgb[2] : 255; | ||
| 1250 | int pa = (ct.has_alpha && ct.rgb) ? ct.rgb[3] : 255; | ||
| 1206 | fill(p.panel, Col{20, 23, 29, 250}, &clip); | 1251 | fill(p.panel, Col{20, 23, 29, 250}, &clip); |
| 1207 | outline(p.panel, C_BORDER, &clip); | 1252 | outline(p.panel, C_BORDER, &clip); |
| 1208 | 1253 | ||
| @@ -1236,6 +1281,23 @@ static void draw_picker(const Rect &clip, const Rect &cr, const Ctrl &ct, | |||
| 1236 | } | 1281 | } |
| 1237 | outline(p.hue, Col{0, 0, 0, 255}, &clip); | 1282 | outline(p.hue, Col{0, 0, 0, 255}, &clip); |
| 1238 | 1283 | ||
| 1284 | // Alpha bar: checkerboard behind a transparent->opaque colour gradient. | ||
| 1285 | if (ct.has_alpha) { | ||
| 1286 | draw_checker(p.alpha, &clip); | ||
| 1287 | int ax = S(4.0f); | ||
| 1288 | if (ax < 2) ax = 2; | ||
| 1289 | for (int xx = 0; xx < p.alpha.w; xx += ax) { | ||
| 1290 | int a = p.alpha.w > 1 ? 255 * xx / (p.alpha.w - 1) : 255; | ||
| 1291 | int rw = ax < p.alpha.w - xx ? ax : p.alpha.w - xx; | ||
| 1292 | fill(Rect{p.alpha.x + xx, p.alpha.y, rw, p.alpha.h}, | ||
| 1293 | Col{pr, pg, pb, a}, &clip); | ||
| 1294 | } | ||
| 1295 | outline(p.alpha, Col{0, 0, 0, 255}, &clip); | ||
| 1296 | int amx = p.alpha.x + (int)((float)pa / 255.0f * (float)p.alpha.w); | ||
| 1297 | line(amx, p.alpha.y - S(2.0f), amx, p.alpha.y + p.alpha.h + S(2.0f), | ||
| 1298 | Col{255, 255, 255, 255}); | ||
| 1299 | } | ||
| 1300 | |||
| 1239 | // Selection markers. | 1301 | // Selection markers. |
| 1240 | int mx = p.sv.x + (int)(ct.sat * (float)p.sv.w); | 1302 | int mx = p.sv.x + (int)(ct.sat * (float)p.sv.w); |
| 1241 | int my = p.sv.y + (int)((1.0f - ct.val) * (float)p.sv.h); | 1303 | int my = p.sv.y + (int)((1.0f - ct.val) * (float)p.sv.h); |
| @@ -1249,17 +1311,21 @@ static void draw_picker(const Rect &clip, const Rect &cr, const Ctrl &ct, | |||
| 1249 | Col{255, 255, 255, 255}); | 1311 | Col{255, 255, 255, 255}); |
| 1250 | 1312 | ||
| 1251 | // Preview swatch and hex value. | 1313 | // Preview swatch and hex value. |
| 1252 | int pr = ct.rgb ? ct.rgb[0] : 255; | 1314 | draw_checker(p.preview, &clip); |
| 1253 | int pg = ct.rgb ? ct.rgb[1] : 255; | 1315 | fill(p.preview, Col{pr, pg, pb, pa}, &clip); |
| 1254 | int pb = ct.rgb ? ct.rgb[2] : 255; | ||
| 1255 | fill(p.preview, Col{pr, pg, pb, 255}, &clip); | ||
| 1256 | outline(p.preview, C_BORDER, &clip); | 1316 | outline(p.preview, C_BORDER, &clip); |
| 1257 | char hex[16]; | 1317 | char hex[16]; |
| 1258 | snprintf(hex, sizeof(hex), "#%02X%02X%02X", pr, pg, pb); | 1318 | if (ct.has_alpha) |
| 1319 | snprintf(hex, sizeof(hex), "#%02X%02X%02X%02X", pr, pg, pb, pa); | ||
| 1320 | else | ||
| 1321 | snprintf(hex, sizeof(hex), "#%02X%02X%02X", pr, pg, pb); | ||
| 1259 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f), hex, | 1322 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f), hex, |
| 1260 | g_font_body, g_body_h, p.preview.w, C_TEXT); | 1323 | g_font_body, g_body_h, p.preview.w, C_TEXT); |
| 1261 | char rgb[48]; | 1324 | char rgb[48]; |
| 1262 | snprintf(rgb, sizeof(rgb), "%d %d %d", pr, pg, pb); | 1325 | if (ct.has_alpha) |
| 1326 | snprintf(rgb, sizeof(rgb), "%d %d %d %d", pr, pg, pb, pa); | ||
| 1327 | else | ||
| 1328 | snprintf(rgb, sizeof(rgb), "%d %d %d", pr, pg, pb); | ||
| 1263 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f) + g_body_h, | 1329 | text_in(clip, p.preview.x, p.preview.y + p.preview.h + S(8.0f) + g_body_h, |
| 1264 | rgb, g_font_body, g_body_h, p.preview.w, C_DIM); | 1330 | rgb, g_font_body, g_body_h, p.preview.w, C_DIM); |
| 1265 | } | 1331 | } |
| @@ -1581,7 +1647,7 @@ static void handle_mouse_click() { | |||
| 1581 | int base = label_row_h(ct); | 1647 | int base = label_row_h(ct); |
| 1582 | bool is_open = (g_picker_ctrl == idx); | 1648 | bool is_open = (g_picker_ctrl == idx); |
| 1583 | if (is_open) { | 1649 | if (is_open) { |
| 1584 | PickerRects p = picker_rects(cr, by, base); | 1650 | PickerRects p = picker_rects(cr, by, base, ct.has_alpha); |
| 1585 | if (p.sv.has(mx, my)) { | 1651 | if (p.sv.has(mx, my)) { |
| 1586 | g_picker_drag = 1; | 1652 | g_picker_drag = 1; |
| 1587 | picker_apply(g_ctrls[idx], p); | 1653 | picker_apply(g_ctrls[idx], p); |
| @@ -1592,6 +1658,11 @@ static void handle_mouse_click() { | |||
| 1592 | picker_apply(g_ctrls[idx], p); | 1658 | picker_apply(g_ctrls[idx], p); |
| 1593 | return; | 1659 | return; |
| 1594 | } | 1660 | } |
| 1661 | if (ct.has_alpha && p.alpha.has(mx, my)) { | ||
| 1662 | g_picker_drag = 3; | ||
| 1663 | picker_apply(g_ctrls[idx], p); | ||
| 1664 | return; | ||
| 1665 | } | ||
| 1595 | } | 1666 | } |
| 1596 | Rect sw{cr.x + cr.w - S(96.0f), by + (base - S(20.0f)) / 2, | 1667 | Rect sw{cr.x + cr.w - S(96.0f), by + (base - S(20.0f)) / 2, |
| 1597 | S(72.0f), S(20.0f)}; | 1668 | S(72.0f), S(20.0f)}; |
| @@ -2015,9 +2086,12 @@ static void draw_card(const Rect &clip, int index, int y) { | |||
| 2015 | int pr = ct.rgb ? ct.rgb[0] : 255; | 2086 | int pr = ct.rgb ? ct.rgb[0] : 255; |
| 2016 | int pg = ct.rgb ? ct.rgb[1] : 255; | 2087 | int pg = ct.rgb ? ct.rgb[1] : 255; |
| 2017 | int pb = ct.rgb ? ct.rgb[2] : 255; | 2088 | int pb = ct.rgb ? ct.rgb[2] : 255; |
| 2089 | int pa = (ct.has_alpha && ct.rgb) ? ct.rgb[3] : 255; | ||
| 2018 | Rect sw{cr.x + cr.w - S(96.0f), | 2090 | Rect sw{cr.x + cr.w - S(96.0f), |
| 2019 | by + (base_h - S(20.0f)) / 2, S(72.0f), S(20.0f)}; | 2091 | by + (base_h - S(20.0f)) / 2, S(72.0f), S(20.0f)}; |
| 2020 | fill(sw, Col{pr, pg, pb, 255}, &clip); | 2092 | if (pa < 255) |
| 2093 | draw_checker(sw, &clip); | ||
| 2094 | fill(sw, Col{pr, pg, pb, pa}, &clip); | ||
| 2021 | outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip); | 2095 | outline(sw, picker_open_for(ct) ? C_ACCENT : C_BORDER, &clip); |
| 2022 | if (picker_open_for(ct)) | 2096 | if (picker_open_for(ct)) |
| 2023 | draw_picker(clip, cr, ct, by); | 2097 | draw_picker(clip, cr, ct, by); |
| @@ -236,15 +236,16 @@ extern bool g_proj_fuse, g_proj_radius; | |||
| 236 | struct ChamsGroup { | 236 | struct ChamsGroup { |
| 237 | bool vis_on; | 237 | bool vis_on; |
| 238 | int vis_mat; | 238 | int vis_mat; |
| 239 | int vis_rgb[3]; | 239 | int vis_rgb[4]; // r, g, b, a (0..255) |
| 240 | bool inv_on; | 240 | bool inv_on; |
| 241 | int inv_mat; | 241 | int inv_mat; |
| 242 | int inv_rgb[3]; | 242 | int inv_rgb[4]; |
| 243 | }; | 243 | }; |
| 244 | extern ChamsGroup g_chams_hostile, g_chams_neutral, g_chams_friendly; | 244 | extern ChamsGroup g_chams_hostile, g_chams_neutral, g_chams_friendly; |
| 245 | extern bool g_chams_viewmodel; | 245 | extern bool g_chams_viewmodel; |
| 246 | extern int g_chams_vm_mat; | 246 | extern int g_chams_vm_mat; |
| 247 | extern int g_chams_vm_rgb[3];extern bool g_tint_world_on, g_tint_sky_on, g_tint_prop_on; | 247 | extern int g_chams_vm_rgb[4]; |
| 248 | extern bool g_tint_world_on, g_tint_sky_on, g_tint_prop_on; | ||
| 248 | extern int g_tint_world_rgb[3], g_tint_sky_rgb[3], g_tint_prop_rgb[3]; | 249 | extern int g_tint_world_rgb[3], g_tint_sky_rgb[3], g_tint_prop_rgb[3]; |
| 249 | extern bool g_fog_skybox, g_fog_disable; | 250 | extern bool g_fog_skybox, g_fog_disable; |
| 250 | extern int g_fog_rgb[3], g_fog_start, g_fog_end; | 251 | extern int g_fog_rgb[3], g_fog_start, g_fog_end; |
diff --git a/src/menu.cpp b/src/menu.cpp index bdb9531..873f5ed 100644 --- a/src/menu.cpp +++ b/src/menu.cpp | |||
| @@ -64,12 +64,15 @@ FeatureState g_projectiles{true, 0}; // grenade / rocket ESP | |||
| 64 | bool g_proj_fuse = true; | 64 | bool g_proj_fuse = true; |
| 65 | bool g_proj_radius = true; | 65 | bool g_proj_radius = true; |
| 66 | FeatureState g_chams{false, 0}; | 66 | FeatureState g_chams{false, 0}; |
| 67 | ChamsGroup g_chams_hostile{true, 3, {255, 60, 60}, true, 3, {255, 60, 60}}; | 67 | ChamsGroup g_chams_hostile{true, 3, {255, 60, 60, 255}, true, 3, |
| 68 | ChamsGroup g_chams_neutral{true, 3, {220, 220, 220}, false, 3, {220, 220, 220}}; | 68 | {255, 60, 60, 255}}; |
| 69 | ChamsGroup g_chams_friendly{true, 3, {60, 255, 60}, false, 3, {60, 255, 60}}; | 69 | ChamsGroup g_chams_neutral{true, 3, {220, 220, 220, 255}, false, 3, |
| 70 | {220, 220, 220, 255}}; | ||
| 71 | ChamsGroup g_chams_friendly{true, 3, {60, 255, 60, 255}, false, 3, | ||
| 72 | {60, 255, 60, 255}}; | ||
| 70 | bool g_chams_viewmodel = false; | 73 | bool g_chams_viewmodel = false; |
| 71 | int g_chams_vm_mat = 3; | 74 | int g_chams_vm_mat = 3; |
| 72 | int g_chams_vm_rgb[3] = {200, 200, 255}; | 75 | int g_chams_vm_rgb[4] = {200, 200, 255, 255}; |
| 73 | bool g_item_health = true; | 76 | bool g_item_health = true; |
| 74 | bool g_item_ammo = true; | 77 | bool g_item_ammo = true; |
| 75 | bool g_item_armor = true; | 78 | bool g_item_armor = true; |
| @@ -244,17 +247,18 @@ void config_save() { | |||
| 244 | fprintf(f, "[chams]\nactive=%d\nbind=%d\n", g_chams.active, g_chams.bind); | 247 | fprintf(f, "[chams]\nactive=%d\nbind=%d\n", g_chams.active, g_chams.bind); |
| 245 | auto save_chams = [&](const char *name, const ChamsGroup &g) { | 248 | auto save_chams = [&](const char *name, const ChamsGroup &g) { |
| 246 | fprintf(f, "[%s]\nvis=%d\nvis_mat=%d\nvis_r=%d\nvis_g=%d\nvis_b=%d\n" | 249 | fprintf(f, "[%s]\nvis=%d\nvis_mat=%d\nvis_r=%d\nvis_g=%d\nvis_b=%d\n" |
| 247 | "inv=%d\ninv_mat=%d\ninv_r=%d\ninv_g=%d\ninv_b=%d\n", | 250 | "vis_a=%d\ninv=%d\ninv_mat=%d\ninv_r=%d\ninv_g=%d\ninv_b=%d\n" |
| 251 | "inv_a=%d\n", | ||
| 248 | name, (int)g.vis_on, g.vis_mat, g.vis_rgb[0], g.vis_rgb[1], | 252 | name, (int)g.vis_on, g.vis_mat, g.vis_rgb[0], g.vis_rgb[1], |
| 249 | g.vis_rgb[2], (int)g.inv_on, g.inv_mat, g.inv_rgb[0], | 253 | g.vis_rgb[2], g.vis_rgb[3], (int)g.inv_on, g.inv_mat, |
| 250 | g.inv_rgb[1], g.inv_rgb[2]); | 254 | g.inv_rgb[0], g.inv_rgb[1], g.inv_rgb[2], g.inv_rgb[3]); |
| 251 | }; | 255 | }; |
| 252 | save_chams("chams_hostile", g_chams_hostile); | 256 | save_chams("chams_hostile", g_chams_hostile); |
| 253 | save_chams("chams_neutral", g_chams_neutral); | 257 | save_chams("chams_neutral", g_chams_neutral); |
| 254 | save_chams("chams_friendly", g_chams_friendly); | 258 | save_chams("chams_friendly", g_chams_friendly); |
| 255 | fprintf(f, "[chams_vm]\non=%d\nmat=%d\nr=%d\ng=%d\nb=%d\n", | 259 | fprintf(f, "[chams_vm]\non=%d\nmat=%d\nr=%d\ng=%d\nb=%d\na=%d\n", |
| 256 | (int)g_chams_viewmodel, g_chams_vm_mat, g_chams_vm_rgb[0], | 260 | (int)g_chams_viewmodel, g_chams_vm_mat, g_chams_vm_rgb[0], |
| 257 | g_chams_vm_rgb[1], g_chams_vm_rgb[2]); | 261 | g_chams_vm_rgb[1], g_chams_vm_rgb[2], g_chams_vm_rgb[3]); |
| 258 | fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" | 262 | fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" |
| 259 | "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n" | 263 | "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n" |
| 260 | "usable=%d\n", | 264 | "usable=%d\n", |
| @@ -432,11 +436,13 @@ static bool config_load() { | |||
| 432 | if (v > 6) v = 6; | 436 | if (v > 6) v = 6; |
| 433 | g.vis_mat = v; | 437 | g.vis_mat = v; |
| 434 | } else if (strcmp(key, "vis_r") == 0 || strcmp(key, "vis_g") == 0 || | 438 | } else if (strcmp(key, "vis_r") == 0 || strcmp(key, "vis_g") == 0 || |
| 435 | strcmp(key, "vis_b") == 0) { | 439 | strcmp(key, "vis_b") == 0 || strcmp(key, "vis_a") == 0) { |
| 436 | int v = atoi(val); | 440 | int v = atoi(val); |
| 437 | if (v < 0) v = 0; | 441 | if (v < 0) v = 0; |
| 438 | if (v > 255) v = 255; | 442 | if (v > 255) v = 255; |
| 439 | g.vis_rgb[key[4] == 'r' ? 0 : key[4] == 'g' ? 1 : 2] = v; | 443 | int idx = key[4] == 'r' ? 0 : key[4] == 'g' ? 1 |
| 444 | : key[4] == 'b' ? 2 : 3; | ||
| 445 | g.vis_rgb[idx] = v; | ||
| 440 | } else if (strcmp(key, "inv") == 0) | 446 | } else if (strcmp(key, "inv") == 0) |
| 441 | g.inv_on = atoi(val) != 0; | 447 | g.inv_on = atoi(val) != 0; |
| 442 | else if (strcmp(key, "inv_mat") == 0) { | 448 | else if (strcmp(key, "inv_mat") == 0) { |
| @@ -445,11 +451,13 @@ static bool config_load() { | |||
| 445 | if (v > 6) v = 6; | 451 | if (v > 6) v = 6; |
| 446 | g.inv_mat = v; | 452 | g.inv_mat = v; |
| 447 | } else if (strcmp(key, "inv_r") == 0 || strcmp(key, "inv_g") == 0 || | 453 | } else if (strcmp(key, "inv_r") == 0 || strcmp(key, "inv_g") == 0 || |
| 448 | strcmp(key, "inv_b") == 0) { | 454 | strcmp(key, "inv_b") == 0 || strcmp(key, "inv_a") == 0) { |
| 449 | int v = atoi(val); | 455 | int v = atoi(val); |
| 450 | if (v < 0) v = 0; | 456 | if (v < 0) v = 0; |
| 451 | if (v > 255) v = 255; | 457 | if (v > 255) v = 255; |
| 452 | g.inv_rgb[key[4] == 'r' ? 0 : key[4] == 'g' ? 1 : 2] = v; | 458 | int idx = key[4] == 'r' ? 0 : key[4] == 'g' ? 1 |
| 459 | : key[4] == 'b' ? 2 : 3; | ||
| 460 | g.inv_rgb[idx] = v; | ||
| 453 | } | 461 | } |
| 454 | } | 462 | } |
| 455 | if (in_chams_vm) { | 463 | if (in_chams_vm) { |
| @@ -461,11 +469,13 @@ static bool config_load() { | |||
| 461 | if (v > 6) v = 6; | 469 | if (v > 6) v = 6; |
| 462 | g_chams_vm_mat = v; | 470 | g_chams_vm_mat = v; |
| 463 | } else if (strcmp(key, "r") == 0 || strcmp(key, "g") == 0 || | 471 | } else if (strcmp(key, "r") == 0 || strcmp(key, "g") == 0 || |
| 464 | strcmp(key, "b") == 0) { | 472 | strcmp(key, "b") == 0 || strcmp(key, "a") == 0) { |
| 465 | int v = atoi(val); | 473 | int v = atoi(val); |
| 466 | if (v < 0) v = 0; | 474 | if (v < 0) v = 0; |
| 467 | if (v > 255) v = 255; | 475 | if (v > 255) v = 255; |
| 468 | g_chams_vm_rgb[key[0] == 'r' ? 0 : key[0] == 'g' ? 1 : 2] = v; | 476 | int idx = key[0] == 'r' ? 0 : key[0] == 'g' ? 1 |
| 477 | : key[0] == 'b' ? 2 : 3; | ||
| 478 | g_chams_vm_rgb[idx] = v; | ||
| 469 | } | 479 | } |
| 470 | } | 480 | } |
| 471 | if (in_aim) { | 481 | if (in_aim) { |
| @@ -693,14 +703,18 @@ void config_reset_defaults() { | |||
| 693 | g_proj_fuse = true; | 703 | g_proj_fuse = true; |
| 694 | g_proj_radius = true; | 704 | g_proj_radius = true; |
| 695 | g_chams = {false, 0}; | 705 | g_chams = {false, 0}; |
| 696 | g_chams_hostile = {true, 3, {255, 60, 60}, true, 3, {255, 60, 60}}; | 706 | g_chams_hostile = {true, 3, {255, 60, 60, 255}, true, 3, |
| 697 | g_chams_neutral = {true, 3, {220, 220, 220}, false, 3, {220, 220, 220}}; | 707 | {255, 60, 60, 255}}; |
| 698 | g_chams_friendly = {true, 3, {60, 255, 60}, false, 3, {60, 255, 60}}; | 708 | g_chams_neutral = {true, 3, {220, 220, 220, 255}, false, 3, |
| 709 | {220, 220, 220, 255}}; | ||
| 710 | g_chams_friendly = {true, 3, {60, 255, 60, 255}, false, 3, | ||
| 711 | {60, 255, 60, 255}}; | ||
| 699 | g_chams_viewmodel = false; | 712 | g_chams_viewmodel = false; |
| 700 | g_chams_vm_mat = 3; | 713 | g_chams_vm_mat = 3; |
| 701 | g_chams_vm_rgb[0] = 200; | 714 | g_chams_vm_rgb[0] = 200; |
| 702 | g_chams_vm_rgb[1] = 200; | 715 | g_chams_vm_rgb[1] = 200; |
| 703 | g_chams_vm_rgb[2] = 255; | 716 | g_chams_vm_rgb[2] = 255; |
| 717 | g_chams_vm_rgb[3] = 255; | ||
| 704 | g_item_health = true; | 718 | g_item_health = true; |
| 705 | g_item_ammo = true; | 719 | g_item_ammo = true; |
| 706 | g_item_armor = true; | 720 | g_item_armor = true; |
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 | ||
| 251 | void 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 | |||
| 251 | void chams_apply(void *mat, bool ignorez, int style, bool force_white, | 260 | void 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, | |||
| 270 | void chams_reset(void *mat) { | 281 | void 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 | ||
| 281 | void hkdModelExecute(void *self, const void *state, const void *info, | 294 | void 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); |
