Code:Collision Normals
From CloudModding OoT Wiki
(Redirected from Collision Normals)
MN for the algorithm, JSA for implementing it originally
C
Python code translated to C by spinout.
#include <math.h>
#define U16(a,p) (((a)[p]<<8)|((a)[p+1]))
#define S16(a,p) (signed short)U16(a,p)
void FixCollision(unsigned char * data, int vertOff, int TriOff, int TriCount)
{
int i, pos, end = TriOff + (TriCount << 4);
int v1, v2, v3, p1[3], p2[3], p3[3], dx[2], dy[2], dz[2], dn, ni[3];
float nf[3], nd;
for(pos=TriOff;pos<end;pos+=0x10)
{
v1 = U16(data, pos + 2);
v2 = U16(data, pos + 4);
v3 = U16(data, pos + 6);
for(i=0;i<3;i++)
{
p1[i] = S16(data, vertOff + (v1 * 0x6) + (i << 1));
p2[i] = S16(data, vertOff + (v2 * 0x6) + (i << 1));
p3[i] = S16(data, vertOff + (v3 * 0x6) + (i << 1));
}
dx[0] = p1[0] - p2[0]; dx[1] = p2[0] - p3[0];
dy[0] = p1[1] - p2[1]; dy[1] = p2[1] - p3[1];
dz[0] = p1[2] - p2[2]; dz[1] = p2[2] - p3[2];
ni[0] = (dy[0] * dz[1]) - (dz[0] * dy[1]);
ni[1] = (dz[0] * dx[1]) - (dx[0] * dz[1]);
ni[2] = (dx[0] * dy[1]) - (dy[0] * dx[1]);
for(i=0;i<3;i++)
nf[i] = (float)ni[i] * ni[i];
nd = nf[0] + nf[1] + nf[2];
for(i=0;i<3;i++)
{
if (nd)
nf[i] /= nd;
nf[i] *= 0x3FFF0001;
nf[i] = sqrt(nf[i]);
if(ni[i] < 0)
nf[i] *= -1;
}
dn = (int)( (nf[0] / 0x7FFF * p1[0]) + (nf[1] / 0x7FFF * p1[1]) + (nf[2] / 0x7FFF * p1[2]) ) * -1;
if(dn < 0)
dn+=0x10000;
data[pos+0xE] = (dn>>8)&0xFF;
data[pos+0xF] = dn&0xFF;
for(i=0;i<3;i++)
{
ni[i] = (int)nf[i];
if(ni[i] < 0)
ni[i] += 0x10000;
data[pos+8+(i<<1)] = (ni[i]>>8)&0xFF;
data[pos+9+(i<<1)] = ni[i]&0xFF;
}
}
}
C#
C# implementation by xdaniel, based on above C code. Non-standard functions ("Helpers" class) should be self-explanatory:
private void FixCollision(ref List<byte> Data, int VertOff, int TriOff, int TriCount)
{
int i, pos, end = TriOff + (TriCount << 4);
int v1, v2, v3, dn;
int[] p1 = new int[3], p2 = new int[3], p3 = new int[3], dx = new int[2], dy = new int[2], dz = new int[2], ni = new int[3];
float nd;
float[] nf = new float[3];
for (pos = TriOff; pos < end; pos += 0x10)
{
v1 = Helpers.Read16(Data, pos + 2);
v2 = Helpers.Read16(Data, pos + 4);
v3 = Helpers.Read16(Data, pos + 6);
for (i = 0; i < 3; i++)
{
p1[i] = Helpers.Read16S(Data, VertOff + (v1 * 0x6) + (i << 1));
p2[i] = Helpers.Read16S(Data, VertOff + (v2 * 0x6) + (i << 1));
p3[i] = Helpers.Read16S(Data, VertOff + (v3 * 0x6) + (i << 1));
}
dx[0] = p1[0] - p2[0]; dx[1] = p2[0] - p3[0];
dy[0] = p1[1] - p2[1]; dy[1] = p2[1] - p3[1];
dz[0] = p1[2] - p2[2]; dz[1] = p2[2] - p3[2];
ni[0] = (dy[0] * dz[1]) - (dz[0] * dy[1]);
ni[1] = (dz[0] * dx[1]) - (dx[0] * dz[1]);
ni[2] = (dx[0] * dy[1]) - (dy[0] * dx[1]);
for (i = 0; i < 3; i++)
nf[i] = (float)ni[i] * ni[i];
nd = nf[0] + nf[1] + nf[2];
for (i = 0; i < 3; i++)
{
if (nd != 0)
nf[i] /= nd;
nf[i] *= 0x3FFF0001;
nf[i] = (float)Math.Sqrt((double)nf[i]);
if (ni[i] < 0)
nf[i] *= -1;
}
dn = (int)( (nf[0] / 0x7FFF * p1[0]) + (nf[1] / 0x7FFF * p1[1]) + (nf[2] / 0x7FFF * p1[2]) ) * -1;
if (dn < 0)
dn += 0x10000;
Helpers.Overwrite16(ref Data, pos + 0xE, (ushort)(dn & 0xFFFF));
for (i = 0; i < 3; i++)
{
ni[i] = (int)nf[i];
if (ni[i] < 0)
ni[i] += 0x10000;
Helpers.Overwrite16(ref Data, (pos + 8 + (i << 1)), (ushort)(ni[i] & 0xFFFF));
}
}
}
Python
Deciphered from VB spaghetti to Python by spinout.
from struct import pack, unpack
def FixCollision(data, vertOff, TriOff, TriCount):
for pos in range(TriOff, TriOff + (TriCount << 4), 0x10):
v1,v2,v3 = unpack(">HHH", data[pos+0x2:][:0x6])
p1 = unpack(">hhh", data[vertOff + (v1 * 0x6):][:0x6])
p2 = unpack(">hhh", data[vertOff + (v2 * 0x6):][:0x6])
p3 = unpack(">hhh", data[vertOff + (v3 * 0x6):][:0x6])
dx = [p1[0] - p2[0], p2[0] - p3[0]]
dy = [p1[1] - p2[1], p2[1] - p3[1]]
dz = [p1[2] - p2[2], p2[2] - p3[2]]
n = [(dy[0] * dz[1]) - (dz[0] * dy[1]),
(dz[0] * dx[1]) - (dx[0] * dz[1]),
(dx[0] * dy[1]) - (dy[0] * dx[1])]
n_ = n[:]
for i in range(3):
n[i] *= float(n[i])
nd = n[0] + n[1] + n[2]
for i in range(3):
if nd:
n[i] /= nd
n[i] *= 0x3FFF0001
n[i] = sqrt(n[i])
if(n_[i] < 0):
n[i] *= -1
dn = int(((n[0] / 0x7FFF * p1[0]) + (n[1] / 0x7FFF * p1[1]) + (n[2] / 0x7FFF * p1[2]) ) * -1)
if(dn < 0):
dn+=0x10000
dn = dn & 0xFFFF
for i in range(3):
n[i] = int(n[i])
if(n[i] < 0):
n[i] += 0x10000
n[i] = n[i] & 0xFFFF
norms = pack(">HHHH", n[0], n[1], n[2], dn)
if (norms != data[pos+0x8][:0x8]):
data = data[:pos+0x8]+norms+data[pos+0x10:]
return data