summaryrefslogtreecommitdiffstats
path: root/src/studio.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/studio.cpp178
1 files changed, 178 insertions, 0 deletions
diff --git a/src/studio.cpp b/src/studio.cpp
new file mode 100644
index 0000000..dd6f109
--- /dev/null
+++ b/src/studio.cpp
@@ -0,0 +1,178 @@
1// studio.cpp — colour static props at the StudioRender level.
2//
3// Dynamic props are tinted through their client entity's m_clrRender (see
4// esp.cpp). Map-static props have no entity: the engine's static-prop manager
5// calls IStudioRender::DrawModelStaticProp, and the colour modulation used for
6// the draw comes from IStudioRender::SetColorModulation. Hook both on the
7// interface object so the prop colour is substituted only while a prop model
8// is being drawn.
9//
10// VStudioRender025 vtable (verified against studiorender.so's
11// CStudioRenderContext vtable at .data.rel.ro):
12// 27 = SetColorModulation(float const*)
13// 28 = SetAlphaModulation(float)
14// 30 = DrawModelStaticProp(const DrawModelInfo_t&, const matrix3x4_t&, int)
15// (The 2013 SDK header lists these five slots earlier; this build's layout
16// has additional methods before them.)
17
18#include "hl2h.h"
19#include <cstdio>
20#include <cstring>
21#include <dlfcn.h>
22
23namespace {
24
25using SetColorFn = void (*)(void *, const float *);
26using SetAlphaFn = void (*)(void *, float);
27using DrawStaticFn = void (*)(void *, void *, void *, int);
28
29SetColorFn g_orig_set_color = nullptr;
30SetAlphaFn g_orig_set_alpha = nullptr;
31DrawStaticFn g_orig_draw_static = nullptr;
32
33bool g_install_tried = false;
34bool g_installed = false;
35int g_prop_depth = 0;
36
37bool prop_tint_on() {
38 return feature_active(FEAT_WORLD_TINT) && g_tint_prop_on;
39}
40
41void prop_color(float out[4]) {
42 out[0] = (float)g_tint_prop_rgb[0] / 255.0f;
43 out[1] = (float)g_tint_prop_rgb[1] / 255.0f;
44 out[2] = (float)g_tint_prop_rgb[2] / 255.0f;
45 out[3] = 1.0f;
46}
47
48// DrawModelInfo_t starts with studiohdr_t*; studiohdr_t::name is at +12
49// (id, version, checksum, then char name[64]).
50const char *info_model_name(void *info) {
51 if (!info)
52 return nullptr;
53 void *hdr = *(void **)info;
54 if (!hdr)
55 return nullptr;
56 const char *name = (const char *)hdr + 12;
57 size_t n = strnlen(name, 128);
58 if (n < 7 || n >= 128)
59 return nullptr;
60 for (size_t i = 0; i < n; i++) {
61 unsigned char c = (unsigned char)name[i];
62 if (c < 0x20 || c > 0x7e)
63 return nullptr;
64 }
65 return name;
66}
67
68bool is_prop_model(const char *name) {
69 return name && strncmp(name, "models/props", 12) == 0;
70}
71
72void hook_set_color(void *self, const float *color) {
73 if (g_prop_depth > 0 && prop_tint_on()) {
74 float c[4];
75 prop_color(c);
76 g_orig_set_color(self, c);
77 return;
78 }
79 g_orig_set_color(self, color);
80}
81
82void hook_set_alpha(void *self, float alpha) {
83 if (g_prop_depth > 0 && prop_tint_on()) {
84 g_orig_set_alpha(self, 1.0f);
85 return;
86 }
87 g_orig_set_alpha(self, alpha);
88}
89
90void hook_draw_static_prop(void *self, void *info, void *model_to_world,
91 int flags) {
92 bool prop = prop_tint_on() && is_prop_model(info_model_name(info));
93 if (prop) {
94 // The engine may have set the modulation just before this call; override
95 // it here as well as from the SetColorModulation hook (the static-prop
96 // renderer can call it either side of DrawModelStaticProp).
97 float c[4];
98 prop_color(c);
99 g_orig_set_color(self, c);
100 g_orig_set_alpha(self, 1.0f);
101 g_prop_depth++;
102 }
103 g_orig_draw_static(self, info, model_to_world, flags);
104 if (prop)
105 g_prop_depth--;
106}
107
108std::string loaded_module_path(const char *needle) {
109 FILE *maps = fopen("/proc/self/maps", "r");
110 if (!maps)
111 return {};
112 char line[1024];
113 std::string found;
114 while (fgets(line, sizeof(line), maps)) {
115 char *p = strchr(line, '/');
116 if (!p)
117 continue;
118 size_t pl = strlen(p);
119 while (pl && (p[pl - 1] == '\n' || p[pl - 1] == '\r'))
120 p[--pl] = 0;
121 if (!strstr(p, needle) || !strstr(p, ".so"))
122 continue;
123 found = p;
124 if (!strstr(p, "(deleted)"))
125 break;
126 }
127 fclose(maps);
128 return found;
129}
130
131} // namespace
132
133void studio_props_init() {
134 if (g_install_tried)
135 return;
136 g_install_tried = true;
137
138 std::string path = loaded_module_path("studiorender");
139 void *h = nullptr;
140 if (!path.empty())
141 h = dlopen(path.c_str(), RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
142 if (!h)
143 h = dlopen("studiorender.so", RTLD_NOLOAD | RTLD_LAZY | RTLD_GLOBAL);
144 if (!h) {
145 logf("studio: studiorender.so not loaded");
146 return;
147 }
148 auto cf = (CreateInterfaceFn)dlsym(h, "CreateInterface");
149 if (!cf) {
150 logf("studio: studiorender CreateInterface missing");
151 return;
152 }
153 void *sr = cf("VStudioRender025", nullptr);
154 if (!sr) {
155 logf("studio: VStudioRender025 not exposed");
156 return;
157 }
158
159 void **old_vt = *(void ***)sr;
160 if (!old_vt) {
161 logf("studio: interface has no vtable");
162 return;
163 }
164 static void *vt[49];
165 memcpy(vt, old_vt, sizeof(vt));
166
167 g_orig_set_color = (SetColorFn)vt[27];
168 g_orig_set_alpha = (SetAlphaFn)vt[28];
169 g_orig_draw_static = (DrawStaticFn)vt[30];
170 vt[27] = (void *)&hook_set_color;
171 vt[28] = (void *)&hook_set_alpha;
172 vt[30] = (void *)&hook_draw_static_prop;
173
174 *(void ***)sr = vt;
175 g_installed = true;
176 logf("studio: IStudioRender %p hooked (setcolor=%p drawstatic=%p)", sr,
177 (void *)g_orig_set_color, (void *)g_orig_draw_static);
178}