summaryrefslogtreecommitdiffstats
path: root/src/studio.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/studio.cpp71
1 files changed, 56 insertions, 15 deletions
diff --git a/src/studio.cpp b/src/studio.cpp
index 3ee6cc5..69a2e07 100644
--- a/src/studio.cpp
+++ b/src/studio.cpp
@@ -68,9 +68,11 @@ const char *info_model_name(void *info) {
68 void *hdr = *(void **)info; 68 void *hdr = *(void **)info;
69 if (!hdr) 69 if (!hdr)
70 return nullptr; 70 return nullptr;
71 // studiohdr_t::name is char[64]; scanning further would read the header's
72 // length/eyeposition fields and could return a bogus "name".
71 const char *name = (const char *)hdr + 12; 73 const char *name = (const char *)hdr + 12;
72 size_t n = strnlen(name, 128); 74 size_t n = strnlen(name, 64);
73 if (n < 7 || n >= 128) 75 if (n < 7 || n >= 64)
74 return nullptr; 76 return nullptr;
75 for (size_t i = 0; i < n; i++) { 77 for (size_t i = 0; i < n; i++) {
76 unsigned char c = (unsigned char)name[i]; 78 unsigned char c = (unsigned char)name[i];
@@ -127,8 +129,13 @@ void hook_draw_model(void *self, void *results, void *info, void *bone,
127 } 129 }
128 g_orig_draw_model(self, results, info, bone, flex, flex_delayed, 130 g_orig_draw_model(self, results, info, bone, flex, flex_delayed,
129 model_origin, flags); 131 model_origin, flags);
130 if (prop) 132 if (prop) {
131 g_prop_depth--; 133 g_prop_depth--;
134 // Don't leave the prop tint bound: models drawn without an explicit
135 // SetColorModulation would inherit it.
136 const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
137 g_orig_set_color(self, white);
138 }
132} 139}
133 140
134void hook_draw_array(void *self, void *info, int count, void *instances, 141void hook_draw_array(void *self, void *info, int count, void *instances,
@@ -158,8 +165,11 @@ void hook_draw_static_prop(void *self, void *info, void *model_to_world,
158 if (prop) 165 if (prop)
159 g_prop_depth++; 166 g_prop_depth++;
160 g_orig_draw_static(self, info, model_to_world, flags); 167 g_orig_draw_static(self, info, model_to_world, flags);
161 if (prop) 168 if (prop) {
162 g_prop_depth--; 169 g_prop_depth--;
170 const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
171 g_orig_set_color(self, white);
172 }
163} 173}
164 174
165std::string loaded_module_path(const char *needle) { 175std::string loaded_module_path(const char *needle) {
@@ -279,7 +289,8 @@ void chams_apply(void *mat, bool ignorez, int style, bool force_white,
279 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5); 289 vfunc<FlagFn>(mat, 29)(mat, 1 << 6 /* SELFILLUM */, style == 5);
280} 290}
281 291
282void chams_reset(void *mat) { using FlagFn = void (*)(void *, int, bool); 292void chams_reset(void *mat) {
293 using FlagFn = void (*)(void *, int, bool);
283 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false); 294 vfunc<FlagFn>(mat, 29)(mat, 1 << 15, false);
284 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false); 295 vfunc<FlagFn>(mat, 29)(mat, 1 << 10, false);
285 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false); 296 vfunc<FlagFn>(mat, 29)(mat, 1 << 28, false);
@@ -288,6 +299,11 @@ void chams_reset(void *mat) { using FlagFn = void (*)(void *, int, bool);
288 vfunc<FlagFn>(mat, 29)(mat, 1 << 6, false); 299 vfunc<FlagFn>(mat, 29)(mat, 1 << 6, false);
289 chams_color(mat, 1.0f, 1.0f, 1.0f); 300 chams_color(mat, 1.0f, 1.0f, 1.0f);
290 chams_alpha(mat, 1.0f); 301 chams_alpha(mat, 1.0f);
302 // AlphaModulate is applied per-entity, separate from $alpha, and was left at
303 // the last chams alpha. Styles 0/3/4/6 share one material, so a translucent
304 // pass permanently half-faded it for every later draw.
305 using AlphaFn = void (*)(void *, float);
306 vfunc<AlphaFn>(mat, 27)(mat, 1.0f);
291} 307}
292 308
293// Model draws take their final alpha from IVRenderView::SetBlend; material 309// Model draws take their final alpha from IVRenderView::SetBlend; material
@@ -310,6 +326,10 @@ void hkdModelExecute(void *self, const void *state, const void *info,
310 void *bone) { 326 void *bone) {
311 if (!g_orig_model_exec) 327 if (!g_orig_model_exec)
312 return; 328 return;
329 if (!init_live()) {
330 g_orig_model_exec(self, state, info, bone);
331 return;
332 }
313 if (feature_active(FEAT_CHAMS) && info && g_force_override) { 333 if (feature_active(FEAT_CHAMS) && info && g_force_override) {
314 // ModelRenderInfo_t::entity_index is at 0x30 on 32-bit. 334 // ModelRenderInfo_t::entity_index is at 0x30 on 32-bit.
315 int idx = *(const int *)((const char *)info + 0x30); 335 int idx = *(const int *)((const char *)info + 0x30);
@@ -497,17 +517,32 @@ void chams_preload() {
497 if (now - last < 1.5) 517 if (now - last < 1.5)
498 return; 518 return;
499 last = now; 519 last = now;
520 using RefFn = void (*)(void *);
500 for (int i = 0; i < 7; i++) { 521 for (int i = 0; i < 7; i++) {
501 if (g_style_mats[i]) 522 if (g_style_mats[i])
502 continue; 523 continue;
503 void *m = world_find_material(chams_material_name(i)); 524 const char *name = chams_material_name(i);
525 // Styles 0/3/4/6 and 2/5 resolve to the same material. Reuse the pointer
526 // and reference it only once instead of incrementing the shared material
527 // up to four times.
528 void *m = nullptr;
529 for (int j = 0; j < 7; j++) {
530 if (g_style_mats[j] && strcmp(chams_material_name(j), name) == 0) {
531 m = g_style_mats[j];
532 break;
533 }
534 }
535 bool fresh = m == nullptr;
536 if (!m)
537 m = world_find_material(name);
504 if (m) { 538 if (m) {
505 // FindMaterial can hand back an unreferenced material; the engine warns 539 // FindMaterial can hand back an unreferenced material; the engine warns
506 // ("bad reference count 0") and may reset its vars when it is bound. 540 // ("bad reference count 0") and may reset its vars when it is bound.
507 using RefFn = void (*)(void *); 541 if (fresh)
508 vfunc<RefFn>(m, 12)(m); // IMaterial::IncrementReferenceCount 542 vfunc<RefFn>(m, 12)(m); // IMaterial::IncrementReferenceCount
509 g_style_mats[i] = m; 543 g_style_mats[i] = m;
510 logf("chams: preloaded style %d %s = %p", i, chams_material_name(i), m); 544 logf("chams: preloaded style %d %s = %p%s", i, name, m,
545 fresh ? "" : " (shared)");
511 } 546 }
512 } 547 }
513 if (!g_style_mats[7]) { 548 if (!g_style_mats[7]) {
@@ -535,14 +570,17 @@ void chams_init() {
535 } 570 }
536 g_force_override = (ForceOverrideFn)vt[1]; 571 g_force_override = (ForceOverrideFn)vt[1];
537 g_orig_model_exec = (ModelExecFn)vt[19]; 572 g_orig_model_exec = (ModelExecFn)vt[19];
538 if (!g_engine.contains((uintptr_t)g_force_override) || 573 if (!mod_engine().contains((uintptr_t)g_force_override) ||
539 !g_engine.contains((uintptr_t)g_orig_model_exec)) { 574 !mod_engine().contains((uintptr_t)g_orig_model_exec)) {
540 logf("chams: implausible vtable entries override=%p draw=%p", 575 logf("chams: implausible vtable entries override=%p draw=%p",
541 (void *)g_force_override, (void *)g_orig_model_exec); 576 (void *)g_force_override, (void *)g_orig_model_exec);
542 return; 577 return;
543 } 578 }
544 static void *nvt[32]; 579 void **nvt = vtable_clone(g_iface.modelrender, 32);
545 memcpy(nvt, vt, sizeof(nvt)); 580 if (!nvt) {
581 logf("chams: vtable clone failed");
582 return;
583 }
546 nvt[19] = (void *)&hkdModelExecute; 584 nvt[19] = (void *)&hkdModelExecute;
547 g_modelrender = g_iface.modelrender; 585 g_modelrender = g_iface.modelrender;
548 *(void ***)g_modelrender = nvt; 586 *(void ***)g_modelrender = nvt;
@@ -581,8 +619,11 @@ void studio_props_init() {
581 logf("studio: interface has no vtable"); 619 logf("studio: interface has no vtable");
582 return; 620 return;
583 } 621 }
584 static void *vt[49]; 622 void **vt = vtable_clone(sr, 49);
585 memcpy(vt, old_vt, sizeof(vt)); 623 if (!vt) {
624 logf("studio: vtable clone failed");
625 return;
626 }
586 627
587 g_orig_set_color = (SetColorFn)vt[27]; 628 g_orig_set_color = (SetColorFn)vt[27];
588 g_orig_set_alpha = (SetAlphaFn)vt[28]; 629 g_orig_set_alpha = (SetAlphaFn)vt[28];