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.
#include "_types.hpp"
#if !sMOBILE
#include "_start.hpp"
#endif
#include <stdarg.h>
#include <malloc.h>
#if sLINK_INTMATH
#include "_intmath.hpp"
#endif
/****************************************************************************/
/*** ***/
/*** Init/Exit ***/
/*** ***/
/****************************************************************************/
void InitIntMath();
void sInitTypes()
{
#if !sINTRO
InitIntMath();
#endif
#if sLINK_INTMATH
sInitIntMath2();
#endif
}
void sExitTypes()
{
}
/****************************************************************************/
/*** ***/
/*** Forwards ***/
/*** ***/
/****************************************************************************/
static sU32 sRandomSeed=0x74382381;
sU32 sGetRnd()
{
sU32 i;
#if sMOBILE
sU32 eax,ebx;
eax = sRandomSeed;
eax = eax*0x343fd+0x269ec3;
ebx = eax;
eax = eax*0x343fd+0x269ec3;
sRandomSeed = eax;
eax = (eax>>10)&0x0000ffff;
ebx = (ebx<< 6)&0xffff0000;
i = eax|ebx;
#else
__asm
{
mov eax,sRandomSeed
imul eax,eax,343fdh
add eax,269ec3h
mov ebx,eax
imul eax,eax,343fdh
add eax,269ec3h
mov sRandomSeed,eax
sar eax,10
and eax,00000ffffh
shl ebx,6
and ebx,0ffff0000h
or eax,ebx
mov i,eax
}
#endif
return i;
}
/****************************************************************************/
sU32 sGetRnd(sU32 max)
{
return sGetRnd()%max;
}
/****************************************************************************/
#if !sMOBILE
sF32 sFGetRnd()
{
return ((sGetRnd()&0x3fffffff)*1.0f)/0x40000000;
}
#endif
/****************************************************************************/
#if !sMOBILE
sF32 sFGetRnd(sF32 max)
{
return ((sGetRnd()&0x3fffffff)*max)/0x40000000;
}
#endif
/****************************************************************************/
void sSetRndSeed(sInt seed)
{
sRandomSeed = seed+seed*17+seed*121+(seed*121/17);
sGetRnd();
sRandomSeed ^= seed+seed*17+seed*121+(seed*121/17);
sGetRnd();
sRandomSeed ^= seed+seed*17+seed*121+(seed*121/17);
sGetRnd();
sRandomSeed ^= seed+seed*17+seed*121+(seed*121/17);
sGetRnd();
}
/****************************************************************************/
sInt sFindLowerPower(sInt x)
{
sInt y = 0;
while((2<<y)<=x) y++;
return y;
};
sInt sMakePower2(sInt val)
{
sInt p;
p = 1;
while(p<val)
p = p*2;
return p;
}
/****************************************************************************/
sInt sGetPower2(sInt val)
{
sInt p;
p = 1;
while((1<<p)<val)
p++;
return p;
}
/****************************************************************************/
#if !sMOBILE
sU32 sDec3(sF32 x,sF32 y,sF32 z)
{
sInt ix,iy,iz;
ix = sRange<sInt>(x*511,511,-511)&0x3ff;
iy = sRange<sInt>(y*511,511,-511)&0x3ff;
iz = sRange<sInt>(z*511,511,-511)&0x3ff;
return (ix)|(iy<<10)|(iz<<20);
}
#endif
/****************************************************************************/
#if !sMOBILE
void sHermite(sF32 *d,sF32 *p0,sF32 *p1,sF32 *p2,sF32 *p3,sInt count,sF32 fade,sF32 t,sF32 c,sF32 b,sBool ignoretime)
{
sF32 f1,f2,f3,f4;
sF32 t0,t1,t2,t3;
sF32 a1,b1,a2,b2;
sInt i;
a1 = (1-t)*(1-c)*(1+b);
b1 = (1-t)*(1+c)*(1-b);
a2 = (1-t)*(1+c)*(1+b);
b2 = (1-t)*(1-c)*(1-b);
t1 = p1[-1];
t2 = p2[-1];
if(p0==0)
{
p0 = p2;
a1 = -a1;
t0 = t1+(t1-t2);
}
else
{
t0 = p0[-1];
}
if(p3==0)
{
p3 = p1;
b2 = -b2;
t3 = t2+(t2-t1);
}
else
{
t3 = p3[-1];
}
f1 = 2*fade*fade*fade - 3*fade*fade + 1;
f2 = -2*fade*fade*fade + 3*fade*fade;
f3 = fade*fade*fade - 2*fade*fade + fade;
f4 = fade*fade*fade - fade*fade;
if(!ignoretime)
{
t0 = t1-t0;
t1 = t2-t1;
t2 = t3-t2;
f3 = f3 * t1/(t1+t0);
f4 = f4 * t1/(t1+t2);
}
else
{
f3 *= 0.5f;
f4 *= 0.5f;
}
sVERIFY(count<=9);
for(i=0;i<count;i++)
{
d[i] = f1 * p1[i]
+ f2 * p2[i]
+ f3 * (a1*(p1[i]-p0[i]) + b1*(p2[i]-p1[i]))
+ f4 * (a2*(p2[i]-p1[i]) + b2*(p3[i]-p2[i]));
}
}
void sHermiteD(sF32 *d,sF32 *dd,sF32 *p0,sF32 *p1,sF32 *p2,sF32 *p3,sInt count,sF32 fade,sF32 t,sF32 c,sF32 b,sBool ignoretime)
{
sF32 f1,f2,f3,f4;
sF32 t0,t1,t2,t3;
sF32 a1,b1,a2,b2;
sF32 f1d,f2d,f3d,f4d;
sInt i;
a1 = (1-t)*(1-c)*(1+b);
b1 = (1-t)*(1+c)*(1-b);
a2 = (1-t)*(1+c)*(1+b);
b2 = (1-t)*(1-c)*(1-b);
t1 = p1[-1];
t2 = p2[-1];
if(p0==0)
{
p0 = p2;
a1 = -a1;
t0 = t1+(t1-t2);
}
else
{
t0 = p0[-1];
}
if(p3==0)
{
p3 = p1;
b2 = -b2;
t3 = t2+(t2-t1);
}
else
{
t3 = p3[-1];
}
f1 = 2*fade*fade*fade - 3*fade*fade + 1;
f2 = -2*fade*fade*fade + 3*fade*fade;
f3 = fade*fade*fade - 2*fade*fade + fade;
f4 = fade*fade*fade - fade*fade;
f1d = 6*fade*fade - 6*fade;
f2d = -6*fade*fade + 6*fade;
f3d = 3*fade*fade - 4*fade + 1;
f4d = 3*fade*fade - 2*fade;
if(!ignoretime)
{
t0 = t1-t0;
t1 = t2-t1;
t2 = t3-t2;
f3 = f3 * t1/(t1+t0);
f4 = f4 * t1/(t1+t2);
f3d = f3d * t1/(t1+t0);
f4d = f4d * t1/(t1+t2);
}
else
{
f3 *= 0.5f;
f4 *= 0.5f;
f3d *= 0.5f;
f4d *= 0.5f;
}
f1d *= 0.25f;
f2d *= 0.25f;
f3d *= 0.25f;
f4d *= 0.25f;
sVERIFY(count<=9);
for(i=0;i<count;i++)
{
d[i] = f1 * p1[i]
+ f2 * p2[i]
+ f3 * (a1*(p1[i]-p0[i]) + b1*(p2[i]-p1[i]))
+ f4 * (a2*(p2[i]-p1[i]) + b2*(p3[i]-p2[i]));
dd[i] = f1d * p1[i]
+ f2d * p2[i]
+ f3d * (a1*(p1[i]-p0[i]) + b1*(p2[i]-p1[i]))
+ f4d * (a2*(p2[i]-p1[i]) + b2*(p3[i]-p2[i]));
}
}
#endif
/*
sInt sRangeInt(sInt a,sInt b,sInt c)
{
return sRange(a,b,c);
}
sF32 sRangeF32(sF32 a,sF32 b,sF32 c)
{
return sRange(a,b,c);
}
*/
#if !sMOBILE
#if sINTRO || sNOCRT
/****************************************************************************/
sF64 sFACos(sF64 f)
{
__asm
{
fld qword ptr [f];
fld1;
fchs;
fcomp st(1);
fstsw ax;
je suckt;
fld st;
fld1;
fsubrp st(1), st;
fxch st(1);
fld1;
faddp st(1), st;
fdivp st(1), st;
fsqrt;
fld1;
jmp short end;
suckt:
fld1;
fldz;
end:
fpatan;
fadd st, st;
fstp qword ptr [f];
}
return f;
}
sF64 sFMod(sF64 a,sF64 b)
{
__asm
{
fld qword ptr [b];
fld qword ptr [a];
fprem;
fstp st(1);
fstp qword ptr [a];
}
return a;
}
sF64 sFPow(sF64 a,sF64 b)
{
// faster pow based on code by agner fog
__asm
{
fld qword ptr [b];
fld qword ptr [a];
ftst;
fstsw ax;
sahf;
jz zero;
fyl2x;
fist dword ptr [a];
sub esp, 12;
mov dword ptr [esp],0;
mov dword ptr [esp+4],0x80000000;
fisub dword ptr [a];
mov eax, dword ptr [a];
add eax, 0x3fff;
mov [esp+8], eax;
jle underflow;
cmp eax, 0x8000;
jge overflow;
f2xm1;
fld1;
fadd;
fld tbyte ptr [esp];
add esp, 12;
fmul;
jmp end;
underflow:
fstp st;
fldz;
add esp, 12;
jmp end;
overflow:
push 0x7f800000;
fstp st;
fld dword ptr [esp];
add esp, 16;
jmp end;
zero:
fstp st(1);
end:
}
}
/*sF64 sFPow(sF64 a,sF64 b)
{
__asm
{
fld qword ptr [a];
fld qword ptr [b];
fxch st(1);
ftst;
fstsw ax;
sahf;
jz zero;
fyl2x;
fld1;
fld st(1);
fprem;
f2xm1;
faddp st(1), st;
fscale;
zero:
fstp st(1);
fstp qword ptr [a];
}
return a;
}*/
sF64 sFExp(sF64 f)
{
__asm
{
fld qword ptr [f];
fldl2e;
fmulp st(1), st;
fld1;
fld st(1);
fprem;
f2xm1;
faddp st(1), st;
fscale;
fstp st(1);
fstp qword ptr [f];
}
return f;
}
#endif
sInt sQuadraticRoots(const sF32 *coeffs,sF32 *roots)
{
if(sFAbs(coeffs[2]) > 1e-20f) // not degenerate
{
sF32 disc = sSquare(coeffs[1]) - 4.0f * coeffs[0] * coeffs[2];
if(disc > 1e-20f) // positive, two roots
{
sF32 root = sFSqrt(disc);
sF32 b = coeffs[1];
sF32 q = (b > 0.0f) ? -0.5f * (b + root) : -0.5f * (b - root);
roots[0] = q / coeffs[2];
roots[1] = coeffs[0] / q;
return 2;
}
else if(disc > -1e-20f) // zero, one root
{
roots[0] = -0.5f * coeffs[1] / coeffs[2];
return 1;
}
else // negative, no root
return 0;
}
else // degenerate, only a linear function
{
if(sFAbs(coeffs[1]) > 1e-20f)
{
roots[0] = -coeffs[0] / coeffs[1];
return 1;
}
else
return 0; // 0 or infinitely many solutions
}
}
sBool sNormalFloat(sF32 value)
{
const sU32 binval = (sU32 &) value;
sInt exp = ((binval >> 23) & 0xff) - 127;
if(exp == -127) // zero
return (binval & 0x7fffffff) == 0;
else
return (exp >= -126 && exp <= 127);
}
#endif
/****************************************************************************/
/****************************************************************************/
/*** ***/
/*** Int Math ***/
/*** ***/
/****************************************************************************/
/****************************************************************************/
#if !sINTRO
#define sSINUSFULL 0x4000 // 360 degrees for sAngle
#define FSIN_PTS 512
#define FSIN_MAX 0x10000
#define FSIN_STEP (FSIN_MAX/FSIN_PTS)
static sInt sSinus[sSINUSFULL/4+1];
/****************************************************************************/
/****************************************************************************/
void InitIntMath()
{
sU32 t1,t2,val,v;
sInt i;
val=0x1921fc; // Sinus
t1=0;
t2=0x80000000;
for(i=1;i<sSINUSFULL/4;i++)
{
t1+=((sU64)t2*val)>>32;
t2-=((sU64)t1*val)>>32;
v=t1/(0x80000000/0x10000);
sSinus[ i] = v;
}
sSinus[sSINUSFULL/4*0]=0;
sSinus[sSINUSFULL/4*1]=0x10000;
}
/****************************************************************************/
sInt sISinOld(sInt w)
{
w = (w*sSINUSFULL>>16) & (sSINUSFULL-1);
if(w>=sSINUSFULL/2)
{
w=w-sSINUSFULL/2;
if(w<sSINUSFULL/4)
return -sSinus[w];
else
return -sSinus[sSINUSFULL/2-w];
}
else
{
if(w<sSINUSFULL/4)
return sSinus[w];
else
return sSinus[sSINUSFULL/2-w];
}
}
/****************************************************************************/
sInt sICosOld(sInt w)
{
return sISinOld(w+0x4000);
}
#endif
/****************************************************************************/
/*** ***/
/*** Memory ***/
/*** ***/
/****************************************************************************/
void sCopyMemFast(void *d,const void *s,sInt c)
{
#if !sINTRO && !sMOBILE
if(sSystem->CpuMask & sCPU_MMX2)
{
__asm
{
mov esi, [s];
mov edi, [d];
mov ecx, [c];
shr ecx, 6;
jz tail;
copy:
prefetchnta [esi+384];
movq mm0, [esi+ 0];
movq mm1, [esi+ 8];
movq mm2, [esi+16];
movq mm3, [esi+24];
movq mm4, [esi+32];
movq mm5, [esi+40];
movq mm6, [esi+48];
movq mm7, [esi+56];
movntq [edi+ 0], mm0;
movntq [edi+ 8], mm1;
movntq [edi+16], mm2;
movntq [edi+24], mm3;
movntq [edi+32], mm4;
movntq [edi+40], mm5;
movntq [edi+48], mm6;
movntq [edi+56], mm7;
add esi, 64;
add edi, 64;
dec ecx;
jnz copy;
emms;
tail:
mov ecx, [c];
and ecx, 63;
jz end;
rep movsb;
end:
}
}
else
#endif
sCopyMem(d,s,c);
}
void sCopyMem4(sU32 *d,const sU32 *s,sInt c)
{
c *= 4;
if(c >= 256*1024)
sCopyMemFast(d,s,c);
else
sCopyMem(d,s,c);
/*__asm
{
mov esi,[s]
mov edi,[d]
mov ecx,[c]
rep movsd
}*/
}
#if !sINTRO
void sCopyMem8(sU64 *d,const sU64 *s,sInt c)
{
c *= 8;
if(c >= 256*1024)
sCopyMemFast(d,s,c);
else
sCopyMem(d,s,c);
/*__asm
{
mov esi,[s]
mov edi,[d]
mov ecx,[c]
add ecx,ecx
rep movsd
}*/
}
#endif
/****************************************************************************/
/*** ***/
/*** String ***/
/*** ***/
/****************************************************************************/
sChar *sDupString(sChar *s,sInt minsize)
{
sInt size;
sChar *d;
if(s==0)
return 0;
size = sGetStringLen(s)+1;
if(minsize>size)
size = minsize;
d = new sChar[size];
sCopyString(d,s,size);
return d;
}
void sCopyString(sChar *d,const sChar *s,sInt size)
{
while(size>0 && *s)
{
size--;
*d++ = *s++;
}
*d = 0;
}
/****************************************************************************/
void sAppendString(sChar *d,const sChar *s,sInt size)
{
while(size>0 && *d)
{
size--;
d++;
}
while(size>0 && *s)
{
size--;
*d++ = *s++;
}
*d = 0;
}
/****************************************************************************/
void sParentString(sChar *path)
{
sChar *s,*e;
e = path;
s = path;
while(s[0] && s[1])
{
if(*s=='/' && (s!=path || s[-1]!=':'))
e = s+1;
s++;
}
*e = 0;
}
sChar *sFileFromPathString(sChar *path)
{
sChar *s;
s = path;
while(*path)
{
if(*path=='\\' || *path=='/')
s = path+1;
path++;
}
return s;
}
sChar *sFileExtensionString(sChar *path)
{
sChar *s = 0;
while(*path)
{
if(*path=='.')
s = path;
path++;
}
return s;
}
/****************************************************************************/
sInt sCmpString(const sChar *a,const sChar *b)
{
sInt aa,bb;
do
{
aa = *a++;
bb = *b++;
}
while(aa!=0 && aa==bb);
return sSign(aa-bb);
}
sInt sCmpStringI(const sChar *a,const sChar *b)
{
sInt aa,bb;
do
{
aa = *a++;
bb = *b++;
if(aa>='A' && aa<='Z') aa=aa-'A'+'a';
if(bb>='A' && bb<='Z') bb=bb-'A'+'a';
}
while(aa!=0 && aa==bb);
return sSign(aa-bb);
}
sInt sCmpMemI(const sChar *a,const sChar *b,sInt len)
{
sInt aa,bb;
sInt i;
for(i=0;i<len;i++)
{
aa = *a++;
bb = *b++;
if(aa>='A' && aa<='Z') aa=aa-'A'+'a';
if(bb>='A' && bb<='Z') bb=bb-'A'+'a';
if(aa!=bb)
return sSign(aa-bb);
}
return 0;
}
const sChar *sFindString(const sChar *s,const sChar *f)
{
sInt len,i,slen;
len = sGetStringLen(f);
slen = sGetStringLen(s);
for(i=0;i<=slen-len;i++)
{
if(sCmpMem((const sPtr)(s+i),(const sPtr)f,len)==0)
return s+i;
}
return 0;
}
/*
const sChar *sFindStringI(const sChar *s,const sChar *f)
{
sInt len,i,slen;
len = sGetStringLen(f);
slen = sGetStringLen(s);
for(i=0;i<=slen-len;i++)
{
if(sCmpMemI(s+i,f,len)==0)
return s+i;
}
return 0;
}
*/
sInt sAtoi(const sChar *s)
{
sInt val;
val = 0;
while(*s>='0' && *s<='9')
val = val * 10 + (*s++) - '0';
return val;
}
/****************************************************************************/
/****************************************************************************/
sInt sScanInt(const sChar *&scan)
{
sInt val;
sInt sign;
sign = 1;
val = 0;
if(*scan=='\'')
{
if(scan[1]!=0 && scan[2]=='\'')
{
val = scan[1];
scan+=3;
return val;
}
return 0;
}
if(*scan=='+')
scan++;
else if(*scan=='-')
{
sign = -1;
scan++;
}
if(*scan=='$' || *scan=='#')
{
scan++;
for(;;)
{
if(*scan>='0' && *scan<='9')
val = val*16+(*scan)-'0';
else if(*scan>='a' && *scan<='f')
val = val*16+(*scan)-'a'+10;
else if(*scan>='A' && *scan<='F')
val = val*16+(*scan)-'A'+10;
else
break;
scan++;
}
}
else
{
while(*scan>='0' && *scan<='9')
val = val*10+(*scan++)-'0';
}
return val*sign;
}
sInt sScanInt(sChar *&scan)
{
return sScanInt((const sChar *&) scan);
}
sInt sScanHex(const sChar *&scan)
{
sInt val;
sInt sign;
sign = 1;
val = 0;
if(*scan=='+')
scan++;
else if(*scan=='-')
{
sign = -1;
scan++;
}
for(;;)
{
if(*scan>='0' && *scan<='9')
val = val*16+(*scan)-'0';
else if(*scan>='a' && *scan<='f')
val = val*16+(*scan)-'a'+10;
else if(*scan>='A' && *scan<='F')
val = val*16+(*scan)-'A'+10;
else
break;
scan++;
}
return val*sign;
}
sInt sScanHex(sChar *&scan)
{
return sScanHex((const sChar *&) scan);
}
/****************************************************************************/
#if !sMOBILE
sF32 sScanFloat(const sChar *&scan)
{
sF64 val;
sInt sign;
sF64 dec;
sign = 1;
val = 0;
if(*scan=='+')
scan++;
else if(*scan=='-')
{
sign = -1;
scan++;
}
while(*scan>='0' && *scan<='9')
val = val*10+(*scan++)-'0';
if(*scan=='.')
{
scan++;
dec = 1.0;
while(*scan>='0' && *scan<='9')
{
dec = dec/10.0;
val = val + ((*scan++)-'0')*dec;
}
}
return val*sign;
}
sF32 sScanFloat(sChar *&scan)
{
return sScanFloat((const sChar *&) scan);
}
#endif
/****************************************************************************/
sBool sScanString(const sChar *&scan,sChar *buffer,sInt size)
{
if(*scan!='"')
return sFALSE;
scan++;
while(*scan!='"' && *scan!=0 && *scan!='\r' && *scan!='\n' && size>1)
{
*buffer++ = *scan++;
size--;
}
*buffer++ = 0;
if(*scan=='"')
{
scan++;
return sTRUE;
}
else
return sFALSE;
}
sBool sScanString(sChar *&scan,sChar *buffer,sInt size)
{
return sScanString((const sChar *&) scan,buffer,size);
}
/****************************************************************************/
sBool sScanName(const sChar *&scan,sChar *buffer,sInt size)
{
sBool done;
done = sFALSE;
if(!((*scan>='a' && *scan<='z') ||
(*scan>='A' && *scan<='Z') || *scan=='_' ))
return sFALSE;
*buffer++ = *scan++;
size--;
while(size>1)
{
if(!((*scan>='a' && *scan<='z') ||
(*scan>='A' && *scan<='Z') ||
(*scan>='0' && *scan<='9') || *scan=='_' ))
{
*buffer++=0;
return sTRUE;
}
*buffer++ = *scan++;
size--;
}
*buffer++=0;
return sFALSE;
}
sBool sScanName(sChar *&scan,sChar *buffer,sInt size)
{
return sScanName((const sChar *&) scan,buffer,size);
}
/****************************************************************************/
void sScanSpace(const sChar *&scan)
{
while(*scan==' ' || *scan=='\t' || *scan=='\r' || *scan=='\n')
scan++;
}
void sScanSpace(sChar *&scan)
{
sScanSpace((const sChar *&) scan);
}
/****************************************************************************/
sBool sScanCycle(const sChar *s,sInt index,sInt &start,sInt &len)
{
start = 0;
len = 0;
while(index>0)
{
while(s[start]!='|' && s[start]!=0)
start++;
if(s[start]!='|')
return sFALSE;
start++;
index--;
}
while(s[start+len]!='|' && s[start+len]!=0)
len++;
return sTRUE;
}
/****************************************************************************/
/*** ***/
/*** Formatted Printing ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE && !sNOCRT
extern "C" char * __cdecl _fcvt( double value, int count, int *dec, int *sign );
extern "C" char * __cdecl _ecvt( double value, int count, int *dec, int *sign );
#endif
sBool sFormatString(sChar *d,sInt left,const sChar *s,const sChar **fp)
{
sInt c;
sInt field0;
sInt field1;
sInt minus;
sInt null;
sInt len;
sChar buffer[64];
sChar *string;
sInt val;
sInt arg;
sInt sign;
sInt i;
#if !sMOBILE && !sNOCRT
sF64 fval;
#endif
static sChar hex[17] = sTXT("0123456789abcdef");
static sChar HEX[17] = sTXT("0123456789ABCDEF");
arg = 0;
left--;
c = *s++;
while(c)
{
if(c=='%')
{
c = *s++;
minus = 0;
null = 0;
field0 = 0;
field1 = 4;
if(c=='-')
{
minus = 1;
c = *s++;
}
if(c=='0')
{
null = 1;
}
while(c>='0' && c<='9')
{
field0 = field0*10 + c - '0';
c = *s++;
}
if(c=='.')
{
field1=0;
c = *s++;
while(c>='0' && c<='9')
{
field1 = field1*10 + c - '0';
c = *s++;
}
}
if(c=='%')
{
c = *s++;
if(left>0)
{
*d++ = '%';
left--;
}
}
else if(c=='d' || c=='x' || c=='X' || c=='i' || c=='f' || c=='e')
{
len = 0;
sign = 0;
if(c=='f' || c=='e')
{
#if !sMOBILE && !sNOCRT
fval = sVARARGF(fp,arg);arg+=2;
#else
arg+=2;
#endif
}
else
{
val = sVARARG(fp,arg);arg++;
}
if(c=='f') // this is preliminary!!!!!!!
{
#if sINTRO || sMOBILE || sNOCRT
string = sTXT("???");
#else
if(fval<0)
field1++;
string = _fcvt(fval,field1,&i,&sign);
#endif
if(i<0)
{
buffer[len++]='.';
while(i<=-1)
{
i++;
buffer[len++]='0';
}
i=-1;
}
while(*string)
{
if(i==0)
buffer[len++]='.';
i--;
buffer[len++]=*string++;
}
}
else if(c=='e')
{
#if sINTRO || sMOBILE || sNOCRT
string = sTXT("???");
#else
if(fval<0)
field1++;
string = _ecvt(fval,field1,&i,&sign);
#endif
if(*string)
{
buffer[len++] = *string++;
buffer[len++] = '.';
while(*string)
buffer[len++] = *string++;
buffer[len++] = 'e';
if(i<0)
{
buffer[len++] = '-';
i = -i;
}
else
buffer[len++] = '+';
if(i>=100)
{
buffer[len++] = 'X';
buffer[len++] = 'X';
}
else
{
buffer[len++] = (i/10)%10 + '0';
buffer[len++] = i%10 + '0';
}
}
}
else if(c=='d' || c=='i')
{
if(val==0x80000000)
{
val = val/10;
buffer[len++] = '8';
}
if(val<0)
{
sign = 1;
val = -val;
}
do
{
buffer[len++] = val%10+'0';
val = val/10;
}
while(val!=0);
if(sign)
len++;
}
else if(c=='x' || c=='X')
{
do
{
if(c=='x')
buffer[len] = hex[val&15];
else
buffer[len] = HEX[val&15];
val = (val>>4)&0x0fffffff;
len++;
}
while(val!=0);
}
if(!minus && !null)
{
while(field0>len && left>0)
{
*d++ = ' ';
left--;
field0--;
}
}
if(sign && left>0)
{
*d++ = '-';
left--;
field0--;
len--;
}
if(!minus && null)
{
while(field0>len && left>0)
{
*d++ = '0';
left--;
field0--;
}
}
i = 0;
while(len>0 && left>0)
{
len--;
if(c=='f' || c=='e')
*d++ = buffer[i++];
else
*d++ = buffer[len];
left--;
field0--;
}
if(!minus)
{
while(field0>len && left>0)
{
*d++ = ' ';
left--;
field0--;
}
}
c = *s++;
}
else if(c=='c')
{
val = (sInt)sVARARG(fp,arg);arg++;
if(left>0)
{
*d++ = val;
left--;
}
c = *s++;
}
else if(c=='s')
{
string = (sChar * )(sDInt)sVARARG(fp,arg);arg++;
len = sGetStringLen(string);
if(field0<=len)
field0=len;
if(!minus)
{
while(field0>len && left>0)
{
*d++ = ' ';
left--;
field0--;
}
}
while(*string && left>0)
{
*d++=*string++;
left--;
}
if(minus)
{
while(field0>len && left>0)
{
*d++ = ' ';
left--;
field0--;
}
}
c = *s++;
}
else if(c=='h' || c=='H')
{
val = sVARARG(fp,arg);arg++;
if(c=='H')
{
if(sAbs(val)>=0x00010000)
{
if(val>0x80000000)
val |= 0x000000ff;
else
val &= 0xffffff00;
}
}
*d++ = '0';
*d++ = 'x';
*d++ = hex[(val>>28)&15];
*d++ = hex[(val>>24)&15];
*d++ = hex[(val>>20)&15];
*d++ = hex[(val>>16)&15];
*d++ = '.';
*d++ = hex[(val>>12)&15];
*d++ = hex[(val>> 8)&15];
*d++ = hex[(val>> 4)&15];
*d++ = hex[(val )&15];
c = *s++;
}
else if(c!=0)
{
c = *s++;
}
}
else
{
if(left>0)
{
*d++ = c;
left--;
}
c = *s++;
}
}
*d=0;
return left>0; // actually, if text fit's exactly, a false truncation error is reported!
}
/****************************************************************************/
void __cdecl sSPrintF(sChar *buffer,sInt size,const sChar *format,...)
{
sFormatString(buffer,size,format,&format);
}
/****************************************************************************/
/*** ***/
/*** Memory Stack Allocator ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
void sMemStack::Init()
{
Size = 0;
Used = 0;
Size = 0;
Delete = sFALSE;
}
void sMemStack::Init(sInt size)
{
Size = size+15;
#if !sINTRO
Mem = (sU8 *) _aligned_malloc(Size,16);
#else
Mem = new sU8[Size];
#endif
Used = 0;
Delete = sTRUE;
}
void sMemStack::Init(sInt size,sU8 *mem)
{
Size = size;
Mem = mem;
Used = 0;
Delete = sFALSE;
}
void sMemStack::Exit()
{
if(Delete)
{
#if !sINTRO
_aligned_free(Mem);
#else
delete[] Mem;
#endif
}
Init();
}
void sMemStack::Flush()
{
Used = 0;
}
sU8 *sMemStack::Alloc(sInt size)
{
sU8 *r;
size = (size + 15) & ~15;
r = Mem+Used;
Used += size;
sVERIFY(Used<=Size);
return r;
}
void sGrowableMemStack::AddNewBlock()
{
Block *b = new Block;
#if !sINTRO
b->Mem = (sU8 *) _aligned_malloc(BlockSize,16);
#else
b->Mem = new sU8[BlockSize];
#endif
b->Used = 0;
b->Next = Blocks;
Blocks = b;
}
void sGrowableMemStack::FreeAllBlocks()
{
Block *b,*n;
for(b=Blocks;b;b=n)
{
n = b->Next;
#if !sINTRO
_aligned_free(b->Mem);
#else
delete[] b;
#endif
delete b;
}
Blocks = 0;
}
void sGrowableMemStack::Init(sInt size)
{
Blocks = 0;
BlockSize = size;
TotalUsed = 0;
AddNewBlock();
}
void sGrowableMemStack::Exit()
{
FreeAllBlocks();
}
void sGrowableMemStack::Flush()
{
// do we need to resize?
if(TotalUsed > BlockSize)
{
FreeAllBlocks();
BlockSize = TotalUsed + (TotalUsed >> 3);
AddNewBlock();
}
else
Blocks->Used = 0;
TotalUsed = Blocks->Used;
}
sU8 *sGrowableMemStack::Alloc(sInt size)
{
size = (size + 15) & ~15;
if(Blocks->Used + size <= BlockSize)
{
sU8 *r = Blocks->Mem + Blocks->Used;
Blocks->Used += size;
TotalUsed += size;
return r;
}
else
{
if(size > BlockSize)
BlockSize = size;
AddNewBlock();
Blocks->Used = size;
TotalUsed += size;
return Blocks->Mem;
}
}
#endif
/****************************************************************************/
/*** ***/
/*** Perlin Noise Util ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
sVector sPerlinGradient3D[16];
sF32 sPerlinRandom[256][2];
sU8 sPerlinPermute[512];
/****************************************************************************/
static const sChar GTable[16*4] =
{
1,1,0,0, 2,1,0,0, 1,2,0,0, 2,2,0,0,
1,0,1,0, 2,0,1,0, 1,0,2,0, 2,0,2,0,
0,1,1,0, 0,2,1,0, 0,1,2,0, 0,2,2,0,
1,1,0,0, 2,1,0,0, 0,2,1,0, 0,2,2,0
};
static const sF32 GValue[3] = { 0.0f, 1.0, -1.0f };
void sInitPerlin()
{
sInt i,j,x,y;
sSetRndSeed(1);
// 3d gradients
for(i=0;i<64;i++)
(&sPerlinGradient3D[0].x)[i] = GValue[GTable[i]];
// permutation
for(i=0;i<256;i++)
{
sPerlinRandom[i][0]=sGetRnd(0x10000);
sPerlinPermute[i]=i;
}
for(i=0;i<255;i++)
{
for(j=i+1;j<256;j++)
{
if(sPerlinRandom[i][0]>sPerlinRandom[j][0])
{
sSwap(sPerlinRandom[i][0],sPerlinRandom[j][0]);
sSwap(sPerlinPermute[i],sPerlinPermute[j]);
}
}
}
sCopyMem(sPerlinPermute+256,sPerlinPermute,256);
// random
for(i=0;i<256;)
{
x = sGetRnd(0x10000)-0x8000;
y = sGetRnd(0x10000)-0x8000;
if(x*x+y*y<0x8000*0x8000)
{
sPerlinRandom[i][0] = x/32768.0f;
sPerlinRandom[i][1] = y/32768.0f;
i++;
}
}
}
#define ix is[0]
#define iy is[1]
#define iz is[2]
#define P sPerlinPermute
#define G sPerlinGradient3D
void sPerlin3D(const sVector &pos,sVector &out)
{
sVector t0,t1,t2;
sF32 fs[3];
sInt is[3];
for(sInt j=0;j<3;j++)
{
is[j] = sFtol(pos[j]-0.5f); // integer coordinate
fs[j] = pos[j] - is[j]; // fractional part
is[j] &= 255; // integer grid wraps round 256
fs[j] = sRange<sF32>(fs[j],1,0);
fs[j] = fs[j]*fs[j]*fs[j]*(10.0f+fs[j]*(6.0f*fs[j]-15.0f));
}
// trilinear interpolation of grid points
t0.Lin3(G[P[P[P[ix]+iy ]+iz ]&15],G[P[P[P[ix+1]+iy ]+iz ]&15],fs[0]);
t1.Lin3(G[P[P[P[ix]+iy+1]+iz ]&15],G[P[P[P[ix+1]+iy+1]+iz ]&15],fs[0]);
t0.Lin3(t0,t1,fs[1]);
t1.Lin3(G[P[P[P[ix]+iy ]+iz+1]&15],G[P[P[P[ix+1]+iy ]+iz+1]&15],fs[0]);
t2.Lin3(G[P[P[P[ix]+iy+1]+iz+1]&15],G[P[P[P[ix+1]+iy+1]+iz+1]&15],fs[0]);
t1.Lin3(t1,t2,fs[1]);
t0.Lin3(t0,t1,fs[2]);
out = t0;
}
#undef ix
#undef iy
#undef iz
#undef P
#undef G
#endif
/****************************************************************************/
/*** ***/
/*** Compact value encodings ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
void sWriteShort(sU8 *&data,sInt value)
{
sVERIFY(value >= 0 && value <= 32767);
*data++ = (value & 127) | (value>127 ? 128 : 0);
if(value>127)
*data++ = value >> 7;
}
sInt sReadShort(const sU8 *&data)
{
sInt v;
v = *data++;
if(v & 128)
v = (v & 127) | (*data++ << 7);
return v;
}
void sWriteX16(sU8 *&data,sF32 value)
{
sInt v,vn;
v = value * 4096.0f;
vn = (v < -32768) ? -32768 : (v > 32767) ? 32767 : v;
*((sS16 *) data) = vn;
data += 2;
}
sF32 sReadX16(const sU8 *&data)
{
sInt v;
v = *((sS16 *) data);
data += 2;
return v / 4096.0f;
}
static sInt doShift(sU32 v,sInt shift)
{
while(shift>0)
v<<=1,shift--;
while(shift<0)
v>>=1,shift++;
return v;
}
void sWriteF16(sU8 *&data,sF32 v)
{
sU32 value;
sU16 dest;
sInt esrc,edst;
value = *(sU32 *) &v;
esrc = ((value>>23) & 255) - 128;
edst = sRange(esrc,15,-16);
if(edst == -16) // very near zero or zero
*data++ = 0x00;
else if(sFAbs(v - 1.0f) < 1.0f/1024.0f) // very near one
*data++ = 0x80;
else if(sFAbs(v - 0.5f) < 0.5f/1024.0f) // very near 0.5
*data++ = 0x01;
else if(sFAbs(v - 0.25f) < 0.25f/1024.0f) // very near 0.25
*data++ = 0x81;
else
{
dest = ((value>>16) & 32768) // sign
| ((edst+16)<<10)
| (doShift(value>>13,edst-esrc) & 1023);
sVERIFY((dest >> 8) != 0x00 && (dest >> 8) != 0x01 && (dest >> 8) != 0x81);
*data++ = dest >> 8;
*data++ = dest & 0xff;
}
}
sF32 sReadF16(const sU8 *&data)
{
sInt v;
sU32 vd;
v = *data++;
if(v == 0x00) // zero
return 0.0f;
else if(v == 0x80) // one
return 1.0f;
else if(v == 0x01) // 0.5
return 0.5f;
else if(v == 0x81) // minus one
return 0.25f;
else
{
v = (v << 8) | *data++;
vd = (v & 32768) << 16 // sign
| ((((v >> 10) & 31) + 128 - 16) << 23)
| ((v & 1023) << 13);
return *(sF32 *) &vd;
}
}
void sWriteF24(sU8 *&data,sF32 value)
{
sU32 fltv,exp;
if(value == 0.0f)
*data++ = 0;
else if(value == 1.0f)
*data++ = 1;
else if(value == -1.0f)
*data++ = 0xff;
else
{
fltv = *((sU32 *) &value);
exp = (fltv >> 23) & 0xff;
if(exp<=1)
*data++ = 0;
else
{
sVERIFY(exp != 0xff);
// order of bytes: exponent, mantissa 2, sign+mantissa 1
*data++ = exp;
*data++ = fltv >> 8;
*data++ = ((fltv >> 24) & 128) | ((fltv >> 16) & 127);
}
}
}
sF32 sReadF24(const sU8 *&data)
{
sU32 first,second,full;
first = *data++;
if(first == 0)
return 0.0f;
else if(first == 1)
return 1.0f;
else if(first == 0xff)
return -1.0f;
else
{
second = *((sU16 *) data); data += 2;
full = (first << 23) | ((second & 32768) << 16) | ((second & 32767) << 8);
return *((sF32 *) &full);
}
}
#endif
/****************************************************************************/
/*** ***/
/*** File Reading and Writing ***/
/*** ***/
/****************************************************************************/
void sWriteString(sU32 *&data,sChar *str)
{
sInt size;
size = sGetStringLen(str);
*data++ = size;
data[size/4] = 0;
sCopyMem(data,str,size);
data+=(size+3)/4;
}
sBool sReadString(sU32 *&data,sChar *str,sInt max)
{
sInt size;
size = *data++;
if(size+1>max)
{
str[0] = 0;
return sFALSE;
}
sCopyMem(str,data,size);
str[size] = 0;
data+=(size+3)/4;
return sTRUE;
}
sU32 *sWriteBegin(sU32 *&data,sU32 cid,sInt version)
{
*data++ = sMAGIC_BEGIN;
*data++ = cid;
*data++ = version;
*data++ = 0;
return data-1;
}
void sWriteEnd(sU32 *&data,sU32 *header)
{
if(header)
*header = data-(header+1);
*data++ = sMAGIC_END;
}
sInt sReadBegin(sU32 *&data,sU32 cid)
{
sInt version;
sInt size;
if(*data++!=sMAGIC_BEGIN) return 0;
if(*data++!=cid) return 0;
version = *data++;
size = *data++;
if(data[size]!=sMAGIC_END) return 0;
return version;
}
sBool sReadEnd(sU32 *&data)
{
if(*data++!=sMAGIC_END) return 0;
return sTRUE;
}
/****************************************************************************/
/*** ***/
/*** Debugging ***/
/*** ***/
/****************************************************************************/
#if sMOBILE
void sTerminate(sChar *buffer);
void sOutputDebugString(sChar *buffer);
void sVerifyFalse(const sChar *file,sInt line)
{
sFatal(sTXT("%s(%d) : assertion"),file,line);
}
void __cdecl sFatal(const sChar *format,...)
{
static sChar buffer[1024];
// sFatality = 1;
sFormatString(buffer,sCOUNTOF(buffer),format,&format);
sOutputDebugString(buffer);
sOutputDebugString(sTXT("\n"));
sTerminate(buffer);
}
void sDPrint(sChar *text)
{
sOutputDebugString(text);
}
void __cdecl sDPrintF(const sChar *format,...)
{
sChar buffer[1024];
sFormatString(buffer,sCOUNTOF(buffer),format,&format);
sOutputDebugString(buffer);
}
/****************************************************************************/
#else
/****************************************************************************/
void sVerifyFalse(const sChar *file,sInt line)
{
#if !sINTRO
sFatal(sTXT("%s(%d) : assertion"),file,line);
#else
sFatal(sTXT("assertion"));
#endif
}
#if !sINTRO || !sRELEASE
extern sInt sFatality;
extern "C" void __stdcall OutputDebugStringA(char *string);
extern "C" int __stdcall wvsprintfA(char *buffer,const char *fmt,va_list args);
void __cdecl sFatal(const sChar *format,...)
{
static sChar buffer[1024];
sFatality = 1;
sFormatString(buffer,sCOUNTOF(buffer),format,&format);
#if !sRELEASE
OutputDebugStringA(buffer);
OutputDebugStringA("\n");
//__asm { int 3 };
#endif
sSystem->Abort(buffer);
}
#else
extern "C" int __stdcall wvsprintfA(char *buffer,const char *fmt,va_list args);
void __cdecl sFatal(sChar *format,...)
{
static sChar buffer[1024];
va_list arg;
va_start(arg,format);
wvsprintfA(buffer,format,arg);
va_end(arg);
sSystem->Abort(buffer);
}
#endif
#if !sINTRO || !sRELEASE
void sDPrint(sChar *text)
{
#if !sINTRO
sSystem->Log(text);
#endif
}
#endif
#if !sINTRO || !sRELEASE
void __cdecl sDPrintF(const sChar *format,...)
{
sChar buffer[1024];
#if !sINTRO
sFormatString(buffer,sCOUNTOF(buffer),format,&format);
sSystem->Log(buffer);
#else
va_list list;
va_start(list,format);
wvsprintfA(buffer,format,list);
va_end(list);
OutputDebugStringA(buffer);
#endif
}
#endif
/****************************************************************************/
#endif
/****************************************************************************/
/*** ***/
/*** Simple Structs ***/
/*** ***/
/****************************************************************************/
#pragma lekktor(off)
#if !sMOBILE
void sRect::Init(const struct sFRect &r)
{
x0=sFtol(r.x0);
y0=sFtol(r.y0);
x1=sFtol(r.x1);
y1=sFtol(r.y1);
}
#endif
sBool sRect::Hit(sInt x,sInt y)
{
return x>=x0 && x<x1 && y>=y0 && y<y1;
}
sBool sRect::Hit(const sRect &rin)
{
sRect r;
r = *this;
r.And(rin);
return r.x0<r.x1 && r.y0<r.y1;
}
sBool sRect::Inside(const sRect &r)
{
if(x0 < r.x0) return sFALSE;
if(y0 < r.y0) return sFALSE;
if(x1 > r.x1) return sFALSE;
if(y1 > r.y1) return sFALSE;
return sTRUE;
}
void sRect::And(const sRect &r)
{
if(r.x0 > x0) x0 = r.x0;
if(r.y0 > y0) y0 = r.y0;
if(r.x1 < x1) x1 = r.x1;
if(r.y1 < y1) y1 = r.y1;
}
void sRect::Or(const sRect &r)
{
if(r.x0 < x0) x0 = r.x0;
if(r.y0 < y0) y0 = r.y0;
if(r.x1 > x1) x1 = r.x1;
if(r.y1 > y1) y1 = r.y1;
}
void sRect::Sort()
{
if(x0>x1) sSwap(x0,x1);
if(y0>y1) sSwap(y0,y1);
}
void sRect::Extend(sInt i)
{
x0-=i;
y0-=i;
x1+=i;
y1+=i;
}
/****************************************************************************/
/****************************************************************************/
#if !sMOBILE
void sFRect::Init(const struct sRect &r)
{
x0=r.x0;
y0=r.y0;
x1=r.x1;
y1=r.y1;
}
sBool sFRect::Hit(sF32 x,sF32 y)
{
return x>=x0 && x<x1 && y>=y0 && y<y1;
}
sBool sFRect::Hit(const sFRect &rin)
{
sFRect r;
r = *this;
r.And(rin);
return r.x0<r.x1 && r.y0<r.y1;
}
void sFRect::And(const sFRect &r)
{
if(r.x0 > x0) x0 = r.x0;
if(r.y0 > y0) y0 = r.y0;
if(r.x1 < x1) x1 = r.x1;
if(r.y1 < y1) y1 = r.y1;
}
void sFRect::Or(const sFRect &r)
{
if(r.x0 < x0) x0 = r.x0;
if(r.y0 < y0) y0 = r.y0;
if(r.x1 > x1) x1 = r.x1;
if(r.y1 > y1) y1 = r.y1;
}
void sFRect::Sort()
{
if(x0>x1) sSwap(x0,x1);
if(y0>y1) sSwap(y0,y1);
}
void sFRect::Extend(sF32 i)
{
x0-=i;
y0-=i;
x1+=i;
y1+=i;
}
#endif
/****************************************************************************/
#if !sINTRO
void sRandom::Init()
{
Seed(0);
}
void sRandom::Seed(sInt seed)
{
kern = seed+seed*17+seed*121+(seed*121/17);
Int32();
kern ^= seed+seed*17+seed*121+(seed*121/17);
Int32();
kern ^= seed+seed*17+seed*121+(seed*121/17);
Int32();
kern ^= seed+seed*17+seed*121+(seed*121/17);
Int32();
}
sInt sRandom::Int16()
{
sU32 r0;
r0 = kern*0x343fd+0x269ec3;
kern = r0;
r0 = (r0>>10)&0x0000ffff;
return r0;
}
sU32 sRandom::Int32()
{
sU32 r0,r1;
r0 = kern*0x343fd+0x269ec3;
r1 = r0*0x343fd+0x269ec3;
kern = r1;
r1 = (r1>>10)&0x0000ffff;
r0 = (r0<< 6)&0xffff0000;
return r1|r0;
}
static sInt CutRange(sU32 value,sInt max)
{
sInt x;
__asm
{
mov eax, [value];
mul [max];
mov [x], edx;
}
}
sInt sRandom::Int(sInt max)
{
if(max<0x4000)
return (Int16()*max)>>16;
else
return CutRange(Int32(),max);
//return sInt((sU64(Int32())*max)>>32);
}
sF32 sRandom::Float(sF32 max)
{
return Int32()*max/(65536.0f*65536.0f);
}
#endif
/****************************************************************************/
/*** ***/
/*** Vector and Matrix ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
//void sVector::Init(sInt3 &v) {x=v.x/65536.0f; y=v.y/65536.0f; z=v.z/65536.0f; w=0.0f;}
//void sVector::Init(sInt4 &v) {x=v.x/65536.0f; y=v.y/65536.0f; z=v.z/65536.0f; w=v.w/65536.0f;}
//void sVector::InitColor(sU32 col) {x=((col>>0)&0xff)/255.0f;y=((col>>8)&0xff)/255.0f;z=((col>>16)&0xff)/255.0f;w=((col>>24)&0xff)/255.0f;}
//sU32 sVector::GetColor() {return sRange<sInt>(x*255,255,0)|(sRange<sInt>(y*255,255,0)<<8)|(sRange<sInt>(z*255,255,0)<<16)|(sRange<sInt>(w*255,255,0)<<24);}
void sVector::InitRnd()
{
do
{
x = sFGetRnd()*2.0f-1.0f;
y = sFGetRnd()*2.0f-1.0f;
z = sFGetRnd()*2.0f-1.0f;
}
while(Dot3(*this)>1.0f);
}
void sVector::Lin3(const sVector &a,const sVector &b,sF32 t) {x=a.x+(b.x-a.x)*t; y=a.y+(b.y-a.y)*t; z=a.z+(b.z-a.z)*t;}
void sVector::Rotate3(const sMatrix &m,const sVector &v) {Scale3(m.i,v.x); AddScale3(m.j,v.y); AddScale3(m.k,v.z);}
void sVector::Rotate3(const sMatrix &m) {sVector v; v=*this; Rotate3(m,v);}
void sVector::RotateT3(const sMatrix &m,const sVector &v) {x=m.i.Dot3(v); y=m.j.Dot3(v); z=m.k.Dot3(v);}
void sVector::RotateT3(const sMatrix &m) {sVector v; v=*this; RotateT3(m,v);}
void sVector::Cross3(const sVector &a,const sVector &b) {x=a.y*b.z-a.z*b.y; y=a.z*b.x-a.x*b.z; z=a.x*b.y-a.y*b.x;}
sF32 sVector::Abs3() const {return sFSqrt(Dot3(*this));}
void sVector::Unit3() {Scale3(sFInvSqrt(Dot3(*this)));}
sF32 sVector::UnitAbs3() {sF32 e=sFSqrt(Dot3(*this)); if(e>1e-10f) Scale3(1.0f/e); else Init3(1,0,0); return e; }
void sVector::UnitSafe3() {sF32 e=Dot3(*this); if(e>1e-20f) Scale3(sFInvSqrt(e)); else Init3(1,0,0);}
void sVector::Lin4(const sVector &a,const sVector &b,sF32 t) {x=a.x+(b.x-a.x)*t; y=a.y+(b.y-a.y)*t; z=a.z+(b.z-a.z)*t; w=a.w+(b.w-a.w)*t;}
void sVector::Rotate4(const sMatrix &m,const sVector &v) {Scale4(m.i,v.x); AddScale4(m.j,v.y); AddScale4(m.k,v.z); AddScale4(m.l,v.w);}
void sVector::Rotate4(const sMatrix &m) {sVector v; v=*this; Rotate4(m,v);}
void sVector::Rotate34(const sMatrix &m,const sVector &v) {Scale4(m.i,v.x); AddScale4(m.j,v.y); AddScale4(m.k,v.z); Add4(m.l);}
void sVector::Rotate34(const sMatrix &m) {sVector v; v=*this; Rotate34(m,v);}
void sVector::RotateT4(const sMatrix &m,const sVector &v) {x=m.i.Dot4(v); y=m.j.Dot4(v); z=m.k.Dot4(v); w=m.l.Dot4(v);}
void sVector::RotateT4(const sMatrix &m) {sVector v; v=*this; RotateT4(m,v);}
void sVector::RotatePl(const sMatrix &m,const sVector &v) {Rotate3(m,v); w=v.w-Dot3(m.l);}
void sVector::RotatePl(const sMatrix &m) {sVector v; v=*this; RotatePl(m,v);}
void sVector::Cross4(const sVector &a,const sVector &b) {x=a.y*b.z-a.z*b.y; y=a.z*b.x-a.x*b.z; z=a.x*b.y-a.y*b.x; w=0;}
sF32 sVector::Abs4() const {return Dot4(*this);}
void sVector::Unit4() {Scale4(sFInvSqrt(Dot4(*this)));}
sF32 sVector::UnitAbs4() {sF32 e=sFSqrt(Dot4(*this)); if(e>0.000001) Scale4(1.0f/e); else Init4(1,0,0,0); return e; }
void sVector::UnitSafe4() {sF32 e=Dot4(*this); if(e>0.00001) Scale4(sFInvSqrt(e)); else Init4(1,0,0,0);}
sInt sVector::Classify()
{
if(sFAbs(x) > sFAbs(y) && sFAbs(x) > sFAbs(z))
{
if(x>0) return 1;
else return 0;
}
else if(sFAbs(y) > sFAbs(z))
{
if(y>0) return 3;
else return 2;
}
else
{
if(z>0) return 5;
else return 4;
}
}
void sVector::Plane(const sVector &a,const sVector &b,const sVector &c)
{
sVector d1,d2;
d1.Sub3(b,a);
d2.Sub3(c,a);
Cross3(d1,d2);
w = -Dot3(a);
}
void sVector::Write(sU32 *&p)
{
((sF32 *)p)[0] = x;
((sF32 *)p)[1] = y;
((sF32 *)p)[2] = z;
((sF32 *)p)[3] = w;
p+=4;
}
void sVector::Write3(sU32 *&p)
{
((sF32 *)p)[0] = x;
((sF32 *)p)[1] = y;
((sF32 *)p)[2] = z;
p+=3;
}
void sVector::Write3U(sU32 *&p)
{
((sF32 *)p)[0] = x;
((sF32 *)p)[1] = y;
p+=2;
}
void sVector::Read(sU32 *&p)
{
x = ((sF32 *)p)[0];
y = ((sF32 *)p)[1];
z = ((sF32 *)p)[2];
w = ((sF32 *)p)[3];
p+=4;
}
void sVector::Read3(sU32 *&p)
{
x = ((sF32 *)p)[0];
y = ((sF32 *)p)[1];
z = ((sF32 *)p)[2];
w = 1.0f;
p+=3;
}
void sVector::Read3U(sU32 *&p)
{
x = ((sF32 *)p)[0];
y = ((sF32 *)p)[1];
z = sFSqrt(1.0f-x*x-y*y);
w = 1.0f;
p+=2;
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::Write(sU32 *&f)
{
i.Write(f);
j.Write(f);
k.Write(f);
l.Write(f);
}
void sMatrix::WriteR(sU32 *&f)
{
i.Write3U(f);
j.Write3U(f);
l.Write3(f);
}
void sMatrix::Write33(sU32 *&f)
{
i.Write3(f);
j.Write3(f);
k.Write3(f);
}
void sMatrix::Write34(sU32 *&f)
{
i.Write3(f);
j.Write3(f);
k.Write3(f);
l.Write3(f);
}
void sMatrix::Write33R(sU32 *&f)
{
i.Write3U(f);
j.Write3U(f);
}
void sMatrix::Read(sU32 *&f)
{
i.Read(f);
j.Read(f);
k.Read(f);
l.Read(f);
}
void sMatrix::ReadR(sU32 *&f)
{
i.Read3U(f); i.w=0.0f;
j.Read3U(f); j.w=0.0f;
k.Cross3(i,j); k.w=0.0f;
l.Read3(f); l.w=1.0f;
}
void sMatrix::Read33(sU32 *&f)
{
i.Read3(f); i.w = 0.0f;
j.Read3(f); j.w = 0.0f;
k.Read3(f); k.w = 0.0f;
l.Init(0.0f,0.0f,0.0f,1.0f);
}
void sMatrix::Read34(sU32 *&f)
{
i.Read3(f); i.w = 0.0f;
j.Read3(f); j.w = 0.0f;
k.Read3(f); k.w = 0.0f;
l.Read3(f); k.w = 1.0f;
}
void sMatrix::Read33R(sU32 *&f)
{
i.Read3U(f); i.w=0.0f;
j.Read3U(f); j.w=0.0f;
k.Cross3(i,j); k.w=0.0f;
l.Init(0.0f,0.0f,0.0f,1.0f);
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::Init()
{
i.Init(1,0,0,0);
j.Init(0,1,0,0);
k.Init(0,0,1,0);
l.Init(0,0,0,1);
}
/****************************************************************************/
void sMatrix::InitRot(const sVector &v)
{
sF32 abs = v.Abs3();
if(abs<0.00000001)
{
Init();
}
else
{
InitRot(v,abs);
}
}
void sMatrix::InitRot(const sVector &v,sF32 angle)
{
sMatrix c,s;
sVector u;
sF32 cc,ss;
cc = sFCos(angle);
ss = sFSin(angle);
u = v;
u.UnitSafe3();
s.i.x = ss * 0;
s.i.y = ss * u.z;
s.i.z = ss * -u.y;
s.j.x = ss * -u.z;
s.j.y = ss * 0;
s.j.z = ss * u.x;
s.k.x = ss * u.y;
s.k.y = ss * -u.x;
s.k.z = ss * 0;
c.i.x = cc * (1.0f-u.x*u.x);
c.i.y = cc * -u.x*u.y ;
c.i.z = cc * -u.x*u.z ;
c.j.x = cc * -u.y*u.x ;
c.j.y = cc * (1.0f-u.y*u.y);
c.j.z = cc * -u.y*u.z ;
c.k.x = cc * -u.z*u.x ;
c.k.y = cc * -u.z*u.y ;
c.k.z = cc * (1.0f-u.z*u.z);
i.x = u.x*u.x + c.i.x + s.i.x;
i.y = u.x*u.y + c.i.y + s.i.y;
i.z = u.x*u.z + c.i.z + s.i.z;
i.w = 0.0f;
j.x = u.y*u.x + c.j.x + s.j.x;
j.y = u.y*u.y + c.j.y + s.j.y;
j.z = u.y*u.z + c.j.z + s.j.z;
j.w = 0.0f;
k.x = u.z*u.x + c.k.x + s.k.x;
k.y = u.z*u.y + c.k.y + s.k.y;
k.z = u.z*u.z + c.k.z + s.k.z;
k.w = 0.0f;
l.Init4(0,0,0,1);
}
/****************************************************************************/
void sMatrix::InitDir(const sVector &v)
{
j.Init3(0,1,0);
k = v;
k.UnitSafe3();
i.Cross3(j,k);
i.UnitSafe3();
j.Cross3(k,i);
//j.UnitSafe3(); // cross product of orthonormal vectors is normalized
i.w = 0.0f;
j.w = 0.0f;
k.w = 0.0f;
l.Init4(0,0,0,1);
}
/****************************************************************************/
#define ALIGN4_INIT1( X, INIT ) static __declspec(align(16)) X[4] = { INIT, INIT, INIT, INIT }
ALIGN4_INIT1(sU32 SIMD_SP_signBitMask, (1U<<31));
ALIGN4_INIT1(sF32 SIMD_SP_one,1.0f);
ALIGN4_INIT1(sF32 SIMD_SP_oneOverTwoPI,1.0f/sPI2F);
ALIGN4_INIT1(sF32 SIMD_SP_halfPI,sPIF*0.5f);
ALIGN4_INIT1(sF32 SIMD_SP_PI,sPIF);
ALIGN4_INIT1(sF32 SIMD_SP_twoPI,sPI2F);
// constants determined via remez exchange algorithm
// max. relative error ~1.108e-6 (~10ulps)
// => just don't touch this unless you really know what you're doing!!
ALIGN4_INIT1(sF32 SIMD_SP_sin_c0,-1.854219680e-4f);
ALIGN4_INIT1(sF32 SIMD_SP_sin_c1, 8.314273770e-3f);
ALIGN4_INIT1(sF32 SIMD_SP_sin_c2,-1.666585317e-1f);
void SSE_SinCos4(sF32 a[4],sF32 s[4],sF32 c[4])
{
__asm
{
// pointers
mov eax, [a];
mov esi, [s];
mov edi, [c];
// get angles, range reduce [0,pi*2]
movaps xmm0, [eax];
movaps xmm1, [SIMD_SP_oneOverTwoPI];
movaps xmm3, xmm0;
xorps xmm4, xmm4;
mulps xmm1, xmm0;
movhlps xmm2, xmm1;
cmpltps xmm3, xmm4;
cvttss2si ecx, xmm1; // float(int(a[0]))
cvttss2si edx, xmm2; // float(int(a[2]))
cvtsi2ss xmm1, ecx;
cvtsi2ss xmm2, edx;
shufps xmm1, xmm1, 001h; // swap a[0],a[1]
shufps xmm2, xmm2, 001h; // swap a[2],a[3]
andps xmm3, [SIMD_SP_one];
cvttss2si ecx, xmm1; // float(int(a[1]))
cvttss2si edx, xmm2; // float(int(a[3]))
cvtsi2ss xmm1, ecx;
cvtsi2ss xmm2, edx;
shufps xmm1, xmm2, 011h; // float(int(a[0],a[1],a[2],a[3]))
movaps xmm5, [SIMD_SP_signBitMask];
subps xmm1, xmm3;
movaps xmm7, [SIMD_SP_PI];
mulps xmm1, [SIMD_SP_twoPI];
subps xmm0, xmm1;
movaps xmm1, [SIMD_SP_halfPI];
// range reduce [0,pi]
movaps xmm4, xmm5;
movaps xmm6, xmm7;
subps xmm7, xmm0;
movaps xmm0, xmm5;
andps xmm4, xmm7;
andnps xmm0, xmm7;
// range reduce [0,pi/2]
movaps xmm2, xmm0;
cmpltps xmm2, xmm1;
subps xmm6, xmm0;
andps xmm5, xmm2;
minps xmm0, xmm6;
// eval
movaps xmm2, xmm0;
subps xmm1, xmm0;
movaps xmm3, xmm1;
movaps xmm6, [SIMD_SP_sin_c0];
movaps xmm7, [SIMD_SP_sin_c0];
mulps xmm2, xmm2;
mulps xmm3, xmm3;
xorps xmm0, xmm4;
xorps xmm1, xmm5;
mulps xmm6, xmm2;
mulps xmm7, xmm3;
addps xmm6, [SIMD_SP_sin_c1];
addps xmm7, [SIMD_SP_sin_c1];
mulps xmm6, xmm2;
mulps xmm7, xmm3;
addps xmm6, [SIMD_SP_sin_c2];
addps xmm7, [SIMD_SP_sin_c2];
mulps xmm6, xmm2;
mulps xmm7, xmm3;
addps xmm6, [SIMD_SP_one];
addps xmm7, [SIMD_SP_one];
mulps xmm6, xmm0;
mulps xmm7, xmm1;
movaps [esi], xmm6;
movaps [edi], xmm7;
}
}
//#if !sINTRO
void sMatrix::InitEuler(sF32 _a,sF32 _b,sF32 _c)
{
sF32 __declspec(align(16)) x[4],s[4],c[4];
x[0] = _a;
x[1] = _b;
x[2] = _c;
x[3] = 0.0f;
SSE_SinCos4(x,s,c);
i.x = c[1]*c[2];
i.y = c[1]*s[2];
i.z = -s[1];
i.w = 0.0f;
j.x = -c[0]*s[2] + s[0]*s[1]*c[2];
j.y = c[0]*c[2] + s[0]*s[1]*s[2];
j.z = s[0]*c[1];
j.w = 0.0f;
k.x = s[0]*s[2] + c[0]*s[1]*c[2];
k.y = -s[0]*c[2] + c[0]*s[1]*s[2];
k.z = c[0]*c[1];
k.w = 0.0f;
l.Init4(0,0,0,1);
}
//#endif
void sMatrix::InitEulerPI2(const sF32 *a)
{
if(sFAbs(a[0]) < 1e-6f && sFAbs(a[1]) < 1e-6f && sFAbs(a[2]) < 1e-6f)
Init();
else
InitEuler(a[0]*sPI2F,a[1]*sPI2F,a[2]*sPI2F);
}
/****************************************************************************/
void sMatrix::InitSRT(const sF32 *srt)
{
InitEulerPI2(srt+3);
i.Scale3(srt[0]);
j.Scale3(srt[1]);
k.Scale3(srt[2]);
l.Init3(srt[6],srt[7],srt[8]);
}
/****************************************************************************/
void sMatrix::InitRandomSRT(const sF32 *srt)
{
sInt i;
sF32 srtc[9];
for(i=0;i<3;i++)
srtc[i] = (srt[i] - 1.0f) * sFGetRnd() + 1.0f;
for(i=3;i<9;i++)
srtc[i] = srt[i] * (sFGetRnd() - 0.5f) * 2.0f;
InitSRT(srtc);
}
/****************************************************************************/
void sMatrix::InitSRTInv(const sF32 *srt)
{
sVector v;
InitEulerPI2(srt+3);
Trans3();
i.Scale3(1.0f/srt[0]);
j.Scale3(1.0f/srt[1]);
k.Scale3(1.0f/srt[2]);
v.Init3(-srt[6],-srt[7],-srt[8]);
l.Rotate3(*this,v);
}
/****************************************************************************/
void sMatrix::InitClassify(sInt id)
{
static const sVector dirs[6] =
{
{ -1, 0, 0 },
{ 1, 0, 0 },
{ 0,-1, 0 },
{ 0, 1, 0 },
{ 0, 0,-1 },
{ 0, 0, 1 },
};
Init();
k = dirs[id];
switch(id)
{
case 0:
case 1:
case 4:
case 5:
j.Init(0,1,0);
break;
case 2:
j.Init(0,0,1);
break;
case 3:
j.Init(0,0,1);
break;
}
i.Cross3(j,k);
}
/****************************************************************************/
void sMatrix::PivotTransform(sF32 x,sF32 y,sF32 z)
{
sMatrix t1,t2;
t1.Init();
t1.l.x = -x;
t1.l.y = -y;
t1.l.z = -z;
t2 = *this;
MulA(t1,t2);
l.x += x;
l.y += y;
l.z += z;
}
/****************************************************************************/
void sMatrix::FindEuler(sF32 &a,sF32 &b,sF32 &c)
{
sF32 cy;
cy = sFSqrt(i.x*i.x+i.y*i.y);
b = sFATan2(-i.z,cy);
if(cy>1e-4f)
{
a = sFATan2(j.z,k.z);
c = sFATan2(i.y,i.x);
}
else
{
a = sFATan2(-k.y,j.y);
c = 0.0f;
}
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::Trans3()
{
sSwap(i.y,j.x);
sSwap(i.z,k.x);
sSwap(j.z,k.y);
}
/****************************************************************************/
void sMatrix::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 sMatrix::TransR()
{
Trans3();
l.Neg3();
l.Rotate3(*this);
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::InvCheap3()
{
sF32 x,y,z;
x = sFInvSqrt(i.Dot3(i));
y = sFInvSqrt(j.Dot3(j));
z = sFInvSqrt(k.Dot3(k));
i.Scale3(x);
j.Scale3(y);
k.Scale3(z);
Trans3();
i.Scale3(x);
j.Scale3(y);
k.Scale3(z);
}
/****************************************************************************/
void sMatrix::Scale3(sF32 s)
{
i.Scale3(s);
j.Scale3(s);
k.Scale3(s);
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::InvCheap4()
{
sF32 x,y,z;
x = sFInvSqrt(i.Dot3(i));
y = sFInvSqrt(j.Dot3(j));
z = sFInvSqrt(k.Dot3(k));
i.Scale3(x);
j.Scale3(y);
k.Scale3(z);
Trans3();
i.Scale3(x);
j.Scale3(y);
k.Scale3(z);
l.Neg3();
l.Rotate3(*this);
}
/****************************************************************************/
void sMatrix::Scale4(sF32 s)
{
i.Scale4(s);
j.Scale4(s);
k.Scale4(s);
l.Scale4(s);
}
/****************************************************************************/
void sMatrix::Invert(const sMatrix &a)
{
sF32 s = 1.0f/(a.i.x*a.j.y*a.k.z+a.i.y*a.j.z*a.k.x+a.i.z*a.j.x*a.k.y
-a.k.x*a.j.y*a.i.z-a.k.y*a.j.z*a.i.x-a.k.z*a.j.x*a.i.y);
i.x = s*(a.j.y*a.k.z - a.j.z*a.k.y);
i.y = s*(a.k.y*a.i.z - a.i.y*a.k.z);
i.z = s*(a.i.y*a.j.z - a.j.y*a.i.z);
i.w = 0.0f;
j.x = s*(a.k.x*a.j.z - a.j.x*a.k.z);
j.y = s*(a.i.x*a.k.z - a.i.z*a.k.x);
j.z = s*(a.j.x*a.i.z - a.i.x*a.j.z);
j.w = 0.0f;
k.x = s*(a.j.x*a.k.y - a.k.x*a.j.y);
k.y = s*(a.k.x*a.i.y - a.i.x*a.k.y);
k.z = s*(a.i.x*a.j.y - a.j.x*a.i.y);
k.w = 0.0f;
l.x = -i.x*a.l.x - j.x*a.l.y - k.x*a.l.z;
l.y = -i.y*a.l.x - j.y*a.l.y - k.y*a.l.z;
l.z = -i.z*a.l.x - j.z*a.l.y - k.z*a.l.z;
l.w = 1.0f;
}
/****************************************************************************/
void sMatrix::Lin4(sMatrix &m0,sMatrix &m1,sF32 fade)
{
Init();
i.Lin3(m0.i,m1.i,fade);
j.Lin3(m0.j,m1.j,fade);
k.Cross3(i,j);
k.Unit3();
i.Cross3(j,k);
i.Unit3();
j.Unit3();
l.Lin3(m0.l,m1.l,fade);
}
/****************************************************************************/
/****************************************************************************/
void sMatrix::Mul3(const sMatrix &a,const sMatrix &b)
{
i.Scale3(b.i,a.i.x); i.AddScale3(b.j,a.i.y); i.AddScale3(b.k,a.i.z);
j.Scale3(b.i,a.j.x); j.AddScale3(b.j,a.j.y); j.AddScale3(b.k,a.j.z);
k.Scale3(b.i,a.k.x); k.AddScale3(b.j,a.k.y); k.AddScale3(b.k,a.k.z);
/*
i.x = a.i.x*b.i.x + a.i.y*b.j.x + a.i.z*b.k.x;
i.y = a.i.x*b.i.y + a.i.y*b.j.y + a.i.z*b.k.y;
i.z = a.i.x*b.i.z + a.i.y*b.j.z + a.i.z*b.k.z;
j.x = a.j.x*b.i.x + a.j.y*b.j.x + a.j.z*b.k.x;
j.y = a.j.x*b.i.y + a.j.y*b.j.y + a.j.z*b.k.y;
j.z = a.j.x*b.i.z + a.j.y*b.j.z + a.j.z*b.k.z;
k.x = a.k.x*b.i.x + a.k.y*b.j.x + a.k.z*b.k.x;
k.y = a.k.x*b.i.y + a.k.y*b.j.y + a.k.z*b.k.y;
k.z = a.k.x*b.i.z + a.k.y*b.j.z + a.k.z*b.k.z;
*/
}
/****************************************************************************/
void sMatrix::Mul4(const sMatrix &a,const sMatrix &b)
{
// 64 muls, 48 adds
sVector *out = &i;
for(sInt n=0;n<4;n++)
{
sF32 ax,ay,az,aw;
ax = a[n].x; ay = a[n].y; az = a[n].z; aw = a[n].w;
out->x = b.i.x * ax + b.j.x * ay + b.k.x * az + b.l.x * aw;
out->y = b.i.y * ax + b.j.y * ay + b.k.y * az + b.l.y * aw;
out->z = b.i.z * ax + b.j.z * ay + b.k.z * az + b.l.z * aw;
out->w = b.i.w * ax + b.j.w * ay + b.k.w * az + b.l.w * aw;
out++;
}
}
/****************************************************************************/
void sMatrix::MulA(const sMatrix &a,const sMatrix &b)
{
// 36 muls, 27 adds => use when possible!
sVector *out = &i;
// rotational part first (assume a.w = b.w = 0)
for(sInt n=0;n<4;n++)
{
sF32 ax,ay,az;
ax = a[n].x; ay = a[n].y; az = a[n].z;
out->x = b.i.x * ax + b.j.x * ay + b.k.x * az;
out->y = b.i.y * ax + b.j.y * ay + b.k.y * az;
out->z = b.i.z * ax + b.j.z * ay + b.k.z * az;
out->w = 0.0f;
out++;
}
// now add translations
l.x += b.l.x;
l.y += b.l.y;
l.z += b.l.z;
l.w = 1.0f;
}
/****************************************************************************/
/****************************************************************************/
void sQuaternion::InitAxisAngle(const sVector &axis,sF32 angle)
{
sF32 s,c;
sFSinCos(angle * 0.5f,s,c);
s /= axis.Abs3();
w = c;
x = s * axis.x;
y = s * axis.y;
z = s * axis.z;
}
void sQuaternion::Lin(const sQuaternion &a,const sQuaternion &b,sF32 t)
{
sF32 dot = a.w*b.w + a.x*b.x + a.y*b.y + a.z*b.z;
if(dot<0)
{
w = a.w + (-b.w-a.w)*t;
x = a.x + (-b.x-a.x)*t;
y = a.y + (-b.y-a.y)*t;
z = a.z + (-b.z-a.z)*t;
}
else
{
w = a.w + (b.w-a.w)*t;
x = a.x + (b.x-a.x)*t;
y = a.y + (b.y-a.y)*t;
z = a.z + (b.z-a.z)*t;
}
Unit();
}
sF32 sQuaternion::Abs() const
{
return sFSqrt(w*w + x*x + y*y + z*z);
}
void sQuaternion::Unit()
{
Scale(sFInvSqrt(w*w + x*x + y*y + z*z));
}
void sQuaternion::UnitSafe()
{
sF32 len = Abs();
if(len > 1e-6f)
Scale(1.0f / len);
else
Init(1,0,0,0);
}
// Left operand may be *this, right may not.
void sQuaternion::Mul(const sQuaternion &a,const sQuaternion &b)
{
sF32 aw = a.w, ax = a.x, ay = a.y, az = a.z;
w = aw*b.w - ax*b.x - ay*b.y - az*b.z;
x = ax*b.w + aw*b.x - az*b.y + ay*b.z;
y = ay*b.w + az*b.x + aw*b.y - ax*b.z;
z = az*b.w - ay*b.x + ax*b.y + aw*b.z;
}
void sQuaternion::MulL(const sQuaternion &a)
{
sF32 bw = w, bx = x, by = y, bz = z;
w = a.w*bw - a.x*bx - a.y*by - a.z*bz;
x = a.x*bw + a.w*bx - a.z*by + a.y*bz;
y = a.y*bw + a.z*bx + a.w*by - a.x*bz;
z = a.z*bw - a.y*bx + a.x*by + a.w*bz;
}
// Only makes sense for unit quaternions.
void sQuaternion::ToMatrix(sMatrix &m) const
{
sF32 xx = 2.0f*x*x, xy = 2.0f*x*y, xz = 2.0f*x*z;
sF32 yy = 2.0f*y*y, yz = 2.0f*y*z, zz = 2.0f*z*z;
sF32 xw = 2.0f*x*w, yw = 2.0f*y*w, zw = 2.0f*z*w;
// maybe need to transpose this
m.i.x = 1.0f - yy - zz;
m.i.y = xy - zw;
m.i.z = xz + yw;
m.i.w = 0.0f;
m.j.x = xy + zw;
m.j.y = 1.0f - xx - zz;
m.j.z = yz - xw;
m.j.w = 0.0f;
m.k.x = xz - yw;
m.k.y = yz + xw;
m.k.z = 1.0f - xx - yy;
m.k.w = 0.0f;
m.l.x = 0.0f;
m.l.y = 0.0f;
m.l.z = 0.0f;
m.l.w = 1.0f;
}
void sQuaternion::FromMatrix(const sMatrix &mat)
{
sF32 tr,s;
tr = mat.i.x + mat.j.y + mat.k.z;
if(tr>=0)
{
s = (sF32)sFSqrt(tr + 1);
w = s*0.5f;
s = 0.5f / s;
x = (mat.k.y - mat.j.z) * s;
y = (mat.i.z - mat.k.x) * s;
z = (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 );
x = s*0.5f;
s = 0.5f / s;
y = (mat.i.y + mat.j.x) * s;
z = (mat.k.x + mat.i.z) * s;
w = (mat.k.y - mat.j.z) * s;
break;
case 1:
s = (sF32)sFSqrt( (mat.j.y - (mat.k.z+mat.i.x)) + 1.0f );
y = s*0.5f;
s = 0.5f / s;
z = (mat.j.z + mat.k.y) * s;
x = (mat.i.y + mat.j.x) * s;
w = (mat.i.z - mat.k.x) * s;
break;
case 2:
s = (sF32)sFSqrt( (mat.k.z - (mat.i.x+mat.j.y)) + 1.0f );
z = s*0.5f;
s = 0.5f / s;
x = (mat.k.x + mat.i.z) * s;
y = (mat.j.z + mat.k.y) * s;
w = (mat.j.x - mat.i.y) * s;
break;
}
}
}
/****************************************************************************/
/****************************************************************************/
void sAABox::Rotate34(const sAABox &a,const sMatrix &m)
{
sVector v[3];
sInt i;
v[0].Scale3(m.i,a.Max.x-a.Min.x);
v[1].Scale3(m.j,a.Max.y-a.Min.y);
v[2].Scale3(m.k,a.Max.z-a.Min.z);
Min.Rotate34(m,a.Min);
Max = Min;
for(i=0;i<3;i++)
{
if(v[i].x<0) Min.x += v[i].x; else Max.x += v[i].x;
if(v[i].y<0) Min.y += v[i].y; else Max.y += v[i].y;
if(v[i].z<0) Min.z += v[i].z; else Max.z += v[i].z;
}
}
void sAABox::Or(const sAABox &b)
{
Min.x = sMin(Min.x,b.Min.x);
Min.y = sMin(Min.y,b.Min.y);
Min.z = sMin(Min.z,b.Min.z);
Max.x = sMax(Max.x,b.Max.x);
Max.y = sMax(Max.y,b.Max.y);
Max.z = sMax(Max.z,b.Max.z);
}
void sAABox::And(const sAABox &b)
{
Min.x = sMax(Min.x,b.Min.x);
Min.y = sMax(Min.y,b.Min.y);
Min.z = sMax(Min.z,b.Min.z);
Max.x = sMin(Max.x,b.Max.x);
Max.y = sMin(Max.y,b.Max.y);
Max.z = sMin(Max.z,b.Max.z);
}
sBool sAABox::Intersects(const sAABox &b)
{
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 sAABox::IntersectsSphere(const sVector &center,sF32 radius)
{
sF32 d = 0.0f, dt;
if((dt = center.z - Min.z) < 0.0f)
d += dt * dt;
else if((dt = center.z - Max.z) > 0.0f)
d += dt * dt;
if((dt = center.x - Min.x) < 0.0f)
d += dt * dt;
else if((dt = center.x - Max.x) > 0.0f)
d += dt * dt;
if((dt = center.y - Min.y) < 0.0f)
d += dt * dt;
else if((dt = center.y - Max.y) > 0.0f)
d += dt * dt;
return d <= radius * radius;
}
/****************************************************************************/
void sCullPlane::LinearComb(const sVector &a,sF32 wa,const sVector &b,sF32 wb)
{
Plane.Scale4(a,wa);
Plane.AddScale4(b,wb);
CalcNVert();
}
void sCullPlane::From3Points(const sVector &a,const sVector &b,const sVector &c)
{
Plane.Plane(a,b,c);
CalcNVert();
}
void sCullPlane::CalcNVert()
{
sInt ind;
ind = (Plane.x > 0.0f) ? 1 : 0;
ind |= (Plane.y > 0.0f) ? 2 : 0;
ind |= (Plane.z > 0.0f) ? 4 : 0;
NVert = ind;
}
void sCullPlane::Normalize()
{
Plane.Scale4(sFInvSqrt(Plane.Dot3(Plane)));
}
sF32 sCullPlane::Distance(const sVector &x) const
{
return Plane.Dot3(x) + Plane.w;
}
sBool sCullBBox(const sAABox &box,const sCullPlane *planes,sInt planeCount)
{
sVector v;
sInt i,vi;
for(i=0;i<planeCount;i++)
{
vi = planes[i].NVert;
v.x = (vi & 1) ? box.Max.x : box.Min.x;
v.y = (vi & 2) ? box.Max.y : box.Min.y;
v.z = (vi & 4) ? box.Max.z : box.Min.z;
if(planes[i].Distance(v) < -1e-6f) // near vert out
return sTRUE;
}
return sFALSE;
}
/****************************************************************************/
void sFrustum::FromViewProject(const sMatrix &viewProject,const sFRect &viewport)
{
sMatrix temp;
// make transposed view/projection matrix
temp = viewProject;
temp.Trans4();
// build frustum planes from linear combinations
Planes[0].LinearComb(temp.l,-viewport.x0,temp.i, 1.0f); // left
Planes[1].LinearComb(temp.l, viewport.x1,temp.i,-1.0f); // right
Planes[2].LinearComb(temp.l,-viewport.y0,temp.j, 1.0f); // bottom
Planes[3].LinearComb(temp.l, viewport.y1,temp.j,-1.0f); // top
Planes[4].LinearComb(temp.l, 0.0f,temp.k, 1.0f); // near
Planes[5].LinearComb(temp.l, 1.0f,temp.k,-1.0f); // far
NPlanes = Planes[5].Plane.Dot3(Planes[5].Plane) > 1e-20f ? 6 : 5;
}
void sFrustum::ZFailVolume(const sVector &light,const sMatrix &view,sF32 znear,sF32 zoom[2],const sFRect &viewport)
{
sVector points[4];
static const sF32 onEpsilon = 1e-4f;
// calc projection of frustum points onto znear plane in world space
sF32 xs = znear / zoom[0];
sF32 ys = znear / zoom[1];
for(sInt i=0;i<4;i++)
{
points[i] = view.l;
points[i].AddScale3(view.i,xs*((i&1) ? viewport.x1 : viewport.x0));
points[i].AddScale3(view.j,ys*((i&2) ? viewport.y1 : viewport.y0));
points[i].AddScale3(view.k,znear);
}
// build planes
Planes[0].From3Points(points[0],points[1],points[2]); // near
sF32 znd = Planes[0].Distance(light);
if(sFAbs(znd) >= onEpsilon) // before/behind znear
{
Planes[1].From3Points(light,points[1],points[0]); // top
Planes[2].From3Points(light,points[3],points[1]); // right
Planes[3].From3Points(light,points[2],points[3]); // bottom
Planes[4].From3Points(light,points[0],points[2]); // left
if(znd < 0.0f) // we were behind znear, so flip all planes
{
for(sInt i=0;i<5;i++)
{
Planes[i].Plane.Scale4(-1.0f);
Planes[i].CalcNVert();
}
}
// make additional plane to "close off" behind light, improving cull ratio
Planes[5].Plane.Sub3(view.l,light);
Planes[5].Plane.AddScale3(view.k,znear);
Planes[5].Plane.w = -Planes[5].Plane.Dot3(light);
Planes[5].CalcNVert();
NPlanes = 6;
}
else // on znear (degenerate case)
{
Planes[1].Plane.Scale4(Planes[0].Plane,-1.0f);
Planes[1].CalcNVert();
// move planes to encompass epsilon range
Planes[0].Plane.w += onEpsilon;
Planes[1].Plane.w -= onEpsilon;
NPlanes = 2;
}
}
void sFrustum::EnlargeToInclude(const sVector &point)
{
for(sInt i=0;i<NPlanes;i++)
{
sF32 d = Planes[i].Distance(point);
if(d < 0.0f) // point behind plane => move plane backwards
Planes[i].Plane.w -= d;
}
}
void sFrustum::Normalize()
{
for(sInt i=0;i<NPlanes;i++)
Planes[i].Normalize();
}
#pragma lekktor(on)
#endif
/****************************************************************************/
/*** ***/
/*** Static Strings ***/
/*** ***/
/****************************************************************************/
void sSPrintF(const sStringDesc &desc,const sChar *format,...)
{
sFormatString(desc.Buffer,desc.Size,format,&format);
}
/****************************************************************************/
/*** ***/
/*** Object Broker ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
sBroker_::sBroker_()
{
ObjectCount = 0;
ObjectAlloc = 256*1024;
Objects = new sObject*[ObjectAlloc];
RootCount = 0;
RootAlloc = 4*1024;
Roots = new sObject*[RootAlloc];
}
/****************************************************************************/
sBroker_::~sBroker_()
{
delete[] Objects;
delete[] Roots;
}
/****************************************************************************/
/****************************************************************************/
void sBroker_::NewObject(sObject *obj)
{
sVERIFY(ObjectCount<ObjectAlloc);
Objects[ObjectCount] = obj;
obj->TagVal = ObjectCount++;
obj->_Label = 0;
}
/****************************************************************************/
void sBroker_::DeleteObject(sObject *obj)
{
sInt i;
if(obj)
{
if(obj->TagVal&sTAGVAL_ROOT)
RemRoot(obj);
i = obj->TagVal&sTAGVAL_INDEX;
sVERIFY(Objects[i] = obj);
obj = Objects[--ObjectCount];
Objects[i] = obj;
obj->TagVal = (obj->TagVal & (~sTAGVAL_INDEX)) | i;
}
}
/****************************************************************************/
void sBroker_::AddRoot(sObject *root)
{
sVERIFY(!(root->TagVal & sTAGVAL_ROOT));
sVERIFY(RootCount<RootAlloc);
Roots[RootCount++] = root;
root->TagVal |= sTAGVAL_ROOT;
}
void sBroker_::RemRoot(sObject *root)
{
sInt i;
sVERIFY(root->TagVal & sTAGVAL_ROOT);
root->TagVal &= ~sTAGVAL_ROOT;
for(i=0;i<RootCount;i++)
{
if(Roots[i]==root)
{
Roots[i] = Roots[--RootCount];
return;
}
}
sFatal("root table mismatch");
}
/****************************************************************************/
/****************************************************************************/
void sBroker_::Need(sObject *obj)
{
if(obj && !(obj->TagVal & sTAGVAL_USED))
{
obj->TagVal |= sTAGVAL_USED;
obj->Tag();
}
}
/****************************************************************************/
void sBroker_::Free()
{
sInt i;
for(i=0;i<ObjectCount;i++)
Objects[i]->TagVal &= ~sTAGVAL_USED;
for(i=0;i<RootCount;i++)
Need(Roots[i]);
sSystem->Tag();
for(i=0;i<ObjectCount;)
{
if(!(Objects[i]->TagVal & sTAGVAL_USED))
delete Objects[i];
else
i++;
}
}
/****************************************************************************/
void sBroker_::Dump()
{
sInt i;
if(RootCount>0 || ObjectCount>0)
{
sDPrintF("Broker Memory Leak!\n");
sDPrintF("Roots:\n");
for(i=0;i<RootCount;i++)
sDPrintF(" %5d: %08x %08x\n",i,Roots[i],Roots[i]->GetClass());
sDPrintF("All Objects:\n");
for(i=0;i<ObjectCount;i++)
{
sDPrintF(" %5d: %08x %08x %c\n"
,i
,Objects[i]
,Objects[i]->GetClass()
,(Objects[i]->TagVal & sTAGVAL_ROOT) ? 'r':' ');
}
}
}
/****************************************************************************/
/****************************************************************************/
void sObject::Tag()
{
}
sBool sObject::Write(sU32 *&)
{
return sFALSE;
}
sBool sObject::Read(sU32 *&)
{
return sFALSE;
}
sBool sObject::Merge(sU32 *&)
{
return sFALSE;
}
void sObject::Clear()
{
}
void sObject::Copy(sObject *)
{
sFatal("unimplemented copy called");
}
#endif
/****************************************************************************/
/*** ***/
/*** Arrays ***/
/*** ***/
/****************************************************************************/
#pragma lekktor(off)
void sArrayInit(sArrayBase *base,sInt s,sInt c)
{
if(c)
base->Array = new sU8[s*c];
else
base->Array = 0;
base->Count = 0;
base->Alloc = c;
base->TypeSize = s;
}
void sArraySetMax(sArrayBase *base,sInt c)
{
sU8 *n;
//sVERIFY(c > base->Alloc);
sVERIFY(c >= base->Count);
if(c != base->Alloc)
{
n=new sU8[c*base->TypeSize];
if(base->Array)
{
sCopyMem(n,base->Array,base->TypeSize*base->Count);
delete[] base->Array;
}
base->Count=sMin(base->Count,c);
base->Array=n;
base->Alloc=c;
}
}
void sArrayAtLeast(sArrayBase *base,sInt c)
{
if(c>base->Alloc)
sArraySetMax(base,sMax(c,base->Alloc*2-base->Alloc/2));
}
void sArrayCopy(sArrayBase *dest,const sArrayBase *src)
{
dest->Count = 0;
if(src->Count > dest->Alloc)
sArraySetMax(dest,src->Count);
sCopyMem(dest->Array,src->Array,src->TypeSize*src->Count);
dest->Count = src->Count;
}
sU8 *sArrayAdd(sArrayBase *base)
{
sU8 *data;
sArrayAtLeast(base,base->Count+1);
data = base->Array+base->Count*base->TypeSize;
base->Count++;
return data;
}
#pragma lekktor(on)
/****************************************************************************/
/*** ***/
/*** Bitmap ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
sBitmap::sBitmap()
{
Data = 0;
XSize = 0;
YSize = 0;
}
/****************************************************************************/
sBitmap::~sBitmap()
{
Clear();
}
/****************************************************************************/
/****************************************************************************/
void sBitmap::Init(sInt xs,sInt ys)
{
if(xs!=XSize || ys!=YSize)
{
if(Data)
delete[] Data;
XSize = xs;
YSize = ys;
Data = new sU32[XSize*YSize];
}
}
/****************************************************************************/
void sBitmap::Clear()
{
if(Data)
delete[] Data;
Data = 0;
XSize = 0;
YSize = 0;
}
/****************************************************************************/
void sBitmap::Copy(sObject *o)
{
sBitmap *bm;
sVERIFY(o->GetClass()==sCID_BITMAP);
bm = (sBitmap *) o;
Init(bm->XSize,bm->YSize);
sCopyMem4(Data,bm->Data,XSize*YSize);
}
/****************************************************************************/
sBool sBitmap::Write(sU32 *&p)
{
*p++ = 1;
*p++ = XSize;
*p++ = YSize;
sCopyMem4(p,Data,XSize*YSize);
p+=XSize*YSize;
return sTRUE;
}
/****************************************************************************/
sBool sBitmap::Read(sU32 *&p)
{
sInt version;
version = *p++;
if(version<1 || version>1) return sFALSE;
if(p[0]>0x2000 || p[1]>0x2000) return sFALSE;
Init(p[0],p[1]);
p+=2;
sCopyMem4(Data,p,XSize*YSize);
p+=XSize*YSize;
return sTRUE;
}
/****************************************************************************/
/*** ***/
/*** Text ***/
/*** ***/
/****************************************************************************/
#if !sINTRO
/****************************************************************************/
sText::sText(sInt size)
{
sVERIFY(size>0)
Text = new sChar[size];
Text[0] = 0;
Alloc = size;
Used = 0;
}
sText::sText(const sChar *str)
{
sInt len;
len = sGetStringLen(str);
Text = new sChar[len+1];
Text[0] = 0;
Alloc = len+1;
Used = 0;
Init(str,len);
}
sText::~sText()
{
delete[] Text;
}
void sText::Copy(sObject *o)
{
sVERIFY(o->GetClass()==sCID_TEXT);
Init(((sText *)o)->Text);
}
/****************************************************************************/
void sText::Init(const sChar *text,sInt len)
{
if(len==-1)
len = sGetStringLen(text);
Realloc(len+1);
sCopyMem(Text,text,len);
Text[len] = 0;
Used = len;
}
sBool sText::Realloc(sInt size)
{
sChar *s;
FixUsed();
if(size>Alloc)
{
s = new sChar[size];
sCopyString(s,Text,size);
delete[] Text;
Text = s;
Alloc = size;
return 1;
}
else
{
return 0;
}
}
sBool sText::Grow(sInt size)
{
if(size>Alloc)
{
Realloc(sMax(Alloc*2,size*3/2));
return 1;
}
else
{
return 0;
}
}
/****************************************************************************/
sBool sText::Write(sU32 *&data)
{
sInt size;
size = sGetStringLen(Text);
*data++ = size;
data[size/4] = 0;
sCopyMem(data,Text,size);
data+=(size+3)/4;
return sTRUE;
}
sBool sText::Read(sU32 *&data)
{
sInt size;
size = *data++;
Realloc(size+1);
sCopyMem(Text,data,size);
Text[size] = 0;
data+=(size+3)/4;
return sTRUE;
}
/****************************************************************************/
void sText::Clear()
{
Text[0] = 0;
Used = 0;
}
void sText::FixUsed()
{
Used = sGetStringLen(Text);
sVERIFY(Used<Alloc);
}
void sText::Print(const sChar *s)
{
sInt len;
len = sGetStringLen(s);
if(Used+len+1>=Alloc)
Grow(Used+len+1);
sCopyMem(Text+Used,s,len+1);
Used+=len;
}
void sText::PrintF(const sChar *format,...)
{
PrintArg(format,&format);
}
void sText::PrintArg(const sChar *format,const sChar **fp)
{
if(Alloc==0)
Realloc(1024);
while(!sFormatString(Text+Used,Alloc-Used,format,fp))
{
Text[Used] = 0;
Realloc(Alloc*2);
}
Used += sGetStringLen(Text+Used);
}
#endif
/****************************************************************************/
/*** ***/
/*** MusicPlayers ***/
/*** ***/
/****************************************************************************/
sMusicPlayer::sMusicPlayer()
{
Stream = 0;
StreamSize = 0;
StreamDelete = 0;
Status = 0;
RewindBuffer = 0;
RewindSize = 0;
RewindPos = 0;
PlayPos = 0;
}
sMusicPlayer::~sMusicPlayer()
{
if(StreamDelete)
delete[] Stream;
if(RewindBuffer)
delete[] RewindBuffer;
}
sBool sMusicPlayer::Load(sChar *name)
{
sInt size;
sU8 *data;
data = sSystem->LoadFile(name,size);
if(data)
return Load(data,size,sTRUE);
else
{
Stream = 0;
StreamSize = 0;
StreamDelete = sFALSE;
Status = 0;
return sFALSE;
}
}
sBool sMusicPlayer::Load(sU8 *data,sInt size,sBool ownMem)
{
if(StreamDelete)
delete[] Stream;
Stream = data;
StreamSize = size;
StreamDelete = ownMem;
Status = 1;
return sTRUE;
}
sBool sMusicPlayer::LoadCache(sChar *name)
{
sInt size;
sU8 *mem;
mem = sSystem->LoadFile(name,size);
if(mem)
{
RewindBuffer = (sS16 *)mem;
RewindSize = size/4;
RewindPos = size/4;
sVERIFY(Stream==0);
Status = 3;
return sTRUE;
}
else
return sFALSE;
}
sBool sMusicPlayer::LoadAndCache(sChar *name)
{
static sChar buffer[4096];
sInt size;
sU8 *mem;
sCopyString(buffer,name,4096);
sAppendString(buffer,".raw",4096);
if(!LoadCache(buffer))
{
if(Load(name))
{
Start(0);
size = GetTuneLength() * 5; // 25% larger than required, for variable bitrate oggs
mem = new sU8[size];
sInt realsamples = Render((sS16 *)mem,size/4);
sVERIFY(realsamples*4<=size);
RewindBuffer = (sS16 *)mem;
RewindSize = realsamples;
RewindPos = realsamples;
sSystem->SaveFile(buffer,mem,realsamples*4);
return sTRUE;
}
else
return sFALSE;
}
return sTRUE;
}
sBool sMusicPlayer::LoadAndCache(sChar *name,sU8 *data,sInt size,sBool ownMem)
{
static sChar buffer[4096];
sU8 *mem;
sCopyString(buffer,name,4096);
sAppendString(buffer,".raw",4096);
if(!LoadCache(buffer))
{
if(Load(data,size,ownMem))
{
Start(0);
size = GetTuneLength() * 4;
mem = new sU8[size];
Render((sS16 *)mem,size/4);
RewindBuffer = (sS16 *)mem;
RewindSize = size/4;
RewindPos = size/4;
sSystem->SaveFile(buffer,mem,size);
return sTRUE;
}
else
return sFALSE;
}
else if(ownMem)
{
// succesfully loaded from cache, can free data.
delete[] data;
}
return sTRUE;
}
void sMusicPlayer::AllocRewind(sInt bytes)
{
RewindSize = bytes/4;
RewindBuffer = new sS16[bytes/2];
RewindPos = 0;
}
sBool sMusicPlayer::Start(sInt songnr)
{
if(Status==1)
{
if(Init(songnr))
Status = 3;
else
Status = 0;
}
return Status==3;
}
void sMusicPlayer::Stop()
{
if(Status == 3)
Status = 1;
}
sBool sMusicPlayer::Handler(sS16 *buffer,sInt samples,sInt vol)
{
sInt diff,size;
sInt result;
sInt i;
result = 1;
if(Status==3)
{
if(RewindBuffer)
{
if(PlayPos+samples < RewindSize)
{
while(RewindPos<PlayPos+samples && result)
{
diff = PlayPos+samples-RewindPos;
size = Render(RewindBuffer+RewindPos*2,diff);
if(size==0)
result = 0;
RewindPos+=size;
}
size = samples;
if(PlayPos+size>RewindSize)
size = PlayPos-RewindPos;
if(size>0)
{
for(i=0;i<size*2;i++)
buffer[i] = (RewindBuffer[PlayPos*2+i]*vol)>>8;
// sCopyMem(buffer,RewindBuffer+PlayPos*2,size*4);
buffer+=size*2;
PlayPos += size;
samples -= size;
}
}
if(samples>0)
{
sSetMem(buffer,0,samples*4);
}
}
else
{
while(samples>0 && result)
{
size = Render(buffer,samples);
if(size==0)
result = 0;
buffer+=size*2;
PlayPos += size;
samples-=size;
}
}
}
else
{
sSetMem(buffer,0,samples*4);
}
return result;
}
#endif
/****************************************************************************/
/*** ***/
/*** Matrix Stack ***/
/*** ***/
/****************************************************************************/
#if !sMOBILE
void sMatrixStack::Init()
{
Stack.Init(16);
PushIdentity();
}
void sMatrixStack::Exit()
{
Stack.Exit();
}
#endif
/****************************************************************************/
#if !sMOBILE
#pragma lekktor(off)
void sVector::Init(sInt3 &v) {x=v.x/65536.0f; y=v.y/65536.0f; z=v.z/65536.0f; w=0.0f;}
void sVector::Init(sInt4 &v) {x=v.x/65536.0f; y=v.y/65536.0f; z=v.z/65536.0f; w=v.w/65536.0f;}
void sVector::InitColor(sU32 col) {x=((col>>16)&0xff)/255.0f;y=((col>>8)&0xff)/255.0f;z=((col>>0)&0xff)/255.0f;w=((col>>24)&0xff)/255.0f;}
void sVector::InitColorI(sU32 col) {x=((col>>0)&0xff)/255.0f;y=((col>>8)&0xff)/255.0f;z=((col>>16)&0xff)/255.0f;w=((col>>24)&0xff)/255.0f;}
sU32 sVector::GetColor() {return sRange<sInt>(z*255,255,0)|(sRange<sInt>(y*255,255,0)<<8)|(sRange<sInt>(x*255,255,0)<<16)|(sRange<sInt>(w*255,255,0)<<24);}
sU32 sVector::GetColorI() {return sRange<sInt>(x*255,255,0)|(sRange<sInt>(y*255,255,0)<<8)|(sRange<sInt>(z*255,255,0)<<16)|(sRange<sInt>(w*255,255,0)<<24);}
void sVector::Add4(const sVector &a,const sVector &b) {x=a.x+b.x; y=a.y+b.y; z=a.z+b.z; w=a.w+b.w;}
void sVector::Sub4(const sVector &a,const sVector &b) {x=a.x-b.x; y=a.y-b.y; z=a.z-b.z; w=a.w-b.w;}
void sVector::Mul4(const sVector &a,const sVector &b) {x=a.x*b.x; y=a.y*b.y; z=a.z*b.z; w=a.w*b.w;}
void sVector::Neg4(const sVector &a) {x=-a.x; y=-a.y; z=-a.z; w=-a.w;}
void sVector::Add4(const sVector &a) {x+=a.x; y+=a.y; z+=a.z; w+=a.w;}
void sVector::Sub4(const sVector &a) {x-=a.x; y-=a.y; z-=a.z; w-=a.w;}
void sVector::Mul4(const sVector &a) {x*=a.x; y*=a.y; z*=a.z; w*=a.w;}
void sVector::Neg4() {x=-x; y=-y; z=-z; w=-w;}
void sVector::AddMul4(const sVector &a,const sVector &b) {x+=a.x*b.x; y+=a.y*b.y; z+=a.z*b.z; w+=a.w*b.w;}
sF32 sVector::Dot4(const sVector &a) const {return x*a.x + y*a.y + z*a.z + w*a.w;}
void sVector::Scale4(sF32 s) {x*=s; y*=s; z*=s; w*=s;}
void sVector::Scale4(const sVector &a,sF32 s) {x=a.x*s; y=a.y*s; z=a.z*s; w=a.w*s;}
void sVector::AddScale4(const sVector &a,sF32 s) {x+=a.x*s; y+=a.y*s; z+=a.z*s; w+=a.w*s;}
void sVector::Add3(const sVector &a,const sVector &b) {x=a.x+b.x; y=a.y+b.y; z=a.z+b.z;}
void sVector::Sub3(const sVector &a,const sVector &b) {x=a.x-b.x; y=a.y-b.y; z=a.z-b.z;}
void sVector::Mul3(const sVector &a,const sVector &b) {x=a.x*b.x; y=a.y*b.y; z=a.z*b.z;}
void sVector::Neg3(const sVector &a) {x=-a.x; y=-a.y; z=-a.z;}
void sVector::Add3(const sVector &a) {x+=a.x; y+=a.y; z+=a.z;}
void sVector::Sub3(const sVector &a) {x-=a.x; y-=a.y; z-=a.z;}
void sVector::Mul3(const sVector &a) {x*=a.x; y*=a.y; z*=a.z;}
void sVector::Neg3() {x=-x; y=-y; z=-z;}
sF32 sVector::Dot3(const sVector &a) const {return x*a.x+y*a.y+z*a.z;}
void sVector::AddMul3(const sVector &a,const sVector &b) {x+=a.x*b.x; y+=a.y*b.y; z+=a.z*b.z;}
void sVector::Scale3(sF32 s) {x*=s; y*=s; z*=s;}
void sVector::Scale3(const sVector &a,sF32 s) {x=a.x*s; y=a.y*s; z=a.z*s;}
void sVector::AddScale3(const sVector &a,sF32 s) {x+=a.x*s; y+=a.y*s; z+=a.z*s;}
#endif