Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/*+**************************************************************************/
/*** ***/
/*** This file is distributed under a BSD license. ***/
/*** See LICENSE.txt for details. ***/
/*** ***/
/**************************************************************************+*/
/****************************************************************************/
/*** ***/
/*** (C) 2005 Dierk Ohlerich, all rights reserved ***/
/*** ***/
/****************************************************************************/
#define sPEDANTIC_WARN 1
#include "base/math.hpp"
#if !sCONFIG_OPTION_NOSYSTEM
#include "base/system.hpp"
#endif
/****************************************************************************/
sDontInitializeT sDontInitialize;
/****************************************************************************/
static void sInitPerlin();
static void sInitMath()
{
sSetFloat();
sInitPerlin();
}
#if !sCONFIG_OPTION_NOSYSTEM
sADDSUBSYSTEM(Math,0x18,sInitMath,0);
#endif
/****************************************************************************/
/****************************************************************************/
// Find real roots (=Nullstellen) of at² + bt + c.
sInt sSolveQuadratic(sF32 t[],sF32 a,sF32 b,sF32 c)
{
if(a == 0.0f) // yes, exact compares everywhere!
{
if(b == 0.0f)
return 0;
t[0] = -c/b;
return 1;
}
sF32 discr = b*b - 4.0f*a*c;
if(discr > 0.0f)
{
sF32 x = -0.5f * (b + (b >= 0.0f ? 1.0f : -1.0f) * sSqrt(discr));
t[0] = x / a;
t[1] = c / x;
return 2;
}
else if(discr < 0.0f)
return 0;
else
{
t[0] = -0.5f * b / a;
return 1;
}
}
/****************************************************************************/
/****************************************************************************/
sF64 sRombergIntegral(sIntegrand f_,void *user,sF64 a,sF64 b,int maxOrder,sF64 maxError)
{
sF64 t[20];
sVERIFY(0 < maxOrder && maxOrder <= 20);
sVERIFY(a <= b);
if(a == b)
return 0.0f;
// first order: trapezoid rule over whole interval
sF64 result;
sF64 h = b-a;
t[0] = result = 0.5 * h * (f_(a,user) + f_(b,user));
// successively higher orders
sInt i = 1;
for(sInt n=1; i<maxOrder; i++, n *= 2, h *= 0.5)
{
// trapezoid rule for next-higher order
sF64 sum = 0.0;
for(sInt j=0; j<n; j++)
sum += f_(a + h*(j + 0.5),user);
sum = 0.5 * (t[0] + h * sum);
// richardson extrapolation
sF64 lastIn = t[0];
sF64 lastOut = sum;
sF64 ff = 4.0;
t[0] = sum;
for(sInt j=1; j<=i; j++, ff *= 4.0)
{
sF64 in = t[j];
t[j] = lastOut = (ff * lastOut - lastIn) / (ff - 1.0);
lastIn = in;
}
// (relative) error estimation
sF64 errorEst = result ? (t[i] - result) / result : 0.0;
result = t[i];
if(-maxError < errorEst && errorEst < maxError) // don't ask.
break;
}
return result;
}
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
void sVector30::InitColor(sU32 col)
{
x = ((col&0x00ff0000)>>16)/255.0f;
y = ((col&0x0000ff00)>> 8)/255.0f;
z = ((col&0x000000ff) )/255.0f;
}
void sVector30::InitColor(sU32 col,sF32 amp)
{
InitColor(col);
x *= amp;
y *= amp;
z *= amp;
}
sU32 sVector30::GetColor() const
{
sU32 col;
col = (sClamp<sInt>(sInt(x*255+0.5f),0,255)<<16)
| (sClamp<sInt>(sInt(y*255+0.5f),0,255)<< 8)
| (sClamp<sInt>(sInt(z*255+0.5f),0,255) )
| 0x00000000;
return col;
}
void sVector30::Cross(sVector30Arg a,sVector30Arg b)
{
*this = sVector30(a.y*b.z-a.z*b.y
,a.z*b.x-a.x*b.z
,a.x*b.y-a.y*b.x);
}
void sMatrix34::Fade(sF32 f,const sMatrix34 &mat0,const sMatrix34 &mat1)
{
i.Fade(f,mat0.i,mat1.i);
j.Fade(f,mat0.j,mat1.j);
k.Fade(f,mat0.k,mat1.k);
l.Fade(f,mat0.l,mat1.l);
}
void sMatrix34::FadeOrthonormal(sF32 f,const sMatrix34 &mat0,const sMatrix34 &mat1)
{
i.Fade(f,mat0.i,mat1.i);
k.Fade(f,mat0.k,mat1.k);
l.Fade(f,mat0.l,mat1.l);
k.Unit();
j.Cross(k,i);
j.Unit();
i.Cross(j,k);
}
void sMatrix34::FadeOrthonormalPrecise(sF32 f,const sMatrix34 &mat0,const sMatrix34 &mat1)
{
i.Fade(f,mat0.i,mat1.i);
k.Fade(f,mat0.k,mat1.k);
l.Fade(f,mat0.l,mat1.l);
k.UnitPrecise();
j.Cross(k,i);
j.UnitPrecise();
i.Cross(j,k);
}
/****************************************************************************/
// Angle(): get the angle between two vectors (this and a)
/****************************************************************************/
sF32 sVector30::Angle(sVector30Arg a) const
{
sF32 s = x*a.x+y*a.y+z*a.z;
sF32 n1 = x*x+y*y+z*z;
sF32 n2 = a.x*a.x+a.y*a.y+a.z*a.z;
return sFACos(sClamp(s*sFRSqrt(n1*n2), -1.0f, 1.0f));
};
void sVector30::Rotate(const sMatrix34 &m,sVector30Arg v)
{
x = v.x*m.i.x + v.y*m.j.x + v.z*m.k.x + m.l.x;
y = v.x*m.i.y + v.y*m.j.y + v.z*m.k.y + m.l.y;
z = v.x*m.i.z + v.y*m.j.z + v.z*m.k.z + m.l.z;
}
void sVector30::Unit()
{
sF32 e = 1.0f*x*x + 1.0f*y*y + 1.0f*z*z;
if(e>1e-12f)
{
e=sFRSqrt(e);
x = sF32(e*x);
y = sF32(e*y);
z = sF32(e*z);
}
else
{
Init(1,0,0);
}
}
/****************************************************************************/
void sVector30::UnitPrecise()
{
sF32 e = 1.0f*x*x + 1.0f*y*y + 1.0f*z*z;
if(e>1e-12f)
{
e=sRSqrt(e);
x = sF32(e*x);
y = sF32(e*y);
z = sF32(e*z);
}
else
{
Init(1,0,0);
}
}
/****************************************************************************/
void sVector31::InitColor(sU32 col)
{
x = ((col&0x00ff0000)>>16)/255.0f;
y = ((col&0x0000ff00)>> 8)/255.0f;
z = ((col&0x000000ff) )/255.0f;
}
void sVector31::InitColor(sU32 col,sF32 amp)
{
InitColor(col);
x *= amp;
y *= amp;
z *= amp;
}
sU32 sVector31::GetColor() const
{
sU32 col;
col = (sClamp<sInt>(sInt(x*255+0.5f),0,255)<<16)
| (sClamp<sInt>(sInt(y*255+0.5f),0,255)<< 8)
| (sClamp<sInt>(sInt(z*255+0.5f),0,255) )
| 0xff000000;
return col;
}
/****************************************************************************/
void sVector4::InitColor(sU32 col)
{
x = ((col&0x00ff0000)>>16)/255.0f;
y = ((col&0x0000ff00)>> 8)/255.0f;
z = ((col&0x000000ff) )/255.0f;
w = ((col&0xff000000)>>24)/255.0f;
}
void sVector4::InitColor(sU32 col,sF32 amp)
{
InitColor(col);
x *= amp;
y *= amp;
z *= amp;
w *= amp;
}
sU32 sVector4::GetColor() const
{
sU32 col;
col = (sClamp<sInt>(sInt(x*255+0.5f),0,255)<<16)
| (sClamp<sInt>(sInt(y*255+0.5f),0,255)<< 8)
| (sClamp<sInt>(sInt(z*255+0.5f),0,255) )
| (sClamp<sInt>(sInt(w*255+0.5f),0,255)<<24);
return col;
}
void sVector4::InitMRGB8(sU32 col)
{
w = ((col&0xff000000)>>24)+1.0f;
x = w*((col&0x00ff0000)>>16)/255.0f;
y = w*((col&0x0000ff00)>> 8)/255.0f;
z = w*((col&0x000000ff) )/255.0f;
w = 1.0f;
}
sU32 sVector4::GetMRGB8() const
{
sF32 max = sFFloor(sMax(sMax(x,y),z))+1.0f;
sU32 col = (sClamp<sInt>(sInt(x/max*255),0,255)<<16)
| (sClamp<sInt>(sInt(y/max*255),0,255)<< 8)
| (sClamp<sInt>(sInt(z/max*255),0,255) )
| (sClamp<sInt>(sInt(max-1.0f),0,255)<<24);
return col;
}
void sVector4::InitMRGB16(sU64 col)
{
w = ((col>>48)&0xffff)+1.0f;
x = w*((col>>32)&0xffff)/65536.0f;
y = w*((col>>16)&0xffff)/65536.0f;
z = w*((col )&0xffff)/65536.0f;
w = 1.0f;
}
sU64 sVector4::GetMRGB16() const
{
sF32 max = sFFloor(sMax(sMax(x,y),z))+1.0f;
sU64 col = (sClamp<sS64>(sS64(x/max*65536.0f),0,65536)<<32)
| (sClamp<sS64>(sS64(y/max*65536.0f),0,65536)<<16)
| (sClamp<sS64>(sS64(z/max*65536.0f),0,65536) )
| (sClamp<sS64>(sS64(max-1.0f),0,65536)<<48);
return col;
}
void sVector4::InitPlane(sVector31Arg pos,sVector30Arg norm)
{
x = norm.x;
y = norm.y;
z = norm.z;
w = - (pos ^ norm);
}
void sVector4::InitPlane(sVector31Arg p0,sVector31Arg p1,sVector31Arg p2)
{
sVector30 norm;
norm.Cross(p0-p1,p0-p2);
norm.Unit();
x = norm.x;
y = norm.y;
z = norm.z;
w = - (p0 ^ norm);
}
sBool sVector4::operator==(sVector4Arg v) const
{
return x == v.x &&
y == v.y &&
z == v.z &&
w == v.w;
}
void sVector4::Unit4Precise()
{
sF32 e = 1.0f*x*x + 1.0f*y*y + 1.0f*z*z + 1.0f*w*w;
if(e>1e-12f)
{
e=sRSqrt(e);
x = sF32(e*x);
y = sF32(e*y);
z = sF32(e*z);
w = sF32(e*w);
}
else
{
Init(1,0,0,0);
}
}
void sVector4::Unit4()
{
sF32 e = 1.0f*x*x + 1.0f*y*y + 1.0f*z*z + 1.0f*w*w;
if(e>1e-12f)
{
e=sFRSqrt(e);
x = sF32(e*x);
y = sF32(e*y);
z = sF32(e*z);
w = sF32(e*w);
}
else
{
Init(1,0,0,0);
}
}
/****************************************************************************/
sMatrix34::sMatrix34(const sMatrix34CM &m)
{
m.ConvertTo(*this);
}
sMatrix34 &sMatrix34::operator=(const sMatrix34CM &m)
{
m.ConvertTo(*this);
return *this;
}
void sMatrix34::Init()
{
i.Init(1,0,0);
j.Init(0,1,0);
k.Init(0,0,1);
l.Init(0,0,0);
}
void sMatrix34::Euler(sF32 x,sF32 y,sF32 z)
{
EulerXYZ(x,y,z); // it's the same!
}
void sMatrix34::EulerXYZ(sF32 x,sF32 y,sF32 z)
{
sF32 sx,sy,sz;
sF32 cx,cy,cz;
sFSinCos(x,sx,cx);
sFSinCos(y,sy,cy);
sFSinCos(z,sz,cz);
i.x = cy*cz;
i.y = cy*sz;
i.z = -sy;
j.x = sx*cz*sy - cx*sz;
j.y = sx*sz*sy + cx*cz;
j.z = sx*cy;
k.x = cx*cz*sy + sx*sz;
k.y = cx*sz*sy - sx*cz;
k.z = cx*cy;
}
void sMatrix34::FindEulerXYZ(sF32 &x,sF32 &y,sF32 &z) const
{
sF32 rx,ry,rz;
sF32 sy = -i.z;
if(sy >= 0.99999f) // ry very close to 90° (singular)
{
ry = sPIF / 2.0f;
rx = sATan2(j.x,j.y);
rz = 0.0f;
}
else if(sy <= -0.99999f) // ry very close to -90° (singular)
{
ry = -sPIF / 2.0f;
rx = sATan2(-j.x,-k.x);
rz = 0.0f;
}
else
{
sF32 cy = sFSqrt(j.z*j.z + k.z*k.z); // this can be positive or negative!
ry = sATan2(sy,cy);
rz = sATan2(i.y,i.x);
rx = sATan2(j.z,k.z);
}
x = rx;
y = ry;
z = rz;
}
// this chooses a minimal z rotation. this is the better choice for interactive cameras
// cy can be positive or negative! that is where the problem comes from.
void sMatrix34::FindEulerXYZ2(sF32 &x,sF32 &y,sF32 &z) const
{
sF32 rx,ry,rz;
sF32 sy = -i.z;
if(sy >= 0.99999f) // ry very close to 90° (singular)
{
ry = sPIF / 2.0f;
rx = sATan2(j.x,j.y);
rz = 0.0f;
}
else if(sy <= -0.99999f) // ry very close to -90° (singular)
{
ry = -sPIF / 2.0f;
rx = sATan2(-j.x,-k.x);
rz = 0.0f;
}
else
{
sF32 rzp = sATan2(i.y,i.x);
sF32 rzn = sATan2(-i.y,-i.x);
sF32 cy = sFSqrt(j.z*j.z + k.z*k.z); // evil square root that has two possible outcomes!
// if(i.y>=0)
if(sFAbs(rzp)<sFAbs(rzn)) // CHAOS: ask dierk before changing!
{
rx = sATan2(j.z,k.z);
ry = sATan2(sy,cy);
rz = rzp;//sATan2(i.y,i.x);
}
else
{
rx = sATan2(-j.z,-k.z);
ry = sATan2(sy,-cy);
rz = rzn;//sATan2(-i.y,-i.x);
}
}
x = rx;
y = ry;
z = rz;
}
void sMatrix34::CubeFace(sInt n)
{
static const sF32 dir[6][3] =
{
{ 1, 0, 0}, // sTCF_POSX
{-1, 0, 0}, // sTCF_NEGX
{ 0, 1, 0}, // sTCF_POSY
{ 0,-1 ,0}, // sTCF_NEGY
{ 0, 0, 1}, // sTCF_POSZ
{ 0, 0,-1}, // sTCF_NEGZ
};
static const sF32 up[6][3] =
{
{ 0, 1, 0}, // sTCF_POSX
{ 0, 1, 0}, // sTCF_NEGX
{ 0, 0,-1}, // sTCF_POSY
{ 0, 0, 1}, // sTCF_NEGY
{ 0, 1, 0}, // sTCF_POSZ
{ 0, 1, 0}, // sTCF_NEGZ
};
j = sVector30(up [n][0], up [n][1], up [n][2]);
k = sVector30(dir[n][0], dir[n][1], dir[n][2]);
i.Cross(j,k);
l.Init(0,0,0);
}
void sMatrix34::Look(sVector30Arg v)
{
j.Init(0,1,0);
k = v;
k.Unit();
i.Cross(j,k);
i.Unit(); // ist dieses unit überflüssig ?
j.Cross(k,i);
j.Unit();
l.Init(0,0,0);
}
//sTODO("vasco: replace sMatrix34::Look by sMatrix34::Look_");
void sMatrix34::Look(sVector30Arg dir, sVector30Arg up)
{
k = dir;
k.Unit();
j = up;
j.Unit();
i.Cross(j,k);
i.Unit();
j.Cross(k,i);
l.Init(0,0,0);
}
void sMatrix34::Look_(sVector30Arg dir, sVector30Arg up)
{
j = up;
k = dir;
k.Unit();
i.Cross(j,k);
i.Unit();
j.Cross(k,i);
j.Unit();
l.Init(0,0,0);
}
void sMatrix34::LookPrecise(sVector30Arg v)
{
j.Init(0,1,0);
k = v;
k.UnitPrecise();
i.Cross(j,k);
i.UnitPrecise(); // ist dieses unit überflüssig ?
j.Cross(k,i);
j.UnitPrecise();
l.Init(0,0,0);
}
void sMatrix34::LookPrecise(sVector30Arg dir, sVector30Arg up)
{
k = dir;
k.UnitPrecise();
j = up;
j.UnitPrecise();
i.Cross(j,k);
i.UnitPrecise();
j.Cross(k,i);
l.Init(0,0,0);
}
void sMatrix34::LookAt(sVector31Arg dest,sVector31Arg pos)
{
sVector30 dir = dest-pos;
sVector31 l_ = pos;
dir.Unit();
Look(dir);
l = l_;
}
void sMatrix34::LookAt(sVector31Arg dest, sVector31Arg pos, sVector30Arg up)
{
sVector30 dir = dest-pos;
sVector31 l_ = pos;
dir.Unit();
Look(dir,up);
l = l_;
}
void sMatrix34::RotateAxis(sVector30Arg v,sF32 a)
{
sVector30 u;
sF32 as,ac;
u = v;
u.Unit();
ac = sF32(sFCos(a));
as = sF32(sFSin(a));
i.x = (1-u.x*u.x)*ac + u.x*u.x + 0;
i.y = ( -u.x*u.y)*ac + u.x*u.y - u.z*as;
i.z = ( -u.x*u.z)*ac + u.x*u.z + u.y*as;
j.x = ( -u.y*u.x)*ac + u.y*u.x + u.z*as;
j.y = (1-u.y*u.y)*ac + u.y*u.y + 0;
j.z = ( -u.y*u.z)*ac + u.y*u.z - u.x*as;
k.x = ( -u.z*u.x)*ac + u.z*u.x - u.y*as;
k.y = ( -u.z*u.y)*ac + u.z*u.y + u.x*as;
k.z = (1-u.z*u.z)*ac + u.z*u.z + 0;
// as the euler functions, L will not be initialized!
}
void sMatrix34::Cross(sVector30Arg v)
{
i.Init( 0, v.z,-v.y);
j.Init(-v.z, 0, v.x);
k.Init( v.y,-v.x, 0);
l.Init( 0, 0, 0);
}
void sMatrix34::Trans3()
{
sSwap(i.y,j.x);
sSwap(i.z,k.x);
sSwap(j.z,k.y);
}
void sMatrix34::TransR()
{
sVector31 v,w;
Trans3();
v.Init(-l.x,-l.y,-l.z);
l.Init(0,0,0);
w = v*(*this);
l = w;
}
void sMatrix34::InvertOrthogonal()
{
sF32 x,y,z;
x = sFInvSqrt(i^i);
y = sFInvSqrt(j^j);
z = sFInvSqrt(k^k);
i *= x;
j *= y;
k *= z;
Trans3();
i *= x;
j *= y;
k *= z;
l = sVector31(sVector30(-l)*(*this));
}
sF32 sMatrix34::Determinant3x3() const
{
return (i.x*j.y*k.z + i.y*j.z*k.x + i.z*j.x*k.y)
- (i.z*j.y*k.x + i.x*j.z*k.y + i.y*j.x*k.z);
}
sBool sMatrix34::Invert3()
{
// Invert a 3x3 using cofactors. This is faster than using a generic
// Gaussian elimination because of the loop overhead of such a method.
sMatrix34 inv;
inv.i.x = j.y*k.z - j.z*k.y;
inv.i.y = i.z*k.y - i.y*k.z;
inv.i.z = i.y*j.z - i.z*j.y;
inv.j.x = j.z*k.x - j.x*k.z;
inv.j.y = i.x*k.z - i.z*k.x;
inv.j.z = i.z*j.x - i.x*j.z;
inv.k.x = j.x*k.y - j.y*k.x;
inv.k.y = i.y*k.x - i.x*k.y;
inv.k.z = i.x*j.y - i.y*j.x;
sF32 det = i.x*inv.i.x + i.y*inv.j.x + i.z*inv.k.x;
if (sFAbs(det)<sEPSILON) return sFALSE;
det=1.0f/det;
i=inv.i*det;
j=inv.j*det;
k=inv.k*det;
return sTRUE;
}
sBool sMatrix34::Invert34()
{
if (!Invert3()) return sFALSE;
l = sVector31(sVector30(-l)*(*this));
return sTRUE;
}
void sMatrix34::Orthonormalize ()
{
// Gram-Schmidt orthogonalization
i.Unit();
j-=i*(i^j);
j.Unit();
k-=i*(i^k)+j*(j^k);
k.Unit();
}
void sMatrix34::Init(sQuaternionArg q, sVector31Arg p)
{
sF32 xx = 2.0f*q.i*q.i;
sF32 xy = 2.0f*q.i*q.j;
sF32 xz = 2.0f*q.i*q.k;
sF32 yy = 2.0f*q.j*q.j;
sF32 yz = 2.0f*q.j*q.k;
sF32 zz = 2.0f*q.k*q.k;
sF32 xw = 2.0f*q.i*q.r;
sF32 yw = 2.0f*q.j*q.r;
sF32 zw = 2.0f*q.k*q.r;
i.x = 1.0f - (yy + zz);
j.x = (xy + zw);
k.x = (xz - yw);
i.y = (xy - zw);
j.y = 1.0f - (xx + zz);
k.y = (yz + xw);
i.z = (xz + yw);
j.z = (yz - xw);
k.z = 1.0f - (xx + yy);
l=p;
}
void sMatrix34::Init(sQuaternionArg q)
{
sF32 xx = 2.0f*q.i*q.i;
sF32 xy = 2.0f*q.i*q.j;
sF32 xz = 2.0f*q.i*q.k;
sF32 yy = 2.0f*q.j*q.j;
sF32 yz = 2.0f*q.j*q.k;
sF32 zz = 2.0f*q.k*q.k;
sF32 xw = 2.0f*q.i*q.r;
sF32 yw = 2.0f*q.j*q.r;
sF32 zw = 2.0f*q.k*q.r;
i.x = 1.0f - (yy + zz);
j.x = (xy + zw);
k.x = (xz - yw);
i.y = (xy - zw);
j.y = 1.0f - (xx + zz);
k.y = (yz + xw);
i.z = (xz + yw);
j.z = (yz - xw);
k.z = 1.0f - (xx + yy);
l.Init(0,0,0);
}
void sMatrix34::Scale(sF32 x, sF32 y, sF32 z)
{
i.x *= x;
i.y *= x;
i.z *= x;
j.x *= y;
j.y *= y;
j.z *= y;
k.x *= z;
k.y *= z;
k.z *= z;
}
void sMatrix34::ThreePoint(const sVector31 &p0,const sVector31 &p1,const sVector31 &p2,const sVector30 &tweak)
{
sVector30 db;
k = p2-p0;
k.Unit();
db = p1-p0;
db.Unit();
i.Cross(db,k);
i = i + tweak;
j.Cross(k,i);
i.Unit();
j.Unit();
}
void sMatrix34::ThreePoint_(const sVector31 &p0,const sVector31 &p1,const sVector31 &p2,const sVector30 &tweak)
{
sVector30 db;
k = p2-p0;
k.Unit();
db = p1-p0;
db.Unit();
j.Cross(k,db);
j = j + tweak;
j.Unit();
i.Cross(j,k);
i.Unit();
}
void sMatrix34::RotateAroundPivot(sQuaternionArg rot,sVector31Arg pivot)
{
// translate by -pivot, rotate, translate by pivot
// => total transform: Rot*(x-pivot) + pivot = Rot*x + (pivot - Rot*pivot)
Init(rot);
l = pivot - (sVector30(pivot) * *this);
}
void sMatrix34::RotateAroundPivot(sVector30Arg axis,sF32 angle,sVector31Arg pivot)
{
// same as above, with axis-angle rotation
RotateAxis(axis,angle);
l = pivot - (sVector30(pivot) * *this);
}
/****************************************************************************/
void sMatrix34CM::Ident()
{
x.Init(1.0f,0.0f,0.0f,0.0f);
y.Init(0.0f,1.0f,0.0f,0.0f);
z.Init(0.0f,0.0f,1.0f,0.0f);
}
sMatrix34CM::sMatrix34CM(const sMatrix34 &m)
{
*this = m;
}
sMatrix34CM &sMatrix34CM::operator=(const sMatrix34 &m)
{
x.x = m.i.x;
x.y = m.j.x;
x.z = m.k.x;
x.w = m.l.x;
y.x = m.i.y;
y.y = m.j.y;
y.z = m.k.y;
y.w = m.l.y;
z.x = m.i.z;
z.y = m.j.z;
z.z = m.k.z;
z.w = m.l.z;
return *this;
}
void sMatrix34CM::ConvertTo(sMatrix34& s)const
{
s.i.x = x.x;
s.j.x = x.y;
s.k.x = x.z;
s.l.x = x.w;
s.i.y = y.x;
s.j.y = y.y;
s.k.y = y.z;
s.l.y = y.w;
s.i.z = z.x;
s.j.z = z.y;
s.k.z = z.z;
s.l.z = z.w;
}
sF32 sMatrix34CM::Determinant3x3() const
{
return (x.x*y.y*z.z + y.x*z.y*x.z + z.x*x.y*y.z)
- (z.x*y.y*x.z + x.x*z.y*y.z + y.x*x.y*z.z);
}
/****************************************************************************/
void sMatrix44::Init()
{
i.Init(1.0f, 0.0f, 0.0f, 0.0f);
j.Init(0.0f, 1.0f, 0.0f, 0.0f);
k.Init(0.0f, 0.0f, 1.0f, 0.0f);
l.Init(0.0f, 0.0f, 0.0f, 1.0f);
}
void sMatrix44::Trans4()
{
sSwap(i.y,j.x);
sSwap(i.z,k.x);
sSwap(i.w,l.x);
sSwap(j.z,k.y);
sSwap(j.w,l.y);
sSwap(k.w,l.z);
}
void sMatrix44::Trans4(const sMatrix44 &mat)
{
i.x = mat.i.x;
i.y = mat.j.x;
i.z = mat.k.x;
i.w = mat.l.x;
j.x = mat.i.y;
j.y = mat.j.y;
j.z = mat.k.y;
j.w = mat.l.y;
k.x = mat.i.z;
k.y = mat.j.z;
k.z = mat.k.z;
k.w = mat.l.z;
l.x = mat.i.w;
l.y = mat.j.w;
l.z = mat.k.w;
l.w = mat.l.w;
}
void sMatrix44::Scale(sF32 x, sF32 y, sF32 z)
{
i.x *= x;
j.y *= y;
k.z *= z;
}
void sMatrix44::Orthonormalize ()
{
// Gram-Schmidt orthogonalization
i.Unit4();
j-=i*(i^j);
j.Unit4();
k-=i*(i^k)+j*(j^k);
k.Unit4();
l-=i*(i^l)+j*(j^l)+k*(k^l);
l.Unit4();
}
sBool sMatrix44::operator==(const sMatrix44 &mat) const
{
return i == mat.i &&
j == mat.j &&
k == mat.k &&
l == mat.l;
}
void sMatrix44::Invert(const sMatrix44 &a)
{
sF32 idet = 1.0f/a.Determinant();
i.x = (a.j.z*a.k.w*a.l.y - a.j.w*a.k.z*a.l.y + a.j.w*a.k.y*a.l.z - a.j.y*a.k.w*a.l.z - a.j.z*a.k.y*a.l.w + a.j.y*a.k.z*a.l.w)*idet;
i.y = (a.i.w*a.k.z*a.l.y - a.i.z*a.k.w*a.l.y - a.i.w*a.k.y*a.l.z + a.i.y*a.k.w*a.l.z + a.i.z*a.k.y*a.l.w - a.i.y*a.k.z*a.l.w)*idet;
i.z = (a.i.z*a.j.w*a.l.y - a.i.w*a.j.z*a.l.y + a.i.w*a.j.y*a.l.z - a.i.y*a.j.w*a.l.z - a.i.z*a.j.y*a.l.w + a.i.y*a.j.z*a.l.w)*idet;
i.w = (a.i.w*a.j.z*a.k.y - a.i.z*a.j.w*a.k.y - a.i.w*a.j.y*a.k.z + a.i.y*a.j.w*a.k.z + a.i.z*a.j.y*a.k.w - a.i.y*a.j.z*a.k.w)*idet;
j.x = (a.j.w*a.k.z*a.l.x - a.j.z*a.k.w*a.l.x - a.j.w*a.k.x*a.l.z + a.j.x*a.k.w*a.l.z + a.j.z*a.k.x*a.l.w - a.j.x*a.k.z*a.l.w)*idet;
j.y = (a.i.z*a.k.w*a.l.x - a.i.w*a.k.z*a.l.x + a.i.w*a.k.x*a.l.z - a.i.x*a.k.w*a.l.z - a.i.z*a.k.x*a.l.w + a.i.x*a.k.z*a.l.w)*idet;
j.z = (a.i.w*a.j.z*a.l.x - a.i.z*a.j.w*a.l.x - a.i.w*a.j.x*a.l.z + a.i.x*a.j.w*a.l.z + a.i.z*a.j.x*a.l.w - a.i.x*a.j.z*a.l.w)*idet;
j.w = (a.i.z*a.j.w*a.k.x - a.i.w*a.j.z*a.k.x + a.i.w*a.j.x*a.k.z - a.i.x*a.j.w*a.k.z - a.i.z*a.j.x*a.k.w + a.i.x*a.j.z*a.k.w)*idet;
k.x = (a.j.y*a.k.w*a.l.x - a.j.w*a.k.y*a.l.x + a.j.w*a.k.x*a.l.y - a.j.x*a.k.w*a.l.y - a.j.y*a.k.x*a.l.w + a.j.x*a.k.y*a.l.w)*idet;
k.y = (a.i.w*a.k.y*a.l.x - a.i.y*a.k.w*a.l.x - a.i.w*a.k.x*a.l.y + a.i.x*a.k.w*a.l.y + a.i.y*a.k.x*a.l.w - a.i.x*a.k.y*a.l.w)*idet;
k.z = (a.i.y*a.j.w*a.l.x - a.i.w*a.j.y*a.l.x + a.i.w*a.j.x*a.l.y - a.i.x*a.j.w*a.l.y - a.i.y*a.j.x*a.l.w + a.i.x*a.j.y*a.l.w)*idet;
k.w = (a.i.w*a.j.y*a.k.x - a.i.y*a.j.w*a.k.x - a.i.w*a.j.x*a.k.y + a.i.x*a.j.w*a.k.y + a.i.y*a.j.x*a.k.w - a.i.x*a.j.y*a.k.w)*idet;
l.x = (a.j.z*a.k.y*a.l.x - a.j.y*a.k.z*a.l.x - a.j.z*a.k.x*a.l.y + a.j.x*a.k.z*a.l.y + a.j.y*a.k.x*a.l.z - a.j.x*a.k.y*a.l.z)*idet;
l.y = (a.i.y*a.k.z*a.l.x - a.i.z*a.k.y*a.l.x + a.i.z*a.k.x*a.l.y - a.i.x*a.k.z*a.l.y - a.i.y*a.k.x*a.l.z + a.i.x*a.k.y*a.l.z)*idet;
l.z = (a.i.z*a.j.y*a.l.x - a.i.y*a.j.z*a.l.x - a.i.z*a.j.x*a.l.y + a.i.x*a.j.z*a.l.y + a.i.y*a.j.x*a.l.z - a.i.x*a.j.y*a.l.z)*idet;
l.w = (a.i.y*a.j.z*a.k.x - a.i.z*a.j.y*a.k.x + a.i.z*a.j.x*a.k.y - a.i.x*a.j.z*a.k.y - a.i.y*a.j.x*a.k.z + a.i.x*a.j.y*a.k.z)*idet;
}
sF32 sMatrix44::Determinant() const
{
return i.w*j.z*k.y*l.x - i.z*j.w*k.y*l.x - i.w*j.y*k.z*l.x + i.y*j.w*k.z*l.x
+ i.z*j.y*k.w*l.x - i.y*j.z*k.w*l.x - i.w*j.z*k.x*l.y + i.z*j.w*k.x*l.y
+ i.w*j.x*k.z*l.y - i.x*j.w*k.z*l.y - i.z*j.x*k.w*l.y + i.x*j.z*k.w*l.y
+ i.w*j.y*k.x*l.z - i.y*j.w*k.x*l.z - i.w*j.x*k.y*l.z + i.x*j.w*k.y*l.z
+ i.y*j.x*k.w*l.z - i.x*j.y*k.w*l.z - i.z*j.y*k.x*l.w + i.y*j.z*k.x*l.w
+ i.z*j.x*k.y*l.w - i.x*j.z*k.y*l.w - i.y*j.x*k.z*l.w + i.x*j.y*k.z*l.w;
}
void sMatrix44::Perspective(sF32 left, sF32 right, sF32 top, sF32 bottom, sF32 front, sF32 back)
{
// see D3DXMatrixPerspectiveOffCenterLH
sF32 xx = 2.0f * front / (right - left);
sF32 yy = 2.0f * front / (top - bottom);
sF32 xz = (left + right) / (left - right);
sF32 yz = (top + bottom) / (bottom - top);
sF32 zz = back / (back - front);
sF32 zw = front*back / (front - back);
sF32 wz = 1.0f;
i.x = xx;
i.y = 0.0f;
i.z = 0.0f;
i.w = 0.0f;
j.x = 0.0f;
j.y = yy;
j.z = 0.0f;
j.w = 0.0f;
k.x = xz;
k.y = yz;
k.z = zz;
k.w = wz;
l.x = 0.0f;
l.y = 0.0f;
l.z = zw;
l.w = 0.0f;
}
/****************************************************************************/
#ifndef sHASINTRINSIC_MATRIXMUL
sMatrix44 operator* (const sMatrix44 &a,const sMatrix44 &b)
{
sMatrix44 r;
r.i.x = a.i.x*b.i.x + a.i.y*b.j.x + a.i.z*b.k.x + a.i.w*b.l.x;
r.i.y = a.i.x*b.i.y + a.i.y*b.j.y + a.i.z*b.k.y + a.i.w*b.l.y;
r.i.z = a.i.x*b.i.z + a.i.y*b.j.z + a.i.z*b.k.z + a.i.w*b.l.z;
r.i.w = a.i.x*b.i.w + a.i.y*b.j.w + a.i.z*b.k.w + a.i.w*b.l.w;
r.j.x = a.j.x*b.i.x + a.j.y*b.j.x + a.j.z*b.k.x + a.j.w*b.l.x;
r.j.y = a.j.x*b.i.y + a.j.y*b.j.y + a.j.z*b.k.y + a.j.w*b.l.y;
r.j.z = a.j.x*b.i.z + a.j.y*b.j.z + a.j.z*b.k.z + a.j.w*b.l.z;
r.j.w = a.j.x*b.i.w + a.j.y*b.j.w + a.j.z*b.k.w + a.j.w*b.l.w;
r.k.x = a.k.x*b.i.x + a.k.y*b.j.x + a.k.z*b.k.x + a.k.w*b.l.x;
r.k.y = a.k.x*b.i.y + a.k.y*b.j.y + a.k.z*b.k.y + a.k.w*b.l.y;
r.k.z = a.k.x*b.i.z + a.k.y*b.j.z + a.k.z*b.k.z + a.k.w*b.l.z;
r.k.w = a.k.x*b.i.w + a.k.y*b.j.w + a.k.z*b.k.w + a.k.w*b.l.w;
r.l.x = a.l.x*b.i.x + a.l.y*b.j.x + a.l.z*b.k.x + a.l.w*b.l.x;
r.l.y = a.l.x*b.i.y + a.l.y*b.j.y + a.l.z*b.k.y + a.l.w*b.l.y;
r.l.z = a.l.x*b.i.z + a.l.y*b.j.z + a.l.z*b.k.z + a.l.w*b.l.z;
r.l.w = a.l.x*b.i.w + a.l.y*b.j.w + a.l.z*b.k.w + a.l.w*b.l.w;
return r;
}
sMatrix34 operator* (const sMatrix34 &a,const sMatrix34 &b)
{
sMatrix34 r;
r.i.x = a.i.x*b.i.x + a.i.y*b.j.x + a.i.z*b.k.x;
r.i.y = a.i.x*b.i.y + a.i.y*b.j.y + a.i.z*b.k.y;
r.i.z = a.i.x*b.i.z + a.i.y*b.j.z + a.i.z*b.k.z;
r.j.x = a.j.x*b.i.x + a.j.y*b.j.x + a.j.z*b.k.x;
r.j.y = a.j.x*b.i.y + a.j.y*b.j.y + a.j.z*b.k.y;
r.j.z = a.j.x*b.i.z + a.j.y*b.j.z + a.j.z*b.k.z;
r.k.x = a.k.x*b.i.x + a.k.y*b.j.x + a.k.z*b.k.x;
r.k.y = a.k.x*b.i.y + a.k.y*b.j.y + a.k.z*b.k.y;
r.k.z = a.k.x*b.i.z + a.k.y*b.j.z + a.k.z*b.k.z;
r.l.x = a.l.x*b.i.x + a.l.y*b.j.x + a.l.z*b.k.x + b.l.x;
r.l.y = a.l.x*b.i.y + a.l.y*b.j.y + a.l.z*b.k.y + b.l.y;
r.l.z = a.l.x*b.i.z + a.l.y*b.j.z + a.l.z*b.k.z + b.l.z;
return r;
}
sMatrix34CM operator* (const sMatrix34CM &a,const sMatrix34CM &b)
{
sMatrix34CM r;
r.x.x = a.x.x*b.x.x + a.y.x*b.x.y + a.z.x*b.x.z;
r.y.x = a.x.x*b.y.x + a.y.x*b.y.y + a.z.x*b.y.z;
r.z.x = a.x.x*b.z.x + a.y.x*b.z.y + a.z.x*b.z.z;
r.x.y = a.x.y*b.x.x + a.y.y*b.x.y + a.z.y*b.x.z;
r.y.y = a.x.y*b.y.x + a.y.y*b.y.y + a.z.y*b.y.z;
r.z.y = a.x.y*b.z.x + a.y.y*b.z.y + a.z.y*b.z.z;
r.x.z = a.x.z*b.x.x + a.y.z*b.x.y + a.z.z*b.x.z;
r.y.z = a.x.z*b.y.x + a.y.z*b.y.y + a.z.z*b.y.z;
r.z.z = a.x.z*b.z.x + a.y.z*b.z.y + a.z.z*b.z.z;
r.x.w = a.x.w*b.x.x + a.y.w*b.x.y + a.z.w*b.x.z + b.x.w;
r.y.w = a.x.w*b.y.x + a.y.w*b.y.y + a.z.w*b.y.z + b.y.w;
r.z.w = a.x.w*b.z.x + a.y.w*b.z.y + a.z.w*b.z.z + b.z.w;
return r;
}
#endif
/****************************************************************************/
sMatrix34 operator* (const sMatrix34 &a,sF32 b)
{
sMatrix34 res;
res.i=a.i*b;
res.j=a.j*b;
res.k=a.k*b;
res.l=sVector31(a.l*b);
return res;
}
sMatrix44 operator* (const sMatrix44 &a,sF32 b)
{
sMatrix44 res;
res.i=a.i*b;
res.j=a.j*b;
res.k=a.k*b;
res.l=a.l*b;
return res;
}
sMatrix34& operator *= (sMatrix34 &a, sF32 b)
{
a.i*=b;
a.j*=b;
a.k*=b;
a.l=sVector31(a.l*b);
return a;
}
sMatrix44& operator *= (sMatrix44 &a, sF32 b)
{
a.i*=b;
a.j*=b;
a.k*=b;
a.l*=b;
return a;
}
sMatrix34 operator+ (const sMatrix34 &a, const sMatrix34 &b)
{
sMatrix34 res;
res.i=a.i+b.i;
res.j=a.i+b.j;
res.k=a.k+b.k;
res.l=a.l+sVector30(b.l);
return res;
}
sMatrix44 operator+ (const sMatrix44 &a, const sMatrix44 &b)
{
sMatrix44 res;
res.i=a.i+b.i;
res.j=a.i+b.j;
res.k=a.k+b.k;
res.l=a.l+b.l;
return res;
}
sMatrix34 operator- (const sMatrix34 &a, const sMatrix34 &b)
{
sMatrix34 res;
res.i=a.i-b.i;
res.j=a.i-b.j;
res.k=a.k-b.k;
res.l=a.l-sVector30(b.l);
return res;
}
sMatrix44 operator- (const sMatrix44 &a, const sMatrix44 &b)
{
sMatrix44 res;
res.i=a.i-b.i;
res.j=a.i-b.j;
res.k=a.k-b.k;
res.l=a.l-b.l;
return res;
}
sMatrix34& operator+= (sMatrix34 &a, const sMatrix34 &b)
{
a.i+=b.i;
a.j+=b.j;
a.k+=b.k;
a.l+=sVector30(b.l);
return a;
}
sMatrix44& operator+= (sMatrix44 &a, const sMatrix44 &b)
{
a.i+=b.i;
a.j+=b.j;
a.k+=b.k;
a.l+=b.l;
return a;
}
sMatrix34& operator-= (sMatrix34 &a, const sMatrix34 &b)
{
a.i-=b.i;
a.j-=b.j;
a.k-=b.k;
a.l-=sVector30(b.l);
return a;
}
sMatrix44& operator-= (sMatrix44 &a, const sMatrix44 &b)
{
a.i-=b.i;
a.j-=b.j;
a.k-=b.k;
a.l-=b.l;
return a;
}
/****************************************************************************/
#ifndef sHASINTRINSIC_VECTORMATRIXMUL
sVector30 operator* (sVector30Arg a,const sMatrix34 &b)
{
return sVector30(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z
);
}
sVector31 operator* (sVector31Arg a,const sMatrix34 &b)
{
return sVector31(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x + b.l.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y + b.l.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z + b.l.z
);
}
sVector4 operator* (sVector4Arg a,const sMatrix34 &b)
{
return sVector4(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x + a.w*b.l.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y + a.w*b.l.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z + a.w*b.l.z,
a.w
);
}
sVector30 operator* (sVector30Arg a,const sMatrix34CM &b)
{
return sVector30(
a^b.x,
a^b.y,
a^b.z
);
}
sVector31 operator* (sVector31Arg a,const sMatrix34CM &b)
{
return sVector31(
a^b.x,
a^b.y,
a^b.z
);
}
sVector4 operator* (sVector4Arg a,const sMatrix34CM &b)
{
return sVector4(
a^b.x,
a^b.y,
a^b.z,
a.w
);
}
sVector4 operator* (sVector30Arg a,const sMatrix44 &b)
{
return sVector4(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z,
a.x*b.i.w + a.y*b.j.w + a.z*b.k.w
);
}
sVector4 operator* (sVector31Arg a,const sMatrix44 &b)
{
return sVector4(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x + b.l.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y + b.l.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z + b.l.z,
a.x*b.i.w + a.y*b.j.w + a.z*b.k.w + b.l.w
);
}
sVector4 operator* (sVector4Arg a,const sMatrix44 &b)
{
return sVector4(
a.x*b.i.x + a.y*b.j.x + a.z*b.k.x + a.w*b.l.x,
a.x*b.i.y + a.y*b.j.y + a.z*b.k.y + a.w*b.l.y,
a.x*b.i.z + a.y*b.j.z + a.z*b.k.z + a.w*b.l.z,
a.x*b.i.w + a.y*b.j.w + a.z*b.k.w + a.w*b.l.w
);
}
#endif
sFormatStringBuffer& operator% (sFormatStringBuffer &f,sVector2Arg v)
{
if(!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"[");
f.PrintFloat(info,v.x);
f.Print(L",");
f.PrintFloat(info,v.y);
f.Print(L"]");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sVector30 &v)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"[");
f.PrintFloat(info,v.x);
f.Print(L",");
f.PrintFloat(info,v.y);
f.Print(L",");
f.PrintFloat(info,v.z);
f.Print(L",0]");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sVector31 &v)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"[");
f.PrintFloat(info,v.x);
f.Print(L",");
f.PrintFloat(info,v.y);
f.Print(L",");
f.PrintFloat(info,v.z);
f.Print(L",1]");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sVector4 &v)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"[");
f.PrintFloat(info,v.x);
f.Print(L",");
f.PrintFloat(info,v.y);
f.Print(L",");
f.PrintFloat(info,v.z);
f.Print(L",");
f.PrintFloat(info,v.w);
f.Print(L"]");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sMatrix34 &mat)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"i[");
f.PrintFloat(info,mat.i.x);
f.Print(L",");
f.PrintFloat(info,mat.i.y);
f.Print(L",");
f.PrintFloat(info,mat.i.z);
f.Print(L",0]\n");
f.Print(L"j[");
f.PrintFloat(info,mat.j.x);
f.Print(L",");
f.PrintFloat(info,mat.j.y);
f.Print(L",");
f.PrintFloat(info,mat.j.z);
f.Print(L",0]\n");
f.Print(L"k[");
f.PrintFloat(info,mat.k.x);
f.Print(L",");
f.PrintFloat(info,mat.k.y);
f.Print(L",");
f.PrintFloat(info,mat.k.z);
f.Print(L",0]\n");
f.Print(L"l[");
f.PrintFloat(info,mat.l.x);
f.Print(L",");
f.PrintFloat(info,mat.l.y);
f.Print(L",");
f.PrintFloat(info,mat.l.z);
f.Print(L",1]\n");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sMatrix34CM &mat)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"a[");
f.PrintFloat(info,mat.x.x);
f.Print(L",");
f.PrintFloat(info,mat.x.y);
f.Print(L",");
f.PrintFloat(info,mat.x.z);
f.Print(L",");
f.PrintFloat(info,mat.x.w);
f.Print(L"]\n");
f.Print(L"b[");
f.PrintFloat(info,mat.y.x);
f.Print(L",");
f.PrintFloat(info,mat.y.y);
f.Print(L",");
f.PrintFloat(info,mat.y.z);
f.Print(L",");
f.PrintFloat(info,mat.y.w);
f.Print(L"]\n");
f.Print(L"c[");
f.PrintFloat(info,mat.z.x);
f.Print(L",");
f.PrintFloat(info,mat.z.y);
f.Print(L",");
f.PrintFloat(info,mat.z.z);
f.Print(L",");
f.PrintFloat(info,mat.z.w);
f.Print(L"]\n");
f.Fill();
return f;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sMatrix44 &mat)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"i[");
f.PrintFloat(info,mat.i.x);
f.Print(L",");
f.PrintFloat(info,mat.i.y);
f.Print(L",");
f.PrintFloat(info,mat.i.z);
f.Print(L",");
f.PrintFloat(info,mat.i.w);
f.Print(L"]\n");
f.Print(L"j[");
f.PrintFloat(info,mat.j.x);
f.Print(L",");
f.PrintFloat(info,mat.j.y);
f.Print(L",");
f.PrintFloat(info,mat.j.z);
f.Print(L",");
f.PrintFloat(info,mat.j.w);
f.Print(L"]\n");
f.Print(L"k[");
f.PrintFloat(info,mat.k.x);
f.Print(L",");
f.PrintFloat(info,mat.k.y);
f.Print(L",");
f.PrintFloat(info,mat.k.z);
f.Print(L",");
f.PrintFloat(info,mat.k.w);
f.Print(L"]\n");
f.Print(L"l[");
f.PrintFloat(info,mat.l.x);
f.Print(L",");
f.PrintFloat(info,mat.l.y);
f.Print(L",");
f.PrintFloat(info,mat.l.z);
f.Print(L",");
f.PrintFloat(info,mat.l.w);
f.Print(L"]\n");
f.Fill();
return f;
}
/****************************************************************************/
/*** ***/
/*** Quaternion ***/
/*** ***/
/****************************************************************************/
void sQuaternion::Unit()
{
sF32 e = sFRSqrt(1.0f*i*i + 1.0f*j*j + 1.0f*k*k + 1.0f*r*r);
i = sF32(e*i);
j = sF32(e*j);
k = sF32(e*k);
r = sF32(e*r);
// no safety check, zero-quaternions should never come across
}
void sQuaternion::Lerp(sF32 fade,sQuaternionArg a,sQuaternionArg b)
{
sF32 dot = a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k;
#if 1 // this part introduces the interpolation error over 90 DEG (in some cases)
if(dot<0.f)
{
r = -a.r + (b.r+a.r)*fade;
i = -a.i + (b.i+a.i)*fade;
j = -a.j + (b.j+a.j)*fade;
k = -a.k + (b.k+a.k)*fade;
}
else
#endif
{
r = a.r + (b.r-a.r)*fade;
i = a.i + (b.i-a.i)*fade;
j = a.j + (b.j-a.j)*fade;
k = a.k + (b.k-a.k)*fade;
}
}
void sQuaternion::Slerp(sF32 fade,sQuaternionArg a,sQuaternionArg b)
{
sF32 f0,f1;
sF32 angle,s;
sF32 dot;
dot = a.r*b.r + a.i*b.i + a.j*b.j + a.k*b.k;
if(dot<=-1) angle = sPIF;
else if(dot>=1) angle = 0;
else angle = sFACos(dot);
s=sFSin(angle);
if(s==0)
{
*this = (angle<sPIF/2) ? a:b;
}
else
{
f0 = sF32(sFSin((1-fade)*angle)/s);
f1 = sF32(sFSin( fade *angle)/s);
r = f0*a.r + f1*b.r;
i = f0*a.i + f1*b.i;
j = f0*a.j + f1*b.j;
k = f0*a.k + f1*b.k;
}
}
void sQuaternion::FastSlerp(sF32 fade, sQuaternionArg a, sQuaternionArg b)
{
// ideas taken from Jonathan Blow's paper "Hacking Quaternions" [Blow2002]
// use a cubic spline to correct the speed error introduced by lerp
// the function's error is bigger in the 0.5-1.0 range, so just
// mirror the interpolation for the upper half.
// special-case: no blend needed. so save the time
if(fade<=0.f+0.00000001f)
{ i=a.i;
j=a.j;
k=a.k;
r=a.r;
return;
} else if(fade>=1.f-0.00000001f)
{ i=b.i;
j=b.j;
k=b.k;
r=b.r;
return;
}
sF32 K = 1.0f - 0.8228677f * dot(a,b);
K = K*K*0.5069269f;
if (fade>=0.5f)
{ fade = 1.0f-fade;
fade = 1.0f-((fade * K * (2*fade-3) + K + 1)*fade);
} else
{ fade = (fade * K * (2*fade-3) + K + 1)*fade;
}
Lerp(fade,a,b);
#if 1
sF32 e = i*i + j*j + k*k + r*r;
if(e<0.00000000001f) // make the code bulletproof...
{ i = j = r = 0; k = 1;
return;
}
e = sFRSqrt(e);
i = e*i;
j = e*j;
k = e*k;
r = e*r;
#endif
}
void sQuaternion::Init(const sMatrix34 &mat)
{
sF32 tr,s;
tr = mat.i.x + mat.j.y + mat.k.z;
if(tr>=0)
{
s = (sF32)sFSqrt(tr + 1);
r = s*0.5f;
s = 0.5f / s;
i = (mat.k.y - mat.j.z) * s;
j = (mat.i.z - mat.k.x) * s;
k = (mat.j.x - mat.i.y) * s;
}
else
{
int index;
if (mat.j.y > mat.i.x)
{
if (mat.k.z > mat.j.y) index=2; else index=1;
}
else
{
if (mat.k.z > mat.i.x) index=2; else index=0;
}
switch(index)
{
case 0:
s = (sF32)sFSqrt((mat.i.x - (mat.j.y+mat.k.z)) + 1.0f );
i = s*0.5f;
s = 0.5f / s;
j = (mat.i.y + mat.j.x) * s;
k = (mat.k.x + mat.i.z) * s;
r = (mat.k.y - mat.j.z) * s;
break;
case 1:
s = (sF32)sFSqrt( (mat.j.y - (mat.k.z+mat.i.x)) + 1.0f );
j = s*0.5f;
s = 0.5f / s;
k = (mat.j.z + mat.k.y) * s;
i = (mat.i.y + mat.j.x) * s;
r = (mat.i.z - mat.k.x) * s;
break;
case 2:
s = (sF32)sFSqrt( (mat.k.z - (mat.i.x+mat.j.y)) + 1.0f );
k = s*0.5f;
s = 0.5f / s;
i = (mat.k.x + mat.i.z) * s;
j = (mat.j.z + mat.k.y) * s;
r = (mat.j.x - mat.i.y) * s;
break;
}
}
}
void sQuaternion::Init(sVector30Arg axis, sF32 angle)
{
sF32 si;
sFSinCos(angle/2,si,r);
i=si*axis.x;
j=si*axis.y;
k=si*axis.z;
}
/****************************************************************************/
void sQuaternion::Euler(sF32 h, sF32 p, sF32 b)
{
sF32 sh,ch,sp,cp,sb,cb;
sFSinCos(h*0.5f,sh,ch);
sFSinCos(p*0.5f,sp,cp);
sFSinCos(b*0.5f,sb,cb);
const sF32 chcp=ch*cp;
const sF32 shsp=sh*sp;
const sF32 shcp=sh*cp;
const sF32 chsp=ch*sp;
r = chcp*cb - shsp*sb;
i = chcp*sb + shsp*cb;
j = shcp*cb + chsp*sb;
k = chsp*cb - shcp*sb;
}
sVector30 sQuaternion::GetEuler() const
{
sF32 h,p,b;
const sF32 d = i*j+k*r;
if (d>0.4999f)
{
h=2.0f*sFATan2(i,r);
p=sPIF/2.0f;
b=0;
}
else if (d<-0.4999f)
{
h=-2.0f*sFATan2(i,r);
p=-sPIF/2.0f;
b=0;
}
else
{
const sF32 i2=i*i;
const sF32 j2=j*j;
const sF32 k2=k*k;
h=sFATan2(2.0f*(j*r-i*k),1.0f-2.0f*(j2-k2));
p=sFASin(2.0f*d);
b=sFATan2(2.0f*(i*r-j*k),1.0f-2.0f*(i2-k2));
}
return sVector30(h,p,b);
}
void sQuaternion::GetAxisAngle(sVector30 &axis, sF32 &angle)
{
sF32 lensq=i*i+j*j+k*k;
if (lensq>sEPSILON)
{
lensq=sFRSqrt(lensq);
axis.Init(i*lensq,j*lensq,k*lensq);
angle=2*sFACos(r);
}
else
{
axis.Init(1,0,0);
angle=0;
}
}
void sQuaternion::MakeRotation(sVector30Arg v1, sVector30Arg v2)
{
sVector30 axis;
axis.Cross(v2,v1);
sF32 dot=v1^v2;
if (dot < sEPSILON-1)
{
r=i=k=0;
j=1;
return;
}
i=axis.x;
j=axis.y;
k=axis.z;
r=dot+1;
Unit();
}
void sQuaternion::Invert()
{
sF32 lensq=r*r+i*i+j*j+k*k;
if (lensq>sEPSILON)
{
lensq=sFRSqrt(lensq);
r*=lensq;
i*=-lensq;
j*=-lensq;
k*=-lensq;
}
}
void sQuaternion::Invert(sQuaternionArg q)
{
sF32 lensq=q.r*q.r+q.i*q.i+q.j*q.j+q.k*q.k;
if (lensq>sEPSILON)
{
lensq=sFRSqrt(lensq);
r=lensq*q.r;
i=-lensq*q.i;
j=-lensq*q.j;
k=-lensq*q.k;
}
}
void sQuaternion::InvertNorm()
{
i=-i;
j=-j;
k=-k;
}
/*
Quaternion fast_simple_rotation(const Vector3 &a, const Vector3 &b) {
Vector3 axis = cross_product(a, b);
float dot = dot_product(a, b);
if (dot < -1.0f + DOT_EPSILON) return Quaternion(0, 1, 0, 0);
Quaternion result(axis.x * 0.5f, axis.y * 0.5f, axis.z * 0.5f, (dot + 1.0f) * 0.5f);
fast_normalize(&result);
return result;
}
public void set(Quat4d q1) {
double test = q1.x*q1.y + q1.z*q1.w;
if (test > 0.499) { // singularity at north pole
heading = 2 * atan2(q1.x,q1.w);
attitude = Math.PI/2;
bank = 0;
return;
}
if (test < -0.499) { // singularity at south pole
heading = -2 * atan2(q1.x,q1.w);
attitude = - Math.PI/2;
bank = 0;
return;
}
double sqx = q1.x*q1.x;
double sqy = q1.y*q1.y;
double sqz = q1.z*q1.z;
heading = atan2(2*q1.y*q1.w-2*q1.x*q1.z , 1 - 2*sqy - 2*sqz);
attitude = asin(2*test);
bank = atan2(2*q1.x*q1.w-2*q1.y*q1.z , 1 - 2*sqx - 2*sqz)
}
*/
/*
public final void rotate(double heading, double attitude, double bank) {
// Assuming the angles are in radians.
double c1 = Math.cos(heading/2);
double s1 = Math.sin(heading/2);
double c2 = Math.cos(attitude/2);
double s2 = Math.sin(attitude/2);
double c3 = Math.cos(bank/2);
double s3 = Math.sin(bank/2);
double c1c2 = c1*c2;
double s1s2 = s1*s2;
w =c1c2*c3 - s1s2*s3;
x =c1c2*s3 + s1s2*c3;
y =s1*c2*c3 + c1*s2*s3;
z =c1*s2*c3 - s1*c2*s3;
}
*/
/****************************************************************************/
sQuaternion operator* (sQuaternionArg a,sQuaternionArg b)
{
sQuaternion q;
q.i = a.i*b.r + a.r*b.i - a.k*b.j + a.j*b.k;
q.j = a.j*b.r + a.k*b.i + a.r*b.j - a.i*b.k;
q.k = a.k*b.r - a.j*b.i + a.i*b.j + a.r*b.k;
q.r = a.r*b.r - a.i*b.i - a.j*b.j - a.k*b.k;
return q;
}
sVector30 operator* (sVector30Arg a,sQuaternionArg b)
{
/*
From terrainshader: (I derived this by hand and optimized it for min. PS instruction count)
q=quaternion, v=vector
float3 t0 = cross(q.xyz,v.xyz);
float4 t1 = q+q;
return v + t1.w*t0 + cross(t1.xyz,t0);
In this case the imaginary part is inverted, so you need to switch the order for both cross products.
*/
// cross of vector part of v with q
sF32 t0x = a.y*b.k - a.z*b.j;
sF32 t0y = a.z*b.i - a.x*b.k;
sF32 t0z = a.x*b.j - a.y*b.i;
// the sum
sF32 t1x = b.i + b.i;
sF32 t1y = b.j + b.j;
sF32 t1z = b.k + b.k;
sF32 t1r = b.r + b.r;
// final expression
return sVector30(
a.x + t1r * t0x + t0y*t1z - t0z*t1y,
a.y + t1r * t0y + t0z*t1x - t0x*t1z,
a.z + t1r * t0z + t0x*t1y - t0y*t1x
);
}
sVector31 operator* (sVector31Arg a,sQuaternionArg b)
{
// same as above.
// cross of vector part of v with q
sF32 t0x = a.y*b.k - a.z*b.j;
sF32 t0y = a.z*b.i - a.x*b.k;
sF32 t0z = a.x*b.j - a.y*b.i;
// the sum
sF32 t1x = b.i + b.i;
sF32 t1y = b.j + b.j;
sF32 t1z = b.k + b.k;
sF32 t1r = b.r + b.r;
// final expression
return sVector31(
a.x + t1r * t0x + t0y*t1z - t0z*t1y,
a.y + t1r * t0y + t0z*t1x - t0x*t1z,
a.z + t1r * t0z + t0x*t1y - t0y*t1x
);
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f, sQuaternionArg q)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"[");
f.PrintFloat(info,q.r);
f.Print(L"|");
f.PrintFloat(info,q.i);
f.Print(L",");
f.PrintFloat(info,q.j);
f.Print(L",");
f.PrintFloat(info,q.k);
f.Print(L"]");
f.Fill();
return f;
}
/****************************************************************************/
/*** ***/
/*** more vector math ***/
/*** ***/
/****************************************************************************/
sAABBox::sAABBox()
{
Clear();
}
void sAABBox::Clear()
{
Min.x = 1e30f;
Min.y = 1e30f;
Min.z = 1e30f;
Max.x = -1e30f;
Max.y = -1e30f;
Max.z = -1e30f;
}
void sAABBox::Init(const sAABBoxC &s)
{
Min = s.Center-s.Radius;
Max = s.Center+s.Radius;
}
sBool sAABBox::HitPoint(sVector31Arg p) const
{
return (p.x>=Min.x && p.x<=Max.x &&
p.y>=Min.y && p.y<=Max.y &&
p.z>=Min.z && p.z<=Max.z);
}
void sAABBox::And(const sAABBox &box)
{
if(box.Min.x>Min.x) Min.x = box.Min.x;
if(box.Min.y>Min.y) Min.y = box.Min.y;
if(box.Min.z>Min.z) Min.z = box.Min.z;
if(box.Max.x<Max.x) Max.x = box.Max.x;
if(box.Max.y<Max.y) Max.y = box.Max.y;
if(box.Max.z<Max.z) Max.z = box.Max.z;
}
void sAABBox::Add(const sAABBox &box)
{
if(box.Min.x<Min.x) Min.x = box.Min.x;
if(box.Min.y<Min.y) Min.y = box.Min.y;
if(box.Min.z<Min.z) Min.z = box.Min.z;
if(box.Max.x>Max.x) Max.x = box.Max.x;
if(box.Max.y>Max.y) Max.y = box.Max.y;
if(box.Max.z>Max.z) Max.z = box.Max.z;
}
void sAABBox::Add(sVector31Arg p)
{
if(p.x<Min.x) Min.x = p.x;
if(p.y<Min.y) Min.y = p.y;
if(p.z<Min.z) Min.z = p.z;
if(p.x>Max.x) Max.x = p.x;
if(p.y>Max.y) Max.y = p.y;
if(p.z>Max.z) Max.z = p.z;
}
void sAABBox::Add(const sAABBox &box,const sMatrix34 &mat)
{
sVector31 v[8];
box.MakePoints(v);
for(sInt i=0;i<8;i++)
Add(v[i]*mat);
}
void sAABBox::Add(const sAABBoxC &box,const sMatrix34CM &mat)
{
sAABBox b;
sMatrix34 m(mat);
b.Init(box);
Add(b,m);
}
void sAABBox::MakePoints(sVector31 *v) const
{
v[0].Init(Min.x,Min.y,Min.z);
v[1].Init(Max.x,Min.y,Min.z);
v[2].Init(Max.x,Max.y,Min.z);
v[3].Init(Min.x,Max.y,Min.z);
v[4].Init(Min.x,Min.y,Max.z);
v[5].Init(Max.x,Min.y,Max.z);
v[6].Init(Max.x,Max.y,Max.z);
v[7].Init(Min.x,Max.y,Max.z);
}
sBool sAABBox::HitRay(sF32 &dist,const sRay &ray) const
{
sF32 min = 0.0f, max = 1e+20f;
for(sInt i=0;i<3;i++)
{
if(ray.Dir[i])
{
sF32 inv = 1.0f / ray.Dir[i];
sF32 t0 = (Min[i] - ray.Start[i]) * inv;
sF32 t1 = (Max[i] - ray.Start[i]) * inv;
if(t0 > t1) sSwap(t0,t1);
min = sMax(min,t0);
max = sMin(max,t1);
if(min > max) return sFALSE;
}
else if(ray.Start[i] < Min[i] || ray.Start[i] > Max[i])
return sFALSE;
}
dist = min;
return sTRUE;
}
// this is *almost* the same as sIntersectRayAABB, but it handles the case where one or more
// components of dir are zero differently (=without using IEEE infinities).
sBool sAABBox::HitInvRay(sF32 &dist,sVector31Arg origin,sVector30Arg invDir) const
{
sF32 min = 0.0f, max = 1e+20f;
// x and z before y since we have lots of tests in +y or -y direction
if(invDir.x)
{
sF32 t0 = (Min.x - origin.x) * invDir.x;
sF32 t1 = (Max.x - origin.x) * invDir.x;
sF32 tMin = sMin(t0,t1);
sF32 tMax = sMax(t0,t1);
min = sMax(min,tMin);
max = sMin(max,tMax);
}
else if(origin.x < Min.x || origin.x > Max.x)
return sFALSE;
if(invDir.z)
{
sF32 t0 = (Min.z - origin.z) * invDir.z;
sF32 t1 = (Max.z - origin.z) * invDir.z;
sF32 tMin = sMin(t0,t1);
sF32 tMax = sMax(t0,t1);
min = sMax(min,tMin);
max = sMin(max,tMax);
}
else if(origin.z < Min.z || origin.z > Max.z)
return sFALSE;
if(invDir.y)
{
sF32 t0 = (Min.y - origin.y) * invDir.y;
sF32 t1 = (Max.y - origin.y) * invDir.y;
sF32 tMin = sMin(t0,t1);
sF32 tMax = sMax(t0,t1);
min = sMax(min,tMin);
max = sMin(max,tMax);
}
else if(origin.y < Min.y || origin.y > Max.y)
return sFALSE;
if(min > max)
return sFALSE;
dist = min;
return sTRUE;
//for(sInt i=0;i<3;i++)
//{
// if(invDir[i])
// {
// sF32 t0 = (Min[i] - origin[i]) * invDir[i];
// sF32 t1 = (Max[i] - origin[i]) * invDir[i];
// if(t0 > t1) sSwap(t0,t1);
// min = sMax(min,t0);
// max = sMin(max,t1);
// if(min > max) return sFALSE;
// }
// else if(origin[i] < Min[i] || origin[i] > Max[i])
// return sFALSE;
//}
//
//dist = min;
//return sTRUE;
}
sF32 sAABBox::CalcArea()const
{
sF32 area = (Max.x-Min.x)*(Max.y-Min.y);
area += (Max.y-Min.y)*(Max.z-Min.z);
area += (Max.z-Min.z)*(Max.x-Min.x);
return area*2.0f;
}
sF32 sAABBox::CalcVolume()const
{
sF32 area = (Max.x-Min.x)*(Max.y-Min.y)*(Max.z-Min.z);
return area;
}
sBool sAABBox::IsEmpty() const
{
return (Min.x>=Max.x || Min.y>=Max.y || Min.z>=Max.z);
}
sBool sAABBox::IsValid() const
{
return (Min.x<=Max.x || Min.y<=Max.y || Min.z<=Max.z);
}
sBool sAABBox::Intersects(const sAABBox &b) const
{
return sMax(Min.x,b.Min.x) <= sMin(Max.x,b.Max.x)
&& sMax(Min.y,b.Min.y) <= sMin(Max.y,b.Max.y)
&& sMax(Min.z,b.Min.z) <= sMin(Max.z,b.Max.z);
}
sBool sAABBox::IntersectsXZ(const sAABBox &b) const
{
return sMax(Min.x,b.Min.x) <= sMin(Max.x,b.Max.x) && sMax(Min.z,b.Min.z) <= sMin(Max.z,b.Max.z);
}
sBool sAABBox::IntersectsMovingBox(const sAABBox &box,sVector30Arg v,sF32 tMin,sF32 tMax) const
{
sVector30 invV;
invV.x = v.x ? 1.0f / v.x : 0.0f;
invV.y = v.y ? 1.0f / v.y : 0.0f;
invV.z = v.z ? 1.0f / v.z : 0.0f;
return IntersectsMovingBoxInv(box,invV,tMin,tMax);
}
sBool sAABBox::IntersectsMovingBoxInv(const sAABBox &box,sVector30Arg invV,sF32 tMin,sF32 tMax) const
{
if(tMin > tMax)
return sFALSE;
for(sInt i=0;i<3;i++)
{
sF32 iv = invV[i];
if(iv)
{
// calc start/end time of interval overlap
sF32 t0 = (Min[i] - box.Max[i]) * iv;
sF32 t1 = (Max[i] - box.Min[i]) * iv;
if(iv < 0.0f)
sSwap(t0,t1);
// intersect with current interval
tMin = sMax(tMin,t0);
tMax = sMin(tMax,t1);
if(tMin > tMax) // intersection empty?
return sFALSE;
}
else if(Max[i] < box.Min[i] || Min[i] > box.Max[i]) // stationary along that axis, check for overlap
return sFALSE;
}
return sTRUE;
}
sF32 sAABBox::DistanceToSq(sVector31Arg p) const
{
sF32 d=0.0f;
if(p.x < Min.x) d += sSquare(p.x-Min.x);
else if(p.x > Max.x) d += sSquare(p.x-Max.x);
if(p.y < Min.y) d += sSquare(p.y-Min.y);
else if(p.y > Max.y) d += sSquare(p.y-Max.y);
if(p.z < Min.z) d += sSquare(p.z-Min.z);
else if(p.z > Max.z) d += sSquare(p.z-Max.z);
return d;
}
sAABBox &sAABBox::operator*=(const sMatrix34 &m)
{
sVector31 v[8];
MakePoints(v);
for(sInt i=0;i<8;i++)
v[i] = v[i]*m;
Clear();
for(sInt i=0;i<8;i++)
Add(v[i]);
return *this;
}
sInt sAABBox::Classify(sVector30Arg n, sF32 d)
{
sVector31 c = Center();
sF32 radius = Size().Length() * 0.5f;
return ((n ^ c) - d) < radius;
}
sFormatStringBuffer& operator% (sFormatStringBuffer &f,const sAABBox &bbox)
{
if (!*f.Format)
return f;
sFormatStringInfo info;
f.GetInfo(info);
f.Print(L"min[");
f.PrintFloat(info,bbox.Min.x);
f.Print(L",");
f.PrintFloat(info,bbox.Min.y);
f.Print(L",");
f.PrintFloat(info,bbox.Min.z);
f.Print(L"]");
f.Print(L"-max[");
f.PrintFloat(info,bbox.Max.x);
f.Print(L",");
f.PrintFloat(info,bbox.Max.y);
f.Print(L",");
f.PrintFloat(info,bbox.Max.z);
f.Print(L"]");
f.Fill();
return f;
}
/****************************************************************************/
/****************************************************************************/
sBool sRay::HitTriangle(sF32 &dist,sVector31Arg p0,sVector31Arg p1,sVector31Arg p2) const
{
sVector30 d1,d2,n,org,org1,org2;
sF32 angle,e1,e2;
sF32 b;
org = Start-p0;
d2 = p1-p0;
d1 = p2-p0;
n.Cross(d1,d2);
angle = Dir^n;
if(angle<=sEPSILON)
return 0;
org2.Cross(org,d2);
e2 = Dir^org2;
if(e2<0) return 0;
org1.Cross(d1,org);
e1 = Dir^org1;
if(e1<0 || e1+e2>angle) return 0;
b = -org^n;
if(b<0)return 0;
dist = b/angle;
return 1;
}
sBool sRay::HitTriangleDoubleSided(sF32 &dist,sVector31Arg p0,sVector31Arg p1,sVector31Arg p2) const
{
sVector30 d1,d2,n,org,org1,org2;
sF32 angle,e1,e2;
sF32 b;
org = Start-p0;
d2 = p1-p0;
d1 = p2-p0;
n.Cross(d1,d2);
angle = Dir^n;
if(angle<0)
{
angle = -angle;
n.Neg();
sSwap(d1,d2);
}
if(angle<=sEPSILON)
return 0;
org2.Cross(org,d2);
e2 = Dir^org2;
if(e2<=0) return 0;
org1.Cross(d1,org);
e1 = Dir^org1;
if(e1<=0 || e1+e2>angle) return 0;
b = -org^n;
if(b<=0)return 0;
dist = b/angle;
return 1;
}
sBool sRay::HitTriangleBary(sF32 &dist,sVector31Arg p0,sVector31Arg p1,sVector31Arg p2,sF32 &u0,sF32 &u1,sF32 &u2) const
{
sVector30 d1,d2,n,org,org1,org2;
sF32 angle,e1,e2;
sF32 b;
org = Start-p0;
d2 = p1-p0;
d1 = p2-p0;
n.Cross(d1,d2);
angle = Dir^n;
if(angle<=sEPSILON)
return 0;
org2.Cross(org,d2);
e2 = Dir^org2;
if(e2<=0) return 0;
org1.Cross(d1,org);
e1 = Dir^org1;
if(e1<=0 || e1+e2>angle) return 0;
b = -org^n;
if(b<=0)return 0;
sF32 invAngle = 1.0f / angle;
dist = b * invAngle;
u2 = e2 * invAngle;
u1 = e1 * invAngle;
u0 = 1.0f - u1 - u2;
return 1;
}
sBool sRay::HitPlane(sVector31 &intersect,sVector4Arg plane) const
{
sF32 angle;
sF32 dist;
dist = plane^Start; // distance above plane
if(dist<0) return 0; // already below plane.
angle = -(plane^Dir); // direction
if(angle<sEPSILON) return 0; // ray away from plane
intersect = Start + Dir*(dist/angle);
return 1;
}
sBool sRay::HitPlaneDoubleSided(sVector31 &intersect,sVector4Arg plane) const
{
sF32 angle;
sF32 dist;
dist = plane^Start; // distance above plane
angle = -(plane^Dir); // direction
if(dist>0)
{
if(angle<sEPSILON) return 0; // ray away from plane
}
else
{
if(angle>sEPSILON) return 0; // ray away from plane
}
intersect = Start + Dir*(dist/angle);
return 1;
}
sBool sRay::HitSphere(sF32 *dist, sVector31Arg center, sF32 radius) const
{
sF32 r2=radius*radius;
sVector30 dir2=center-Start;
if ((dir2^dir2) <= r2) // ray start in sphere?
{
if (dist) *dist=0;
return 0;
}
sF32 l=Dir^dir2;
if (l<0) return 0; // point is behind ray
sVector30 d=center-(Start+l*Dir);
sF32 d2=d^d;
if (d2<=r2)
{
if (dist)
*dist=l-sFSqrt(r2-d2);
return 1;
}
return 0;
}
sBool sIntersectRayAABB(sF32 &min, sF32 &max, const sVector31 &ro, const sVector30 &ird, const sVector31 &bbmin, const sVector31 &bbmax)
{
sF32 near = (bbmin.x-ro.x)*ird.x;
sF32 far = (bbmax.x-ro.x)*ird.x;
sF32 temp = near;
near = (near>far) ? far : near;
far = (temp>far) ? temp : far;
min = (near>min) ? near : min;
max = (far<max) ? far : max;
if(min>max) return sFALSE;
//result = (min>max) ? sFALSE : result;
near = (bbmin.y-ro.y)*ird.y;
far = (bbmax.y-ro.y)*ird.y;
temp = near;
near = (near>far) ? far : near;
far = (temp>far) ? temp : far;
min = (near>min) ? near : min;
max = (far<max) ? far : max;
if(min>max) return sFALSE;
//result = (min>max) ? sFALSE : result;
near = (bbmin.z-ro.z)*ird.z;
far = (bbmax.z-ro.z)*ird.z;
temp = near;
near = (near>far) ? far : near;
far = (temp>far) ? temp : far;
min = (near>min) ? near : min;
max = (far<max) ? far : max;
if(min>max) return sFALSE;
//result = (min>max) ? sFALSE : result;
return sTRUE;
}
sBool sRay::HitAABB(sF32 &min, sF32 &max, const sVector31& bbmin,const sVector31& bbmax)const
{
// sBool result = sTRUE;
sVector30 ird;
ird.x = 1.0f / Dir.x;
ird.y = 1.0f / Dir.y;
ird.z = 1.0f / Dir.z;
return sIntersectRayAABB(min,max,Start,ird,bbmin,bbmax);
//for(sInt i=0;i<3;i++)
//{
// sF32 idir = 1.0f / Dir[i];
// sF32 near = (bbmin[i]-Start[i])*idir;
// sF32 far = (bbmax[i]-Start[i])*idir;
// if(near>far) sSwap(near,far);
// min = near > min ? near : min;
// max = far < max ? far : max;
// if(min>max) return sFALSE;
//}
//return sTRUE;
}
sInt sRay::IntersectPlane(sF32 &t, sVector4Arg plane)const
{
sF32 nd = plane.x*Dir.x+plane.y*Dir.y+plane.z*Dir.z;
sF32 dist=plane.w-plane.x*Start.x-plane.y*Start.y-plane.z*Start.z;;
if(-sEPSILON<nd && nd<sEPSILON)
{
t = 0.0f;
if(-sEPSILON<dist && dist<sEPSILON)
return 2;
return 0;
}
t=dist/nd;
return 1;
}
sBool sRay::HitBilinearPatch(sF32 &dist,const sVector31 &p00,const sVector31 &p01,const sVector31 &p10,const sVector31 &p11,sF32 *uOut,sF32 *vOut) const
{
sVERIFY((uOut && vOut) || (!uOut && !vOut))
// Algorithm by Ramsey, Potter, Hansen, "Ray Bilinear Patch Intersections",
// Journal of Graphics Tools Vol. 9 No. 3 (2004)
static const sF32 sISECT_EPSILON = 1e-6f;
sVector30 d = p00 - Start;
sVector30 c = p10 - p00;
sVector30 b = p01 - p00;
sVector30 a = (p11 - p10) - b;
sVector30 q = Dir;
// permute all vectors so that q.z has largest absolute value
// this is *not* in the paper, but it's definitely necessary.
if(sFAbs(q.x) >= sFAbs(q.y) && sFAbs(q.x) >= sFAbs(q.z))
{
sSwap(a.x,a.z);
sSwap(b.x,b.z);
sSwap(c.x,c.z);
sSwap(d.x,d.z);
sSwap(q.x,q.z);
}
else if(sFAbs(q.y) >= sFAbs(q.z))
{
sSwap(a.y,a.z);
sSwap(b.y,b.z);
sSwap(c.y,c.z);
sSwap(d.y,d.z);
sSwap(q.y,q.z);
}
sF32 A1 = a.x*q.z - a.z*q.x, A2 = a.y*q.z - a.z*q.y;
sF32 B1 = b.x*q.z - b.z*q.x, B2 = b.y*q.z - b.z*q.y;
sF32 C1 = c.x*q.z - c.z*q.x, C2 = c.y*q.z - c.z*q.y;
sF32 D1 = d.x*q.z - d.z*q.x, D2 = d.y*q.z - d.z*q.y;
sF32 v[2];
sInt nSolutions = sSolveQuadratic(v, A2*C1 - A1*C2, A2*D1 - A1*D2 + B2*C1 - B1*C2, B2*D1 - B1*D2);
sF32 currentMinT = 1e+20f;
sBool gotOne = sFALSE;
for(sInt i=0;i<nSolutions;i++)
{
if(v[i] < -sISECT_EPSILON || v[i] > 1.0f + sISECT_EPSILON)
continue;
// compute u
sF32 da,db,u;
da = v[i] * A2 + B2;
db = v[i] * (A2 - A1) + (B2 - B1);
if(sFAbs(db) >= sFAbs(da))
u = (v[i] * (C1 - C2) + D1 - D2) / db;
else
u = (-v[i] * C2 - D2) / da;
if(u < -sISECT_EPSILON || u > 1.0f + sISECT_EPSILON)
continue;
// compute t
sF32 t = (u*v[i]*a.z + u*b.z + v[i]*c.z + d.z) / q.z;
if(t >= 0.0f && t < currentMinT)
{
if(uOut) *uOut = u, *vOut = v[i];
currentMinT = dist = t;
gotOne = sTRUE;
}
}
return gotOne;
}
/*
static sF32 sDistRaySegmentSquared (const sRay &ray, const sVector31 &seg1, const sVector31 &seg2, sF32 *rayparm=0)
{
sVector30 segd = seg2-seg1;
sF32 extent = segd.Length();
segd*=1/extent;
sVector30 kDiff = ray.Start - seg1;
sF32 fA01 = -ray.Dir ^ segd;
sF32 fB0 = kDiff^ray.Dir;
sF32 fB1 = -kDiff^segd;
sF32 fC = kDiff.LengthSq();
sF32 fDet = sFAbs(1.0f - fA01*fA01);
sF32 fS0, fS1, fSqrDist, fExtDet;
if (fDet >= sEPSILON)
{
// The ray and segment are not parallel.
fS0 = fA01*fB1-fB0;
fS1 = fA01*fB0-fB1;
fExtDet = extent*fDet;
if (fS0 >= 0)
{
if (fS1 >= -fExtDet)
{
if (fS1 <= fExtDet) // region 0
{
// minimum at interior points of ray and segment
sF32 fInvDet = (1.0f)/fDet;
fS0 *= fInvDet;
fS1 *= fInvDet;
fSqrDist = fS0*(fS0+fA01*fS1+(2.0f)*fB0) + fS1*(fA01*fS0+fS1+(2.0f)*fB1)+fC;
}
else // region 1
{
fS1 = extent;
fS0 = -(fA01*fS1+fB0);
if (fS0 > 0)
fSqrDist = -fS0*fS0+fS1*(fS1+(2.0f)*fB1)+fC;
else
{
fS0 = 0;
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
}
}
else // region 5
{
fS1 = -extent;
fS0 = -(fA01*fS1+fB0);
if (fS0 > 0)
fSqrDist = -fS0*fS0+fS1*(fS1+(2.0f)*fB1)+fC;
else
{
fS0 = 0;
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
}
}
else
{
if (fS1 <= -fExtDet) // region 4
{
fS0 = -(-fA01*extent+fB0);
if (fS0 > 0)
{
fS1 = -extent;
fSqrDist = -fS0*fS0+fS1*(fS1+(2.0f)*fB1)+fC;
}
else
{
fS0 = 0;
fS1 = sClamp(-fB1,-extent,extent);
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
}
else if (fS1 <= fExtDet) // region 3
{
fS0 = 0;
fS1 = sClamp(-fB1,-extent,extent);
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
else // region 2
{
fS0 = -(fA01*extent+fB0);
if (fS0 > 0)
{
fS1 = extent;
fSqrDist = -fS0*fS0+fS1*(fS1+(2.0f)*fB1)+fC;
}
else
{
fS0 = 0;
fS1 = sClamp(-fB1,-extent,extent);
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
}
}
}
else
{
// ray and segment are parallel
if (fA01 > 0)
fS1 = -extent;
else
fS1 = extent;
fS0 = -(fA01*fS1+fB0);
if (fS0 > 0)
fSqrDist = -fS0*fS0+fS1*(fS1+(2.0f)*fB1)+fC;
else
fSqrDist = fS1*(fS1+(2.0f)*fB1)+fC;
}
if (rayparm) *rayparm=fS0;
return sFAbs(fSqrDist);
}
sBool sRay::HitCappedCylinder(const sVector31 &cylstart, const sVector31 &cylend, sF32 radius, sF32 *dist) const
{
sF32 d2=sDistRaySegmentSquared(*this,cylstart,cylend,dist);
return (d2<=(radius*radius));
}
*/
/****************************************************************************/
/****************************************************************************/
void sAABBoxC::Clear()
{
Center.Init(0,0,0);
Radius.Init(0,0,0);
}
void sAABBoxC::Add(const sAABBoxC &box)
{
if(Radius.x==0 && Radius.y==0 && Radius.z==0)
{
Radius = box.Radius;
Center = box.Center;
}
else
{
sAABBox s;
s.Min.x = sMin(Center.x-Radius.x,box.Center.x-box.Radius.x);
s.Min.y = sMin(Center.y-Radius.y,box.Center.y-box.Radius.y);
s.Min.z = sMin(Center.z-Radius.z,box.Center.z-box.Radius.z);
s.Max.x = sMax(Center.x+Radius.x,box.Center.x+box.Radius.x);
s.Max.y = sMax(Center.y+Radius.y,box.Center.y+box.Radius.y);
s.Max.z = sMax(Center.z+Radius.z,box.Center.z+box.Radius.z);
Radius = 0.5f*(s.Max-s.Min);
Center = s.Max-Radius;
}
}
/****************************************************************************/
sOBBox::sOBBox()
{
}
void sOBBox::Init(const sAABBox &box)
{
BoxToWorld.Init(1,0,0,0); // identity
Center = box.Center();
HalfExtents.x = 0.5f * (box.Max.x - box.Min.x);
HalfExtents.y = 0.5f * (box.Max.y - box.Min.y);
HalfExtents.z = 0.5f * (box.Max.z - box.Min.z);
}
void sOBBox::Init(const sAABBoxC &box)
{
BoxToWorld.Init(1,0,0,0); // identity
Center = box.Center;
HalfExtents = box.Radius;
}
/****************************************************************************/
void sFrustum::Init(const sMatrix44 &mat,sF32 xMin,sF32 xMax,sF32 yMin,sF32 yMax,sF32 zMin,sF32 zMax)
{
const sVector4 colX(mat.i.x,mat.j.x,mat.k.x,mat.l.x);
const sVector4 colY(mat.i.y,mat.j.y,mat.k.y,mat.l.y);
const sVector4 colZ(mat.i.z,mat.j.z,mat.k.z,mat.l.z);
const sVector4 colW(mat.i.w,mat.j.w,mat.k.w,mat.l.w);
Planes[0] = colX - xMin*colW; // sFP_Left
Planes[1] = xMax*colW - colX; // sFP_Right
Planes[2] = colY - yMin*colW; // sFP_Bottom
Planes[3] = yMax*colW - colY; // sFP_Top
Planes[4] = colZ - zMin*colW; // sFP_Near
Planes[5] = zMax*colW - colZ; // sFP_Far
for(sInt i=0;i<6;i++)
{
AbsPlanes[i].x = sAbs(Planes[i].x);
AbsPlanes[i].y = sAbs(Planes[i].y);
AbsPlanes[i].z = sAbs(Planes[i].z);
AbsPlanes[i].w = Planes[i].w ;
}
}
sInt sFrustum::IsInside(const sAABBoxC &b) const
{
sInt result = sTEST_IN;
for(sInt i=0;i<6;i++)
{
sF32 m = b.Center ^ Planes[i];
sF32 n = b.Radius ^ AbsPlanes[i];
if(m+n<0) return sTEST_OUT;
if(m-n<0) result = sTEST_CLIP;
}
return result;
}
sInt sFrustum::IsInside(const sOBBox &b) const
{
sMatrix34 mat(sDontInitialize);
mat.Init(b.BoxToWorld);
sInt result = sTEST_IN;
for(sInt i=0;i<6;i++)
{
sF32 m = b.Center ^ Planes[i];
sF32 n = b.HalfExtents.x * sFAbs(mat.i ^ Planes[i])
+ b.HalfExtents.y * sFAbs(mat.j ^ Planes[i])
+ b.HalfExtents.z * sFAbs(mat.k ^ Planes[i]);
if(m+n<0) return sTEST_OUT;
if(m-n<0) result = sTEST_CLIP;
}
return result;
}
sBool sFrustum::IsOutside(const sOBBox &b) const
{
sMatrix34 mat(sDontInitialize);
mat.Init(b.BoxToWorld);
for(sInt i=0;i<6;i++)
{
sF32 m = b.Center ^ Planes[i];
sF32 n = b.HalfExtents.x * sFAbs(mat.i ^ Planes[i])
+ b.HalfExtents.y * sFAbs(mat.j ^ Planes[i])
+ b.HalfExtents.z * sFAbs(mat.k ^ Planes[i]);
if(m+n<0) return sTRUE;
}
return sFALSE;
}
void sFrustum::Transform(const sFrustum &src,const sMatrix34 &matx)
{
sMatrix44 mat(matx);
mat.Trans4();
for(sInt i=0;i<6;i++)
{
Planes[i] = src.Planes[i]*mat;
AbsPlanes[i].x = sAbs(Planes[i].x);
AbsPlanes[i].y = sAbs(Planes[i].y);
AbsPlanes[i].z = sAbs(Planes[i].z);
AbsPlanes[i].w = Planes[i].w ;
}
}
void sFrustum::Transform(const sFrustum &src,const sMatrix34CM &matcm)
{
sMatrix44 mat(matcm);
mat.Trans4();
for(sInt i=0;i<6;i++)
{
Planes[i] = src.Planes[i]*mat;
AbsPlanes[i].x = sAbs(Planes[i].x);
AbsPlanes[i].y = sAbs(Planes[i].y);
AbsPlanes[i].z = sAbs(Planes[i].z);
AbsPlanes[i].w = Planes[i].w ;
}
}
/****************************************************************************/
/****************************************************************************/
sF32 sDistSegmentToPointSq(sVector2Arg a,sVector2Arg b,sVector2Arg p)
{
sVector2 ab,ap,bp;
ab = b-a;
ap = p-a;
bp = p-b;
sF32 e = ap^ab;
if(e <= 0.0f) // outside of segment on side of a
return ap^ap;
else
{
sF32 f = ab^ab;
if(e >= f) // outside of segment on side of b
return bp^bp;
else
return (ap^ap) - e*e/f;
}
}
sF32 sDistSegmentToPointSq(const sVector31 &a,const sVector31 &b,const sVector31 &p)
{
sVector30 ab,ap,bp;
ab = b-a;
ap = p-a;
bp = p-b;
sF32 e = ap^ab;
if(e <= 0.0f) // outside of segment on side of a
return ap^ap;
else
{
sF32 f = ab^ab;
if(e >= f) // outside of segment on side of b
return bp^bp;
else
return (ap^ap) - e*e/f;
}
}
sF32 sDistSegmentToPointSq(sVector2Arg a,sVector2Arg b,sVector2Arg p,sF32 &t)
{
sVector2 ab,ap,bp;
ab = b-a;
ap = p-a;
bp = p-b;
sF32 e = ap^ab;
if(e <= 0.0f) // outside of segment on side of a
{
t = 0.0f;
return ap^ap;
}
else
{
sF32 f = ab^ab; // >=0
if(e >= f) // outside of segment on side of b
{
t = 1.0f;
return bp^bp;
}
else
{
t = e/f;
return (ap^ap) - e*t;
}
}
}
sF32 sDistSegmentToPointSq(const sVector31 &a,const sVector31 &b,const sVector31 &p,sF32 &t)
{
sVector30 ab,ap,bp;
ab = b-a;
ap = p-a;
bp = p-b;
sF32 e = ap^ab;
if(e <= 0.0f) // outside of segment on side of a
{
t = 0.0f;
return ap^ap;
}
else
{
sF32 f = ab^ab; // >=0
if(e >= f) // outside of segment on side of b
{
t = 1.0f;
return bp^bp;
}
else
{
t = e/f;
return (ap^ap) - e*t;
}
}
}
/****************************************************************************/
/****************************************************************************/
sSRT::sSRT()
{
Scale.Init(1,1,1);
Rotate.Init(0,0,0);
Translate.Init(0,0,0);
}
void sSRT::Init(sF32 *s)
{
Scale .Init(s[0],s[1],s[2]);
Rotate .Init(s[3],s[4],s[5]);
Translate.Init(s[6],s[7],s[8]);
}
void sSRT::MakeMatrix(sMatrix34 &mat) const
{
mat.EulerXYZ(Rotate.x*sPI2F,Rotate.y*sPI2F,Rotate.z*sPI2F);
mat.Scale(Scale.x,Scale.y,Scale.z);
mat.l = Translate;
}
void sSRT::MakeMatrixInv(sMatrix34 &mat) const
{
mat.Init();
mat.EulerXYZ(Rotate.x*sPI2F,Rotate.y*sPI2F,Rotate.z*sPI2F);
mat.Scale(1/Scale.x,1/Scale.y,1/Scale.z);
mat.Trans3();
mat.l = -Translate*mat;
}
void sSRT::Invert()
{
sMatrix34 mat;
MakeMatrixInv(mat);
Translate = mat.l;
mat.Trans3();
Scale.x = mat.i.Length(); mat.i.Unit();
Scale.y = mat.j.Length(); mat.j.Unit();
Scale.z = mat.k.Length(); mat.k.Unit();
mat.Trans3();
mat.FindEulerXYZ(Rotate.x,Rotate.y,Rotate.z);
Rotate.x /= sPI2F;
Rotate.y /= sPI2F;
Rotate.z /= sPI2F;
}
void sSRT::ToString(const sStringDesc &outStr) const
{
sU32 sx,sy,sz;
sU32 rx,ry,rz;
sU32 tx,ty,tz;
sx = *((const sU32 *) &Scale.x);
sy = *((const sU32 *) &Scale.y);
sz = *((const sU32 *) &Scale.z);
rx = *((const sU32 *) &Rotate.x);
ry = *((const sU32 *) &Rotate.y);
rz = *((const sU32 *) &Rotate.z);
tx = *((const sU32 *) &Translate.x);
ty = *((const sU32 *) &Translate.y);
tz = *((const sU32 *) &Translate.z);
sSPrintF(outStr,L"SRT=[%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x,%08x]",
sx,sy,sz,rx,ry,rz,tx,ty,tz);
}
sBool sSRT::FromString(const sChar *str)
{
sU32 fields[9];
const sChar *p = str;
if(sCmpStringLen(p,L"SRT=[",5) != 0)
return sFALSE;
p += 5;
for(sInt i=0;i<9;i++)
{
if(!sScanHex(p,(sInt&) fields[i],8))
return sFALSE;
if(*p++ != ((i == 8) ? ']' : ','))
return sFALSE;
}
Scale.x = *((const sF32 *) &fields[0]);
Scale.y = *((const sF32 *) &fields[1]);
Scale.z = *((const sF32 *) &fields[2]);
Rotate.x = *((const sF32 *) &fields[3]);
Rotate.y = *((const sF32 *) &fields[4]);
Rotate.z = *((const sF32 *) &fields[5]);
Translate.x = *((const sF32 *) &fields[6]);
Translate.y = *((const sF32 *) &fields[7]);
Translate.z = *((const sF32 *) &fields[8]);
return sTRUE;
}
/****************************************************************************/
/*** ***/
/*** Spline Basics ***/
/*** ***/
/****************************************************************************/
void sHermite(const sF32 x1, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
sF32 x2=x1*x1;
sF32 x3=x2*x1;
c0 = -0.5f*x3 + x2 - 0.5f*x1 ;
c1 = 1.5f*x3 - 2.5f*x2 + 1.0f;
c2 = -1.5f*x3 + 2.0f*x2 + 0.5f*x1 ;
c3 = 0.5f*x3 - 0.5f*x2 ;
}
void sHermiteD(const sF32 x1, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
sF32 x2=x1*x1;
c0 = -1.5f*x2 + 2.0f*x1 - 0.5f;
c1 = 4.5f*x2 - 5.0f*x1 ;
c2 = -4.5f*x2 + 4.0f*x1 + 0.5f;
c3 = 1.5f*x2 - 1.0f*x1 ;
}
void sHermiteUniform(const sF32 x1,sF32 t0,sF32 t1,sF32 t2,sF32 &c0,sF32 &c1,sF32 &c2,sF32 &c3)
{
sF32 x2=x1*x1;
sF32 x3=x2*x1;
sF32 d0,d1,d2,d3;
d0 = -0.5f*x3 + x2 - 0.5f*x1 ;
d1 = 1.5f*x3 - 2.5f*x2 + 1.0f;
d2 = -1.5f*x3 + 2.0f*x2 + 0.5f*x1 ;
d3 = 0.5f*x3 - 0.5f*x2 ;
sF32 f3 = t1 / t2;
sF32 f0 = t1 / t0;
c0 = d0*f0;
c1 = d1+d0-d0*f0;
c2 = d2+d3-d3*f3;
c3 = d3*f3;
}
void sHermiteUniformD(const sF32 x1,sF32 t0,sF32 t1,sF32 t2,sF32 &c0,sF32 &c1,sF32 &c2,sF32 &c3)
{
sF32 x2=x1*x1;
sF32 d0,d1,d2,d3;
d0 = -1.5f*x2 + 2.0f*x1 - 0.5f;
d1 = 4.5f*x2 - 5.0f*x1 ;
d2 = -4.5f*x2 + 4.0f*x1 + 0.5f;
d3 = 1.5f*x2 - 1.0f*x1 ;
sF32 f3 = t1 / t2;
sF32 f0 = t1 / t0;
c0 = d0*f0;
c1 = d1+d0-d0*f0;
c2 = d2+d3-d3*f3;
c3 = d3*f3;
}
void sHermiteWeighted(const sF32 x1, sF32 l0, sF32 l1, sF32 l2, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
sF32 x2 = x1 * x1;
sF32 x3 = x2 * x1;
sF32 il01 = 1.0f / (l0 + l1);
sF32 il12 = 1.0f / (l1 + l2);
sF32 d0 = x3 - 2.0f*x2 + x1;
sF32 d1 = x3 - x2;
c0 = -l0 * il01 * d0;
c1 = 2.0f*x3 - 3.0f*x2 + 1.0f + (l0-l1) * il01 * d0 - l1 * il12 * d1;
c2 = 3.0f*x2 - 2.0f*x3 + l1 * il01 * d0 + (l1-l2) * il12 * d1;
c3 = l2 * il12 * d1;
}
void sUniformBSpline(sF32 x1, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
sF32 x2=x1*x1;
sF32 x3=x2*x1;
static const sF32 i6 = 1.0f / 6.0f;
c0 = -i6*x3 + 0.5f*x2 - 0.5f*x1 + i6;
c1 = 0.5f*x3 - x2 + 4*i6;
c2 = -0.5f*x3 + 0.5f*x2 + 0.5f*x1 + i6;
c3 = i6*x3 ;
}
void sUniformBSplineD(sF32 x1, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
const sF32 x2=x1*x1;
c0 = -0.5f*x2 + x1 - 0.5f;
c1 = 1.5f*x2 - 2.0f*x1 ;
c2 = -1.5f*x2 + x1 + 0.5f;
c3 = 0.5f*x2 ;
}
void sCubicBezier(sF32 t, sF32 &c0, sF32 &c1, sF32 &c2, sF32 &c3)
{
sF32 u = 1.0f - t;
c0 = 1.0f * u*u*u;
c1 = 3.0f * u*u*t;
c2 = 3.0f * u*t*t;
c3 = 1.0f * t*t*t;
}
/****************************************************************************/
/*** ***/
/*** Smooth Function ***/
/*** ***/
/****************************************************************************/
sF32 sSmooth(sF32 x,sF32 s)
{
if(x<=0) return 0;
else if(x>=1) return 1;
else return (s*0.5f)*(x*x) - (s-4)*(x*x)*x + (s*0.5f-3)*(x*x)*(x*x);
}
/****************************************************************************/
/*** ***/
/*** Damping timeslice syncronisation ***/
/*** ***/
/****************************************************************************/
void sMakeDamp(sInt timeslice,sF32 damp,sF32 &d_,sF32 &f_)
{
sF32 f,d;
f = 1;
d = damp;
for(sInt i=1;i<timeslice;i++)
{
f += d;
d *= damp;
}
d_ = d;
f_ = f;
}
/****************************************************************************/
/*** ***/
/*** Filter (2Pole FIR) ***/
/*** ***/
/****************************************************************************/
void sFilter2Pole::Init()
{
sSetMem(this,0,sizeof(*this));
}
void sFilter2Pole::Scale(sF32 s)
{
a0 *= s;
a1 *= s;
a2 *= s;
}
void sFilter2Pole::Band(sF32 f,sF32 bw)
{
sF64 c = sFCos(f*sPI2F);
sF64 r = 1-3*bw;
sF64 k = (1-2*r*c+r*r) / (2-2*c);
a0 = 1-k;
a1 = 2*(k-r)*c;
a2 = r*r-k;
b1 = 2*r*c;
b2 = -r*r;
}
void sFilter2Pole::Low(sF32 f,sF32 rr)
{
// tweaked butterworth
sF64 c = 1/sFTan(f*sPIF);
sF64 r = (1-rr)*sSQRT2F;
a0 = 1/(1 + r*c + c*c);
a1 = 2*a0;
a2 = a0;
b1 = -2*(1 - c*c) * a0;
b2 = -(1 - r*c + c*c) * a0;
}
void sFilter2Pole::High(sF32 f,sF32 rr)
{
// tweaked butterworth
sF64 c = sFTan(f*sPIF);
sF64 r = (1-rr)*sSQRT2F;
a0 = 1/(1 + r*c +c*c);
a1 = -2*a0;
a2 = a0;
b1 = -2*(c*c - 1)*a0;
b2 = -(1 - r*c + c*c)*a0;
}
sF32 sFilter2Pole::Filter(sFilter2PoleTemp &t,sF32 sample)
{
sF64 x0,y0;
x0 = sample;
y0 = x0*a0 + t.x1*a1 + t.x2*a2 + t.y1*b1 + t.y2*b2;
t.x2 = t.x1;
t.x1 = x0;
t.y2 = t.y1;
t.y1 = y0;
return sF32(y0);
}
void sFilter2Pole::Filter(sFilter2PoleTemp &t,sF32 *in,sF32 *out,sInt count)
{
sF64 x0,y0;
for(sInt i=0;i<count;i++)
{
x0 = in[i];
y0 = x0*a0 + t.x1*a1 + t.x2*a2 + t.y1*b1 + t.y2*b2;
out[i] = sF32(y0);
t.x2 = t.x1;
t.x1 = x0;
t.y2 = t.y1;
t.y1 = y0;
}
}
void sFilter2Pole::FilterStereo(sFilter2PoleTemp *t,sF32 *in,sF32 *out,sInt count)
{
sF64 x0,y0;
for(sInt i=0;i<count;i++)
{
x0 = in[i*2+0];
y0 = x0*a0 + t[0].x1*a1 + t[0].x2*a2 + t[0].y1*b1 + t[0].y2*b2;
out[i*2+0] = sF32(y0);
t[0].x2 = t[0].x1;
t[0].x1 = x0;
t[0].y2 = t[0].y1;
t[0].y1 = y0;
}
for(sInt i=0;i<count;i++)
{
x0 = in[i*2+1];
y0 = x0*a0 + t[1].x1*a1 + t[1].x2*a2 + t[1].y1*b1 + t[1].y2*b2;
out[i*2+1] = sF32(y0);
t[1].x2 = t[1].x1;
t[1].x1 = x0;
t[1].y2 = t[1].y1;
t[1].y1 = y0;
}
}
/****************************************************************************/
/*** ***/
/*** Perlin Noise ***/
/*** ***/
/****************************************************************************/
sF32 sPerlinRandom2D[256][2];
sF32 sPerlinRandom3D[256][3];
sInt sPerlinPermute[512];
static void sInitPerlin()
{
sInt i,j;
sRandom rnd;
sInt order[256];
rnd.Seed(0);
// permutation
for(i=0;i<256;i++)
{
order[i]=rnd.Int16();
sPerlinPermute[i]=i;
}
for(i=0;i<255;i++)
{
for(j=i+1;j<256;j++)
{
if(order[i]>order[j])
{
sSwap(order[i],order[j]);
sSwap(sPerlinPermute[i],sPerlinPermute[j]);
}
}
}
for(sInt k=0;k<256;k++)
sPerlinPermute[k+256] = sPerlinPermute[k];
// random 2d
for(i=0;i<256;)
{
sF32 x,y;
x = rnd.Float(2.0f)-1.0f;
y = rnd.Float(2.0f)-1.0f;
if(x*x+y*y<1.0f)
{
sPerlinRandom2D[i][0] = x;
sPerlinRandom2D[i][1] = y;
i++;
}
}
// random 3d
for(i=0;i<256;)
{
sF32 x,y,z;
x = rnd.Float(2.0f)-1.0f;
y = rnd.Float(2.0f)-1.0f;
z = rnd.Float(2.0f)-1.0f;
if(x*x+y*y+z*z<1.0f)
{
sPerlinRandom3D[i][0] = x;
sPerlinRandom3D[i][1] = y;
sPerlinRandom3D[i][2] = z;
i++;
}
}
}
sF32 sPerlin2D(sInt x,sInt y,sInt mask,sInt seed)
{
sInt vx0,vy0,vx1,vy1;
sInt v00,v01,v10,v11;
sF32 f00,f01,f10,f11;
sF32 f0,f1,f;
sF32 tx,ty;
mask &= 255;
vx0 = (x>>16) & mask; vx1 = (vx0+1) & mask; tx=(x&0xffff)/65536.0f;
vy0 = (y>>16) & mask; vy1 = (vy0+1) & mask; ty=(y&0xffff)/65536.0f;
v00 = sPerlinPermute[((vx0))+sPerlinPermute[((vy0))^seed]];
v01 = sPerlinPermute[((vx1))+sPerlinPermute[((vy0))^seed]];
v10 = sPerlinPermute[((vx0))+sPerlinPermute[((vy1))^seed]];
v11 = sPerlinPermute[((vx1))+sPerlinPermute[((vy1))^seed]];
f00 = sPerlinRandom2D[v00][0]*(tx-0)+sPerlinRandom2D[v00][1]*(ty-0);
f01 = sPerlinRandom2D[v01][0]*(tx-1)+sPerlinRandom2D[v01][1]*(ty-0);
f10 = sPerlinRandom2D[v10][0]*(tx-0)+sPerlinRandom2D[v10][1]*(ty-1);
f11 = sPerlinRandom2D[v11][0]*(tx-1)+sPerlinRandom2D[v11][1]*(ty-1);
tx = tx*tx*tx*(10+tx*(6*tx-15));
ty = ty*ty*ty*(10+ty*(6*ty-15));
f0 = f00+(f01-f00)*tx;
f1 = f10+(f11-f10)*tx;
f = f0+(f1-f0)*ty;
return f;
}
sF32 sPerlin3D(sInt x,sInt y,sInt z,sInt mask,sInt seed)
{
sInt vx0,vy0,vz0,vx1,vy1,vz1;
sInt v000,v001,v010,v011;
sInt v100,v101,v110,v111;
sF32 f000,f001,f010,f011;
sF32 f100,f101,f110,f111;
sF32 f00,f01,f10,f11;
sF32 f0,f1,f;
sF32 tx,ty,tz;
mask &= 255;
vx0 = (x>>16) & mask; vx1 = (vx0+1) & mask; tx=(x&0xffff)/65536.0f;
vy0 = (y>>16) & mask; vy1 = (vy0+1) & mask; ty=(y&0xffff)/65536.0f;
vz0 = (z>>16) & mask; vz1 = (vz0+1) & mask; tz=(z&0xffff)/65536.0f;
v000 = sPerlinPermute[vx0+sPerlinPermute[vy0+sPerlinPermute[vz0^seed]]];
v001 = sPerlinPermute[vx1+sPerlinPermute[vy0+sPerlinPermute[vz0^seed]]];
v010 = sPerlinPermute[vx0+sPerlinPermute[vy1+sPerlinPermute[vz0^seed]]];
v011 = sPerlinPermute[vx1+sPerlinPermute[vy1+sPerlinPermute[vz0^seed]]];
v100 = sPerlinPermute[vx0+sPerlinPermute[vy0+sPerlinPermute[vz1^seed]]];
v101 = sPerlinPermute[vx1+sPerlinPermute[vy0+sPerlinPermute[vz1^seed]]];
v110 = sPerlinPermute[vx0+sPerlinPermute[vy1+sPerlinPermute[vz1^seed]]];
v111 = sPerlinPermute[vx1+sPerlinPermute[vy1+sPerlinPermute[vz1^seed]]];
f000 = sPerlinRandom3D[v000][0]*(tx-0)+sPerlinRandom3D[v000][1]*(ty-0)+sPerlinRandom3D[v000][2]*(tz-0);
f001 = sPerlinRandom3D[v001][0]*(tx-1)+sPerlinRandom3D[v001][1]*(ty-0)+sPerlinRandom3D[v001][2]*(tz-0);
f010 = sPerlinRandom3D[v010][0]*(tx-0)+sPerlinRandom3D[v010][1]*(ty-1)+sPerlinRandom3D[v010][2]*(tz-0);
f011 = sPerlinRandom3D[v011][0]*(tx-1)+sPerlinRandom3D[v011][1]*(ty-1)+sPerlinRandom3D[v011][2]*(tz-0);
f100 = sPerlinRandom3D[v100][0]*(tx-0)+sPerlinRandom3D[v100][1]*(ty-0)+sPerlinRandom3D[v100][2]*(tz-1);
f101 = sPerlinRandom3D[v101][0]*(tx-1)+sPerlinRandom3D[v101][1]*(ty-0)+sPerlinRandom3D[v101][2]*(tz-1);
f110 = sPerlinRandom3D[v110][0]*(tx-0)+sPerlinRandom3D[v110][1]*(ty-1)+sPerlinRandom3D[v110][2]*(tz-1);
f111 = sPerlinRandom3D[v111][0]*(tx-1)+sPerlinRandom3D[v111][1]*(ty-1)+sPerlinRandom3D[v111][2]*(tz-1);
tx = tx*tx*tx*(10+tx*(6*tx-15));
ty = ty*ty*ty*(10+ty*(6*ty-15));
tz = tz*tz*tz*(10+tz*(6*tz-15));
f00 = f000+(f001-f000)*tx;
f01 = f010+(f011-f010)*tx;
f10 = f100+(f101-f100)*tx;
f11 = f110+(f111-f110)*tx;
f0 = f00+(f01-f00)*ty;
f1 = f10+(f11-f10)*ty;
f = f0+(f1-f0)*tz;
return f;
}
void sPerlinDerive3D(sInt x,sInt y,sInt z,sInt mask,sInt seed,sF32 &value,sVector30 &dir)
{
sInt vx0,vy0,vz0,vx1,vy1,vz1;
sInt v000,v001,v010,v011;
sInt v100,v101,v110,v111;
sF32 tx,ty,tz;
sF32 px000,px001,px010,px011,px100,px101,px110,px111;
sF32 py000,py001,py010,py011,py100,py101,py110,py111;
sF32 pz000,pz001,pz010,pz011,pz100,pz101,pz110,pz111;
sF32 rx000,rx001,rx010,rx011,rx100,rx101,rx110,rx111;
sF32 ry000,ry001,ry010,ry011,ry100,ry101,ry110,ry111;
sF32 rz000,rz001,rz010,rz011,rz100,rz101,rz110,rz111;
sF32 ra0,ra1,rb0,rb1;
mask &= 255;
vx0 = (x>>16) & mask; vx1 = (vx0+1) & mask; tx=(x&0xffff)/65536.0f;
vy0 = (y>>16) & mask; vy1 = (vy0+1) & mask; ty=(y&0xffff)/65536.0f;
vz0 = (z>>16) & mask; vz1 = (vz0+1) & mask; tz=(z&0xffff)/65536.0f;
v000 = sPerlinPermute[vx0+sPerlinPermute[vy0+sPerlinPermute[vz0^seed]]];
v001 = sPerlinPermute[vx1+sPerlinPermute[vy0+sPerlinPermute[vz0^seed]]];
v010 = sPerlinPermute[vx0+sPerlinPermute[vy1+sPerlinPermute[vz0^seed]]];
v011 = sPerlinPermute[vx1+sPerlinPermute[vy1+sPerlinPermute[vz0^seed]]];
v100 = sPerlinPermute[vx0+sPerlinPermute[vy0+sPerlinPermute[vz1^seed]]];
v101 = sPerlinPermute[vx1+sPerlinPermute[vy0+sPerlinPermute[vz1^seed]]];
v110 = sPerlinPermute[vx0+sPerlinPermute[vy1+sPerlinPermute[vz1^seed]]];
v111 = sPerlinPermute[vx1+sPerlinPermute[vy1+sPerlinPermute[vz1^seed]]];
px000=sPerlinRandom3D[v000][0]; py000=sPerlinRandom3D[v000][1]; pz000=sPerlinRandom3D[v000][2];
px001=sPerlinRandom3D[v001][0]; py001=sPerlinRandom3D[v001][1]; pz001=sPerlinRandom3D[v001][2];
px010=sPerlinRandom3D[v010][0]; py010=sPerlinRandom3D[v010][1]; pz010=sPerlinRandom3D[v010][2];
px011=sPerlinRandom3D[v011][0]; py011=sPerlinRandom3D[v011][1]; pz011=sPerlinRandom3D[v011][2];
px100=sPerlinRandom3D[v100][0]; py100=sPerlinRandom3D[v100][1]; pz100=sPerlinRandom3D[v100][2];
px101=sPerlinRandom3D[v101][0]; py101=sPerlinRandom3D[v101][1]; pz101=sPerlinRandom3D[v101][2];
px110=sPerlinRandom3D[v110][0]; py110=sPerlinRandom3D[v110][1]; pz110=sPerlinRandom3D[v110][2];
px111=sPerlinRandom3D[v111][0]; py111=sPerlinRandom3D[v111][1]; pz111=sPerlinRandom3D[v111][2];
sF32 hx = 3*tx*tx - 2*tx*tx*tx;
sF32 hy = 3*ty*ty - 2*ty*ty*ty;
sF32 hz = 3*tz*tz - 2*tz*tz*tz;
// X
rx000 = px000*(1-hy)*(1-hz);
rx001 = px001*(1-hy)*(1-hz);
rx010 = px010*( hy)*(1-hz);
rx011 = px011*( hy)*(1-hz);
rx100 = px100*(1-hy)*( hz);
rx101 = px101*(1-hy)*( hz);
rx110 = px110*( hy)*( hz);
rx111 = px111*( hy)*( hz);
ry000 = py000*(1-hy)*(1-hz) * (ty-0);
ry001 = py001*(1-hy)*(1-hz) * (ty-0);
ry010 = py010*( hy)*(1-hz) * (ty-1);
ry011 = py011*( hy)*(1-hz) * (ty-1);
ry100 = py100*(1-hy)*( hz) * (ty-0);
ry101 = py101*(1-hy)*( hz) * (ty-0);
ry110 = py110*( hy)*( hz) * (ty-1);
ry111 = py111*( hy)*( hz) * (ty-1);
rz000 = pz000*(1-hy)*(1-hz) * (tz-0);
rz001 = pz001*(1-hy)*(1-hz) * (tz-0);
rz010 = pz010*( hy)*(1-hz) * (tz-0);
rz011 = pz011*( hy)*(1-hz) * (tz-0);
rz100 = pz100*(1-hy)*( hz) * (tz-1);
rz101 = pz101*(1-hy)*( hz) * (tz-1);
rz110 = pz110*( hy)*( hz) * (tz-1);
rz111 = pz111*( hy)*( hz) * (tz-1);
ra0 = rx000 + rx010 + rx100 + rx110;
ra1 = rx001 + rx011 + rx101 + rx111;
rb0 = ry000 + ry010 + ry100 + ry110 + rz000 + rz010 + rz100 + rz110;
rb1 = ry001 + ry011 + ry101 + ry111 + rz001 + rz011 + rz101 + rz111;
value = rb0 + tx*ra0 + tx*tx*3*(rb1-rb0-ra1) + tx*tx*tx*(5*ra1-3*ra0-2*rb1+2*rb0) - tx*tx*tx*tx*2*(ra1-ra0);
dir.x = ra0 + 6*tx*(rb1-rb0-ra1) + 3*tx*tx*(5*ra1-3*ra0-2*rb1+2*rb0) - 8*tx*tx*tx*(ra1-ra0);
// Y
rx000 = px000*(1-hx)*(1-hz) * (tx-0);
rx001 = px001*( hx)*(1-hz) * (tx-1);
rx010 = px010*(1-hx)*(1-hz) * (tx-0);
rx011 = px011*( hx)*(1-hz) * (tx-1);
rx100 = px100*(1-hx)*( hz) * (tx-0);
rx101 = px101*( hx)*( hz) * (tx-1);
rx110 = px110*(1-hx)*( hz) * (tx-0);
rx111 = px111*( hx)*( hz) * (tx-1);
ry000 = py000*(1-hx)*(1-hz);
ry001 = py001*( hx)*(1-hz);
ry010 = py010*(1-hx)*(1-hz);
ry011 = py011*( hx)*(1-hz);
ry100 = py100*(1-hx)*( hz);
ry101 = py101*( hx)*( hz);
ry110 = py110*(1-hx)*( hz);
ry111 = py111*( hx)*( hz);
rz000 = pz000*(1-hx)*(1-hz) * (tz-0);
rz001 = pz001*( hx)*(1-hz) * (tz-0);
rz010 = pz010*(1-hx)*(1-hz) * (tz-0);
rz011 = pz011*( hx)*(1-hz) * (tz-0);
rz100 = pz100*(1-hx)*( hz) * (tz-1);
rz101 = pz101*( hx)*( hz) * (tz-1);
rz110 = pz110*(1-hx)*( hz) * (tz-1);
rz111 = pz111*( hx)*( hz) * (tz-1);
ra0 = ry000 + ry001 + ry100 + ry101;
ra1 = ry010 + ry011 + ry110 + ry111;
rb0 = rx000 + rx001 + rx100 + rx101 + rz000 + rz001 + rz100 + rz101;
rb1 = rx010 + rx011 + rx110 + rx111 + rz010 + rz011 + rz110 + rz111;
dir.y = ra0 + 6*ty*(rb1-rb0-ra1) + 3*ty*ty*(5*ra1-3*ra0-2*rb1+2*rb0) - 8*ty*ty*ty*(ra1-ra0);
// Z
rx000 = px000*(1-hy)*(1-hx) * (tx-0);
rx001 = px001*(1-hy)*( hx) * (tx-1);
rx010 = px010*( hy)*(1-hx) * (tx-0);
rx011 = px011*( hy)*( hx) * (tx-1);
rx100 = px100*(1-hy)*(1-hx) * (tx-0);
rx101 = px101*(1-hy)*( hx) * (tx-1);
rx110 = px110*( hy)*(1-hx) * (tx-0);
rx111 = px111*( hy)*( hx) * (tx-1);
ry000 = py000*(1-hy)*(1-hx) * (ty-0);
ry001 = py001*(1-hy)*( hx) * (ty-0);
ry010 = py010*( hy)*(1-hx) * (ty-1);
ry011 = py011*( hy)*( hx) * (ty-1);
ry100 = py100*(1-hy)*(1-hx) * (ty-0);
ry101 = py101*(1-hy)*( hx) * (ty-0);
ry110 = py110*( hy)*(1-hx) * (ty-1);
ry111 = py111*( hy)*( hx) * (ty-1);
rz000 = pz000*(1-hy)*(1-hx);
rz001 = pz001*(1-hy)*( hx);
rz010 = pz010*( hy)*(1-hx);
rz011 = pz011*( hy)*( hx);
rz100 = pz100*(1-hy)*(1-hx);
rz101 = pz101*(1-hy)*( hx);
rz110 = pz110*( hy)*(1-hx);
rz111 = pz111*( hy)*( hx);
ra0 = rz000 + rz001 + rz010 + rz011;
ra1 = rz100 + rz101 + rz110 + rz111;
rb0 = rx000 + rx001 + rx010 + rx011 + ry000 + ry001 + ry010 + ry011;
rb1 = rx100 + rx101 + rx110 + rx111 + ry100 + ry101 + ry110 + ry111;
dir.z = ra0 + 6*tz*(rb1-rb0-ra1) + 3*tz*tz*(5*ra1-3*ra0-2*rb1+2*rb0) - 8*tz*tz*tz*(ra1-ra0);
}
sF32 sPerlin2D(sF32 x,sF32 y,sInt octaves,sF32 falloff,sInt mode,sInt seed)
{
sInt xi = sInt(x*0x10000);
sInt yi = sInt(y*0x10000);
sInt mask = 0xff;
sF32 sum,amp;
sum = 0;
amp = 1.0f;
for(sInt i=0;i<octaves && i<8;i++)
{
sF32 val = sPerlin2D(xi,yi,mask,seed);
if(mode&1)
val = (sF32)sFAbs(val)*2-1;
if(mode&2)
val = (sF32)sFSin(val*sPI2F);
sum += val * amp;
amp *= falloff;
xi = xi*2;
yi = yi*2;
}
return sum;
}
/****************************************************************************/
/*** ***/
/*** Intersection ***/
/*** ***/
/****************************************************************************/
sBool sGetIntersection(sVector2Arg u1, sVector2Arg u2, sVector2Arg v1, sVector2Arg v2, sF32 *s, sF32 *t, sVector2 *p)
{
sVector2 du(u2.x - u1.x, u2.y - u1.y);
sVector2 dv(v2.x - v1.x, v2.y - v1.y);
sF32 d = (dv.x * du.y - dv.y * du.x);
if (!d)
return sFALSE;
sF32 _t = ((v1.y - u1.y) * du.x - (v1.x - u1.x) * du.y) / d;
if ((_t < 0)||(_t > 1))
return sFALSE;
sF32 _s;
if (sAbs(du.y) > 0.00001f * sMax(1.0f, sMax(sAbs(u1.y), sAbs(u2.y))))
_s = (v1.y - u1.y + _t * dv.y) / du.y;
else
_s = (v1.x - u1.x + _t * dv.x) / du.x;
if ((_s < 0)||(_s > 1))
return sFALSE;
if (t)
*t = _t;
if (s)
*s = _s;
if (p)
p->Init(v1.x + dv.x * _t, v1.y + dv.y * _t);
return sTRUE;
}
sBool sGetIntersection(sVector2Arg u1, sVector2Arg u2, const sFRect &rect, sF32 *s, sVector2 *p)
{
sVector2 _p;
if ((sGetIntersection(u1, u2, sVector2(rect.x0, rect.y0), sVector2(rect.x1, rect.y1), s, sNULL, &_p) && rect.Hit(_p.x, _p.y))
|| (sGetIntersection(u1, u2, sVector2(rect.x1, rect.y0), sVector2(rect.x0, rect.y1), s, sNULL, &_p) && rect.Hit(_p.x, _p.y)))
{
if (p) *p = _p;
return sTRUE;
}
return sFALSE;
}
sInt sGetLineSegmentIntersection(sF32 &dist0, sF32 &dist1, sVector2Arg ls0, sVector2Arg ld0, sVector2Arg ls1, sVector2Arg ld1)
{
sF32 denom = ld1.y*ld0.x-ld1.x*ld0.y;
sF32 nume_a = ld1.x*(ls0.y-ls1.y)-ld1.y*(ls0.x-ls1.x);
sF32 nume_b = ld0.x*(ls0.y-ls1.y)-ld0.y*(ls0.x-ls1.x);
if(sFAbs(denom)<0.00001f)
{
if(nume_a==0.0f && nume_b==0.0f)
{
// coincident lines, check if segments overlap
sF32 lengthsqr = ld0.x*ld0.x+ld0.y*ld0.y;
sF32 length0 = ld0.x*ls1.x+ld0.y*ls1.y;
sF32 length1 = ld0.x*(ls1.x+ld1.x)+ld0.y*(ls1.y+ld1.y);
if(length1<length0)
sSwap(length0,length1);
if(length0<0.0f)
length0 = 0.0f;
if(length1>lengthsqr)
length1 = lengthsqr;
if(length1<length0)
return 0; // line segments not intersecting
sF32 invlsqr = 1.0f / lengthsqr;
dist0 = length0*invlsqr;
dist1 = length1*invlsqr;
return 2;
}
return 0;
}
sF32 invdenom = 1.0f/denom;
dist0 = nume_a*invdenom;
dist1 = nume_b*invdenom;
if(dist0>=0.0f&&dist0<=1.0f&&dist1>=-1.0f&&dist1<=1.0f)
return 1;
return 0;
}
/****************************************************************************/
/*** ***/
/*** Bezier Splines ***/
/*** ***/
/****************************************************************************/
sVector30 sGetBezierSplineFactors3(sF32 n)
{
sF32 m = (1.0f-n);
return sVector30(
m*m,
2.0f*n*m,
n*n);
}
sVector4 sGetBezierSplineFactors4(sF32 n)
{
sF32 m = (1.0f-n);
return sVector4(
m*m*m,
3.0f*n*m*m,
3.0f*n*n*m,
n*n*n);
}
void sGetBezierSplinePoint(sF32 *out, sF32 n, const sF32 *v1, const sF32 *v2, const sF32 *v3, const sU32 d)
{
sVector30 f = sGetBezierSplineFactors3(n);
for (sU32 i = 0; i != d; ++i)
{
out[i] = v1[i] * f[0] + v2[i] * f[1] + v3[i] * f[2];
}
}
void sGetBezierSplinePoint(sF32 *out, sF32 n, const sF32 *v1, const sF32 *v2, const sF32 *v3, const sF32 *v4, const sU32 d)
{
sVector4 f = sGetBezierSplineFactors4(n);
for (sU32 i = 0; i != d; ++i)
{
out[i] = v1[i] * f[0] + v2[i] * f[1] + v3[i] * f[2] + v4[i] * f[3];
}
}
/****************************************************************************/
/*** ***/
/*** RGB <-> HSL color space conversion ***/
/*** ***/
/****************************************************************************/
// HSL: Hue, Saturation, Luminance
// H: position in the spectrum
// S: color saturation
// L: color lightness
void sRgbToHsl(sF32 r, sF32 g, sF32 b, sF32 &h, sF32 &s, sF32 &l)
{
sF32 maxc = sMax(sMax(r,g),b);
sF32 minc = sMin(sMin(r,g),b);
l = (minc+maxc)/2.0f;
if (minc == maxc)
{
h = 0.0f; s = 0.0f;
return;
}
if (l <= 0.5f)
s = (maxc - minc) / (maxc + minc);
else
s = (maxc - minc) / (2.0f-maxc-minc);
sF32 rc = (maxc-r) / (maxc-minc);
sF32 gc = (maxc-g) / (maxc-minc);
sF32 bc = (maxc-b) / (maxc-minc);
if (r == maxc)
h = bc-gc;
else if (g == maxc)
h = 2.0f+rc-bc;
else
h = 4.0f+gc-rc;
h = sAbsMod(h/6.0f, 1.0f);
}
static sF32 _sHslToRgb_GetChannel(sF32 m1, sF32 m2, sF32 hue)
{
hue = sAbsMod(hue, 1.0f);
if (hue < (1.0f/6.0f))
return m1 + (m2-m1)*hue*6.0f;
if (hue < 0.5f)
return m2;
if (hue < (2.0f/3.0f))
return m1 + (m2-m1)*((2.0f/3.0f)-hue)*6.0f;
return m1;
}
void sHslToRgb(sF32 h, sF32 s, sF32 l, sF32 &r, sF32 &g, sF32 &b)
{
if (s == 0.0f)
{
r = l;
g = l;
b = l;
return;
}
sF32 m1,m2;
if (l <= 0.5f)
m2 = l * (1.0f+s);
else
m2 = l+s-(l*s);
m1 = 2.0f*l - m2;
r = _sHslToRgb_GetChannel(m1, m2, h+(1.0f/3.0f));
g = _sHslToRgb_GetChannel(m1, m2, h);
b = _sHslToRgb_GetChannel(m1, m2, h-(1.0f/3.0f));
}
void sHslToRgb(const sVector4 &in, sVector4 &out)
{
out.w = in.w;
sHslToRgb(in.x, in.y, in.z, out.x, out.y, out.z);
}
sU32 sHslToColor(sF32 h, sF32 s, sF32 l, sF32 a)
{
sVector4 v(h,s,l,a);
sHslToRgb(v,v);
return v.GetColor();
}
/****************************************************************************/