// Copyright (C) 2002-2010 Nikolaus Gebhardt
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
#include "cameraControler.h"
#include "IVideoDriver.h"
#include "ISceneManager.h"
#include "Keycodes.h"
#include "ICursorControl.h"
#include "ISceneNodeAnimatorCollisionResponse.h"
#include "ISceneCollisionManager.h"
namespace irr
{
namespace scene
{
//! constructor
CameraControler::CameraControler(gui::ICursorControl* cursorControl,
ISceneManager * smgr, f32 rotateSpeed, bool invertY)
: CursorControl(cursorControl), MaxVerticalAngle(88.0f), manager(smgr),
RotateSpeed(rotateSpeed),MouseYDirection(invertY ? -1.0f : 1.0f),camera(0),
LastAnimationTime(0), firstUpdate(true), hasPressedDown(false),
directionPrepared(false), useLeftMouse(false)
{
#ifdef _DEBUG
setDebugName("CameraControler");
#endif
if (CursorControl)
CursorControl->grab();
}
//! destructor
CameraControler::~CameraControler()
{
if (CursorControl)
CursorControl->drop();
}
//! It is possible to send mouse and key events to the camera. Most cameras
//! may ignore this input, but camera scene nodes which are created for
//! example with scene::ISceneManager::addMayaCameraSceneNode or
//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input
//! for changing their position, look at target or whatever.
bool CameraControler::OnEvent(const SEvent& evt)
{
if(evt.EventType == EET_MOUSE_INPUT_EVENT)
{
if (evt.MouseInput.Event == EMIE_RMOUSE_PRESSED_DOWN)
{
now = then = CursorControl->getPosition();
video::IVideoDriver* driver = manager->getVideoDriver();
core::rect<s32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
hasPressedDown = screenRect.isPointInside(then);
directionPrepared = false;
return true;
}
if (evt.MouseInput.Event == EMIE_MOUSE_MOVED)
{
if (hasPressedDown)
{
then = now;
now = CursorControl->getPosition();
video::IVideoDriver* driver = manager->getVideoDriver();
core::rect<s32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
directionPrepared = screenRect.isPointInside(now);
if (useLeftMouse)
{
// 是否选中魔方
ISceneCollisionManager* collMan = manager->getSceneCollisionManager();
core::line3df ray = collMan->getRayFromScreenCoordinates(now, camera);
scene::ISceneNode * selectedSceneNode = collMan->getSceneNodeFromRayBB(ray);
int id = -1;
if (selectedSceneNode)
id = selectedSceneNode->getID();
if (id != -1)
useLeftMouse = directionPrepared = hasPressedDown = false;
}
}
return true;
}
if (evt.MouseInput.Event == EMIE_RMOUSE_LEFT_UP)
{
directionPrepared = hasPressedDown = false;
return true;
}
if (evt.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN)
{
if (camera == NULL)
return true;
now = then = CursorControl->getPosition();
// 是否选中魔方
ISceneCollisionManager* collMan = manager->getSceneCollisionManager();
core::line3df ray = collMan->getRayFromScreenCoordinates(now, camera);
scene::ISceneNode * selectedSceneNode = collMan->getSceneNodeFromRayBB(ray);
int id = -1;
if (selectedSceneNode)
id = selectedSceneNode->getID();
// 是否在视口内
video::IVideoDriver* driver = manager->getVideoDriver();
core::rect<s32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
useLeftMouse = hasPressedDown = screenRect.isPointInside(then) && id == -1;
directionPrepared = false;
return true;
}
if (evt.MouseInput.Event == EMIE_LMOUSE_LEFT_UP)
{
if (useLeftMouse)
useLeftMouse = directionPrepared = hasPressedDown = false;
return true;
}
if (evt.MouseInput.Event == EMIE_MOUSE_WHEEL)
{
if (evt.MouseInput.Wheel > 0)
camera->setPosition(camera->getPosition() * 0.9);
else
camera->setPosition(camera->getPosition() * 1.1);
return true;
}
}
return false;
}
void CameraControler::animateNode(ISceneNode* node, u32 timeMs)
{
if (!node || node->getType() != ESNT_CAMERA)
return;
camera = static_cast<ICameraSceneNode*>(node);
if (firstUpdate)
{
camera->updateAbsolutePosition();
firstUpdate = false;
}
// If the camera isn't the active camera, and receiving input, then don't process it.
if(!camera->isInputReceiverEnabled())
return;
if(manager && manager->getActiveCamera() != camera)
return;
if (CursorControl && directionPrepared)
{
core::position2d<s32> move = now - then;
video::IVideoDriver* driver = manager->getVideoDriver();
core::vector3df rotate(0, 0, 0);
if (3 * core::abs_(move.X) > core::abs_(move.Y))
{
f32 angle = (move.X * RotateSpeed) / driver->getScreenSize().Width;
rotate.Y = angle;
}
else
{
f32 angle = (move.Y * RotateSpeed) / driver->getScreenSize().Height;
bool XisPositive = camera->getPosition().X > 0;
bool ZisPositive = camera->getPosition().Z > 0;
bool atLelf = now.X * 2 < driver->getScreenSize().Width;
if ((XisPositive + ZisPositive + atLelf) % 2)
rotate.Z = XisPositive ? 1 : -1;
else
rotate.X = ZisPositive ? -1 : 1;
// 修正角度
core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
core::vector3df relativeRotation = target.getHorizontalAngle();
f32 MaxVerticalAngle = 88;
f32 deg = (rotate.X + rotate.Z) * (relativeRotation.dotProduct(rotate) + angle);
if (deg> MaxVerticalAngle * 2 && deg < 360.0f-MaxVerticalAngle)
deg = 360.0f-MaxVerticalAngle;
else if (deg > MaxVerticalAngle && deg < 360.0f-MaxVerticalAngle)
deg = MaxVerticalAngle;
angle = deg * (rotate.X + rotate.Z) - relativeRotation.dotProduct(rotate);
rotate *= angle;
}
camera->setPosition(rotate.rotationToDirection(camera->getPosition()));
camera->setTarget(rotate.rotationToDirection(camera->getTarget()));
}
}
//! Sets the rotation speed
void CameraControler::setRotateSpeed(f32 speed)
{
RotateSpeed = speed;
}
//! Gets the rotation speed
f32 CameraControler::getRotateSpeed() const
{
return RotateSpeed;
}
//! Sets whether the Y axis of the mouse should be inverted.
void CameraControler::setInvertMouse(bool invert)
{
if (invert)
MouseYDirection = -1.0f;
else
MouseYDirection = 1.0f;
}
ISceneNodeAnimator* CameraControler::createClone(ISceneNode* node, ISceneManager* newManager)
{
CameraControler * newAnimator =
new CameraControler(CursorControl, manager, RotateSpeed, core::iszero(MouseYDirection + 1.0f));
return newAnimator;
}
} // namespace scene
} // namespace irr
- 1
- 2
前往页