// This file is distributed under a BSD license. See LICENSE.txt for details. #include "genblobspline.hpp" #include "werkkzeug.hpp" #include "genoverlay.hpp" struct InterpolElem { sF32 Time; sF32 px,py,pz; sQuaternion quat; sF32 zoom; }; /****************************************************************************/ /*** ***/ /*** new spline code ***/ /*** ***/ /****************************************************************************/ /****************************************************************************/ /*** ***/ /*** The Spline Data ***/ /*** ***/ /****************************************************************************/ BlobSpline *MakeBlobSpline(sInt *out_bytes,sInt keys) { sInt bytes = sizeof(BlobSpline)+sizeof(BlobSplineKey)*keys; BlobSpline *Spline = (BlobSpline *) new sU8[bytes]; sSetMem(Spline,0,bytes); Spline->Count = keys; Spline->Version = 3; Spline->Select = -1; Spline->Mode = 0; Spline->Tension = 0; Spline->Continuity = 0; Spline->Uniform = 0; Spline->Target.Init(0,0,0,1); sSetMem(Spline->pad,0,sizeof(Spline->pad)); if(out_bytes) *out_bytes = bytes; return Spline; } BlobSpline *MakeDummyBlobSpline(sInt *out_bytes) { BlobSpline *Spline = MakeBlobSpline(out_bytes,2); Spline->Keys[0].Init(); Spline->Keys[1].Init(); Spline->Keys[1].Time = 1.0f; return Spline; } /****************************************************************************/ void BlobSpline::Sort() { for(sInt i=0;iKeys[j].Time) sSwap(Keys[i],Keys[j]); } sF32 BlobSpline::Normalize() { sMatrix mat; sF32 zoom; sF32 dist; sVector v0,v1,delta; sF32 *dp; dp = new sF32[Count]; Uniform = 1; Sort(); dist = 0; Calc(Keys[0].Time,mat,zoom); v1 = mat.l; for(sInt i=0;iCount = Count; ns->Version = Version; ns->CopyPara(this); for(sInt i=0;iKeys[i] = Keys[i]; return ns; } void BlobSpline::CopyPara(BlobSpline *from) { Select = from->Select; Mode = from->Mode; Target = from->Target; Continuity = from->Continuity; Tension = from->Tension; Uniform = from->Uniform; } void BlobSpline::SetSelect(sInt key) { Select = key; for(sInt i=0;i static void sFindSplineTime(sF32 time,T *Keys,sInt Count ,sF32 *&p0,sF32 *&p1,sF32 *&p2,sF32 *&p3,sF32 &t) { sInt i; if(time<=Keys[0].Time) { i = 1; time = 0; } else if(time>=Keys[Count-1].Time) { i = Count-1; time = Keys[Count-1].Time; } else { for(i=1;itime) break; } sVERIFY(i=0) p0 = &Keys[i-2].Time+1; p1 = &Keys[i-1].Time+1; p2 = &Keys[i ].Time+1; if(i+1=Keys[Count-1].Time) { i = Count-1; time = Keys[Count-1].Time; } else { for(i=1;itime) break; } sVERIFY(i=0) p0 = &Keys[i-2].Time+1; p1 = &Keys[i-1].Time+1; p2 = &Keys[i ].Time+1; if(i+1Count = keys; pipe->Version = 1; pipe->Mode = 0; if(out_bytes) *out_bytes = bytes; return pipe; } BlobPipe *MakeDummyBlobPipe(sInt *out_bytes) { BlobPipe *pipe; pipe = MakeBlobPipe(out_bytes,2); pipe->StartX = 0; pipe->StartY = 0; pipe->StartZ = 0; pipe->Keys[0].PosX = 0; pipe->Keys[0].PosY = 0; pipe->Keys[0].PosZ = 1; pipe->Keys[0].Radius = 0.125f; pipe->Keys[0].Flags = 0; pipe->Keys[1].PosX = 0; pipe->Keys[1].PosY = 1; pipe->Keys[1].PosZ = 1; pipe->Keys[1].Radius = 0.125f; pipe->Keys[1].Flags = 2; return pipe; } void BlobPipe::CopyPara(BlobPipe *from) { StartX = from->StartX; StartY = from->StartY; StartZ = from->StartZ; Tension = from->Tension; } BlobPipe *BlobPipe::Copy() { sInt bytes = sizeof(BlobPipe)+sizeof(BlobPipeKey)*Count; BlobPipe *pipe = (BlobPipe *) new sU8[bytes]; sCopyMem(pipe,this,bytes); return pipe; } /****************************************************************************/ /*** ***/ /*** GenSpline Object ***/ /*** ***/ /****************************************************************************/ GenSpline::GenSpline() { ClassId = KC_SPLINE; } /****************************************************************************/ GenSplineSpline::GenSplineSpline() { Spline = 0; Pipe = 0; } GenSplineSpline::~GenSplineSpline() { if(Spline) delete[] (sU8 *) Spline; if(Pipe) delete[] (sU8 *) Pipe; } void GenSplineSpline::Eval(sF32 time,sF32 phase,sMatrix &mat,sF32 &zoom) { Spline->Calc(time,mat,zoom); } void GenSplineSpline::Init(BlobSpline *data) { sDelete(Spline); if(data) Spline = data->Copy(); } /****************************************************************************/ GenSplineShaker::GenSplineShaker() { Parent = 0; TranslateAmp.Init(); RotateAmp.Init(); TranslateFreq.Init(); RotateFreq.Init(); Center.Init(); OpLink = 0; } GenSplineShaker::~GenSplineShaker() { sRelease(Parent); } void GenSplineShaker::Eval(sF32 time2,sF32 phase,sMatrix &mat,sF32 &zoom) { sMatrix mat1,mat0; sF32 tx,ty,tz,rx,ry,rz; sF32 time,ramp; sF32 amp; amp = 1; if(AmpSpline) AmpSpline->Eval(time2,phase,mat,amp); if(Parent) { Parent->Eval(time2,phase,mat,zoom); } else { mat.Init(); zoom = 1; } sBool fakemode = 0; KEvent *event = OpLink->FirstEvent; if(event==0) fakemode = 1; while(event || fakemode) { if(fakemode) time = GenOverlayManager->KEnv->Var[KV_TIME].x; else time = 1.0f*(event->End-GenOverlayManager->KEnv->BeatTime) / (event->End-event->Start); if(time>0 && time<1) { switch(Mode&15) { default: case 0: ramp = 1-time; break; case 1: ramp = time; time = 1-time; break; case 2: ramp = sFSin(time*sPIF); break; case 3: ramp = 1; break; } ramp *= amp; if(Mode & 32) { sVector v; v = TranslateFreq; v.Scale3(time); sPerlin3D(v,v); tx = v.x; ty = v.y; tz = v.z; v = RotateFreq; v.Scale3(time); sPerlin3D(v,v); rx = v.x; ry = v.y; rz = v.z; } else { tx = sFSin(time*TranslateFreq.x*sPI2F)*TranslateAmp.x*ramp; ty = sFSin(time*TranslateFreq.y*sPI2F)*TranslateAmp.y*ramp; tz = sFSin(time*TranslateFreq.z*sPI2F)*TranslateAmp.z*ramp; rx = sFSin(time*RotateFreq.x*sPI2F)*RotateAmp.x*ramp; ry = sFSin(time*RotateFreq.y*sPI2F)*RotateAmp.y*ramp; rz = sFSin(time*RotateFreq.z*sPI2F)*RotateAmp.z*ramp; } tx = tx*TranslateAmp.x*ramp; ty = ty*TranslateAmp.y*ramp; tz = tz*TranslateAmp.y*ramp; rx = rx*RotateAmp.x*ramp; ry = ry*RotateAmp.y*ramp; rz = rz*RotateAmp.z*ramp; mat1.InitEuler(rx,ry,rz); mat1.l.Init(tx,ty,tz,1); if(Mode&16) { mat.l.x -= Center.x; mat.l.y -= Center.y; mat.l.z -= Center.z; mat0 = mat; mat.MulA(mat0,mat1); mat.l.x += Center.x; mat.l.y += Center.y; mat.l.z += Center.z; } else { mat0 = mat; mat.MulA(mat1,mat0); } } if(fakemode) fakemode = 0; else event = event->NextOp; } } /****************************************************************************/ GenSplineMeta::GenSplineMeta() { sVERIFY(sCOUNTOF(Times)==sCOUNTOF(Splines)); for(sInt i=0;i(Times[i],1,0); if(Splines[i]==0) Times[i] = 100; else Count++; } for(sInt i=0;iTimes[j]) { sSwap(Times[i],Times[j]); sSwap(Splines[i],Splines[j]); } } } } void GenSplineMeta::Eval(sF32 time,sF32 phase,sMatrix &mat,sF32 &zoom) { InterpolElem Meta[sCOUNTOF(Splines)]; InterpolElem result; sF32 *p0,*p1,*p2,*p3; sF32 t; sMatrix mat1; sF32 zoom1; for(sInt i=0;iEval(time,phase,mat1,zoom1); Meta[i].Time = Times[i]; Meta[i].px = mat1.l.x; Meta[i].py = mat1.l.y; Meta[i].pz = mat1.l.z; Meta[i].quat.FromMatrix(mat1); Meta[i].zoom = zoom1; } sFindSplineTime(phase,Meta,Count,p0,p1,p2,p3,t); sHermite(&result.px,p0,p1,p2,p3,8,t,0,0,0,0); result.quat.ToMatrix(mat); mat.l.Init(result.px,result.py,result.pz); zoom = result.zoom; } /****************************************************************************/ /*** ***/ /*** operators ***/ /*** ***/ /****************************************************************************/ KObject * __stdcall Init_Misc_Spline(KOp *op) { GenSplineSpline *gs = new GenSplineSpline; gs->Init((BlobSpline *)op->GetBlobData()); if(gs->Spline->Version<3) { gs->Spline->Uniform = 0; gs->Spline->Tension = 0; gs->Spline->Continuity = 0; } gs->Spline->Version = 3; return gs; } /****************************************************************************/ KObject * __stdcall Init_Misc_Shaker(KOp *op,GenSpline *parent,GenSpline *ampspline,sInt mode,sF323 ta,sF323 ra,sF323 tf,sF323 rf,sF32 time,sF323 center) { GenSplineShaker *gs = new GenSplineShaker; gs->Mode = mode; gs->TranslateAmp.x = ta.x; gs->TranslateAmp.y = ta.y; gs->TranslateAmp.z = ta.z; gs->RotateAmp.x = ra.x; gs->RotateAmp.y = ra.y; gs->RotateAmp.z = ra.z; gs->TranslateFreq.x = tf.x; gs->TranslateFreq.y = tf.y; gs->TranslateFreq.z = tf.z; gs->RotateFreq.x = rf.x; gs->RotateFreq.y = rf.y; gs->RotateFreq.z = rf.z; gs->Center.x = center.x; gs->Center.y = center.y; gs->Center.z = center.z; gs->Parent = parent; gs->AmpSpline = ampspline; gs->OpLink = op; sRelease(ampspline); return gs; } /****************************************************************************/ KObject * __stdcall Init_Misc_PipeSpline(KOp *op) { sQuaternion quat; sVector v,d,p,ax; sF32 oldrad; sMatrix mat,mat0,mat1; BlobPipe *pipe = (BlobPipe *) op->GetBlobData(); if(!pipe) { sInt size; pipe = MakeDummyBlobPipe(&size); op->SetBlob((sU8 *)pipe,size); } sVERIFY(pipe) GenSplineSpline *gs = new GenSplineSpline; gs->Spline = MakeBlobSpline(0,pipe->Count*2); gs->Spline->Mode = 4; gs->Pipe = pipe->Copy(); mat.InitEuler(0,0,gs->Pipe->Rotation*sPI2F); oldrad = 0; v.Init(pipe->StartX,pipe->StartY,pipe->StartZ); for(sInt i=0;iCount;i++) { // get point p = v; // p = old point v.x = pipe->Keys[i].PosX; // v = new point v.y = pipe->Keys[i].PosY; v.z = pipe->Keys[i].PosZ; d.x = v.x - p.x; // d = direction vector d.y = v.y - p.y; d.z = v.z - p.z; d.UnitSafe3(); // calculate old point position sF32 angle; sF32 ac = mat.k.Dot3(d); // unfortunatly, this is sometimes slightly inaccurate, exceeding the -1..1 range of acos(x) if(ac<=-1) ac=-1;//angle = -sPIF; else if(ac>=1) ac=1;//angle= sPIF; /* else */ angle = sFACos(ac); ax.Cross3(mat.k,d); mat1.InitRot(ax,angle); mat0 = mat; mat.Mul3(mat0,mat1); quat.FromMatrix(mat); quat.ToMatrix(mat1); // old point p.AddScale3(d,oldrad); gs->Spline->Keys[i*2+0].Time = i+0.0f; gs->Spline->Keys[i*2+0].px = p.x; gs->Spline->Keys[i*2+0].py = p.y; gs->Spline->Keys[i*2+0].pz = p.z; gs->Spline->Keys[i*2+0].rx = quat.x; gs->Spline->Keys[i*2+0].ry = quat.y; gs->Spline->Keys[i*2+0].rz = quat.z; gs->Spline->Keys[i*2+0].Zoom = quat.w; // new point oldrad = pipe->Keys[i].Radius; p = v; p.AddScale3(d,-oldrad); gs->Spline->Keys[i*2+1].Time = i+0.5f; gs->Spline->Keys[i*2+1].px = p.x; gs->Spline->Keys[i*2+1].py = p.y; gs->Spline->Keys[i*2+1].pz = p.z; gs->Spline->Keys[i*2+1].rx = quat.x; gs->Spline->Keys[i*2+1].ry = quat.y; gs->Spline->Keys[i*2+1].rz = quat.z; gs->Spline->Keys[i*2+1].Zoom = quat.w; } gs->Spline->Tension = pipe->Tension; gs->Spline->Normalize(); return gs; } /****************************************************************************/ KObject * __stdcall Init_Misc_MetaSpline(Init_Misc_MetaSplinePara para) { GenSplineMeta *gs = new GenSplineMeta; for(sInt i=0;i<8;i++) { gs->Splines[i] = para.sp[i]; gs->Times[i] = para.time[i]; } gs->Sort(); return gs; } /****************************************************************************/ KObject * __stdcall Init_Misc_SplineScale(KOp *op,KObject *splineinput,sF32 px,sF32 py,sF32 pz,sInt bits) { if(splineinput->ClassId!=KC_SPLINE) return 0; GenSpline *gs = (GenSpline *) splineinput; BlobSpline *obs = gs->GetBlobSpline(); if(!obs) return 0; BlobSpline *bs = obs->Copy(); for(sInt i=0;iCount;i++) { bs->Keys[i].px *= px; bs->Keys[i].py *= py; bs->Keys[i].pz *= pz; if(bits & 1) bs->Keys[i].rx = 0; if(bits & 2) bs->Keys[i].ry = 0; if(bits & 4) bs->Keys[i].rz = 0; } GenSplineSpline *gss = new GenSplineSpline; gss->Init(bs); // free splines gs->Release(); delete bs; return gss; }