#include "Crawler.h"
#include "Crawler.c7"
#include "Tringula.h"
#include "ParaSurf.h"
ClassImp(Crawler);
void Crawler::_init()
{
mDriveMode = DM_ConstVelocities;
mLevH = 0.1f;
mRayOffset = 0;
mThrottle.SetMinMaxDelta(-1, 4, 1, 1.5);
mThrottle.SetStdDesireDelta(2);
mWheel.SetMinMaxDelta(-1, 1, 0.5, 1);
mWheel.SetStdDesireDelta(1);
const Float_t turret_speed = 0.15f;
mLaserUpDn.SetMinMaxDelta(-0.35, 0.7, turret_speed, turret_speed);
mLaserUpDn.SetStdDesireDelta(2.0f*turret_speed);
mLaserLtRt.SetMinMaxDelta(-1.0, 1.0, turret_speed,turret_speed);
mLaserLtRt.SetStdDesireDelta(2.0f*turret_speed);
mLaserCharge.SetMinMax(0, 60);
mLaserLen = 0;
}
Crawler::Crawler(const Text_t* n, const Text_t* t) :
Dynamico(n, t)
{
_init();
}
Crawler::~Crawler()
{}
void Crawler::SetTringula(Tringula* tring)
{
PARENT_GLASS::SetTringula(tring);
mRayOffset = 2.0f * mTringula->GetMesh()->GetTTvor()->mMaxEdgeLen;
if (*mMesh)
{
const Float_t* mmbb = mMesh->GetTTvor()->mMinMaxBox;
mLaserBeg.Set(0, 0, mmbb[5]);
mLaserLen = 0.75f * mmbb[3];
}
}
void Crawler::TimeTick(Double_t t, Double_t dt)
{
static const Exc_t _eh("Crawler::TimeTick ");
const Float_t dtf = dt;
mThrottle. TimeTick(dtf);
mWheel. TimeTick(dtf);
mLaserUpDn.TimeTick(dtf);
mLaserLtRt.TimeTick(dtf);
mLaserCharge.Delta(100.0f*dtf);
switch (mDriveMode)
{
case DM_Parked:
mVVec.Set(0,0,0);
break;
case DM_ConstVelocities:
break;
case DM_Controllers:
mVVec.Set(mThrottle.Get(), 0, 0);
mWVec.Set(mWheel.Get(), 0, 0);
break;
}
using namespace Opcode;
RayCollider RC;
RC.SetTemporalCoherence(true);
RC.SetClosestHit(true);
CollisionFaces CF;
RC.SetDestination(&CF);
Opcode::Point velocity;
Float_t velocity_mag2, velocity_mag, step_length;
mTrans.RotateVec3(mVVec, velocity);
velocity_mag2 = velocity.SquareMagnitude();
velocity_mag = sqrtf(velocity_mag2);
step_length = velocity_mag * dtf + mExtraStep;
mExtraStep = 0;
if (mDriveMode == DM_Controllers)
{
Float_t dp;
dp = mTerrainUp.Dot(mTrans.PtrBaseVecX());
if (fabsf(dp) > 0.001f)
mTrans.RotateLF(1, 3, 2.0f*dtf*(acosf(dp) - HALFPI));
dp = mTerrainUp.Dot(mTrans.PtrBaseVecY());
if (fabsf(dp) > 0.001f)
mTrans.RotateLF(2, 3, 2.0f*dtf*(acosf(dp) - HALFPI));
}
mTrans.Move3PF(velocity.x * dtf, velocity.y * dtf, velocity.z * dtf);
mTrans.RotateLF(1, 2, dtf*mWVec.x);
mTrans.RotateLF(2, 3, dtf*mWVec.y);
mTrans.RotateLF(3, 1, dtf*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);
}
}
Opcode::Point& pos = * (Opcode::Point*) ref_trans().ArrT();
if (mGrav.DecaySafeties(dtf, step_length))
{
mTringula->GetParaSurf()->pos2grav(pos, 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);
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);
}
}
Opcode::Ray R;
R.mDir = mGrav.Dir();
Int_t reoffset_count = 0;
reoffset:
R.mOrig.Msc(pos, R.mDir, mRayOffset);
TriMesh* terrain_mesh = mTringula->GetMesh();
UInt_t cache = mOPCRCCache;
if (RC.Collide(R, *terrain_mesh->GetOPCModel(), 0, &mOPCRCCache))
{
if (CF.GetNbFaces() == 1)
{
const CollisionFace& cf = CF.GetFaces()[0];
pos.TMac(R.mDir, cf.mDistance - mRayOffset - mLevH);
if (cache != mOPCRCCache)
{
mTerrainUp.Set(terrain_mesh->GetTTvor()->TriangleNormal(mOPCRCCache));
if (mDriveMode != DM_Controllers)
{
mTrans.SetBaseVec(3, mTerrainUp);
mTrans.OrtoNorm3Column(2, 3);
mTrans.SetBaseVecViaCross(1);
}
}
}
else
{
if (mTringula->GetParaSurf()->IsValidPos(pos))
{
if (reoffset_count < 5)
{
ISmess(_eh + RC.CollideInfo(true, R) + GForm(" Increasing ray-offset from %f for '%s'.", mRayOffset, GetName()));
mRayOffset *= 2;
++reoffset_count;
goto reoffset;
}
else
{
ISmess(_eh + RC.CollideInfo(true, R) + GForm(" Increasing ray-offset did not help - parking '%s'", GetName()));
SetDriveMode(DM_Parked);
}
}
else
{
ISmess(_eh + RC.CollideInfo(true, R) + GForm(" Fallen off - parking, ray-offset was %f for '%s'.", mRayOffset, GetName()));
SetDriveMode(DM_Parked);
}
}
if (reoffset_count != 0)
{
mRayOffset = 2.0f * mTringula->GetMesh()->GetTTvor()->mMaxEdgeLen;
}
}
else
{
ISwarn(_eh + RC.CollideInfo(false, R));
}
}
void Crawler::ShootLaser()
{
HTransF& trans = ref_last_trans();
Opcode::Ray ray;
ray.mOrig = mLaserBeg;
trans.RotateVec3IP(ray.mOrig);
ray.mOrig.Add(trans.ref_pos());
const Float_t p = mLaserLtRt.Get(), t = mLaserUpDn.Get();
const Float_t ct = cosf(t);
ray.mDir.Set(ct*cosf(p), ct*sinf(p), sinf(t));
trans.RotateVec3IP(ray.mDir);
ray.mOrig.TMac(ray.mDir, mLaserLen);
mTringula->LaserShot(this, ray, mLaserCharge.Get());
mLaserCharge.Set(0);
}