summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/gui.cpp20
-rw-r--r--src/hl2h.cpp1
-rw-r--r--src/hl2h.h10
-rw-r--r--src/menu.cpp45
-rw-r--r--src/world.cpp248
5 files changed, 320 insertions, 4 deletions
diff --git a/src/gui.cpp b/src/gui.cpp
index 3f1651d..9d27a09 100644
--- a/src/gui.cpp
+++ b/src/gui.cpp
@@ -375,6 +375,26 @@ static void build_cards() {
375 add_card(2, &g_fullbright, "Fullbright", 375 add_card(2, &g_fullbright, "Fullbright",
376 "Ignore world lighting so dark areas are visible.", true); 376 "Ignore world lighting so dark areas are visible.", true);
377 377
378 int tint = add_card(2, &g_world_tint, "World tint",
379 "Multiply world and skybox material colour. "
380 "Independent of Fullbright lighting.", true);
381 add_toggle(tint, "World brushes",
382 "Tint world textures (sky and water excluded from this part).",
383 &g_tint_world_on);
384 add_slider(tint, "World red", "Red channel of the world tint (0-255).", 0,
385 255, &g_tint_world_rgb[0]);
386 add_slider(tint, "World green", "Green channel of the world tint (0-255).", 0,
387 255, &g_tint_world_rgb[1]);
388 add_slider(tint, "World blue", "Blue channel of the world tint (0-255).", 0,
389 255, &g_tint_world_rgb[2]);
390 add_toggle(tint, "Skybox", "Tint the skybox textures.", &g_tint_sky_on);
391 add_slider(tint, "Sky red", "Red channel of the sky tint (0-255).", 0, 255,
392 &g_tint_sky_rgb[0]);
393 add_slider(tint, "Sky green", "Green channel of the sky tint (0-255).", 0,
394 255, &g_tint_sky_rgb[1]);
395 add_slider(tint, "Sky blue", "Blue channel of the sky tint (0-255).", 0, 255,
396 &g_tint_sky_rgb[2]);
397
378 int spread = add_card(3, &g_spread, "Spread control", 398 int spread = add_card(3, &g_spread, "Spread control",
379 "Choose a server shot seed that tightens the cone.", 399 "Choose a server shot seed that tightens the cone.",
380 true); 400 true);
diff --git a/src/hl2h.cpp b/src/hl2h.cpp
index 375cd5a..dfe4e57 100644
--- a/src/hl2h.cpp
+++ b/src/hl2h.cpp
@@ -584,6 +584,7 @@ static void do_move(int seq, float frametime) {
584 aimbot_reset_lock(); 584 aimbot_reset_lock();
585 silentaim_reset_lock(); 585 silentaim_reset_lock();
586 fullbright_invalidate(); 586 fullbright_invalidate();
587 world_tint_invalidate();
587 } 588 }
588 589
589 if (feature_active(FEAT_SPREAD)) { 590 if (feature_active(FEAT_SPREAD)) {
diff --git a/src/hl2h.h b/src/hl2h.h
index 2824d3c..e90ba91 100644
--- a/src/hl2h.h
+++ b/src/hl2h.h
@@ -178,7 +178,8 @@ enum FeatureId {
178 FEAT_SPREAD = 8, 178 FEAT_SPREAD = 8,
179 FEAT_ITEM_ESP = 9, 179 FEAT_ITEM_ESP = 9,
180 FEAT_FULLBRIGHT = 10, 180 FEAT_FULLBRIGHT = 10,
181 FEAT_COUNT = 11 181 FEAT_WORLD_TINT = 11,
182 FEAT_COUNT = 12
182}; 183};
183enum EspOption { 184enum EspOption {
184 ESP_OPT_SHOW_NEUTRAL = 0, 185 ESP_OPT_SHOW_NEUTRAL = 0,
@@ -210,7 +211,10 @@ struct FeatureState {
210}; 211};
211 212
212extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp, 213extern FeatureState g_bhop, g_abh, g_jumpbug, g_melee, g_spread, g_esp,
213 g_aimbot, g_triggerbot, g_silentaim, g_item_esp, g_fullbright; 214 g_aimbot, g_triggerbot, g_silentaim, g_item_esp, g_fullbright,
215 g_world_tint;
216extern bool g_tint_world_on, g_tint_sky_on;
217extern int g_tint_world_rgb[3], g_tint_sky_rgb[3];
214extern bool g_bhop_autostrafe; 218extern bool g_bhop_autostrafe;
215extern bool g_jumpbug_assist; 219extern bool g_jumpbug_assist;
216extern bool g_spread_no_spread; 220extern bool g_spread_no_spread;
@@ -248,6 +252,8 @@ void resolve_netvars();
248bool cvar_set_int(const char *name, int value); 252bool cvar_set_int(const char *name, int value);
249void fullbright_update(); 253void fullbright_update();
250void fullbright_invalidate(); 254void fullbright_invalidate();
255void world_tint_update();
256void world_tint_invalidate();
251bool resolve_server_netvars(); 257bool resolve_server_netvars();
252int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out); 258int server_entity_health(int idx, int *maxhealth, int *lifestate, void **base_out);
253bool server_set_velocity_z(int idx, float vz); 259bool server_set_velocity_z(int idx, float vz);
diff --git a/src/menu.cpp b/src/menu.cpp
index 9a249f8..6a7ffe5 100644
--- a/src/menu.cpp
+++ b/src/menu.cpp
@@ -46,6 +46,11 @@ FeatureState g_triggerbot{true, 603}; // default Mouse4
46FeatureState g_silentaim{true, 602}; // default Mouse3 46FeatureState g_silentaim{true, 602}; // default Mouse3
47FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default 47FeatureState g_item_esp{true, 0}; // valuable item tags, always-on by default
48FeatureState g_fullbright{false, 0}; // mat_fullbright world lighting 48FeatureState g_fullbright{false, 0}; // mat_fullbright world lighting
49FeatureState g_world_tint{false, 0}; // material colour modulation
50bool g_tint_world_on = true;
51bool g_tint_sky_on = true;
52int g_tint_world_rgb[3] = {255, 255, 255};
53int g_tint_sky_rgb[3] = {255, 255, 255};
49bool g_item_health = true; 54bool g_item_health = true;
50bool g_item_ammo = true; 55bool g_item_ammo = true;
51bool g_item_armor = true; 56bool g_item_armor = true;
@@ -187,6 +192,12 @@ void config_save() {
187 g_silentaim.bind, g_silent_fov); 192 g_silentaim.bind, g_silent_fov);
188 fprintf(f, "[fullbright]\nactive=%d\nbind=%d\n", g_fullbright.active, 193 fprintf(f, "[fullbright]\nactive=%d\nbind=%d\n", g_fullbright.active,
189 g_fullbright.bind); 194 g_fullbright.bind);
195 fprintf(f, "[worldtint]\nactive=%d\nbind=%d\nworld=%d\nsky=%d\n"
196 "wr=%d\nwg=%d\nwb=%d\nsr=%d\nsg=%d\nsb=%d\n",
197 g_world_tint.active, g_world_tint.bind, (int)g_tint_world_on,
198 (int)g_tint_sky_on, g_tint_world_rgb[0], g_tint_world_rgb[1],
199 g_tint_world_rgb[2], g_tint_sky_rgb[0], g_tint_sky_rgb[1],
200 g_tint_sky_rgb[2]);
190 fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n" 201 fprintf(f, "[items]\nactive=%d\nbind=%d\nhealth=%d\nammo=%d\n"
191 "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n", 202 "armor=%d\nweapons=%d\ncrates=%d\ndistance=%d\nmax_dist=%d\n",
192 g_item_esp.active, g_item_esp.bind, (int)g_item_health, 203 g_item_esp.active, g_item_esp.bind, (int)g_item_health,
@@ -220,7 +231,8 @@ static bool config_load() {
220 char line[256]; 231 char line[256];
221 FeatureState *cur = nullptr; 232 FeatureState *cur = nullptr;
222 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false, 233 bool in_esp = false, in_bhop = false, in_aim = false, in_silent = false,
223 in_jumpbug = false, in_spread = false, in_items = false; 234 in_jumpbug = false, in_spread = false, in_items = false,
235 in_tint = false;
224 while (fgets(line, sizeof(line), f)) { 236 while (fgets(line, sizeof(line), f)) {
225 line[strcspn(line, "\r\n")] = 0; 237 line[strcspn(line, "\r\n")] = 0;
226 if (line[0] == '[') { 238 if (line[0] == '[') {
@@ -240,6 +252,8 @@ static bool config_load() {
240 cur = &g_item_esp; 252 cur = &g_item_esp;
241 else if (strstr(line, "[fullbright]")) 253 else if (strstr(line, "[fullbright]"))
242 cur = &g_fullbright; 254 cur = &g_fullbright;
255 else if (strstr(line, "[worldtint]"))
256 cur = &g_world_tint;
243 else if (strstr(line, "[aimbot]")) 257 else if (strstr(line, "[aimbot]"))
244 cur = &g_aimbot; 258 cur = &g_aimbot;
245 else if (strstr(line, "[triggerbot]")) 259 else if (strstr(line, "[triggerbot]"))
@@ -255,6 +269,7 @@ static bool config_load() {
255 in_jumpbug = (cur == &g_jumpbug); 269 in_jumpbug = (cur == &g_jumpbug);
256 in_spread = (cur == &g_spread); 270 in_spread = (cur == &g_spread);
257 in_items = (cur == &g_item_esp); 271 in_items = (cur == &g_item_esp);
272 in_tint = (cur == &g_world_tint);
258 } else if (cur) { 273 } else if (cur) {
259 char *eq = strchr(line, '='); 274 char *eq = strchr(line, '=');
260 if (!eq) 275 if (!eq)
@@ -325,6 +340,25 @@ static bool config_load() {
325 if (v > 180) v = 180; 340 if (v > 180) v = 180;
326 g_silent_fov = v; 341 g_silent_fov = v;
327 } 342 }
343 if (in_tint) {
344 if (strcmp(key, "world") == 0)
345 g_tint_world_on = atoi(val) != 0;
346 else if (strcmp(key, "sky") == 0)
347 g_tint_sky_on = atoi(val) != 0;
348 else if (strcmp(key, "wr") == 0 || strcmp(key, "wg") == 0 ||
349 strcmp(key, "wb") == 0) {
350 int v = atoi(val);
351 if (v < 0) v = 0;
352 if (v > 255) v = 255;
353 g_tint_world_rgb[key[1] == 'r' ? 0 : key[1] == 'g' ? 1 : 2] = v;
354 } else if (strcmp(key, "sr") == 0 || strcmp(key, "sg") == 0 ||
355 strcmp(key, "sb") == 0) {
356 int v = atoi(val);
357 if (v < 0) v = 0;
358 if (v > 255) v = 255;
359 g_tint_sky_rgb[key[1] == 'r' ? 0 : key[1] == 'g' ? 1 : 2] = v;
360 }
361 }
328 if (in_esp) { 362 if (in_esp) {
329 if (strcmp(key, "neutral") == 0) 363 if (strcmp(key, "neutral") == 0)
330 g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0; 364 g_esp_opt[ESP_OPT_SHOW_NEUTRAL] = atoi(val) != 0;
@@ -378,6 +412,11 @@ void config_reset_defaults() {
378 g_esp_opt[i] = true; 412 g_esp_opt[i] = true;
379 g_item_esp = {true, 0}; 413 g_item_esp = {true, 0};
380 g_fullbright = {false, 0}; 414 g_fullbright = {false, 0};
415 g_world_tint = {false, 0};
416 g_tint_world_on = true;
417 g_tint_sky_on = true;
418 g_tint_world_rgb[0] = g_tint_world_rgb[1] = g_tint_world_rgb[2] = 255;
419 g_tint_sky_rgb[0] = g_tint_sky_rgb[1] = g_tint_sky_rgb[2] = 255;
381 g_item_health = true; 420 g_item_health = true;
382 g_item_ammo = true; 421 g_item_ammo = true;
383 g_item_armor = true; 422 g_item_armor = true;
@@ -495,7 +534,7 @@ static FeatureState *feature_state(int feature) {
495 static FeatureState *feats[FEAT_COUNT] = { 534 static FeatureState *feats[FEAT_COUNT] = {
496 &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot, 535 &g_bhop, &g_abh, &g_esp, &g_aimbot, &g_triggerbot,
497 &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_item_esp, 536 &g_silentaim, &g_jumpbug, &g_melee, &g_spread, &g_item_esp,
498 &g_fullbright}; 537 &g_fullbright, &g_world_tint};
499 if (feature < 0 || feature >= FEAT_COUNT) 538 if (feature < 0 || feature >= FEAT_COUNT)
500 return nullptr; 539 return nullptr;
501 return feats[feature]; 540 return feats[feature];
@@ -701,6 +740,7 @@ void fullbright_update() {
701void outer_draw() { 740void outer_draw() {
702 poll_keyboard(); 741 poll_keyboard();
703 fullbright_update(); 742 fullbright_update();
743 world_tint_update();
704 gui_handle_input(); 744 gui_handle_input();
705 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open 745 // HL2H_DRAW_TEST=1 draws a probe rect without needing the GUI open
706 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr; 746 static bool draw_test = getenv("HL2H_DRAW_TEST") != nullptr;
@@ -721,6 +761,7 @@ void outer_draw() {
721 if (le != last_local) { 761 if (le != last_local) {
722 last_local = le; 762 last_local = le;
723 font_reset = true; 763 font_reset = true;
764 world_tint_invalidate();
724 } 765 }
725 } 766 }
726 if (font_reset && g_font) { 767 if (font_reset && g_font) {
diff --git a/src/world.cpp b/src/world.cpp
new file mode 100644
index 0000000..eeffb99
--- /dev/null
+++ b/src/world.cpp
@@ -0,0 +1,248 @@
1// world.cpp — world/sky material colour modulation.
2//
3// Same mechanism Amalgam uses for its "World modulation": walk every material
4// in the material system and call IMaterial::ColorModulate on the ones whose
5// texture group is the world (or the skybox). This multiplies the material's
6// albedo; it does not touch lightmaps, so it is cheap and does not recompile
7// shaders.
8//
9// HL2's materialsystem.so registers "VMaterialSystem080" (the SDK 2013 name
10// for the modern layout) and exports CreateInterface, so the interface is
11// obtained exactly like VClient017/VGUI_Surface030 elsewhere in this cheat.
12//
13// Vtable slots are taken from the 2013 SDK headers:
14// IMaterialSystem: FirstMaterial=73 NextMaterial=74 InvalidMaterial=75
15// GetMaterial=76 GetNumMaterials=77
16// IMaterial: GetName=0 GetTextureGroupName=1 ColorModulate=28
17
18#include "hl2h.h"
19#include <cstdio>
20#include <cstdlib>
21#include <cstring>
22#include <dlfcn.h>
23
24namespace {
25
26constexpr int MATSYS_FirstMaterial = 73;
27constexpr int MATSYS_NextMaterial = 74;
28constexpr int MATSYS_InvalidMaterial = 75;
29constexpr int MATSYS_GetMaterial = 76;
30constexpr int MATSYS_GetNumMaterials = 77;
31
32constexpr int MAT_GetName = 0;
33constexpr int MAT_GetTextureGroupName = 1;
34constexpr int MAT_ColorModulate = 28;
35
36constexpr const char *GROUP_WORLD = "World textures";
37constexpr const char *GROUP_SKYBOX = "SkyBox textures";
38
39void *g_matsys = nullptr;
40bool g_matsys_tried = false;
41bool g_matsys_failed = false;
42bool g_matsys_logged = false;
43
44// Last state handed to the material system. Colour changes are applied when
45// this differs from the desired state, so the all-material walk runs only on
46// toggles/colour edits/level changes, never every frame.
47struct Tint {
48 bool valid;
49 int world_r, world_g, world_b;
50 int sky_r, sky_g, sky_b;
51};
52Tint g_applied{false, 255, 255, 255, 255, 255, 255};
53
54struct MatCalls {
55 using FirstFn = unsigned short (*)(void *);
56 using NextFn = unsigned short (*)(void *, unsigned short);
57 using InvalidFn = unsigned short (*)(void *);
58 using GetFn = void *(*)(void *, unsigned short);
59 using CountFn = int (*)(void *);
60 using NameFn = const char *(*)(void *);
61 using GroupFn = const char *(*)(void *);
62 using ModulateFn = void (*)(void *, float, float, float);
63};
64
65// Reject obviously bogus strings returned by a mis-mapped vtable slot instead
66// of walking thousands of materials with garbage pointers.
67bool plausible_name(const char *s) {
68 if (!s || !*s)
69 return false;
70 size_t n = strnlen(s, 512);
71 if (n == 0 || n >= 512)
72 return false;
73 for (size_t i = 0; i < n; i++) {
74 unsigned char c = (unsigned char)s[i];
75 if (c < 0x20 || c == 0x7f)
76 return false;
77 }
78 return true;
79}
80
81std::string find_loaded_module(const char *needle) {
82 FILE *maps = fopen("/proc/self/maps", "r");
83 if (!maps)
84 return {};
85 char line[1024];
86 std::string found;
87 while (fgets(line, sizeof(line), maps)) {
88 char *p = strchr(line, '/');
89 if (!p)
90 continue;
91 size_t pl = strlen(p);
92 while (pl && (p[pl - 1] == '\n' || p[pl - 1] == '\r'))
93 p[--pl] = 0;
94 if (!strstr(p, needle) || !strstr(p, ".so"))
95 continue;
96 found = p;
97 if (!strstr(p, "(deleted)"))
98 break;
99 }
100 fclose(maps);
101 return found;
102}
103
104void *material_system() {
105 if (g_matsys_tried)
106 return g_matsys;
107 g_matsys_tried = true;
108
109 std::string path = find_loaded_module("materialsystem");
110 void *h = nullptr;
111 if (!path.empty())
112 h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
113 // The engine always dlopens the module by name; NOLOAD only attaches to the
114 // already-mapped copy, so we never spawn a second material system.
115 if (!h)
116 h = dlopen("materialsystem.so", RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
117 if (!h) {
118 g_matsys_failed = true;
119 logf("tint: materialsystem.so not loaded");
120 return nullptr;
121 }
122 auto cf = (CreateInterfaceFn)dlsym(h, "CreateInterface");
123 if (!cf) {
124 g_matsys_failed = true;
125 logf("tint: materialsystem CreateInterface missing");
126 return nullptr;
127 }
128 static const char *names[] = {"VMaterialSystem080", "VMaterialSystem082",
129 "VMaterialSystem081", nullptr};
130 for (const char **n = names; *n; n++) {
131 int ret = 0;
132 void *ms = cf(*n, &ret);
133 if (!ms)
134 continue;
135 g_matsys = ms;
136 logf("tint: %s = %p via %s", *n, ms,
137 path.empty() ? "materialsystem.so" : path.c_str());
138 return ms;
139 }
140 g_matsys_failed = true;
141 logf("tint: material system interface not exposed");
142 return nullptr;
143}
144
145// Push one colour pair over all materials. Groups that are off get white so a
146// previously tinted world is restored.
147bool apply_tint(int world_r, int world_g, int world_b, int sky_r, int sky_g,
148 int sky_b) {
149 void *ms = material_system();
150 if (!ms)
151 return false;
152
153 auto invalid = vfunc<MatCalls::InvalidFn>(ms, MATSYS_InvalidMaterial);
154 auto first = vfunc<MatCalls::FirstFn>(ms, MATSYS_FirstMaterial);
155 auto next = vfunc<MatCalls::NextFn>(ms, MATSYS_NextMaterial);
156 auto get = vfunc<MatCalls::GetFn>(ms, MATSYS_GetMaterial);
157 auto count = vfunc<MatCalls::CountFn>(ms, MATSYS_GetNumMaterials);
158
159 int total = count(ms);
160 if (total <= 0 || total > 200000) {
161 logf("tint: GetNumMaterials() = %d (unexpected; disabled)", total);
162 g_matsys_failed = true;
163 toastf(TOAST_ERROR, "World tint: material system layout mismatch");
164 return false;
165 }
166
167 float wr = world_r / 255.0f, wg = world_g / 255.0f, wb = world_b / 255.0f;
168 float sr = sky_r / 255.0f, sg = sky_g / 255.0f, sb = sky_b / 255.0f;
169
170 unsigned short inv = invalid(ms);
171 int seen = 0, world_hits = 0, sky_hits = 0;
172 for (unsigned short h = first(ms); h != inv; h = next(ms, h)) {
173 if (++seen > total + 16) {
174 logf("tint: material walk runaway (%d > %d); stopped", seen, total);
175 break;
176 }
177 void *mat = get(ms, h);
178 if (!mat)
179 continue;
180 auto name_fn = vfunc<MatCalls::NameFn>(mat, MAT_GetName);
181 auto group_fn = vfunc<MatCalls::GroupFn>(mat, MAT_GetTextureGroupName);
182 auto mod_fn = vfunc<MatCalls::ModulateFn>(mat, MAT_ColorModulate);
183 const char *name = name_fn(mat);
184 const char *group = group_fn(mat);
185 if (!plausible_name(name) || !plausible_name(group))
186 continue;
187 // The first material's name also validates the IMaterial vtable mapping
188 // before we poke any colour state.
189 if (!g_matsys_logged) {
190 g_matsys_logged = true;
191 logf("tint: first material \"%s\" group \"%s\"", name, group);
192 }
193 bool is_world = strncmp(group, GROUP_WORLD, strlen(GROUP_WORLD)) == 0;
194 bool is_sky = strncmp(group, GROUP_SKYBOX, strlen(GROUP_SKYBOX)) == 0 ||
195 strstr(name, "sky") != nullptr;
196 if (is_world && !strstr(name, "sky")) {
197 mod_fn(mat, wr, wg, wb);
198 world_hits++;
199 } else if (is_sky) {
200 mod_fn(mat, sr, sg, sb);
201 sky_hits++;
202 }
203 }
204 logf("tint: applied world=%d(%d,%d,%d) sky=%d(%d,%d,%d) of %d materials",
205 world_hits, world_r, world_g, world_b, sky_hits, sky_r, sky_g, sky_b,
206 total);
207 return true;
208}
209
210} // namespace
211
212void world_tint_invalidate() { g_applied.valid = false; }
213
214void world_tint_update() {
215 bool on = feature_active(FEAT_WORLD_TINT);
216 bool world_on = on && g_tint_world_on;
217 bool sky_on = on && g_tint_sky_on;
218
219 int wr = world_on ? g_tint_world_rgb[0] : 255;
220 int wg = world_on ? g_tint_world_rgb[1] : 255;
221 int wb = world_on ? g_tint_world_rgb[2] : 255;
222 int sr = sky_on ? g_tint_sky_rgb[0] : 255;
223 int sg = sky_on ? g_tint_sky_rgb[1] : 255;
224 int sb = sky_on ? g_tint_sky_rgb[2] : 255;
225
226 bool white = wr == 255 && wg == 255 && wb == 255 && sr == 255 &&
227 sg == 255 && sb == 255;
228 if (g_applied.valid && g_applied.world_r == wr && g_applied.world_g == wg &&
229 g_applied.world_b == wb && g_applied.sky_r == sr &&
230 g_applied.sky_g == sg && g_applied.sky_b == sb)
231 return;
232 // Nothing was ever tinted and nothing is requested: no need to walk the
233 // material list just to write white over white.
234 if (!g_applied.valid && white) {
235 g_applied = {true, wr, wg, wb, sr, sg, sb};
236 return;
237 }
238 if (g_matsys_failed && !world_on && !sky_on) {
239 g_applied = {true, wr, wg, wb, sr, sg, sb};
240 return;
241 }
242 if (!apply_tint(wr, wg, wb, sr, sg, sb)) {
243 if (g_matsys_failed)
244 g_applied = {true, wr, wg, wb, sr, sg, sb};
245 return;
246 }
247 g_applied = {true, wr, wg, wb, sr, sg, sb};
248}