#include "TringuCam.h"
#include "Glasses/TSPupilInfo.h"
#include "TringuRep.h"
#include "Extendio.h"
#include "Statico.h"
#include "Dynamico.h"
#include <Glasses/ZQueen.h>
#include <Glasses/ZHashList.h>
#include <Glasses/ScreenText.h>
#include <Glasses/WGlWidget.h>
#include <Glasses/Eventor.h>
#include <Glasses/TimeMaker.h>
#include <Glasses/WSTube.h>
#include "TringuCam.c7"
#include "TringulaTester.h"
#include "TriMesh.h"
#include "ParaSurf.h"
#include <RnrBase/Fl_Event_Enums.h>
#include <TMath.h>
ClassImp(TringuCam);
void TringuCam::_init()
{
bKeysVerbose = bMouseVerbose = false;
mChgParCameraMove.SetValueParams (1, 0.5, 1.2, 0.4, 0.05);
mChgParCameraMove.SetDesireParams(1, 0.3, 1, 0.1, 0.2);
mFwdBck.fChangeParams = &mChgParCameraMove;
mFwdBck.SetMinMax(-20, 100);
mKeyStateMap['w'] = &mFwdBck.fIncKey;
mKeyStateMap['s'] = &mFwdBck.fDecKey;
mLftRgt.fChangeParams = &mChgParCameraMove;
mLftRgt.SetMinMax(-10, 10);
mKeyStateMap['a'] = &mLftRgt.fIncKey;
mKeyStateMap['d'] = &mLftRgt.fDecKey;
mUpDown.fChangeParams = &mChgParCameraMove;
mUpDown.SetMinMax(-30, 30);
mKeyStateMap['r'] = &mUpDown.fIncKey;
mKeyStateMap['f'] = &mUpDown.fDecKey;
mChgParCameraRotate.SetValueParams (0.1, 0.5, 1.2, 0.4, 0.05);
mChgParCameraRotate.SetDesireParams(0.1, 0.3, 0.1, 0.1, 0.2);
mSpinUp.fChangeParams = &mChgParCameraRotate;
mSpinUp.SetMinMax(-TMath::Pi(), TMath::Pi());
mKeyStateMap['q'] = &mSpinUp.fIncKey;
mKeyStateMap['e'] = &mSpinUp.fDecKey;
mMouseAction = MA_PickExtendios;
mExpectBeta = EB_Nothing;
mRayLength = 0;
bMouseDown = false;
mStampInterval = 25;
mStampCount = 0;
mHeight = 0;
mRayColl.SetCulling (true);
mRayColl.SetClosestHit(true);
mRayColl.SetDestination(&mCollFaces);
mCollVertex = -1;
}
WSTube* TringuCam::make_tube(Statico* stato0, Statico* stato1, const TString& grad_name)
{
WSTube* tube = new WSTube(GForm("Tube %s - %s; %s", stato0->GetName(), stato1->GetName(), grad_name.Data()));
tube->SetTransSource(WSTube::TS_Transes);
const HTransF& tA = stato0->ref_last_trans();
const HTransF& tB = stato1->ref_last_trans();
tube->RefTransA().SetFromArray(tA);
tube->RefTransA().MoveLF(3, 2.0*stato0->get_tring_tvor()->mCtrExtBox[5]);
tube->RefTransB().SetFromArray(tB);
tube->RefTransB().MoveLF(3, 2.0*stato1->get_tring_tvor()->mCtrExtBox[5]);
tube->RefVecA().SetXYZT(0, 0, 2, 1);
tube->RefVecB().SetXYZT(0, 0, -2, 1);
tube->SetTexture((ZImage*) mQueen->FindLensByPath(GForm("var/gradients/%s",
grad_name.Data())));
tube->SetFat(false);
tube->SetLineW(1.6);
tube->SetTLevel(30);
tube->SetPLevel(3);
tube->SetDefWidth(0.04);
tube->SetDefTension(1.5);
tube->SetTexUScale(2);
tube->SetDtexU(-0.3);
return tube;
}
inline TringuCam::KeyInfo* TringuCam::FindKeyInfo(Int_t key)
{
map<Int_t, KeyInfo*>::iterator i = mKeyStateMap.find(key);
return (i != mKeyStateMap.end()) ? i->second : 0;
}
Int_t TringuCam::KeyDown(Int_t key)
{
KeyInfo* ki = FindKeyInfo(key);
if (ki == 0) return 0;
if (ki->fIsDown == false)
{
ki->fIsDown = true;
ValueInfo *vi = ki->fValueInfo;
KeyValueChangeParams &C = * vi->fChangeParams;
if (vi->fSustain)
{
if (ki->fDecayTimeout > 0)
{
vi->fSustainSet = true;
if (ki->fIsInc)
{
if (vi->fSustainDesire < 0) vi->fSustainDesire = 0;
else vi->fSustainDesire = vi->fMaxValue;
}
else
{
if (vi->fSustainDesire > 0) vi->fSustainDesire = 0;
else vi->fSustainDesire = vi->fMinValue;
}
}
else
{
ki->fDesiredValue = ki->fIsInc ? vi->fMaxValue : - vi->fMinValue;
}
}
else
{
if (ki->fDecayTimeout > 0)
{
ki->fDesiredValue += C.fDesireIncDeltaFactor * ki->fDesiredValue;
ki->fDesiredValue += C.fDesireIncStep;
}
else
{
ki->fDesiredValue = TMath::Ceil(ki->fDesiredValue + 0.001);
}
}
if (ki->fIsInc)
{
if (ki->fDesiredValue > vi->fMaxValue)
ki->fDesiredValue = vi->fMaxValue;
}
else
{
if (ki->fDesiredValue > -vi->fMinValue)
ki->fDesiredValue = - vi->fMinValue;
}
}
return 1;
}
Int_t TringuCam::KeyUp(Int_t key)
{
KeyInfo* ki = FindKeyInfo(key);
if (ki == 0) return 0;
if (ki->fIsDown == true)
{
ki->fIsDown = false;
ValueInfo* vi = ki->fValueInfo;
KeyInfo* oki = ki->fIsInc ? &vi->fDecKey : &vi->fIncKey;
KeyValueChangeParams& C = * vi->fChangeParams;
ki->fDecayTimeout = C.fDesireDecayTimeout;
if (oki->fIsDown == false)
{
if (vi->fSustain)
{
if (!vi->fSustainSet)
vi->fSustainDesire = vi->fValue;
vi->fSustainSet = false;
}
else
{
vi->fDecayTimeout = C.fValueDecayTimeout;
}
}
}
return 1;
}
void TringuCam::MouseDown(A_Rnr::Fl_Event& ev)
{
static const Exc_t _eh("TringuCam::MouseDown ");
bMouseDown = true;
switch (mMouseAction)
{
case MA_Nothing:
{
break;
}
case MA_RayCollide:
{
TringulaTester *tt = dynamic_cast<TringulaTester*>(mTringuRep->GetElementByName("TringulaTester"));
if (tt)
{
CalculateMouseRayVectors();
tt->SetRayVectors(mMouseRayPos, mMouseRayDir);
tt->RayCollideTerrain();
}
else
{
ISwarn(_eh + "can not get TringulaTester as child of TringuRep.");
}
break;
}
case MA_AddField:
{
CalculateMouseRayVectors();
MouseRayCollide();
mTringuRep->AddField(mCollPoint, mCollVertex, 1.0f);
break;
}
case MA_SprayField:
{
mTringuRep->BeginSprayField();
break;
}
case MA_PickExtendios:
{
CalculateMouseRayVectors();
Opcode::Ray ray(&mMouseRayPos[0], &mMouseRayDir[0]);
Float_t rng = mTringula->RayCollideClosestHit(ray, true);
Extendio *ext = mTringula->PickExtendios(ray, rng);
if (bMouseVerbose)
printf("TringuCam::MouseDown picked %s, state=0x%x\n",
ext ? ext->GetName() : "<none>", ev.fState);
if (mExpectBeta == EB_ConnectStaticos)
{
Statico* stato = dynamic_cast<Statico*>(ext);
if (stato)
{
Statico* beta = dynamic_cast<Statico*>(*mPrepBeta);
if (beta) {
WSTube* tube = make_tube(beta, stato, mGradName);
mQueen->CheckIn(tube);
{
GLensWriteHolder _wlck(*mTringula);
mTringula->GetTubes()->Add(tube);
}
tube->AnimateConnect();
}
}
mExpectBeta = EB_Nothing;
SetPrepBeta(0);
}
else
{
mPupilInfo->SelectExtendio(ext, ev.fState & FL_CTRL);
}
break;
}
case MA_NewLandMark:
{
printf ("Sucking new landmark\n");
CalculateMouseRayVectors();
MouseRayCollide();
if (mCollVertex != -1)
{
TriMesh *mesh = dynamic_cast<TriMesh*>(mQueen->FindLensByPath("var/meshes/LandMark"));
GLensReadHolder _tlck(*mTringula);
mTringula->AddLandMark(mesh, mCollPoint);
}
mMouseAction = mPrevAction;
Stamp(FID());
break;
}
default:
{
printf("Unhandled case!!!!\n");
break;
}
}
}
void TringuCam::MouseUp()
{
bMouseDown = false;
if (mMouseAction == MA_SprayField)
{
mTringuRep->EndSprayField();
}
}
void TringuCam::CalculateMouseRayVectors()
{
mPupilInfo->TransformMouseRayVectors(*mTringula, mMouseRayPos, mMouseRayDir);
}
void TringuCam::MouseRayCollide()
{
Opcode::Ray ray(mMouseRayPos, mMouseRayDir);
mRayColl.SetMaxDist(mRayLength > 0 ? mRayLength : Opcode::MAX_FLOAT);
Bool_t status = mRayColl.Collide(ray, *mTringula->GetMesh()->GetOPCModel());
if (bMouseVerbose)
printf("TringuCam::MouseRayCollide status=%d, n_faces=%d\n",
status, mCollFaces.GetNbFaces());
if (status && mCollFaces.GetNbFaces() > 0)
{
using namespace Opcode;
const CollisionFace& cf = mCollFaces.GetFaces()[0];
if (bMouseVerbose)
printf(" fc=%6d d=%7.3f u=%7.3f v=%7.3f\n",
cf.mFaceID, cf.mDistance, cf.mU, cf.mV);
TringTvor& TT = * mTringula->GetMesh()->GetTTvor();
Int_t *t = TT.Triangle(cf.mFaceID);
Float_t *v0 = TT.Vertex(t[0]);
Float_t *v1 = TT.Vertex(t[1]);
Float_t *v2 = TT.Vertex(t[2]);
Point e1(v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]);
Point e2(v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]);
mCollFace = cf;
mCollPoint.Set(v0); mCollPoint += cf.mU*e1 + cf.mV*e2;
Int_t ci = (cf.mU + cf.mV <= 0.5) ? 0 : (cf.mU >= cf.mV) ? 1 : 2;
mCollVertex = t[ci];
if (bMouseVerbose)
printf(" x=%7.3f y=%7.3f z=%7.3f closest index=%d vertex=%d\n",
mCollPoint.x, mCollPoint.y, mCollPoint.z, ci, mCollVertex);
}
else
{
mCollVertex = -1;
}
}
void TringuCam::TimeTick(Double_t t, Double_t dt)
{
mFwdBck.TimeTick(dt);
if (mFwdBck.fValue) MoveLF(1, dt*mFwdBck.fValue);
mLftRgt.TimeTick(dt);
if (mLftRgt.fValue) MoveLF(2, dt*mLftRgt.fValue);
mUpDown.TimeTick(dt);
if (mUpDown.fValue) mHeight += dt*mUpDown.fValue;
if (mHeight > mTringula->GetMaxCameraH())
mHeight = mTringula->GetMaxCameraH();
mSpinUp.TimeTick(dt);
if (mSpinUp.fValue) RotateLF(1, 2, dt*mSpinUp.fValue);
{
Float_t pos[3], fgh[3], hdir[3];
mTrans.GetPos(pos);
mTringula->GetParaSurf()->pos2fgh (pos, fgh);
mTringula->GetParaSurf()->fgh2hdir(fgh, hdir);
mTrans.SetBaseVec(3, hdir);
mTrans.OrtoNorm3Column(1, 3);
mTrans.SetBaseVecViaCross(2);
mTrans.MoveLF(3, mHeight - fgh[2]);
}
if (*mInfoTxt != 0)
mInfoTxt->SetText
(GForm("FWD: + %5.2f | %+5.2f | - %5.2f || "
"LFT: + %5.2f | %+5.2f | - %5.2f || "
" UP: + %5.2f | %+5.2f | - %5.2f",
mFwdBck.fIncKey.fDesiredValue, mFwdBck.fValue, mFwdBck.fDecKey.fDesiredValue,
mLftRgt.fIncKey.fDesiredValue, mLftRgt.fValue, mLftRgt.fDecKey.fDesiredValue,
mUpDown.fIncKey.fDesiredValue, mUpDown.fValue, mUpDown.fDecKey.fDesiredValue));
if (bMouseDown && mMouseAction == MA_SprayField && mTringuRep->GetField() != 0)
{
CalculateMouseRayVectors();
MouseRayCollide();
mTringuRep->AddField(mCollPoint, mCollVertex, dt);
}
if (mStampInterval && --mStampCount < 0)
{
mStampCount = mStampInterval;
Stamp();
}
}
void
TringuCam::ValueInfo::IncValue(Float_t& value, Float_t desire,
Float_t step, Float_t delta_fac)
{
if (value < desire)
{
if (delta_fac) step += delta_fac*(desire - value);
value += step;
if (value > desire) value = desire;
}
}
void
TringuCam::ValueInfo::DecValue(Float_t& value, Float_t desire,
Float_t step, Float_t delta_fac)
{
desire = -desire;
if (value > desire)
{
if (delta_fac) step += delta_fac*(value - desire);
value -= step;
if (value < desire) value = desire;
}
}
void
TringuCam::ValueInfo::DecayValue(Float_t& value, Float_t decay,
Float_t delta_fac)
{
if (value > 0)
{
if (delta_fac) decay += delta_fac*value;
if (value > decay) value -= decay;
else value = 0;
}
else
{
if (delta_fac) decay -= delta_fac*value;
if (-value > decay) value += decay;
else value = 0;
}
}
void
TringuCam::ValueInfo::DecayTimeoutOrValue(Float_t& timeout, Float_t& value,
Float_t dt, Float_t decay,
Float_t delta_fac)
{
if (timeout != 0)
DecayValue(timeout, dt);
else if (value != 0)
DecayValue(value, decay, delta_fac);
}
void
TringuCam::ValueInfo::ApproachValue(Float_t& value, Float_t desire,
Float_t inc_step, Float_t inc_delta_fac,
Float_t dec_step, Float_t dec_delta_fac)
{
if (value < desire)
IncValue(value, desire, inc_step, inc_delta_fac);
else if (value > desire)
DecValue(value, -desire, dec_step, dec_delta_fac);
}
void TringuCam::ValueInfo::TimeTick(Float_t dt)
{
KeyValueChangeParams& C = * fChangeParams;
Float_t val_acc = dt*C.fValueAccel;
Float_t val_acc_dfac = dt*C.fValueAccelDeltaFactor;
Float_t val_decay = dt*C.fValueDecay;
Float_t val_decay_dfac = dt*C.fValueDecayDeltaFactor;
Float_t des_decay = dt*C.fDesireDecay;
Float_t des_decay_dfac = dt*0.1;
if (fSustain)
{
if (fIncKey.fIsDown && fDecKey.fIsDown)
{
}
else if ( ! fIncKey.fIsDown && ! fDecKey.fIsDown)
{
ApproachValue(fValue, fSustainDesire, val_acc, val_acc_dfac, val_decay, val_decay_dfac);
DecayTimeoutOrValue(fIncKey.fDecayTimeout, fIncKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
DecayTimeoutOrValue(fDecKey.fDecayTimeout, fDecKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
else
{
if (fIncKey.fIsDown)
{
ApproachValue(fValue, fMaxValue, val_acc, val_acc_dfac, val_decay, val_decay_dfac);
DecayTimeoutOrValue(fDecKey.fDecayTimeout, fDecKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
else
{
ApproachValue(fValue, fMinValue, val_acc, val_acc_dfac, val_decay, val_decay_dfac);
DecayTimeoutOrValue(fIncKey.fDecayTimeout, fIncKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
}
}
else
{
if (fIncKey.fIsDown && fDecKey.fIsDown)
{
if (fValue != 0) DecayValue(fValue, val_decay+val_acc, val_decay_dfac+val_acc_dfac);
}
else if ( ! fIncKey.fIsDown && ! fDecKey.fIsDown)
{
DecayTimeoutOrValue(fDecayTimeout, fValue, dt, val_decay, val_decay_dfac);
DecayTimeoutOrValue(fIncKey.fDecayTimeout, fIncKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
DecayTimeoutOrValue(fDecKey.fDecayTimeout, fDecKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
else
{
if (fIncKey.fIsDown)
{
IncValue(fValue, fIncKey.fDesiredValue, val_acc, val_acc_dfac);
DecayTimeoutOrValue(fDecKey.fDecayTimeout, fDecKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
else
{
DecValue(fValue, fDecKey.fDesiredValue, val_acc, val_acc_dfac);
DecayTimeoutOrValue(fIncKey.fDecayTimeout, fIncKey.fDesiredValue,
dt, des_decay, des_decay_dfac);
}
}
}
}
void TringuCam::ExtendioDetails(Extendio* ext)
{
if (ext)
ext->Dump();
}
void TringuCam::ExtendioExplode(Extendio* ext)
{
static const Exc_t _eh("TringuCam::ExtendioExplode ");
printf("Extendio '%s' exploding at your command!\n", ext->GetName());
ext->TakeDamage(1000);
}
void TringuCam::PrepConnectStatos(Statico* stato, Int_t id, const TString& grad)
{
SetPrepBeta(stato);
mExpectBeta = EB_ConnectStaticos;
mGradName = grad;
}
void TringuCam::Suspend()
{
mEventor->Stop();
mPupilInfo->SetAutoRedraw(true);
}
void TringuCam::Resume()
{
mTimeMaker->SetLastTOK(false);
mPupilInfo->SetAutoRedraw(false);
mEventor->Start();
}
namespace {
const char* help_text =
"\n"
"================================================================================\n"
"HELP FOR GREED-WORLD TECH-DEMO\n"
"================================================================================\n"
"Movement keys\n"
"--------------------------------------------------------------------------------\n"
"w, s - move forward / backward\n"
"q, e - turn left / right\n"
"a, d - move left / right\n"
"r, f - move up / down\n"
"Press a key several times to move faster.\n"
"================================================================================\n"
"Mouse buttons\n"
"--------------------------------------------------------------------------------\n"
"Mouse-1 - select objects\n"
"Mouse-2 - rotate up/down, left/right\n"
"Number-widgets can be manipulated by Mouse-drag (M2 - x10, M3 - x100)\n"
"================================================================================\n"
"Camera / screen controls\n"
"--------------------------------------------------------------------------------\n"
"Home - look horizontally / return camera home\n"
"Ctrl-F12 - fullscreen mode\n"
"Ctrl-` - go to native gled event handling (or switch back)\n"
"--------------------------------------------------------------------------------\n";
}
void TringuCam::Help()
{
fputs(help_text, stdout);
}
#include <Glasses/ZVector.h>
void TringuCam::RandomStatico()
{
static const Exc_t _eh("TringuCam::RandomStatico ");
ZVector *statos = dynamic_cast<ZVector*>
(mQueen->FindLensByPath("var/meshes/rndstatos"));
if (!statos)
throw _eh + "stato-mesh vector not found.";
GLensReadHolder _tlck(*mTringula);
Statico* s = mTringula->RandomStatico(statos);
if (s == 0)
throw _eh + "placement seems to have failed.";
else
printf("%screated '%s'\n", _eh.Data(), s->GetName());
}
void TringuCam::MakeLandMark()
{
if (mMouseAction != MA_NewLandMark)
mPrevAction = mMouseAction;
mMouseAction = MA_NewLandMark;
Stamp(FID());
}