#include "Flyer.h"
#include "Flyer.c7"
#include "Tringula.h"
#include "ParaSurf.h"
ClassImp(Flyer);
void Flyer::_init()
{
mHeight = 0;
mGravHChange = 0;
bGravFixUpDir = true;
mTerrainSafety = 0;
mTerrainProbeRadius = 0;
}
Flyer::Flyer(const Text_t* n, const Text_t* t) :
Dynamico(n, t)
{
_init();
}
Flyer::~Flyer()
{}
void Flyer::TimeTick(Double_t t, Double_t dt)
{
static const Exc_t _eh("Flyer::TimeTick ");
Opcode::Point velocity;
Float_t velocity_mag2, velocity_mag, step_length;
calculate_velocity:
mTrans.RotateVec3(mVVec, velocity);
velocity_mag2 = velocity.SquareMagnitude();
velocity_mag = sqrtf(velocity_mag2);
step_length = velocity_mag * dt + mExtraStep;
mExtraStep = 0;
const Float_t dh = - (mGrav.Down() | velocity) * dt;
if (mHeight + dh > mTringula->GetMaxFlyerH())
{
if (mHeight < mTringula->GetMaxFlyerH())
{
printf("Fixing speed for %s, hp=%f, mh=%f\n", GetName(), mHeight + dh, mTringula->GetMaxFlyerH());
velocity.TMac(mGrav.Down(), dh / dt);
mTrans.RotateBackVec3(velocity, mVVec);
goto calculate_velocity;
}
}
mHeight += dh;
mGravHChange += dh;
mTrans.Move3PF(velocity.x * dt, velocity.y * dt, velocity.z * dt);
mTrans.RotateLF(1, 2, dt*mWVec.x);
mTrans.RotateLF(2, 3, dt*mWVec.y);
mTrans.RotateLF(3, 1, dt*mWVec.z);
mSafety -= step_length;
if (mSafety < 0)
{
Bool_t trans_changed = mTringula->CheckBoundaries(this, mSafety);
if (trans_changed)
{
mTrans.RotateVec3(mVVec, velocity);
velocity_mag2 = velocity.SquareMagnitude();
velocity_mag = sqrtf(velocity_mag2);
}
}
if (mGrav.DecaySafeties(dt, step_length))
{
Float_t assumed_h = mGrav.fH + mGravHChange;
Opcode::Point old_grav_dir(mGrav.fDown);
mTringula->GetParaSurf()->pos2grav(ref_trans().ArrT(), mGrav);
Float_t vl = mGrav.Dir() | velocity; if (vl < 0) vl = -vl;
Float_t vt = sqrtf(velocity_mag2 - vl*vl);
update_grav_safeties(vl, vt);
Float_t fdh = mGrav.fH - assumed_h;
mTrans.Move3PF(mGrav.fDown[0] * fdh, mGrav.fDown[1] * fdh, mGrav.fDown[2] * fdh);
mHeight = assumed_h;
mGrav.fH = assumed_h;
mGravHChange = 0;
if (bGravFixUpDir)
{
Opcode::Matrix3x3 m;
m.FromTo(old_grav_dir, mGrav.Down());
mTrans.MultLeft3x3(m);
}
if (mDebugBits & DB_GravData)
{
mGrav.Print();
printf(" v_mag=%f, vl=%f, vt=%f, t_safe=%f, d_safe=%f (d/v)=%f\n",
velocity_mag, vl, vt, mGrav.fSafeTime, mGrav.fSafeDistance,
mGrav.fSafeDistance / velocity_mag);
}
}
mTerrainSafety -= step_length;
if (mTerrainSafety < 0)
{
static const Float_t probe_inc_fac = 1.414;
static const Float_t probe_dec_fac = 0.707;
Float_t min_r = mMesh->GetTTvor()->GetMaxVertexDistance();
Opcode::SphereCache SCache;
Opcode::SphereCollider SC;
SC.SetFirstContact(true);
Opcode::Sphere S(ref_pos(), 0);
while (mTerrainProbeRadius >= min_r)
{
S.SetRadius(mTerrainProbeRadius);
bool cs = SC.Collide(SCache, S, *mTringula->GetMesh()->GetOPCModel());
if (cs)
{
if (SC.GetContactStatus())
{
mTerrainProbeRadius *= probe_dec_fac;
}
else
{
mTerrainSafety = mTerrainProbeRadius;
mTerrainProbeRadius *= probe_inc_fac;
break;
}
}
else
{
printf("%s something wrong in sphere-terrain collision test.\n",
_eh.Data());
}
}
if (mTerrainProbeRadius < min_r)
{
CollisionSegments segments;
Int_t ns = collide_with_tringula(segments);
if (ns > 0)
{
Opcode::Point dr(segments.RefCenter());
dr.Sub(ref_pos());
if ((dr | velocity) > 0)
{
mTrans.RotateLF(1, 2, TMath::Pi());
}
}
mTerrainSafety = 0;
mTerrainProbeRadius = min_r;
}
}
}