It is still unfinished, but useable. On my todo list are adding possibility to rotate camera along up axis, and adding possibility to zoom/pan camera around cursor.
Code: Select all
// Controls :
// Mouse middle + Mouse move = move camera
// Mouse pointer X/Y at border = move camera
// Mouse wheel up/down = zoom camera
Code: Select all
irr::scene::ICameraSceneNode* node = smgr->addCameraSceneNode(0, irr::core::vector3df(0,0,0), irr::core::vector3df(0,0,0));
irr::scene::ISceneNodeAnimatorCameraRTS* animator = new irr::scene::CSceneNodeAnimatorCameraRTS(device->getCursorControl(),device->getTimer());
node->addAnimator(animator);
animator->drop();
Code: Select all
#ifndef __I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
#define __I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
namespace irr
{
namespace scene
{
class ISceneNodeAnimator;
//! A scene node animator for RTS-style camera
class ISceneNodeAnimatorCameraRTS : public ISceneNodeAnimator
{
public:
//! Returns the speed of movement
virtual f32 getMoveSpeed() const = 0;
//! Sets the speed of movement
virtual void setMoveSpeed(f32 moveSpeed) = 0;
//! Returns the rotation speed
virtual f32 getRotateSpeed() const = 0;
//! Set the rotation speed
virtual void setRotateSpeed(f32 rotateSpeed) = 0;
//! Returns the zoom speed
virtual f32 getZoomSpeed() const = 0;
//! Set the zoom speed
virtual void setZoomSpeed(f32 zoomSpeed) = 0;
//! Returns the camera zoom
virtual f32 getZoom() const = 0;
//! Set the camera zoom
virtual void setZoom(f32 multiplier) = 0;
//! Returns the current distance, i.e. orbit radius
virtual f32 getDistance() const = 0;
//! Set the distance
virtual void setDistance(f32 dist) = 0;
//! Get the camera angle
virtual f32 getAngle() const = 0;
//! Set the camera angle
virtual void setAngle(f32 a) = 0;
//! Get the camera angle for close zoom
virtual f32 getAngleClose() const = 0;
//! Set the camera angle
virtual void setAngleClose(f32 a) = 0;
};
} // end namespace scene
} // end namespace irr
#endif //__I_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
Code: Select all
// This is an extension for the "Irrlicht Engine".
// See copyright notice in irrlicht.h
#ifndef __C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
#define __C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
#include "irrlicht.h"
#include "ISceneNodeAnimatorCameraRTS.h"
namespace irr
{
namespace gui
{
class ICursorControl;
}
namespace scene
{
//! Scene node animator for RTS cameras
class CSceneNodeAnimatorCameraRTS : public ISceneNodeAnimatorCameraRTS
{
public:
//! Constructor
CSceneNodeAnimatorCameraRTS(gui::ICursorControl* cursor, ITimer* timer, f32 distance=36.055, f32 angle=0.9828, f32 angle_close=0.5880,
f32 translateSpeed = 0.01f, f32 rotateSpeed = 0.1f, f32 zoomSpeed=0.1f);
//! Destructor
virtual ~CSceneNodeAnimatorCameraRTS();
//! Animates the scene node, currently only works on cameras
virtual void animateNode(ISceneNode* node, u32 timeMs);
//! Event receiver
virtual bool OnEvent(const SEvent& event);
//! Returns the speed of movement
virtual f32 getMoveSpeed() const;
//! Sets the speed of movement
virtual void setMoveSpeed(f32 moveSpeed);
//! Returns the rotation speed
virtual f32 getRotateSpeed() const;
//! Set the rotation speed
virtual void setRotateSpeed(f32 rotateSpeed);
//! Returns the zoom speed
virtual f32 getZoomSpeed() const;
//! Set the zoom speed
virtual void setZoomSpeed(f32 zoomSpeed);
//! Returns the camera zoom
virtual f32 getZoom() const;
//! Set the camera zoom
virtual void setZoom(f32 multiplier);
//! Returns the current distance, i.e. orbit radius
virtual f32 getDistance() const;
//! Set the distance
virtual void setDistance(f32 dist);
//! Get the camera angle
virtual f32 getAngle() const;
//! Set the camera angle
virtual void setAngle(f32 a);
//! Get the camera angle for close zoom
virtual f32 getAngleClose() const;
//! Set the camera angle
virtual void setAngleClose(f32 a);
//! This animator will receive events when attached to the active camera
virtual bool isEventReceiverEnabled() const
{
return true;
}
//! Returns the type of this animator
virtual ESCENE_NODE_ANIMATOR_TYPE getType() const
{
return ESNAT_CAMERA_FPS;
}
//! Creates a clone of this animator.
/** Please note that you will have to drop
(IReferenceCounted::drop()) the returned pointer once you're
done with it. */
virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0);
private:
void allKeysUp();
void animate();
bool isMouseKeyDown(s32 key) const;
bool MouseKeys[3];
//bool MouseMiddleDown;
enum MOUSE_KEY
{
MOUSE_KEY_RIGHT,
MOUSE_KEY_MIDDLE,
MOUSE_KEY_LEFT
};
gui::ICursorControl *CursorControl;
ITimer* Timer;
u32 LastUpdate;
f32 distance;
f32 angle;
f32 angle_close;
core::position2df MousePos;
core::position2df MousePos_old;
f32 ZoomSpeed;
f32 RotateSpeed;
f32 TranslateSpeed;
f32 MinZoom;
f32 NewZoom;
f32 CurrentZoom;
f32 MaxZoom;
f32 RotZ;
f32 MaxRotZ;
bool Zooming;
bool Rotating;
bool Scrolling;
bool Scroll_lock;
bool Dragging;
};
} // end namespace scene
} // end namespace irr
#endif//__C_SCENE_NODE_ANIMATOR_CAMERA_RTS_H_INCLUDED__
Code: Select all
#include "CSceneNodeAnimatorCameraRTS.h"
#include "math.h"
namespace irr
{
namespace scene
{
CSceneNodeAnimatorCameraRTS::CSceneNodeAnimatorCameraRTS(gui::ICursorControl* cursor, f32 distance, f32 angle, f32 angle_close,
f32 translateSpeed, f32 rotateSpeed, f32 zoomSpeed)
: CursorControl(cursor), MousePos(0.5f, 0.5f), MousePos_old(0.5f, 0.5f),
ZoomSpeed(zoomSpeed), RotateSpeed(rotateSpeed), TranslateSpeed(translateSpeed),
Zooming(false), Rotating(false), Scrolling(false), Scroll_lock(false), Dragging(false),
MinZoom(0.2f), MaxZoom(5.f), NewZoom(1.0f), CurrentZoom(1.0f), RotZ(0.0f),
distance(), angle(angle), angle_close(angle_close)
{
if (CursorControl)
{
CursorControl->grab();
MousePos = CursorControl->getRelativePosition();
}
allKeysUp();
}
//! destructor
CSceneNodeAnimatorCameraRTS::~CSceneNodeAnimatorCameraRTS()
{
if (CursorControl)
{
CursorControl->drop();
}
}
bool CSceneNodeAnimatorCameraRTS::OnEvent(const SEvent& event)
{
//if (event.EventType != EET_MOUSE_INPUT_EVENT)
// return false;
switch(event.EventType)
{
case EET_MOUSE_INPUT_EVENT:
switch(event.MouseInput.Event)
{
case EMIE_MMOUSE_PRESSED_DOWN:
MouseKeys[1] = true;
break;
case EMIE_MMOUSE_LEFT_UP:
MouseKeys[1] = false;
break;
case EMIE_MOUSE_MOVED:
MousePos = CursorControl->getRelativePosition();
break;
case EMIE_MOUSE_WHEEL:
NewZoom -= event.MouseInput.Wheel * ZoomSpeed * (CurrentZoom / (MaxZoom * MinZoom));
break;
/*case EMIE_LMOUSE_PRESSED_DOWN:
case EMIE_RMOUSE_PRESSED_DOWN:
case EMIE_LMOUSE_LEFT_UP:
case EMIE_RMOUSE_LEFT_UP:
case EMIE_LMOUSE_DOUBLE_CLICK:
case EMIE_RMOUSE_DOUBLE_CLICK:
case EMIE_MMOUSE_DOUBLE_CLICK:
case EMIE_LMOUSE_TRIPLE_CLICK:
case EMIE_RMOUSE_TRIPLE_CLICK:
case EMIE_MMOUSE_TRIPLE_CLICK:
case EMIE_COUNT:*/
default:
return false;
}
break;
case EET_KEY_INPUT_EVENT:
/*for (u32 i=0; i<KeyMap.size(); ++i)
{
if (KeyMap[i].KeyCode == event.KeyInput.Key)
{
CursorKeys[KeyMap[i].Action] = event.KeyInput.PressedDown;
return true;
}
}
break;*/
default:
return false;
}
return true;
}
bool CSceneNodeAnimatorCameraRTS::isMouseKeyDown(s32 key) const
{
return MouseKeys[key];
}
void CSceneNodeAnimatorCameraRTS::allKeysUp()
{
for (s32 i=0; i<3; ++i)
MouseKeys[i] = false;
}
//! OnAnimate() is called just before rendering the whole scene.
void CSceneNodeAnimatorCameraRTS::animateNode(ISceneNode *node, u32 timeMs)
{
// Controls :
// Mouse middle + Mouse move = move camera
// Mouse pointer X/Y at border = move camera
// Mouse wheel up/down = zoom camera
if (!node || node->getType() != ESNT_CAMERA)
return;
ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
// If the camera isn't the active camera, and receiving input, then don't process it.
if (!camera->isInputReceiverEnabled())
return;
scene::ISceneManager * scnmgr = camera->getSceneManager();
if (scnmgr && scnmgr->getActiveCamera() != camera)
return;
if (!CursorControl)
{
return;
}
// Camera movement
core::vector3df pos = camera->getPosition();
core::vector3df target = camera->getTarget();
core::vector3df translate(0,0,0);
core::vector3df zoom_vector(0,distance*sin(angle),distance*cos(angle));
core::vector3df zoom_close(0,zoom_vector.Y - distance*sin(angle_close),zoom_vector.Z - distance*cos(angle_close));
//core::vector3df zoom_close(0,20,30);
//core::vector3df zoom_point(0,0,0);
if(isMouseKeyDown(MOUSE_KEY_MIDDLE) && !Zooming) //&& !Translating)
{
Dragging = true;
if(MousePos != MousePos_old)
{
translate.X += TranslateSpeed*(MousePos.X - MousePos_old.X)*scnmgr->getVideoDriver()->getScreenSize().Width * (CurrentZoom / (MaxZoom * MinZoom));
translate.Z += TranslateSpeed*(MousePos_old.Y - MousePos.Y)*scnmgr->getVideoDriver()->getScreenSize().Height * (CurrentZoom / (MaxZoom * MinZoom));
MousePos_old = MousePos;
}
if ((MousePos.X < 0.005) || (MousePos.X > 0.995) || (MousePos.Y < 0.005) || (MousePos.Y > 0.995))
{
Scroll_lock = true;
}
}
else
{
MousePos_old = MousePos;
Dragging = false;
if((MousePos.X > 0.005) && (MousePos.X < 0.995) && (MousePos.Y > 0.005) && (MousePos.Y < 0.995))
{
Scroll_lock = false;
}
}
if(CurrentZoom != NewZoom && !Dragging && !Scrolling)
{
if(NewZoom >= MaxZoom)
{
NewZoom = MaxZoom;
}
else if(NewZoom <= MinZoom)
{
NewZoom = MinZoom;
}
CurrentZoom = NewZoom;
#ifdef _DEBUG
fprintf(stderr, "DEBUG: CurrentZoom %f\n", CurrentZoom);
#endif //_DEBUG
/*if(CurrentZoom < 1.f)
{
zoom_vector += zoom_close * (1.f - CurrentZoom - MinZoom*(CurrentZoom-1.f));
}*/
Zooming = true;
}
else
{
NewZoom = CurrentZoom;
Zooming = false;
}
if(!Dragging && !Zooming && !Scroll_lock)
{
u32 TimeDelta = Timer->getTime() - LastUpdate;
LastUpdate = Timer->getTime();
if (MousePos.X < 0.005) //Up
{
translate.X += TranslateSpeed * static_cast<irr::f32>(TimeDelta);
//#ifdef _DEBUG
// fprintf(stderr, "DEBUG: MousePos.X %f\n", MousePos.X);
//#endif //_DEBUG
}
else if (MousePos.X > 0.995) //Down
{
translate.X -= TranslateSpeed * static_cast<irr::f32>(TimeDelta);
//#ifdef _DEBUG
// fprintf(stderr, "DEBUG: MousePos.X %f\n", MousePos.X);
//#endif //_DEBUG
}
if (MousePos.Y < 0.005) //Left
{
translate.Z -= TranslateSpeed * static_cast<irr::f32>(TimeDelta);
//#ifdef _DEBUG
// fprintf(stderr, "DEBUG: MousePos.Y %f\n", MousePos.Y);
//#endif //_DEBUG
}
else if (MousePos.Y > 0.995) //Right
{
translate.Z += TranslateSpeed * static_cast<irr::f32>(TimeDelta);
//#ifdef _DEBUG
// fprintf(stderr, "DEBUG: MousePos.Y %f\n", MousePos.Y);
//#endif //_DEBUG
}
if(translate.X + translate.Y == 0)
{
Scrolling = false;
}
else
{
Scrolling = true;
}
}
target += translate; // + zoom_point;
pos = target;
if(CurrentZoom < 1.f)
{
pos += (zoom_vector * ((CurrentZoom - MinZoom)/(1.f - MinZoom)) + zoom_close * (1-(CurrentZoom - MinZoom)/(1.f - MinZoom)))*CurrentZoom;
}
else
{
pos += zoom_vector*CurrentZoom;
}
camera->setPosition(pos);
camera->setTarget(target);
//camera->setTarget(translate);
}
//! Returns the speed of movement
f32 CSceneNodeAnimatorCameraRTS::getMoveSpeed() const
{
return TranslateSpeed;
}
//! Sets the speed of movement
void CSceneNodeAnimatorCameraRTS::setMoveSpeed(f32 speed)
{
TranslateSpeed = speed;
}
//! Returns the rotation speed
f32 CSceneNodeAnimatorCameraRTS::getRotateSpeed() const
{
return RotateSpeed;
}
//! Set the rotation speed
void CSceneNodeAnimatorCameraRTS::setRotateSpeed(f32 speed)
{
RotateSpeed = speed;
}
//! Returns the zoom speed
f32 CSceneNodeAnimatorCameraRTS::getZoomSpeed() const
{
return ZoomSpeed;
}
//! Set the zoom speed
void CSceneNodeAnimatorCameraRTS::setZoomSpeed(f32 speed)
{
ZoomSpeed = speed;
}
//! Returns the camera zoom
f32 CSceneNodeAnimatorCameraRTS::getZoom() const
{
return CurrentZoom;
}
//! Set the camera zoom
void CSceneNodeAnimatorCameraRTS::setZoom(f32 multiplier)
{
if(multiplier < MaxZoom)
{
CurrentZoom = MaxZoom;
}
else if(multiplier > MinZoom)
{
CurrentZoom = MinZoom;
}
else
{
CurrentZoom = multiplier;
}
}
//! Returns the current distance, i.e. orbit radius
f32 CSceneNodeAnimatorCameraRTS::getDistance() const
{
return distance;
}
//! Set the distance
void CSceneNodeAnimatorCameraRTS::setDistance(f32 dist)
{
distance = dist;
}
//! Get the camera angle
f32 CSceneNodeAnimatorCameraRTS::getAngle() const
{
return angle;
}
//! Set the camera angle
void CSceneNodeAnimatorCameraRTS::setAngle(f32 a)
{
angle = a;
}
//! Get the camera angle for close zoom
f32 CSceneNodeAnimatorCameraRTS::getAngleClose() const
{
return angle_close;
}
//! Set the camera angle
void CSceneNodeAnimatorCameraRTS::setAngleClose(f32 a)
{
angle_close = a;
}
ISceneNodeAnimator* CSceneNodeAnimatorCameraRTS::createClone(ISceneNode* node, ISceneManager* newManager)
{
CSceneNodeAnimatorCameraRTS * newAnimator =
new CSceneNodeAnimatorCameraRTS(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed);
return newAnimator;
}
} // end namespace scene
} // end namespace irr