#include "CSceneNodeAnimatorCameraFPS.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "Keycodes.h"
#include "ICursorControl.h"
#include "ICameraSceneNode.h"
#include "ISceneNodeAnimatorCollisionResponse.h"
namespace irr
{
namespace scene
{
CSceneNodeAnimatorCameraFPS::CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl,
f32 rotateSpeed, f32 moveSpeed, f32 jumpSpeed,
SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement, bool invertY)
: CursorControl(cursorControl), MaxVerticalAngle(88.0f),
MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed),
MouseYDirection(invertY ? -1.0f : 1.0f),
LastAnimationTime(0), firstUpdate(true), NoVerticalMovement(noVerticalMovement)
{
#ifdef _DEBUG
setDebugName("CCameraSceneNodeAnimatorFPS");
#endif
if (CursorControl)
CursorControl->grab();
allKeysUp();
if (!keyMapArray || !keyMapSize)
{
KeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP));
KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN));
KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT));
KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT));
KeyMap.push_back(SCamKeyMap(EKA_JUMP_UP, irr::KEY_KEY_J));
}
else
{
setKeyMap(keyMapArray, keyMapSize);
}
}
CSceneNodeAnimatorCameraFPS::~CSceneNodeAnimatorCameraFPS()
{
if (CursorControl)
CursorControl->drop();
}
bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt)
{
switch(evt.EventType)
{
case EET_KEY_INPUT_EVENT:
for (u32 i=0; i<KeyMap.size(); ++i)
{
if (KeyMap[i].keycode == evt.KeyInput.Key)
{
CursorKeys[KeyMap[i].action] = evt.KeyInput.PressedDown;
return true;
}
}
break;
case EET_MOUSE_INPUT_EVENT:
if (evt.MouseInput.Event == EMIE_MOUSE_MOVED)
{
CursorPos = CursorControl->getRelativePosition();
return true;
}
break;
default:
break;
}
return false;
}
void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs)
{
if (!node || node->getType() != ESNT_CAMERA)
return;
ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
if (firstUpdate)
{
camera->updateAbsolutePosition();
if (CursorControl && camera)
{
CursorControl->setPosition(0.5f, 0.5f);
CursorPos = CenterCursor = CursorControl->getRelativePosition();
}
LastAnimationTime = timeMs;
firstUpdate = false;
}
if(!camera->isInputReceiverEnabled())
return;
scene::ISceneManager * smgr = camera->getSceneManager();
if(smgr && smgr->getActiveCamera() != camera)
return;
f32 timeDiff = (f32) ( timeMs - LastAnimationTime );
LastAnimationTime = timeMs;
core::vector3df pos = camera->getPosition();
core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
core::vector3df relativeRotation = target.getHorizontalAngle();
if (CursorControl)
{
if (CursorPos != CenterCursor)
{
relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed;
relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection;
if (relativeRotation.X > MaxVerticalAngle*2 &&
relativeRotation.X < 360.0f-MaxVerticalAngle)
{
relativeRotation.X = 360.0f-MaxVerticalAngle;
}
else
if (relativeRotation.X > MaxVerticalAngle &&
relativeRotation.X < 360.0f-MaxVerticalAngle)
{
relativeRotation.X = MaxVerticalAngle;
}
CursorControl->setPosition(0.5f, 0.5f);
CenterCursor = CursorControl->getRelativePosition();
CursorPos = CenterCursor;
}
video::IVideoDriver* driver = smgr->getVideoDriver();
core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
bool reset = !screenRect.isPointInside(mousepos);
if(reset)
{
CursorControl->setPosition(0.5f, 0.5f);
CenterCursor = CursorControl->getRelativePosition();
CursorPos = CenterCursor;
}
}
target.set(0,0, core::max_(1.f, pos.getLength()));
core::vector3df movedir = target;
core::matrix4 mat;
mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
mat.transformVect(target);
if (NoVerticalMovement)
{
mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
mat.transformVect(movedir);
}
else
{
movedir = target;
}
movedir.normalize();
if (CursorKeys[EKA_MOVE_FORWARD])
pos += movedir * timeDiff * MoveSpeed;
if (CursorKeys[EKA_MOVE_BACKWARD])
pos -= movedir * timeDiff * MoveSpeed;
core::vector3df strafevect = target;
strafevect = strafevect.crossProduct(camera->getUpVector());
if (NoVerticalMovement)
strafevect.Y = 0.0f;
strafevect.normalize();
if (CursorKeys[EKA_STRAFE_LEFT])
pos += strafevect * timeDiff * MoveSpeed;
if (CursorKeys[EKA_STRAFE_RIGHT])
pos -= strafevect * timeDiff * MoveSpeed;
if (CursorKeys[EKA_JUMP_UP])
{
const ISceneNodeAnimatorList& animators = camera->getAnimators();
ISceneNodeAnimatorList::ConstIterator it = animators.begin();
while(it != animators.end())
{
if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
{
ISceneNodeAnimatorCollisionResponse * collisionResponse =
static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
if(!collisionResponse->isFalling())
collisionResponse->jump(JumpSpeed);
}
it++;
}
}
camera->setPosition(pos);
target += pos;
camera->setTarget(target);
}
void CSceneNodeAnimatorCameraFPS::allKeysUp()
{
for (u32 i=0; i<6; ++i)
CursorKeys[i] = false;
}
void CSceneNodeAnimatorCameraFPS::setRotateSpeed(f32 speed)
{
RotateSpeed = speed;
}
void CSceneNodeAnimatorCameraFPS::setMoveSpeed(f32 speed)
{
MoveSpeed = speed;
}
f32 CSceneNodeAnimatorCameraFPS::getRotateSpeed() const
{
return RotateSpeed;
}
f32 CSceneNodeAnimatorCameraFPS::getMoveSpeed() const
{
return MoveSpeed;
}
void CSceneNodeAnimatorCameraFPS::setKeyMap(SKeyMap *map, u32 count)
{
KeyMap.clear();
for (u32 i=0; i<count; ++i)
{
switch(map[i].Action)
{
case EKA_MOVE_FORWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, map[i].KeyCode));
break;
case EKA_MOVE_BACKWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, map[i].KeyCode));
break;
case EKA_STRAFE_LEFT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, map[i].KeyCode));
break;
case EKA_STRAFE_RIGHT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, map[i].KeyCode));
break;
case EKA_JUMP_UP: KeyMap.push_back(SCamKeyMap(EKA_JUMP_UP, map[i].KeyCode));
break;
default:
break;
}
}
}
void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow)
{
NoVerticalMovement = !allow;
}
void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert)
{
if (invert)
MouseYDirection = -1.0f;
else
MouseYDirection = 1.0f;
}
ISceneNodeAnimator* CSceneNodeAnimatorCameraFPS::createClone(ISceneNode* node, ISceneManager* newManager)
{
CSceneNodeAnimatorCameraFPS * newAnimator =
new CSceneNodeAnimatorCameraFPS(CursorControl, RotateSpeed, MoveSpeed, JumpSpeed,
0, 0, NoVerticalMovement);
newAnimator->setKeyMap(KeyMap);
return newAnimator;
}
void CSceneNodeAnimatorCameraFPS::setKeyMap(const core::array<SCamKeyMap>& keymap)
{
KeyMap=keymap;
}
}
}