Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- class DSH_cPoint: object
- {
- vector3 pos;
- static DSH_cPoint init(vector3 pushPos)
- {
- let p = new("DSH_cPoint");
- p.pos = pushPos;
- return p;
- }
- }
- class DSH_ActorPoint: object
- {
- color col;
- vector3 pos;
- vector3 nextpos;
- actor act;
- static DSH_ActorPoint init(vector3 pushPos)
- {
- let p = new("DSH_actorPoint");
- p.pos = pushPos;
- p.col = "AAFFFF";
- return p;
- }
- }
- class DSH_kBezier : object play
- {
- actor spawner;
- array<DSH_cPoint> cPoints; //these are the control points for the curves
- array<DSH_ActorPoint> actorPoints; //these are were actors will be spawned
- array<actor> beamActors; //these are the actual actors
- //Credits to 3saster for writing this much improved version of the function!
- static Vector3 PointOnCurve(double t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, bool unitspeed=false, int prec=50, double arcLength = -1)
- {
- // based off of this to get unit speed
- // https://gamedev.stackexchange.com/a/27138
- if(unitspeed) //precise but slow
- {
- Vector3 v1 = -3*p0 +9*p1 -9*p2 +3*p3;
- Vector3 v2 = 6*p0 -12*p1 +6*p2;
- Vector3 v3 = -3*p0 +3*p1;
- double ts = 0;
- double L = arcLength >= 0 ? arcLength : CurveLength(p0, p1, p2, p3) * t;
- for(int p=0; p<prec; p++)
- {
- Vector3 scaler = ts*ts*v1+ts*v2+v3;
- ts += L/prec/scaler.Length();
- }
- return PointOnCurve(ts,p0,p1,p2,p3);
- }
- else //much faster
- {
- double u = 1 - t;
- double tt = t*t;
- double uu = u*u;
- double uuu = uu * u;
- double ttt = tt * t;
- Vector3 p = uuu * p0; //first term
- p += 3 * uu * t * p1; //second term
- p += 3 * u * tt * p2; //third term
- p += ttt * p3; //fourth term
- return p;
- }
- }
- //Credits to 3saster!
- static double CurveLength(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, int prec=5000, double tend=1)
- {
- Array<double> ds;
- double precision = 1./(prec - prec%2);
- for(double t = 0; t <= tend; t += precision)
- {
- double u = 1 - t;
- double tt = t*t;
- double uu = u*u;
- Vector3 p = (0,0,0);
- p += 3 * uu * 1 * (p1 - p0); //first term
- p += 6 * u * t * (p2 - p1); //second term
- p += 3 * 1 * tt * (p3 - p2); //third term
- ds.push( sqrt(p.x*p.x + p.y*p.y + p.z*p.z) );
- }
- // Simpson's Rule
- double arclength = ds[0] + ds[ds.size()-1];
- //4's
- for(int i = 1; i < ds.Size()-1; i += 1)
- {
- arclength += 2*ds[i];
- }
- //2's
- for(int i = 2; i < ds.Size()-1; i += 2)
- {
- arclength += 2*ds[i];
- }
- return arclength*precision/3;
- }
- void SubdivideSingleCurve(int index, double t = 0.5, bool extendcurve = true)
- {
- vector3 p0 = cPoints[index].pos;
- vector3 p1 = cPoints[index+1].pos;
- vector3 p2 = cPoints[index+2].pos;
- vector3 p3 = cPoints[index+3].pos;
- vector3 p11 = ((1.0 - t)*p0) + (t*p1);
- vector3 p21 = ((1.0 - t)*p1) + (t*p2);
- vector3 p31 = ((1.0 - t)*p2) + (t*p3);
- vector3 p12 = ((1.0 - t)*p11)+ (t*p21);
- vector3 p22 = ((1.0 - t)*p21)+ (t*p31);
- vector3 p13 = ((1.0 - t)*p12)+ (t*p22);
- //overwrite indices for the first part of the new divided curve;
- cPoints[index+1].pos = p11;
- cPoints[index+2].pos = p12;
- cPoints[index+3].pos = p13;
- //insert new control points.
- if(extendcurve)
- {
- InsertPoint(p22, index+4);
- InsertPoint(p31, index+5);
- InsertPoint(p3, index+6); //put the original endpoint back :)
- }
- else //this would be for when the function is called for repositioning
- {
- cPoints[index+4].pos = p22;
- cPoints[index+5].pos = p31;
- cPoints[index+6].pos = p3;
- }
- }
- void BeginCurveExplicit(vector3 p0, vector3 p1, vector3 p2, vector3 p3, bool subdivision = false)
- {
- //the first curve in the spline needs to have 4 control points.
- cPoints.Push(DSH_cPoint.init(p0));
- cPoints.Push(DSH_cPoint.init(p1));
- cPoints.Push(DSH_cPoint.init(p2));
- cPoints.Push(DSH_cPoint.init(p3));
- if(subdivision)
- {
- SubdivideSingleCurve(0, 0.5,true);
- }
- }
- void InsertPoint(vector3 p,int index)
- {
- cPoints.insert(index,DSH_cPoint.init(p));
- }
- void ExtendCurveExplicit(vector3 p0, vector3 p1, vector3 p2, bool subdivision = false)
- {
- //the second one and all later ones will share a control point with the last curve.
- cPoints.Push(DSH_cPoint.init(p0));
- cPoints.Push(DSH_cPoint.init(p1));
- cPoints.Push(DSH_cPoint.init(p2));
- if(subdivision)
- {
- SubdivideSingleCurve(cPoints.size()-4, 0.5,true);
- }
- }
- void RepositionCurve4(int index, vector3 p0, vector3 p1, vector3 p2, vector3 p3)
- {
- //the first curve in the spline needs to have 4 control points.
- cPoints[index].pos = p0;
- cPoints[index-1].pos = p1;
- cPoints[index-2].pos = p2;
- cPoints[index-3].pos = p3;
- }
- void RepositionCurve3(int index, vector3 p0, vector3 p1, vector3 p2)
- {
- //the first curve in the spline needs to have 4 control points.
- cPoints[index].pos = p0;
- cPoints[index-1].pos = p1;
- cPoints[index-2].pos = p2;
- }
- void SpawnOrRepositionBeams(int limit = 4, bool Reposition = false)
- {
- int siz = cPoints.size();
- if(true)
- {
- for(int k = 0; k<siz; k++)
- {
- actor bleb = DSH_Dot(actor.spawn("DSH_Dot",cPoints[k].pos));
- //bleb.SetShade( color(255,int(255*(double(k)/siz)),0,0) );
- }
- }
- if(siz <= 4)
- return;
- //TODO: will need special case for this
- limit = max(4, limit);
- //TODO - maybe remove this?
- int counter = 0;
- for(int i = 3; i< siz; i+=3)
- {
- for(int j = 0; j<limit; j++)
- {
- vector3 startpoint = PointOnCurve(j / double(limit), cPoints[i].pos, cPoints[i-1].pos, cPoints[i-2].pos, cPoints[i-3].pos,false);
- vector3 endpoint = PointOnCurve((j+1) / double(limit), cPoints[i].pos, cPoints[i-1].pos, cPoints[i-2].pos, cPoints[i-3].pos,False);
- actor beam;
- if(i < (siz*0.5)) //reverse the start/end order at approx the half way mark.
- {
- vector3 temp = startpoint;
- startpoint = endpoint;
- endpoint = temp;
- }
- if(!reposition) //if there are no beams already loaded, we spawn one
- {
- beam = actor.spawn("DSH_BasicBeam",startpoint);
- beamActors.push(beam);
- }
- else //otherwise we pick the right one from the array
- {
- beam = beamActors[counter];
- beam.args[0] = 1; //the beam will remove itself unless we continually refresh this value. Using args[] so they don't have to inherit from anything.
- }
- let p = playerpawn(spawner); //special case for players, to attempt fancy interpolation
- if(p)
- {
- //the below is a bit overengineered atm
- vector3 spdif = level.vec3diff((p.pos.xy, p.player.viewz),startpoint);
- vector3 spoff = level.vec3offset((p.pos.xy,p.player.viewz),spdif) ;
- vector3 dif = level.Vec3Diff(spoff,endpoint);
- spoff += (p.vel.xy,0);
- beam.SetOrigin(spoff,true);
- vector2 angs = DSH_kMath.AnglesFromVec3(dif);
- beam.A_SetAngle(angs.x,SPF_INTERPOLATE);
- beam.A_SetPitch(angs.y-(reposition*90),SPF_INTERPOLATE);
- beam.scale = (1.0,dif.length());
- beam.args[0] = 1;
- }
- counter++;
- }
- }
- //console.PrintF("counter is %i",counter);
- }
- void GenerateActorPoints(int pointsPerCurve = 4)
- {
- //cPoints is an array that contains every control point of the polybezier
- int siz = cPoints.size();
- int halfway = floor(siz*0.5);
- //will need special case later on probably.
- if(siz <= 4)
- return;
- //not strictly needed perhaps, but cubic curves don't make sense with less than 4 segments per curve imo
- pointsPerCurve = max(4, pointsPerCurve);
- //increased every time we create and actor point
- int counter = 0;
- for(int i = 3; i< siz; i+=3) //three steps forward because we check backwards in the nested loop
- {
- for(int j = pointsPerCurve; j>=0; j--)
- {
- vector3 newPoint = PointOnCurve(j / double(pointsPerCurve), cPoints[i].pos, cPoints[i-1].pos, cPoints[i-2].pos, cPoints[i-3].pos,false);
- //old method. We don't want to have to sample twice per point, since we can set/get from or on previous points.
- //vector3 endpoint = PointOnCurve((j+1) / double(pointsPerCurve), cPoints[i].pos, cPoints[i-1].pos, cPoints[i-2].pos, cPoints[i-3].pos,False);
- DSH_ActorPoint pt = DSH_ActorPoint(DSH_actorPoint.init(newPoint));
- //the idea of the block below is to orient the pos/nextpos of the
- //actor points so their pos (i.e where the real actor will be
- //spawned) is oriented outward to the end points from the midddle
- //point. Like this: <<<<<<<<middle>>>>>>>>>>
- //|||||||||||||||||||||||||||
- if(i < halfway)
- {
- pt.pos = newPoint;
- if(counter>0)
- {
- actorPoints[counter-1].nextpos = newPoint;
- }
- }
- else if(i <= halfway+1 && j == pointsPerCurve) //this is supposed to happen once, exactly after the halfway mark.
- {
- actorPoints[counter-1].nextpos = newPoint;
- //current actor will be effectively invisible here, but this makes everything work.
- //TODO: send halp
- pt.pos = newPoint;
- pt.nextpos = newPoint;
- }
- else
- {
- pt.pos = actorPoints[counter-1].nextPos;
- pt.nextPos = newPoint;
- }
- //|||||||||||||||||||||||||||
- actorPoints.push(pt);
- counter++;
- }
- }
- }
- void ActorsOnPoints(bool maintain = false)
- {
- int siz = actorpoints.size();
- for(int i = 0; i< siz; i++)
- {
- actor beam;
- vector3 startpoint = actorpoints[i].pos;
- vector3 endpoint = actorpoints[i].nextpos;
- if(!maintain)
- {
- beam = actor.spawn("DSH_BasicBeam",startpoint);
- actorPoints[i].act = beam;
- }
- else
- {
- beam = actorPoints[i].act;
- }
- let p = playerpawn(spawner); //special case for players, to attempt fancy interpolation
- if(p)
- {
- //TODO: the below is a bit overengineered atm
- vector3 spdif = level.vec3diff((p.pos.xy, p.player.viewz),startpoint);
- vector3 spoff = level.vec3offset((p.pos.xy,p.player.viewz),spdif) ;
- vector3 dif = level.Vec3Diff(spoff,endpoint);
- spoff += (p.vel.xy,0);
- beam.SetOrigin(spoff,true);
- vector2 angs = DSH_kMath.AnglesFromVec3(dif);
- beam.A_SetAngle(angs.x,SPF_INTERPOLATE);
- beam.A_SetPitch(angs.y,SPF_INTERPOLATE);
- beam.scale = (1.0,dif.length());
- beam.args[0] = 1;
- beam.SetShade(actorpoints[i].col);
- }
- }
- }
- }
- Class DSH_BasicBeam : actor
- {
- override void tick()
- {
- super.tick();
- args[0]--;
- }
- default
- {
- +noblockmap;
- +nogravity;
- +nointeraction;
- renderstyle "addshaded";
- StencilColor "aaFFFF";
- alpha 2;
- }
- Override void PostBeginPlay()
- {
- self.pitch -= 90.0;
- }
- states
- {
- spawn:
- TNT1 A 1 nodelay;
- goto beamloop;
- beamloop:
- MODL A 1 bright;
- TNT1 A 0 A_JumpIf(args[0] <= 0,"byebyebeam");
- loop;
- byebyebeam:
- tnt1 A 0;
- stop;
- }
- }
- class DSH_Dot : actor
- {
- default
- {
- +noblockmap;
- +nogravity;
- +nointeraction;
- renderstyle "addshaded";
- StencilColor "FF0000";
- scale 0.24;
- alpha 2;
- }
- Override void PostBeginPlay()
- {
- self.pitch -= 90.0;
- }
- states
- {
- spawn:
- TNT1 A 0 nodelay;
- BAL1 A 1 bright;
- stop;
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement