You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

478 lines
13 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
#include "HeadSpin.h"
#include "plCameraModifier.h"
#include "plCameraBrain.h"
#include "plVirtualCamNeu.h"
#include "hsTimer.h"
#include "plgDispatch.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../plMessage/plInputEventMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../pnMessage/plTimeMsg.h"
#include "../pnKeyedObject/plKey.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../plInputCore/plInputDevice.h"
#include "../plInputCore/plInputManager.h"
#include "hsResMgr.h"
#include "../pnMessage/plCameraMsg.h"
#include "../plPhysical/plSimDefs.h"
#include "plPhysical.h"
#include "../pnSceneObject/plSimulationInterface.h"
#include "../plAvatar/plAvatarMgr.h"
#include "../plAvatar/plArmatureMod.h"
#include "../plAvatar/plAvCallbackAction.h"
// new stuff
plCameraModifier1::plCameraModifier1() :
fBrain(nil),
fSubObj(nil),
fFOVw(45.0f),
fFOVh(33.75f),
fAnimated(false),
fStartAnimOnPush(false),
fStopAnimOnPop(false),
fResetAnimOnPop(false),
fInSubLastUpdate(false),
fUpdateBrainTarget(false)
{
fFrom.Set(0,0,0);
fAt.Set(0,1,0);
}
plCameraModifier1::~plCameraModifier1()
{
int i;
for (i = 0; i < GetNumTrans(); i++)
delete(GetTrans(i));
fTrans.SetCountAndZero(0);
for (i = 0; i < fMessageQueue.Count(); i++)
hsRefCnt_SafeUnRef(fMessageQueue[i]);
fMessageQueue.SetCountAndZero(0);
for (i = 0; i < fFOVInstructions.Count(); i++)
hsRefCnt_SafeUnRef(fFOVInstructions[i]);
fFOVInstructions.SetCountAndZero(0);
}
void plCameraModifier1::AddTarget(plSceneObject* so)
{
fTarget = so;
if( plVirtualCam1::Instance() )
plVirtualCam1::Instance()->AddCameraLoaded(so);
fFrom = (so->GetWorldToLocal().GetTranslate());
if (GetBrain())
{
if (fTarget->GetCoordinateInterface())
GetBrain()->AddTarget();
else
fUpdateBrainTarget = true; // update the brain later
}
if (GetKey())
{
plgDispatch::Dispatch()->RegisterForExactType(plEvalMsg::Index(), GetKey());
}
}
void plCameraModifier1::SetSubject(plSceneObject* pObj)
{
if (GetBrain())
GetBrain()->SetSubject(pObj);
else
fSubObj = pObj;
}
plSceneObject* plCameraModifier1::GetSubject()
{
if (GetBrain())
return GetBrain()->GetSubject();
else
return fSubObj;
}
void plCameraModifier1::SetFOVw(hsScalar f, hsBool fUpdateVCam)
{
fFOVw = f;
if (plVirtualCam1::Instance() && fUpdateVCam)
plVirtualCam1::SetFOV(fFOVw, fFOVh, this);
}
void plCameraModifier1::SetFOVh(hsScalar f, hsBool fUpdateVCam)
{
fFOVh = f;
if (plVirtualCam1::Instance() && fUpdateVCam)
plVirtualCam1::SetFOV(fFOVw, fFOVh, this);
}
hsBool plCameraModifier1::SetFaded(hsBool b)
{
if (GetBrain())
return GetBrain()->SetFaded(b);
return false;
}
hsBool plCameraModifier1::GetFaded()
{
if (GetBrain())
return GetBrain()->GetFaded();
return false;
}
hsBool plCameraModifier1::MsgReceive(plMessage* msg)
{
if (GetBrain())
GetBrain()->MsgReceive(msg);
plCameraMsg* pCamMsg = plCameraMsg::ConvertNoRef(msg);
if (pCamMsg)
{
if (pCamMsg->Cmd(plCameraMsg::kAddFOVKeyframe))
{
hsRefCnt_SafeRef(msg);
fFOVInstructions.Append(pCamMsg);
return true;
}
else
if (pCamMsg->Cmd(plCameraMsg::kSetAnimated))
{
fAnimated = true;
return true;
}
}
plEventCallbackMsg* pEventMsg = plEventCallbackMsg::ConvertNoRef(msg);
if (pEventMsg)
{
double time = (double)fFOVInstructions[pEventMsg->fIndex]->GetConfig()->fAccel;
double time2 = (double)pEventMsg->fEventTime;
time = hsABS(time - time2);
hsScalar h = fFOVInstructions[pEventMsg->fIndex]->GetConfig()->fFOVh;
if (GetBrain())
GetBrain()->SetFOVGoal(h, time);
}
plAnimCmdMsg* pAnimMsg = plAnimCmdMsg::ConvertNoRef(msg);
if (pAnimMsg)
{
hsRefCnt_SafeRef(msg);
msg->ClearReceivers();
msg->AddReceiver(msg->GetSender());
fMessageQueue.Append(msg);
return true;
}
plGenRefMsg* pRefMsg = plGenRefMsg::ConvertNoRef(msg);
if (pRefMsg )
{
if( pRefMsg->GetContext() & (plRefMsg::kOnCreate | plRefMsg::kOnRequest) )
{
if (pRefMsg->fType == kRefBrain)
{
plCameraBrain1* pBrain = plCameraBrain1::ConvertNoRef(pRefMsg->GetRef());
if (pBrain)
{
pBrain->SetCamera(this);
fBrain = pBrain;
if (fSubObj)
fBrain->SetSubject(fSubObj);
}
}
else
if (pRefMsg->fType == kRefCallbackMsg && fMessageQueue[pRefMsg->fWhich] != nil)
{
plgDispatch::MsgSend(fMessageQueue[pRefMsg->fWhich]);
fMessageQueue[pRefMsg->fWhich] = nil;
}
}
else if( pRefMsg->GetContext() & (plRefMsg::kOnDestroy | plRefMsg::kOnRemove) )
{
plCameraBrain1* pBrain = (plCameraBrain1*)(pRefMsg->GetRef());
if (fBrain == pBrain)
fBrain = nil;
}
return true;
}
return plSingleModifier::MsgReceive(msg);
}
void plCameraModifier1::Update()
{
// update the brain
// this freeze thing is a useful debugging tool...
if (plVirtualCam1::Instance()->freeze)
return;
if (GetBrain())
{
if (fUpdateBrainTarget && fTarget->GetCoordinateInterface()) // if we need to update the brain and the target is loaded
{
fUpdateBrainTarget = false;
GetBrain()->AddTarget(); // update the brain's target
}
hsBool moveInSub = !(GetBrain()->HasFlag(plCameraBrain1::kIgnoreSubworldMovement));
if (moveInSub && GetBrain()->GetSubject())
{
plKey worldKey = nil;
// First check if this is a physical. If so, grab the subworld from that
if (GetBrain()->GetSubject()->GetSimulationInterface())
{
plPhysical* phys = GetBrain()->GetSubject()->GetSimulationInterface()->GetPhysical();
if (phys)
worldKey = phys->GetWorldKey();
}
// Also, check if this is an avatar. They don't have physicals, you
// have to ask the avatar controller for the subworld key.
if (!worldKey)
{
plArmatureMod* armMod = plAvatarMgr::FindAvatar(plKey(GetBrain()->GetSubject()->GetKey()));
if (armMod && armMod->GetController() )
worldKey = armMod->GetController()->GetSubworld();
}
if (worldKey)
{
// this picks up and moves the camera to it's previous subworld coordinate (so the subworld isn't moving out from underneath us)
hsMatrix44 l2w, w2l;
plSceneObject* so = plSceneObject::ConvertNoRef(worldKey->ObjectIsLoaded());
if (so)
{
l2w = so->GetLocalToWorld();
w2l = so->GetWorldToLocal();
if (fInSubLastUpdate)
{
if (!(fLastSubPos == fFrom && fLastSubPOA == fAt))
{
SetTargetPos(l2w * fLastSubPos);
SetTargetPOA(l2w * fLastSubPOA);
}
}
else
{
fInSubLastUpdate = true;
}
GetBrain()->Update();
fLastSubPos = w2l * GetTargetPos();
fLastSubPOA = w2l * GetTargetPOA();
}
return;
}
else
{
fInSubLastUpdate = false;
}
}
GetBrain()->Update();
fLastSubPos = GetTargetPos();
fLastSubPOA = GetTargetPOA();
}
}
void plCameraModifier1::Read(hsStream* stream, hsResMgr* mgr)
{
hsKeyedObject::Read(stream, mgr);
fBrain = nil;
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, 0, kRefBrain), plRefFlags::kActiveRef);
int count = stream->ReadSwap32();
int i;
for (i = 0; i < count; i++)
{
plKey key = mgr->ReadKey(stream);
hsBool cutpos = stream->ReadBool();
hsBool cutpoa = stream->ReadBool();
hsBool ignore = stream->ReadBool();
hsScalar v = stream->ReadSwapScalar();
hsScalar a = stream->ReadSwapScalar();
hsScalar d = stream->ReadSwapScalar();
hsScalar pV = stream->ReadSwapScalar();
hsScalar pA = stream->ReadSwapScalar();
hsScalar pD = stream->ReadSwapScalar();
CamTrans* camTrans = TRACKED_NEW CamTrans(key);
camTrans->fAccel = a;
camTrans->fDecel = d;
camTrans->fVelocity = v;
camTrans->fPOAAccel = pA;
camTrans->fPOADecel = pD;
camTrans->fPOAVelocity = pV;
camTrans->fCutPos = cutpos;
camTrans->fCutPOA = cutpoa;
camTrans->fIgnore = ignore;
fTrans.Append(camTrans);
}
fFOVw = stream->ReadSwapFloat();
fFOVh = stream->ReadSwapFloat();
int n = stream->ReadSwap32();
fMessageQueue.SetCountAndZero(n);
for(i = 0; i < n; i++ )
{
plMessage* pMsg = plMessage::ConvertNoRef(mgr->ReadCreatable(stream));
fMessageQueue[i] = pMsg;
}
for(i = 0; i < n; i++ )
{
mgr->ReadKeyNotifyMe(stream, TRACKED_NEW plGenRefMsg(GetKey(), plRefMsg::kOnCreate, i, kRefCallbackMsg), plRefFlags::kActiveRef);
}
n = stream->ReadSwap32();
fFOVInstructions.SetCountAndZero(n);
for(i = 0; i < n; i++ )
{
plCameraMsg* pMsg = plCameraMsg::ConvertNoRef(mgr->ReadCreatable(stream));
fFOVInstructions[i] = pMsg;
}
fAnimated = stream->ReadBool();
fStartAnimOnPush = stream->ReadBool();
fStopAnimOnPop = stream->ReadBool();
fResetAnimOnPop = stream->ReadBool();
}
void plCameraModifier1::Write(hsStream* stream, hsResMgr* mgr)
{
hsKeyedObject::Write(stream, mgr);
if (fBrain)
mgr->WriteKey(stream, fBrain );
int i = fTrans.Count();
stream->WriteSwap32(i);
for (i = 0; i < fTrans.Count(); i++)
{
mgr->WriteKey(stream, fTrans[i]->fTransTo);
stream->WriteBool(fTrans[i]->fCutPos);
stream->WriteBool(fTrans[i]->fCutPOA);
stream->WriteBool(fTrans[i]->fIgnore);
stream->WriteSwapScalar(fTrans[i]->fVelocity);
stream->WriteSwapScalar(fTrans[i]->fAccel);
stream->WriteSwapScalar(fTrans[i]->fDecel);
stream->WriteSwapScalar(fTrans[i]->fPOAVelocity);
stream->WriteSwapScalar(fTrans[i]->fPOAAccel);
stream->WriteSwapScalar(fTrans[i]->fPOADecel);
}
stream->WriteSwapFloat(fFOVw);
stream->WriteSwapFloat(fFOVh);
stream->WriteSwap32(fMessageQueue.Count());
for (i = 0; i < fMessageQueue.Count(); i++)
{
mgr->WriteCreatable(stream, fMessageQueue[i]);
}
for (i = 0; i < fMessageQueue.Count(); i++)
{
mgr->WriteKey(stream, fMessageQueue[i]->GetSender());
}
stream->WriteSwap32(fFOVInstructions.Count());
for (i = 0; i < fFOVInstructions.Count(); i++)
{
mgr->WriteCreatable(stream, fFOVInstructions[i]);
}
stream->WriteBool(fAnimated);
stream->WriteBool(fStartAnimOnPush);
stream->WriteBool(fStopAnimOnPop);
stream->WriteBool(fResetAnimOnPop);
}
void plCameraModifier1::Push(hsBool recenter)
{
if (fAnimated)
{
if (fStartAnimOnPush)
{
plAnimCmdMsg* pMsg = TRACKED_NEW plAnimCmdMsg;
pMsg->SetCmd(plAnimCmdMsg::kRunForward);
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
pMsg->AddReceiver(GetTarget()->GetKey());
if (GetBrain() && GetBrain()->GetSubject())
pMsg->AddReceiver(GetBrain()->GetSubject()->GetKey());
pMsg->Send();
}
}
if (fBrain)
fBrain->Push(recenter);
if (GetKey())
{
plgDispatch::Dispatch()->RegisterForExactType(plMouseEventMsg::Index(), GetKey());
}
}
void plCameraModifier1::Pop()
{
if (fAnimated)
{
if (fStopAnimOnPop)
{
plAnimCmdMsg* pMsg = TRACKED_NEW plAnimCmdMsg;
pMsg->SetCmd(plAnimCmdMsg::kStop);
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
pMsg->AddReceiver(GetTarget()->GetKey());
if (GetBrain() && GetBrain()->GetSubject())
pMsg->AddReceiver(GetBrain()->GetSubject()->GetKey());
pMsg->Send();
}
if (fResetAnimOnPop)
{
plAnimCmdMsg* pMsg = TRACKED_NEW plAnimCmdMsg;
pMsg->SetCmd(plAnimCmdMsg::kGoToBegin);
pMsg->SetBCastFlag(plMessage::kPropagateToModifiers);
pMsg->AddReceiver(GetTarget()->GetKey());
if (GetBrain() && GetBrain()->GetSubject())
pMsg->AddReceiver(GetBrain()->GetSubject()->GetKey());
pMsg->Send();
}
}
if (fBrain)
fBrain->Pop();
if (GetKey()) // the reason we might not have a key is a special run-time POA which doesn't need to receive messages...
{
plgDispatch::Dispatch()->UnRegisterForExactType(plMouseEventMsg::Index(), GetKey());
}
}
void plCameraModifier1::SetTransform(hsPoint3 at)
{
if (!GetTarget())
return;
hsMatrix44 l2w;
hsMatrix44 w2l;
hsVector3 up(0,0,1);
l2w.Make(&fFrom, &at, &up);
l2w.GetInverse(&w2l);
IGetTargetCoordinateInterface(0)->SetTransform( l2w, w2l );
}