// This file is distributed under a BSD license. See LICENSE.txt for details. #include "geneffect.hpp" #include "genmaterial.hpp" #include "genbitmap.hpp" #include "genmesh.hpp" #include "genminmesh.hpp" #include "kkriegergame.hpp" #include "genoverlay.hpp" #include "engine.hpp" #include "material11.hpp" #include "_util.hpp" #include "_startdx.hpp" #include "geneffectex.hpp" #include "geneffectcubes.hpp" #include extern sF32 GlobalFps; /****************************************************************************/ /****************************************************************************/ /*** ***/ /*** Effekte ohne besonderen Grund... ***/ /*** ***/ /****************************************************************************/ /****************************************************************************/ void SetVert2(sF32 *fp,sF32 x,sF32 y,sF32 z,sF32 u,sF32 v,sU32 col=~0) { fp[0] = x; fp[1] = y; fp[2] = z; fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = col; fp[6] = u; fp[7] = v; } /****************************************************************************/ /*** ***/ /*** Starter-Effekt. ***/ /*** ***/ /*** Für copy & paste ***/ /*** ***/ /****************************************************************************/ void Chaos0(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt count) { GenMaterial *mtrl; sInt geo; sU16 *ip; sVertexDouble *vp; sInt i; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; geo = sSystem->GeoAdd(sFVF_DOUBLE,sGEO_TRI); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,4*count,6*count,(sF32 **)&vp,(void **)&ip); for(i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Einige sich anziehende Gravitationsquellen. ***/ /*** ***/ /*** Die Simulation wird jeden Frame mit neuen Startwerten durchgeführt.***/ /*** Aus den Bewegungsbahnen werden Bänder dargestellt. ***/ /*** ***/ /*** Divisionen durch Null werden noch nicht abgefangen. ***/ /*** ***/ /****************************************************************************/ void Chaos1(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt maxcount) { const sInt pcount = 8; const sInt steps = 250; GenMaterial *mtrl; sInt geo; sF32 *fp; sU16 *ip; sInt i,j,k; sF32 s; sMatrix Pos[pcount],mat; sVector Speed[pcount]; sVector d; sF32 dist,t; sU32 col; sInt invert; static sMatrix record[pcount][steps]; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_TRI); s = 0.25f; for(invert = -1;invert<=1;invert+=2) { sSetRndSeed(seed); t = a.z+24; for(i=0;iPasses[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,steps*2,(steps-1)*6,&fp,(void **)&ip); for(i=0;i(2-mat.j.Abs3(),2,1)*0.25f; mat.k.Unit3(); mat.i.Cross3(mat.j,mat.k); mat.i.Unit3(); mat.j.Cross3(mat.k,mat.i); col = 255-(i*255/steps); col = 0xff000000|(col<<16)|(col<<8)|(col<<0); SetVert2(fp,mat.l.x+mat.i.x*s,mat.l.y+mat.i.y*s,mat.l.z+mat.i.z*s,0,i*1.0f*invert,col); fp += 8; SetVert2(fp,mat.l.x-mat.i.x*s,mat.l.y-mat.i.y*s,mat.l.z-mat.i.z*s,1,i*1.0f*invert,col); fp += 8; } for(i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); } } sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** UV-Animator ***/ /*** ***/ /*** Ein Quad wird mehrfach gezeichnet. ***/ /*** Dabei werden zwei paare UV-Koordinaten rotiert, verschoben und ***/ /*** skaliert. ***/ /*** Man sollte damit zwei Texturen multiplizieren und additiv blenden. ***/ /*** ***/ /****************************************************************************/ void Chaos2(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt maxcount) { GenMaterial *mtrl; sInt geo; sU16 *ip; sInt i; sInt steps; sVertexDouble *vp; sF32 s0,c0,s1,c1; sF32 r0,r1,z; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; steps = maxcount; geo = sSystem->GeoAdd(sFVF_DOUBLE,sGEO_TRI); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,steps*4,(steps)*6,(sF32 **)&vp,(void **)&ip); r0 = a.x; r1 = a.y; z = a.z; for(i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Plane-Partition ***/ /*** ***/ /*** Unterteile eine ebene immer wieder. ***/ /*** ***/ /****************************************************************************/ struct Chaos3Cell { sVector Vertex[4]; sInt Level; sInt Leaf; sU32 Color; sF32 Wx,Wy; }; void Chaos3(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt count) { GenMaterial *mtrl; sInt geo; sU16 *ip; sVertexDouble *vp; sInt i,j,cc,cd; const sInt maxcell = 1024; sInt max; Chaos3Cell *cp,*ca,*cb; static Chaos3Cell cells[maxcell]; sVector v1,v2,v; sVector vd[4]; sF32 f,fa,fb; sU32 col; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; sSetRndSeed(seed); // generate cells cc = 0; cd = 0; cp = &cells[cc++]; cp->Level = 0; cp->Leaf = 0; cp->Color = sGetRnd()|0xff808080; cp->Wx = 1.0f; cp->Wy = 1.0f; cp->Vertex[0].Init(-16,0,-16,1); cp->Vertex[1].Init( 16,0,-16,1); cp->Vertex[2].Init( 16,0, 16,1); cp->Vertex[3].Init(-16,0, 16,1); for(;ccLevel>=2 && sFGetRnd()Leaf = 0; ca->Level++; ca->Leaf = 1; ca->Color = sGetRnd()|0xff808080; cb->Level++; cb->Leaf = 1; cb->Color = sGetRnd()|0xff808080; v1.Sub3(cp->Vertex[0],cp->Vertex[3]); v1.Add3(cp->Vertex[1]); v1.Sub3(cp->Vertex[2]); v2.Sub3(cp->Vertex[0],cp->Vertex[1]); v2.Add3(cp->Vertex[3]); v2.Sub3(cp->Vertex[2]); fa = v1.Abs3(); fb = v2.Abs3(); if(cp->Wx/cp->Wy>1.0f+(sFGetRnd(2)-1.0f)*a.z) // by x or z axxis? { fa = sFGetRnd(b.x)+(1.0f-b.x)/2; fb = (sFGetRnd(1)-0.5f)*(b.y*2/(cp->Level+2)); v1.Lin3(cp->Vertex[0],cp->Vertex[1],fa+fb); v2.Lin3(cp->Vertex[3],cp->Vertex[2],fa-fb); ca->Vertex[0] = v1; ca->Vertex[3] = v2; cb->Wx = cp->Wx*fa; cb->Vertex[1] = v1; cb->Vertex[2] = v2; ca->Wx = cp->Wx*(1-fa); } else { fa = sFGetRnd(b.x)+(1.0f-b.x)/2; fb = (sFGetRnd(1)-0.5f)*(b.y*2/(cp->Level+2)); v1.Lin3(cp->Vertex[0],cp->Vertex[3],fa+fb); v2.Lin3(cp->Vertex[1],cp->Vertex[2],fa-fb); ca->Vertex[0] = v1; ca->Vertex[1] = v2; cb->Wy = cp->Wx*fa; cb->Vertex[3] = v1; cb->Vertex[2] = v2; ca->Wy = cp->Wx*(1-fa); } } // draw cells max = cc; geo = sSystem->GeoAdd(sFVF_DOUBLE,sGEO_TRI); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,4*max,6*max,(sF32 **)&vp,(void **)&ip); for(i=0;iColor; vp[0+i*4].Init(0,0,0,col,0,1,0,0); vp[1+i*4].Init(0,0,0,col,1,1,0,0); vp[2+i*4].Init(0,0,0,col,1,0,0,0); vp[3+i*4].Init(0,0,0,col,0,0,0,0); // f = cp->Level*a.x; f = a.x; for(j=0;j<4;j++) { v.Sub3(cp->Vertex[j],cp->Vertex[(j+1)&3]); v.Unit3(); vd[j].Init(v.z*f,0,-v.x*f,0); } for(j=0;j<4;j++) { vp[j+i*4].x = cp->Vertex[j].x+vd[(j+3)&3].x+vd[(j+0)&3].x; vp[j+i*4].y = cp->Level*0.1; vp[j+i*4].z = cp->Vertex[j].z+vd[(j+3)&3].z+vd[(j+0)&3].z; } } for(i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Der gute alte Timeslice-Effect (Rubber Cube) ***/ /*** ***/ /*** ... nur dass ich dies mal alle phasen jeden frame neu zeichne, ***/ /*** in den selben framebuffer (additiv), und mit einer projezierten ***/ /*** textur das ding in scheiben schneide - World Space ***/ /*** ***/ /*** Ich habe also volle Kontrolle über alle Bewegungen, kann das ***/ /*** Objekt morphen und alles einfrieren und im 3d-Raum herumfliegen... ***/ /*** ***/ /****************************************************************************/ void Chaos4(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt count) { GenMaterial *mtrl; sInt geo; sU16 *ip; volatile sVertexDouble *vp; sInt i; sInt tsx,tsy,ttt,tsl; sInt x,y,t,s; sF32 ri,ro,fx,fy,scale; sVector v; sMatrix mat; static sVector cache[4096]; sVector *p; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; tsl = count; ttt = 4; tsx = 12; tsy = 24; sVERIFY(ttt*(tsx+1)*(tsy+1)<4096); p = cache; for(t=0;tGeoAdd(sFVF_DOUBLE,sGEO_TRI); for(s=0;sPasses[0].Mtrl; mtrl11->SRT1[1] = 0.5f/(scale/(tsl-1.0f)); mtrl11->SRT1[7] = mtrl11->SRT1[1]*(s/(tsl-1.0f)*scale-(scale/2))+0.5f; mtrl11->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,(tsx+1)*(tsy+1)*ttt,6*tsx*tsy*ttt,(sF32 **)&vp,(void **)&ip); p = cache; for(t=0;tx = v.x; vp->y = v.y; vp->z = v.z; vp->c0 = ~0; vp->u0 = x*1.0f/tsx; vp->v0 = y*1.0f/tsy; vp->u1 = 0; vp->v1 = 0; vp++; } } } i = 0; for(t=0;tGeoEnd(geo); sSystem->GeoDraw(geo); } sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Allgemeiner code für die Effekte ***/ /*** ***/ /****************************************************************************/ KObject * __stdcall Init_Effect_Chaos1(class GenMaterial *mtrl,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt maxcount) { if(mtrl) mtrl->Release(); return new GenEffect; } void __stdcall Exec_Effect_Chaos1(KOp *op,KEnvironment *kenv,sF323 a,sF323 b,sF323 c,sInt flags,sInt effect,sInt seed,sInt maxcount) { switch(effect) { case 0: Chaos0(op,kenv,a,b,c,flags,effect,seed,maxcount); break; case 1: Chaos1(op,kenv,a,b,c,flags,effect,seed,maxcount); break; case 2: Chaos2(op,kenv,a,b,c,flags,effect,seed,maxcount); break; case 3: Chaos3(op,kenv,a,b,c,flags,effect,seed,maxcount); break; case 4: Chaos4(op,kenv,a,b,c,flags,effect,seed,maxcount); break; } } /****************************************************************************/ /*** ***/ /*** Tourque Effect ***/ /*** ***/ /****************************************************************************/ #if !sINTRO struct sVector3 { sF32 x,y,z; void Init(const sVector &v) { x = v.x; y = v.y; z = v.z; } }; sMAKEZONE(TourquePart,"TourquePart",0x400000); sMAKEZONE(TourqueCons,"TourqueCons",0x600000); sMAKEZONE(TourqueDraw,"TourqueDraw",0x800000); class TourqueSimulator { enum { FieldDim = 32, MaskField = FieldDim - 1, yStep = FieldDim, zStep = FieldDim*FieldDim, }; public: struct Constraint { sInt p0,p1; // particle indices sF32 restLenSq; // squared rest length }; sArray Constraints; private: sVector3 *ForceField; sInt StepTimer; // ---- particles static sF32 __forceinline SmoothStep(sF32 x) { return x*x*(3.0f - 2.0f*x); } static void __forceinline xLerp(sVector3 &out,const sVector3 *base,sInt d,sF32 t) { out.x = base->x + t * (base[d].x - base->x); out.y = base->y + t * (base[d].y - base->y); out.z = base->z + t * (base[d].z - base->z); } static void __forceinline vLerp(sVector3 &out,const sVector3 &a,const sVector3 &b,sF32 t) { out.x = a.x + t * (b.x - a.x); out.y = a.y + t * (b.y - a.y); out.z = a.z + t * (b.z - a.z); } void MoveParticles(sF32 speed,sF32 damp) { sZONE(TourquePart); sVector3 *oldPos,*newPos; oldPos = ParticlePos[0]; newPos = ParticlePos[1]; sF32 scale = 4.0f, offset = scale * FieldDim / 2.0f; sF32 magic = 12582912.0f; // 1.5*2^23 // process each particle for(sInt i=0;ix * scale + offset; sF32 y = oldPos->y * scale + offset; sF32 z = oldPos->z * scale + offset; // rounded version, fractional part sF32 rx = (magic + x) - magic, fx = SmoothStep(x - rx); sF32 ry = (magic + y) - magic, fy = SmoothStep(y - ry); sF32 rz = (magic + z) - magic, fz = SmoothStep(z - rz); // integer grid position sInt ix = sInt(rx) & MaskField, nx = (ix + 1) & MaskField; sInt iy = sInt(ry) & MaskField, ny = (iy + 1) & MaskField; sInt iz = sInt(rz) & MaskField, nz = (iz + 1) & MaskField; const sVector3 *field = ForceField + ix + iy * yStep + iz * zStep; sInt deltaX = nx - ix; sInt deltaY = (ny - iy) * yStep, deltaZ = (nz - iz) * zStep; // calc force sVector3 t0,t1,t2,force; xLerp(t0,field + 0 + 0,deltaX,fx); xLerp(t1,field + 0 + deltaY,deltaX,fx); vLerp(t0,t0,t1,fy); xLerp(t1,field + deltaZ + 0,deltaX,fx); xLerp(t2,field + deltaZ + deltaY,deltaX,fx); vLerp(t1,t1,t2,fy); vLerp(force,t0,t1,fz); // verlet integration newPos->x = oldPos->x + (oldPos->x - newPos->x)*damp + force.x*speed; newPos->y = oldPos->y + (oldPos->y - newPos->y)*damp + force.y*speed; newPos->z = oldPos->z + (oldPos->z - newPos->z)*damp + force.z*speed; } } void Constrain() { sZONE(TourqueCons); Constraint *cons = Constraints.Array; sVector3 *parts = ParticlePos[1]; // enforce stick constraints for(sInt i=0;ip0 >= ParticleCount || cons->p1 >= ParticleCount) continue; // get particles sVector3 *p0 = parts + cons->p0; sVector3 *p1 = parts + cons->p1; // difference, squared distance sF32 dx = p1->x - p0->x, dy = p1->y - p0->y, dz = p1->z - p0->z; sF32 dsq = dx*dx + dy*dy + dz*dz; // approximately enforce constraint sF32 sc = 0.5f - cons->restLenSq / (dsq + cons->restLenSq); p0->x += dx * sc; p1->x -= dx * sc; p0->y += dy * sc; p1->y -= dy * sc; p0->z += dz * sc; p1->z -= dz * sc; } } void TimeStep(sF32 speed,sF32 damp) { // swap old and new particles sSwap(ParticlePos[0],ParticlePos[1]); MoveParticles(speed,damp); Constrain(); } // ---- force field __forceinline sInt Index(sInt x,sInt y,sInt z) { return (x & MaskField) + (y & MaskField) * yStep + (z & MaskField) * zStep; } __forceinline sVector3 &Field(sInt x,sInt y,sInt z) { return ForceField[Index(x,y,z)]; } void PreprocessField(sF32 postScale = 0.001f) { // alloc temp space sF32 *div = new sF32[FieldDim*FieldDim*FieldDim]; sF32 *high = new sF32[FieldDim*FieldDim*FieldDim]; // calc divergence field sF32 scale = 1.0f / FieldDim; sF32 invScale = 1.0f / scale; for(sInt z=0;z= 1000) { TimeStep(speed,damp); StepTimer -= 1000; } return StepTimer / 1000.0f; } void ClearConstraints() { Constraints.Count = 0; } void AddConstraint(sInt p0,sInt p1,sF32 len) { Constraint *cons = Constraints.Add(); cons->p0 = p0; cons->p1 = p1; cons->restLenSq = len*len; } void ResetField() { RandomField(); PreprocessField(); } void MeshField(GenMesh *mesh,sF32 strength) { // clear force field RandomField(0.001f * strength / 40.0f); // twirlify PreprocessField(0.001f * strength / 80.0f); // calc density field sVector *vb = mesh->VertBuf; sInt step = mesh->VertSize(); sInt count = mesh->Vert.Count; sF32 *dens = new sF32[FieldDim*FieldDim*FieldDim]; for(sInt z=0;zRelease(); if(mesh) // count tris { sInt nTris = 0; mesh->CalcNormals(); for(sInt i=0;iFace.Count;i++) { if(!mesh->Face[i].Material) continue; sInt e = mesh->Face[i].Edge, ee = e, count = 0; do { e = mesh->NextFaceEdge(e); count++; } while(e != ee); nTris += count-2; } maxcount = nTris*3; } maxcount = sMin(maxcount,TourqueSimulator::MaxParticles); if(TourqueSim[Slot]==0 || TourqueSim[Slot]->TourqueCount!=maxcount || TourqueSim[Slot]->OldSeed != Seed) { sSetRndSeed(Seed); if(TourqueSim[Slot]) delete TourqueSim[Slot]; sREGZONE(TourquePart); sREGZONE(TourqueCons); sREGZONE(TourqueDraw); TourqueSim[Slot] = new TourqueSimulator(maxcount); TourqueSim[Slot]->OldSeed = Seed; } if((Flags & 3) != TourqueSim[Slot]->TourqueMode) { TourqueSim[Slot]->ClearConstraints(); if(mesh) { sInt nPart = 0; TourqueSim[Slot]->MeshField(mesh,0.04f * 16.0f); // setup particles to match vertices in mesh. also add constraints for(sInt i=0;iFace.Count;i++) { if(!mesh->Face[i].Material) continue; // collect verts sInt verts[64]; sInt e = mesh->Face[i].Edge, ee = e, count = 0; do { verts[count++] = mesh->GetVertId(e); e = mesh->NextFaceEdge(e); } while(e != ee); // build tris for(sInt j=2;jVertPos(verts[0]); sVector v1 = mesh->VertPos(verts[j-1]); sVector v2 = mesh->VertPos(verts[j]); //sF32 speed = sFExp(sFGetRnd() * 11.0f - 20.0f); sF32 speed = 0.0f; TourqueSim[Slot]->ParticlePos[0][nPart+0].Init(v0); TourqueSim[Slot]->ParticlePos[0][nPart+1].Init(v1); TourqueSim[Slot]->ParticlePos[0][nPart+2].Init(v2); v0.AddScale3(mesh->VertNorm(verts[0]),speed); v1.AddScale3(mesh->VertNorm(verts[j-1]),speed); v2.AddScale3(mesh->VertNorm(verts[j]),speed); TourqueSim[Slot]->ParticlePos[1][nPart+0].Init(v0); TourqueSim[Slot]->ParticlePos[1][nPart+1].Init(v1); TourqueSim[Slot]->ParticlePos[1][nPart+2].Init(v2); TourqueSim[Slot]->AddConstraint(nPart+0,nPart+1,v0.Distance(v1)); TourqueSim[Slot]->AddConstraint(nPart+1,nPart+2,v1.Distance(v2)); TourqueSim[Slot]->AddConstraint(nPart+2,nPart+0,v2.Distance(v0)); nPart += 3; } } TourqueSim[Slot]->TourquePCount = nPart; TourqueSim[Slot]->TourqueIndex = nPart; } else { switch(Flags&3) { case 1: for(sInt i=0;iAddConstraint(i,(i+1)%maxcount,0.05f); break; case 2: for(sInt i=0;iAddConstraint(i+j,i+((j+1)&15),0.05f); break; } } TourqueSim[Slot]->TourqueMode = Flags & 3; } return new GenEffect; } void __stdcall Exec_Effect_Tourque(KOp *op,KEnvironment *kenv, sInt Seed,sInt maxcount,sInt Rate,sInt Flags, sF32 SizeF,sF32 SizeS,sF32 Speed,sF32 Damp,sF323 Pos,sF323 Range,sInt Slot) { GenMaterial *mtrl; sInt geo; volatile sVertexTSpace3 *vp; sVector side; sVector av,ar; const sF32 minspeed=0.001f; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; sBool triMode = op->GetLink(1) != 0; if(triMode) { maxcount = TourqueSim[Slot]->TourquePCount; Flags |= 32; } static sBool init = sFALSE; static sInt emitTick = 0; av.Init(Pos.x,Pos.y,Pos.z,1); ar.Init(Range.x,Range.y,Range.z,1); if(TourqueSim[Slot]->LastTime-100>kenv->CurrentTime) { TourqueSim[Slot]->LastTime = kenv->CurrentTime; TourqueSim[Slot]->TourqueIndex = 0; } sInt slices = 0; const sInt timeSliceLen=10; if(kenv->CurrentTime - TourqueSim[Slot]->LastTime >= timeSliceLen) { slices = (kenv->CurrentTime - TourqueSim[Slot]->LastTime) / timeSliceLen; TourqueSim[Slot]->LastTime += slices * timeSliceLen; } slices = sMin(slices,100); for(sInt i=0;iTourqueIndex < maxcount) { for(sInt i=0;iParticlePos[0][TourqueSim[Slot]->TourqueIndex%maxcount]; sVector v; v.InitRnd(); v.Mul3(ar); v.Add3(av); tp->x = v.x; tp->y = v.y; tp->z = v.z; TourqueSim[Slot]->ParticlePos[1][TourqueSim[Slot]->TourqueIndex%maxcount] = *tp; TourqueSim[Slot]->TourqueIndex++; } } /*for(sInt i=0;iParticlePos[0][TourqueIndex%maxcount]; tp->x = v.x + ((j == 1) ? 0.10f : 0.0f); tp->y = v.y; tp->z = v.z + ((j == 2) ? 0.10f : 0.0f); TourqueSim->ParticlePos[1][TourqueIndex%maxcount] = *tp; TourqueIndex++; } }*/ while(TourqueSim[Slot]->TourqueIndex>2*maxcount) TourqueSim[Slot]->TourqueIndex-=maxcount; } maxcount = sMin(maxcount,TourqueSimulator::MaxParticles); maxcount = sMin(maxcount,TourqueSim[Slot]->TourqueIndex); if(!maxcount) return; TourqueSim[Slot]->ParticleCount = maxcount; sF32 tFactor = TourqueSim[Slot]->Advance(kenv->TimeDelta,Speed,Damp); sBool cubes = Flags & 0x40; sInt used=0; kenv->CurrentCam.ModelSpace = kenv->ExecStack.Top(); if(!cubes) { geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_TRI); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,(triMode?1:3)*maxcount,0,(sF32 **)&vp,0); } sVector3 *pOld = TourqueSim[Slot]->ParticlePos[0]; sVector3 *pNew = TourqueSim[Slot]->ParticlePos[1]; sZONE(TourqueDraw); sInt ctr = 2; sU32 normCode; sMatrix mat; mat = kenv->ExecStack.Top(); for(sInt i=0;ix - pOld->x; forw.y = pNew->y - pOld->y; forw.z = pNew->z - pOld->z; // position pos.x = pOld->x + tFactor * forw.x; pos.y = pOld->y + tFactor * forw.y; pos.z = pOld->z + tFactor * forw.z; if(triMode) { if(++ctr == 3) { sVector d1,d2,n; d1.x = pNew[1].x - pNew->x; d1.y = pNew[1].y - pNew->y; d1.z = pNew[1].z - pNew->z; d2.x = pNew[2].x - pNew->x; d2.y = pNew[2].y - pNew->y; d2.z = pNew[2].z - pNew->z; n.Cross3(d1,d2); n.Unit3(); normCode = (sFtol(n.x*127.5f+127.5f)<<16) + (sFtol(n.y*127.5f+127.5f)<<8) + sFtol(n.z*127.5f+127.5f); ctr = 0; } vp->x = pos.x; vp->y = pos.y; vp->z = pos.z; vp->n = normCode; vp->s = 0x80ff80; vp->c = ~0; vp->u = 0.0f; vp->v = 0.0f; vp++; } else { // direction sF32 speed = forw.UnitAbs3(); if(speedSide); side.Cross3(upos,forw); side.Unit3(); side.Scale3(0.125f); side.Add3(tp->Side); side.Unit3(); tp->Side = side;*/ side.Init(1,0,0,0); // draw pos.Rotate34(mat); if(cubes) { CubeBuffer[used++].Init(forw.x*SizeF,forw.y*SizeF,forw.z*SizeF,SizeS); CubeBuffer[used++].Init(pos.x,pos.y,pos.z,SizeS); } else { forw.Scale3(SizeF); side.Scale3(SizeS); upos.Add3(pos,forw); ((sVertexTSpace3 *) vp)[0].Init(upos.x,upos.y,upos.z,~0,0,0); upos.Sub3(pos,forw); upos.Add3(side); ((sVertexTSpace3 *) vp)[1].Init(upos.x,upos.y,upos.z,~0,0,1); upos.Sub3(pos,forw); upos.Sub3(side); ((sVertexTSpace3 *) vp)[2].Init(upos.x,upos.y,upos.z,~0,1,0); vp+=3; } } } if(!cubes) { sSystem->GeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); } CubeCount = used/2; } #endif /****************************************************************************/ /****************************************************************************/ struct StreamPart { sVector Rand[3]; // randomize vertices of triangle sVector Pos; // x/z deviation on stream sF32 Fade; // fading }; static StreamPart StreamParts[0x10000]; static sInt StreamPartInit; KObject * __stdcall Init_Effect_Stream(class GenMaterial *mtrl,StreamPara para) { if(!StreamPartInit) { StreamPartInit = 1; for(sInt i=0;i<0x10000;i++) { StreamParts[i].Rand[0].InitRnd(); StreamParts[i].Rand[0].w = 0; StreamParts[i].Rand[1].InitRnd(); StreamParts[i].Rand[1].w = 0; StreamParts[i].Rand[2].InitRnd(); StreamParts[i].Rand[2].w = 0; StreamParts[i].Pos.InitRnd(); StreamParts[i].Pos.w = 1; StreamParts[i].Fade = sFGetRnd(); } } return new GenEffect; } /****************************************************************************/ void __stdcall Exec_Effect_Stream(KOp *op,KEnvironment *kenv,StreamPara para) { GenMaterial *mtrl; sInt geo; sVertexTSpace3 *vp; StreamPart *sp; sMatrix mat[4]; mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; sInt maxcount = para.Count; sInt maxvert = maxcount*3; kenv->CurrentCam.ModelSpace.Init(); geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_TRI); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,maxvert,0,(sF32 **)&vp,0); sSetRndSeed(para.Seed); sp = StreamParts; for(sInt i=0;i<4;i++) { mat[i].Init(); mat[i].l = para.Pos[i]; mat[i].l.w = 1; mat[i].i.x = para.Pos[i].w; mat[i].j.y = para.Pos[i].w; mat[i].k.z = para.Pos[i].w; } for(sInt i=0;iPos; pos.w = 1; s = sFMod((sp->Fade+para.StuffX),1); f[0] = (1-s)*(1-s)*(1-s); f[1] = 3* s *(1-s)*(1-s); f[2] = 3* s * s *(1-s); f[3] = s * s * s; for(sInt j=0;j<3;j++) { upos = pos; upos.AddScale3(sp->Rand[j],para.SizeF); b[0].Rotate34(mat[0],upos); b[1].Rotate34(mat[1],upos); b[2].Rotate34(mat[2],upos); b[3].Rotate34(mat[3],upos); upos. Scale3(b[0],f[0]); upos.AddScale3(b[1],f[1]); upos.AddScale3(b[2],f[2]); upos.AddScale3(b[3],f[3]); vp[j].Init(upos.x,upos.y,upos.z,~0,0,0); } vp+=3; sp++; } sSystem->GeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Breakpoint 06 Invitation: Scene Spirit Effect ***/ /*** ***/ /****************************************************************************/ #if !sINTRO KObject * __stdcall Init_Effect_BP06Spirit(class GenMaterial *mtrl,class GenMaterial *mtrl2,sF323 pos,sF32 radius,sF32 corerad,sF32 perlfreq,sF32 perlamp,sF32 perlanim,sU32 coli,sU32 colo,sU32 colc,sInt partcount,sF32 partrad,sF32 partspeed,sF32 partthick,sF32 partanim,sInt segments) { sRelease(mtrl2); return MakeEffect(mtrl); } void __stdcall Exec_Effect_BP06Spirit(KOp *op,KEnvironment *kenv,sF323 pos,sF32 radius,sF32 corerad,sF32 perlfreq,sF32 perlamp,sF32 perlanim,sU32 coli,sU32 colo,sU32 colc,sInt partcount,sF32 partrad,sF32 partspeed,sF32 partthick,sF32 partanim,sInt segments) { GenMaterial *mtrl; GenMaterial *mtrl2; sInt geo; sF32 *fp; sU16 *ip; sMatrix mat; sVector p,d; static sVector Ring[256]; // check material mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; mtrl2 = (GenMaterial *) op->GetLinkCache(1); if(!(mtrl2 && mtrl2->Passes.Count>0)) mtrl2 = mtrl; kenv->CurrentCam.ModelSpace.Init(); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_TRI); // perpare shape sInt max = sRange(segments,255,3); sSystem->GetTransform(sGT_MODELVIEW,mat); for(sInt i=0;iGeoBegin(geo,max+1,max*3,&fp,(void **)&ip); for(sInt i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); // paint particles sRandom rnd; sSystem->GeoBegin(geo,partcount*4,partcount*6,&fp,(void **)&ip); for(sInt i=0;i> 12; time = time&0xfff; sF32 side = rnd.Float(2)*partthick; sInt sidesign = rnd.Int(2)?-1:1; sInt pos0 = rnd.Int(max*1024); sF32 posf = (pos0&(1024-1))/1024.0f; pos0 = (pos0/1024+timernd*7)%max; sInt pos1 = (pos0+1)%max; p.x = Ring[pos0].x + (Ring[pos1].x-Ring[pos0].x)*posf; p.y = Ring[pos0].y + (Ring[pos1].y-Ring[pos0].y)*posf; p.z = Ring[pos0].z + (Ring[pos1].z-Ring[pos0].z)*posf; d.x = p.x-pos.x; d.y = p.y-pos.y; d.z = p.z-pos.z; d.Unit3(); p.AddScale3(d,sidesign*(side+time*partspeed/4096)); sF32 s = (1-time/4096.0f)*partrad; fp[0] = p.x + s*(- mat.i.x*s + mat.i.y*s); fp[1] = p.y + s*(- mat.j.x*s + mat.j.y*s); fp[2] = p.z + s*(- mat.k.x*s + mat.k.y*s); fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colo; fp[6] = 0; fp[7] = 0; fp += 8; fp[0] = p.x + s*(+ mat.i.x*s + mat.i.y*s); fp[1] = p.y + s*(+ mat.j.x*s + mat.j.y*s); fp[2] = p.z + s*(+ mat.k.x*s + mat.k.y*s); fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colo; fp[6] = 1; fp[7] = 0; fp += 8; fp[0] = p.x + s*(+ mat.i.x*s - mat.i.y*s); fp[1] = p.y + s*(+ mat.j.x*s - mat.j.y*s); fp[2] = p.z + s*(+ mat.k.x*s - mat.k.y*s); fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colo; fp[6] = 1; fp[7] = 1; fp += 8; fp[0] = p.x + s*(- mat.i.x*s - mat.i.y*s); fp[1] = p.y + s*(- mat.j.x*s - mat.j.y*s); fp[2] = p.z + s*(- mat.k.x*s - mat.k.y*s); fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colo; fp[6] = 0; fp[7] = 1; fp += 8; } for(sInt i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); // paint core mtrl2->Passes[0].Mtrl->Set(kenv->CurrentCam); sSystem->GeoBegin(geo,4,6,&fp,(void **)&ip); fp[0] = corerad*( - mat.i.x + mat.i.y)+pos.x; fp[1] = corerad*( - mat.j.x + mat.j.y)+pos.y; fp[2] = corerad*( - mat.k.x + mat.k.y)+pos.z; fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colc; fp[6] = 0.0f; fp[7] = 0.0f; fp += 8; fp[0] = corerad*( + mat.i.x + mat.i.y)+pos.x; fp[1] = corerad*( + mat.j.x + mat.j.y)+pos.y; fp[2] = corerad*( + mat.k.x + mat.k.y)+pos.z; fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colc; fp[6] = 1.0f; fp[7] = 0.0f; fp += 8; fp[0] = corerad*( + mat.i.x - mat.i.y)+pos.x; fp[1] = corerad*( + mat.j.x - mat.j.y)+pos.y; fp[2] = corerad*( + mat.k.x - mat.k.y)+pos.z; fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colc; fp[6] = 1.0f; fp[7] = 1.0f; fp += 8; fp[0] = corerad*( - mat.i.x - mat.i.y)+pos.x; fp[1] = corerad*( - mat.j.x - mat.j.y)+pos.y; fp[2] = corerad*( - mat.k.x - mat.k.y)+pos.z; fp[3] = 0; fp[4] = 0; *((sU32 *)(&fp[5])) = colc; fp[6] = 0.0f; fp[7] = 1.0f; fp += 8; sQuad(ip,0,1,2,3); sSystem->GeoEnd(geo); sSystem->GeoDraw(geo); // done sSystem->GeoRem(geo); } #endif /****************************************************************************/ /*** ***/ /*** Breakpoint 06 Invitation: Dschungelgelöt ***/ /*** ***/ /****************************************************************************/ KObject * __stdcall Init_Effect_BP06Jungle(GenMaterial *mtrl,sInt segments,sInt slices,sF32 thickness,sF32 thickscale,sF32 length,sF32 lenscale,sF32 sangle,sF32 carfreq,sF32 caramp,sF32 modfreq,sF32 modamp,sF32 modphase) { return MakeEffect(mtrl); } void __stdcall Exec_Effect_BP06Jungle(KOp *op,KEnvironment *kenv,sInt segments,sInt slices,sF32 thickness,sF32 thickscale,sF32 length,sF32 lenscale,sF32 sangle,sF32 carfreq,sF32 caramp,sF32 modfreq,sF32 modamp,sF32 modphase) { GenMaterial *mtrl; volatile sVertexTSpace3 *vp; sU16 *ip; sInt geo; // check material mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; kenv->CurrentCam.ModelSpace = kenv->ExecStack.Top(); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_TRI|sGEO_DYNAMIC); // paint the effect sSystem->GeoBegin(geo,(segments+1)*(slices+1),segments*slices*6,(sF32 **) &vp,(void **) &ip); sF32 angle; sF32 posx,posy; angle = sangle; posx = posy = 0.0f; length /= segments; lenscale = sFPow(lenscale,1.0f / segments); thickscale = sFPow(thickscale,1.0f / segments); caramp /= segments; angle = sangle; for(sInt i=0;i<=segments;i++) { // calculate angles sF32 ca,sa,v; v = 1.0f * i / segments; angle += caramp * sFCos(sPI2F * v * (carfreq + modamp * sFSin(sPI2F * (v * modfreq + modphase)))); sFSinCos(angle*sPI2F,sa,ca); // build the segments for(sInt j=0;j<=slices;j++) { sF32 u = 1.0f * j / slices; vp->x = posx + (u - 0.5f) * ca * thickness; vp->y = posy - (u - 0.5f) * sa * thickness; vp->z = 0.0f; vp->n = 0x808000; vp->s = 0x80ff80; vp->c = 0xffffffff; vp->u = u; vp->v = 1.0f - v; vp++; } // update angle and position posx += sa * length; posy += ca * length; length *= lenscale; thickness *= thickscale; } sInt slice1 = slices + 1; for(sInt i=0;iGeoEnd(geo); sSystem->GeoDraw(geo); // done sSystem->GeoRem(geo); } /****************************************************************************/ /*** ***/ /*** Gridkram ***/ /*** ***/ /****************************************************************************/ KObject * __stdcall Init_Effect_GridStuff(GenMaterial *mtrl,sInt xRes,sInt yRes,sU32 col1,sU32 col2) { return MakeEffect(mtrl); } static sU32 getColor(sF32 fade,sU32 col1,sU32 col2) { sInt f = sRange(fade*255,255,0); sInt col1rb = col1 & 0xff00ff; sInt col1ag = (col1 >> 8) & 0xff00ff; sInt col2rb = col2 & 0xff00ff; sInt col2ag = (col2 >> 8) & 0xff00ff; sInt rb = (col1rb + ((f*(col2rb - col1rb))>>8)) & 0xff00ff; sInt ag = (col1ag + ((f*(col2ag - col1ag))>>8)) & 0xff00ff; return (ag<<8) | rb; } void __stdcall Exec_Effect_GridStuff(KOp *op,KEnvironment *kenv,sInt xRes,sInt yRes,sU32 col1,sU32 col2) { GenMaterial *mtrl; volatile sVertexTSpace3 *vp; sInt geo; // check material mtrl = (GenMaterial *) op->GetLinkCache(0); if(!(mtrl && mtrl->Passes.Count>0)) return; kenv->CurrentCam.ModelSpace = kenv->ExecStack.Top(); mtrl->Passes[0].Mtrl->Set(kenv->CurrentCam); geo = sSystem->GeoAdd(sFVF_TSPACE3,sGEO_QUAD|sGEO_DYNAMIC); // calc random heightfield sF32 *heights = new sF32[xRes*yRes]; sSetRndSeed(0x12345); sF32 time = kenv->Var[KV_TIME].x; sInt timeInt = sInt(time); sF32 timeFrac = time - timeInt + (timeInt<0); timeInt &= 0xff; // random points interpolated with catmull-rom for(sInt i=0;i>8)]; // 4 base points sF32 basev[4]; for(sInt j=0;j<4;j++) basev[j] = sPerlinPermute[(prePerm+timeInt+j-1) & 0xff] / 255.0f; // interpolate (catmull-rom) heights[i] = (((0.5f * (basev[3] - basev[0]) + 1.5f*(basev[1]-basev[2])) * timeFrac + basev[0] - 2.5f * basev[1] + 2.0f * basev[2] - 0.5f * basev[3]) * timeFrac + 0.5f * (basev[2] - basev[0])) * timeFrac + basev[1]; //heights[i] = sFGetRnd(); } // all independent quads sSystem->GeoBegin(geo,(xRes*yRes+(xRes-1)*yRes+xRes*(yRes-1))*4,0,(sF32 **) &vp,0); const sF32 yScale = 5.0f; // main quads for(sInt y=0;y>1); vp->x = x + (k&1); vp->y = h * yScale; vp->z = y + 1 - (k>>1); vp->n = 0x80ff80; vp->s = 0x8080ff; vp->c = c; vp->u = x + (k&1); vp->v = y + (k>>1); vp++; } } } // horizontal connectors for(sInt y=0;y= h2 ? 0xff8080 : 0x008080; for(sInt j=0;j<4;j++) { sInt k = j ^ (j>>1); vp->x = x + 1; vp->y = ((k&1) ? h2 : h1) * yScale; vp->z = y + 1 - (k>>1); vp->n = n; vp->s = 0x8080ff; vp->c = (k&1) ? c2 : c1; vp->u = x + 1 + (k&1); vp->v = y + (k>>1); vp++; } } } // vertical connectors for(sInt y=0;y= h2 ? 0x8080ff : 0x808000; for(sInt j=0;j<4;j++) { sInt k = j ^ (j>>1); vp->x = x + 1 - (k&1); vp->y = ((k&2) ? h2 : h1) * yScale; vp->z = y + 1; vp->n = n; vp->s = 0xff8080; vp->c = (k&2) ? c2 : c1; vp->u = x + (k&1); vp->v = y + 1 + (k>>1); vp++; } } } sSystem->GeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); delete[] heights; } /****************************************************************************/ /*** ***/ /*** Image Jukebox ***/ /*** ***/ /****************************************************************************/ GenImageList::GenImageList() { ClassId = KC_IMGLIST; Images.Init(); } GenImageList::~GenImageList() { Clear(); Images.Exit(); } void GenImageList::Copy(KObject *o) { sVERIFY(o->ClassId == KC_IMGLIST); Clear(); Append(*((GenImageList *) o)); } void GenImageList::Clear() { for(sInt i=0;iRemTexture(Images[i].TexHandle); } void GenImageList::AddImage(sInt handle,sInt xRes,sInt yRes) { if(handle != sINVALID) { sSystem->AddRefTexture(handle); Image* img = Images.Add(); img->TexHandle = handle; img->XRes = xRes; img->YRes = yRes; } } void GenImageList::Append(const GenImageList& other) { Images.AtLeast(Images.Count + other.Images.Count); for(sInt i=0;iAddRefTexture(img->TexHandle); } } sInt GenImageList::GetImage(sInt index,sInt *xRes,sInt *yRes) const { if(index<0 || index>=Images.Count) return sINVALID; if(xRes) *xRes = Images[index].XRes; if(yRes) *yRes = Images[index].YRes; return Images[index].TexHandle; } GenImageList * __stdcall Init_Misc_ImageList(KOp *op) { sInt xRes = *op->GetEditPtrU(0); sInt yRes = *op->GetEditPtrU(1); GenImageList *result = new GenImageList; for(sInt i=0;iGetInputCount();i++) { KObject *in = op->GetInput(i)->Cache; if(in->ClassId == KC_IMGLIST) result->Append(*((GenImageList *) in)); else if(in->ClassId == KC_BITMAP) { GenBitmap *bmp = (GenBitmap *) in; if(bmp->Texture == sINVALID) bmp->MakeTexture(bmp->Format); result->AddImage(bmp->Texture,xRes,yRes); } else { delete result; result = 0; break; } } if(result) { // give up refs to inputs if successful for(sInt i=0;iGetInputCount();i++) op->GetInput(i)->Cache->Release(); } return result; } class sMaterialImageJukebox : public sMaterial { sInt Setup; public: sInt Tex; sF32 Whiten; sF32 Amplify; sF32 Fade; sMaterialImageJukebox() { sU32 states[256],*st=states; static const sU32 vShader[] = { 0xfffe0101, // vs.1.1 0x0000001f, 0x80000000, 0x900f0000, // dcl_position v0 0x0000001f, 0x80000005, 0x900f0001, // dcl_texcoord v1 0x00000014, 0xc00f0000, 0x90e40000, 0xa0e40000, // m4x4 oPos,v0,c0 0x00000001, 0xe00f0000, 0x90e40001, // mov oT0,v1 0x0000ffff, // end }; static const sU32 pShader[] = { 0xffff0200, // ps.2.0 0x0200001f, 0x80000000, 0xb00f0000, // dcl t0 0x0200001f, 0x90000000, 0xa00f0800, // dcl_2d s0 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, // texld r0,t0,s0 0x04000012, 0x800f0001, 0xa0550000, 0x80e40000, 0x80ff0000, // lrp r1,c0.y,r0,r0.w 0x03000005, 0x80070000, 0x80e40001, 0xa0aa0000, // mul r0.rgb,r1,c0.z 0x0300000a, 0x80070000, 0x80e40000, 0x80ff0000, // min r0.rgb,r0,r0.a 0x03000005, 0x800f0000, 0x80e40000, 0xa0ff0000, // mul r0,r0,r0.a 0x02000001, 0x800f0800, 0x80e40000, // mov oC0,r0 0x0000ffff, // end }; // render states *st++ = sD3DRS_ALPHATESTENABLE; *st++ = 0; *st++ = sD3DRS_ZENABLE; *st++ = sD3DZB_TRUE; *st++ = sD3DRS_ZWRITEENABLE; *st++ = 0; *st++ = sD3DRS_ZFUNC; *st++ = sD3DCMP_LESS; *st++ = sD3DRS_CULLMODE; *st++ = sD3DCULL_NONE; *st++ = sD3DRS_COLORWRITEENABLE; *st++ = 15; *st++ = sD3DRS_SLOPESCALEDEPTHBIAS; *st++ = 0; *st++ = sD3DRS_DEPTHBIAS; *st++ = 0; *st++ = sD3DRS_FOGENABLE; *st++ = 0; *st++ = sD3DRS_STENCILENABLE; *st++ = 0; *st++ = sD3DRS_ALPHABLENDENABLE; *st++ = 1; *st++ = sD3DRS_SRCBLEND; *st++ = sD3DBLEND_ONE; *st++ = sD3DRS_DESTBLEND; *st++ = sD3DBLEND_INVSRCALPHA; *st++ = sD3DRS_BLENDOP; *st++ = sD3DBLENDOP_ADD; // sampler setup *st++ = sD3DSAMP_0|sD3DSAMP_MAGFILTER; *st++ = sD3DTEXF_LINEAR; *st++ = sD3DSAMP_0|sD3DSAMP_MINFILTER; *st++ = sD3DTEXF_LINEAR; *st++ = sD3DSAMP_0|sD3DSAMP_MIPFILTER; *st++ = sD3DTEXF_LINEAR; *st++ = sD3DSAMP_0|sD3DSAMP_ADDRESSU; *st++ = sD3DTADDRESS_CLAMP; *st++ = sD3DSAMP_0|sD3DSAMP_ADDRESSV; *st++ = sD3DTADDRESS_CLAMP; // terminator *st++ = ~0U; *st++ = ~0U; // create setup Setup = sSystem->MtrlAddSetup(states,vShader,pShader); Whiten = 0.0f; Amplify = 1.0f; Fade = 1.0f; } ~sMaterialImageJukebox() { if(Setup != sINVALID) sSystem->MtrlRemSetup(Setup); } void Set(const sMaterialEnv &env) { sMaterialInstance inst; sMatrix mat; sVector pc[2]; inst.NumTextures = 1; inst.Textures[0] = Tex; inst.NumVSConstants = 4; inst.VSConstants = &mat.i; inst.NumPSConstants = 2; inst.PSConstants = pc; // change to proper ortho projection here mat.Mul4(env.ModelSpace,sSystem->LastViewProject); mat.Trans4(); pc[0].Init(1.0f,1.0f-Whiten,Amplify,Fade); pc[1].Init(0.0f,0.0f,0.0f,0.0f); sSystem->MtrlSetSetup(Setup); sSystem->MtrlSetInstance(inst); } }; KObject * __stdcall Init_Effect_ImageJukebox(GenImageList *list,sInt pass,sInt index,sF32 whiten,sF32 amplify,sF32 fade) { GenMaterial *mtrl = new GenMaterial; mtrl->AddPass(new sMaterialImageJukebox,ENGU_OTHER,MPP_STATIC,pass); GenEffect *fx = new GenEffect; fx->Material = mtrl; fx->Pass = pass; fx->Usage = ENGU_OTHER; if(list) list->Release(); return fx; } void __stdcall Exec_Effect_ImageJukebox(KOp *op,KEnvironment *kenv,sInt pass,sInt index,sF32 whiten,sF32 amplify,sF32 fade) { GenImageList *list = (GenImageList *) op->GetLinkCache(0); if(!list || list->ClassId != KC_IMGLIST) return; // prepare texture/material GenEffect *fx = (GenEffect *) op->Cache; sMaterialImageJukebox *mtrl = (sMaterialImageJukebox *) fx->Material->Passes[0].Mtrl; sInt xRes,yRes; mtrl->Tex = list->GetImage(index,&xRes,&yRes); mtrl->Whiten = whiten; mtrl->Amplify = amplify; mtrl->Fade = fade; // set material kenv->CurrentCam.ModelSpace = kenv->ExecStack.Top(); mtrl->Set(kenv->CurrentCam); // calc dimensions sF32 xDim = xRes / 256.0f; sF32 yDim = yRes / 256.0f; // paint the quad sVertexDouble *vert; sInt geo = sSystem->GeoAdd(sFVF_DOUBLE,sGEO_QUAD); sSystem->GeoBegin(geo,4,0,(sF32 **) &vert,0); vert[0].Init(-xDim, yDim,0,~0U,0,0); vert[1].Init( xDim, yDim,0,~0U,1,0); vert[2].Init( xDim,-yDim,0,~0U,1,1); vert[3].Init(-xDim,-yDim,0,~0U,0,1); sSystem->GeoEnd(geo); sSystem->GeoDraw(geo); sSystem->GeoRem(geo); }