Skip to content

Commit e1b7cb8

Browse files
committed
iMorph
1 parent d137d41 commit e1b7cb8

File tree

2 files changed

+322
-2
lines changed

2 files changed

+322
-2
lines changed

src/SB/Core/gc/iMorph.cpp

Lines changed: 308 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,311 @@
11
#include "iMorph.h"
2+
#include "iModel.h"
23

4+
#include "rpusrdat.h"
5+
#include <string.h>
36
#include <types.h>
7+
8+
static RpGeometry* s_geom;
9+
static RpMorphTarget* s_tgt;
10+
static F32* s_alloc;
11+
static F32* s_vTemp;
12+
static F32* s_nTemp;
13+
static S32 s_numV;
14+
15+
static void MorphCommon(RpAtomic* model, RwMatrixTag* mat, S16** v_array, S16* weight, U32 normals,
16+
F32 scale, S32 dorender)
17+
{
18+
S16* va[4];
19+
S16 wa[4];
20+
21+
U32 i;
22+
U32 a = 0;
23+
S32 wsum = 0;
24+
25+
RwV3d* oldVerts = NULL;
26+
27+
RpUserDataArray* usr;
28+
DirtyMorph* dm;
29+
30+
S32 useNormals = 0;
31+
s_geom = model->geometry;
32+
RwV3d* oldNorms = NULL;
33+
s_tgt = s_geom->morphTarget;
34+
s_numV = s_geom->numVertices;
35+
s_alloc = NULL;
36+
s_nTemp = NULL;
37+
38+
if (normals && s_geom->object.flags & 0x10)
39+
{
40+
useNormals = 1;
41+
}
42+
43+
oldVerts = s_tgt->verts;
44+
S32 lockMode = (4 & ((-useNormals | useNormals) >> 0x1F)) | 2;
45+
46+
if (useNormals)
47+
{
48+
oldNorms = s_tgt->normals;
49+
}
50+
51+
for (i = 0; i < 4; i++)
52+
{
53+
if (v_array[i] != NULL && weight[i] != 0)
54+
{
55+
va[a] = v_array[i];
56+
wa[a] = weight[i];
57+
wsum += weight[i];
58+
a++;
59+
}
60+
}
61+
62+
usr = RpGeometryGetUserDataArray(s_geom, 0);
63+
64+
if (usr != NULL)
65+
{
66+
dm = (DirtyMorph*)usr->data;
67+
68+
s_vTemp = (F32*)((U32)((char*)dm + 32) & ~0xF);
69+
70+
if (s_vTemp < (F32*)((char*)dm + 32))
71+
s_vTemp = (F32*)((char*)s_vTemp + 16);
72+
73+
if (s_tgt)
74+
s_tgt->verts = (RwV3d*)s_vTemp;
75+
76+
if (useNormals)
77+
{
78+
U32 vSize = s_numV * 3 * sizeof(F32);
79+
s_nTemp = (F32*)((U32)((char*)s_vTemp + vSize + 15) & ~0xF);
80+
81+
if (s_tgt)
82+
s_tgt->normals = (RwV3d*)s_nTemp;
83+
}
84+
85+
U32 isHit = 0;
86+
87+
if (dm->count == a && dm->weight[0] == wa[0])
88+
{
89+
isHit = 1;
90+
for (i = 0; i < a; ++i)
91+
{
92+
if (dm->weight[i] != wa[i] || dm->v_array[i] != va[i])
93+
{
94+
isHit = 0;
95+
break;
96+
}
97+
}
98+
}
99+
100+
if (isHit)
101+
{
102+
if (dorender)
103+
iModelRender(model, mat);
104+
105+
s_tgt->verts = oldVerts;
106+
if (oldNorms)
107+
s_tgt->normals = oldNorms;
108+
109+
return;
110+
}
111+
112+
dm->count = a;
113+
dm->scale = scale;
114+
115+
for (i = 0; i < a; ++i)
116+
{
117+
dm->weight[i] = wa[i];
118+
dm->v_array[i] = va[i];
119+
}
120+
121+
RpGeometryLock(s_geom, lockMode);
122+
}
123+
124+
if (a == 3)
125+
{
126+
// not sure what's actually going on here
127+
// m2c says:
128+
// spE = 0;
129+
// sp1C = sp18;
130+
dm->v_array[a] = 0;
131+
}
132+
if (usr == NULL)
133+
{
134+
if (s_numV == 0)
135+
{
136+
s_vTemp = NULL;
137+
}
138+
else
139+
{
140+
s_vTemp = (F32*)xMemPushTemp(s_numV * sizeof(RwV3d) + 16);
141+
142+
s_alloc = s_vTemp;
143+
144+
while ((U32)s_vTemp & 0xF)
145+
{
146+
s_vTemp++;
147+
}
148+
}
149+
150+
if (useNormals && s_geom->object.flags & 0x10)
151+
{
152+
if (s_numV == 0)
153+
{
154+
s_nTemp = NULL;
155+
}
156+
else
157+
{
158+
s_nTemp = (F32*)xMemPushTemp(s_numV * sizeof(RwV3d) + 16);
159+
160+
if (s_alloc == 0)
161+
{
162+
s_alloc = s_nTemp;
163+
}
164+
165+
while ((U32)s_nTemp & 0xF)
166+
{
167+
s_nTemp++;
168+
}
169+
}
170+
}
171+
}
172+
173+
if (a == 1)
174+
{
175+
FastS16unpack(s_vTemp, va[0], s_numV * 3, scale * wsum);
176+
}
177+
else if (a == 2)
178+
{
179+
FastS16weight2(s_vTemp, va, wa, s_numV * 3, scale);
180+
}
181+
else
182+
{
183+
FastS16weight4(s_vTemp, va, wa, s_numV * 3, scale);
184+
}
185+
186+
if (s_nTemp != NULL)
187+
{
188+
F32 normScale = 1.0f / (wsum * 16384.0f);
189+
190+
U32 stride = ((s_numV * 3 + 7) * 2) & 0xFFFFFFF0;
191+
192+
for (i = 0; i < a; ++i)
193+
{
194+
va[i] = (S16*)((char*)va[i] + (((s_numV * 3 + 7) * 2) & 0xFFFFFFF0));
195+
}
196+
197+
if (a == 1)
198+
{
199+
FastS16unpack(s_nTemp, va[0], s_numV * 3, normScale * wsum);
200+
}
201+
else if (a == 2)
202+
{
203+
FastS16weight2(s_nTemp, va, wa, s_numV * 3, normScale);
204+
}
205+
else
206+
{
207+
FastS16weight4(s_nTemp, va, wa, s_numV * 3, normScale);
208+
}
209+
}
210+
211+
if (usr != NULL)
212+
{
213+
RpGeometryUnlock(s_geom);
214+
if (dorender)
215+
{
216+
iModelRender(model, mat);
217+
}
218+
s_tgt->verts = oldVerts;
219+
if (useNormals)
220+
{
221+
s_tgt->normals = oldNorms;
222+
}
223+
}
224+
else if (dorender)
225+
{
226+
RpGeometryLock(s_geom, lockMode);
227+
oldVerts = s_tgt->verts;
228+
s_tgt->verts = (RwV3d*)s_vTemp;
229+
if (useNormals)
230+
{
231+
oldNorms = s_tgt->normals;
232+
s_tgt->normals = (RwV3d*)s_nTemp;
233+
}
234+
RpGeometryUnlock(s_geom);
235+
iModelRender(model, mat);
236+
s_tgt->verts = oldVerts;
237+
if (useNormals)
238+
{
239+
s_tgt->normals = oldNorms;
240+
}
241+
}
242+
}
243+
244+
void iMorphOptimize(RpAtomic* model, S32 normals)
245+
{
246+
S32 hasNormals = (normals != 0);
247+
RpGeometry* geom = model->geometry;
248+
249+
if (RpGeometryGetUserDataArrayCount(geom) == 0)
250+
{
251+
S32 numElements = ((hasNormals + 1) * geom->numVertices) * sizeof(RwV3d) + 56;
252+
253+
S32 usridx = RpGeometryAddUserDataArray(geom, "MORPHSTATE", rpINTUSERDATA, numElements);
254+
RpUserDataArray* usr = RpGeometryGetUserDataArray(geom, usridx);
255+
256+
memset(usr->data, 0, 0x20);
257+
}
258+
}
259+
260+
void iMorphRender(RpAtomic* model, RwMatrix* mat, S16** v_array, S16* weight, U32 normals,
261+
F32 scale)
262+
263+
{
264+
MorphCommon(model, mat, v_array, weight, normals, scale, 1);
265+
if (s_alloc != NULL)
266+
{
267+
xMemPopTemp(s_alloc);
268+
s_alloc = NULL;
269+
}
270+
return;
271+
}
272+
273+
void FastS16unpack(F32* dest, S16* v, S32 count, F32 scale)
274+
{
275+
for (S32 i = 0; i < count; i++)
276+
{
277+
dest[i] = v[i] * scale;
278+
}
279+
}
280+
281+
void FastS16weight2(F32* dest, S16** v_array, S16* weight, S32 count, F32 scale)
282+
{
283+
S32 i;
284+
S16* a = v_array[0];
285+
S16* b = v_array[1];
286+
F32 s0 = scale * weight[0];
287+
F32 s1 = scale * weight[1];
288+
289+
for (i = 0; i < count; i++)
290+
{
291+
dest[i] = a[i] * s0 + b[i] * s1;
292+
}
293+
}
294+
295+
void FastS16weight4(F32* dest, S16** v_array, S16* weight, S32 count, F32 scale)
296+
{
297+
S32 i;
298+
S16* a0 = v_array[0];
299+
S16* a1 = v_array[1];
300+
S16* a2 = v_array[2];
301+
S16* a3 = v_array[3];
302+
F32 s0 = scale * weight[0];
303+
F32 s1 = scale * weight[1];
304+
F32 s2 = scale * weight[2];
305+
F32 s3 = scale * weight[3];
306+
307+
for (i = 0; i < count; ++i)
308+
{
309+
dest[i] = a0[i] * s0 + a1[i] * s1 + a2[i] * s2 + a3[i] * s3;
310+
}
311+
}

src/SB/Core/gc/iMorph.h

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,19 @@
66
#include <rwcore.h>
77
#include <rpworld.h>
88

9+
struct DirtyMorph // total size: 0x20
10+
{
11+
U32 count;
12+
F32 scale;
13+
S16 weight[4]; // offset 0x8, size 0x8
14+
S16* v_array[4]; // offset 0x10, size 0x10
15+
};
16+
917
void iMorphOptimize(RpAtomic* model, S32 normals);
10-
void iMorphRender(RpAtomic* model, RwMatrix* mat, S16** v_array, S16* weight, U32 normals, F32 scale);
18+
void iMorphRender(RpAtomic* model, RwMatrix* mat, S16** v_array, S16* weight, U32 normals,
19+
F32 scale);
20+
void FastS16unpack(F32* dest, S16* v, S32 count, F32 scale);
21+
void FastS16weight2(F32* dest, S16** v_array, S16* weight, S32 count, F32 scale);
22+
void FastS16weight4(F32* dest, S16** v_array, S16* weight, S32 count, F32 scale);
1123

12-
#endif
24+
#endif

0 commit comments

Comments
 (0)