aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp355
1 files changed, 355 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp
new file mode 100644
index 0000000..5612f8a
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp
@@ -0,0 +1,355 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5#include "CSceneNodeAnimatorCameraFPS.h"
6#include "IVideoDriver.h"
7#include "ISceneManager.h"
8#include "Keycodes.h"
9#include "ICursorControl.h"
10#include "ICameraSceneNode.h"
11#include "ISceneNodeAnimatorCollisionResponse.h"
12
13namespace irr
14{
15namespace scene
16{
17
18//! constructor
19CSceneNodeAnimatorCameraFPS::CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl,
20 f32 rotateSpeed, f32 moveSpeed, f32 jumpSpeed,
21 SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement, bool invertY)
22: CursorControl(cursorControl), MaxVerticalAngle(88.0f),
23 MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed),
24 MouseYDirection(invertY ? -1.0f : 1.0f),
25 LastAnimationTime(0), firstUpdate(true), firstInput(true), NoVerticalMovement(noVerticalMovement)
26{
27 #ifdef _DEBUG
28 setDebugName("CCameraSceneNodeAnimatorFPS");
29 #endif
30
31 if (CursorControl)
32 CursorControl->grab();
33
34 allKeysUp();
35
36 // create key map
37 if (!keyMapArray || !keyMapSize)
38 {
39 // create default key map
40 KeyMap.push_back(SKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP));
41 KeyMap.push_back(SKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN));
42 KeyMap.push_back(SKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT));
43 KeyMap.push_back(SKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT));
44 KeyMap.push_back(SKeyMap(EKA_JUMP_UP, irr::KEY_KEY_J));
45 }
46 else
47 {
48 // create custom key map
49 setKeyMap(keyMapArray, keyMapSize);
50 }
51}
52
53
54//! destructor
55CSceneNodeAnimatorCameraFPS::~CSceneNodeAnimatorCameraFPS()
56{
57 if (CursorControl)
58 CursorControl->drop();
59}
60
61
62//! It is possible to send mouse and key events to the camera. Most cameras
63//! may ignore this input, but camera scene nodes which are created for
64//! example with scene::ISceneManager::addMayaCameraSceneNode or
65//! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input
66//! for changing their position, look at target or whatever.
67bool CSceneNodeAnimatorCameraFPS::OnEvent(const SEvent& evt)
68{
69 switch(evt.EventType)
70 {
71 case EET_KEY_INPUT_EVENT:
72 for (u32 i=0; i<KeyMap.size(); ++i)
73 {
74 if (KeyMap[i].KeyCode == evt.KeyInput.Key)
75 {
76 CursorKeys[KeyMap[i].Action] = evt.KeyInput.PressedDown;
77 return true;
78 }
79 }
80 break;
81
82 case EET_MOUSE_INPUT_EVENT:
83 if (evt.MouseInput.Event == EMIE_MOUSE_MOVED)
84 {
85 CursorPos = CursorControl->getRelativePosition();
86 return true;
87 }
88 break;
89
90 default:
91 break;
92 }
93
94 return false;
95}
96
97
98void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs)
99{
100 if (!node || node->getType() != ESNT_CAMERA)
101 return;
102
103 ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
104
105 if (firstUpdate)
106 {
107 camera->updateAbsolutePosition();
108 if (CursorControl )
109 {
110 CursorControl->setPosition(0.5f, 0.5f);
111 CursorPos = CenterCursor = CursorControl->getRelativePosition();
112 }
113
114 LastAnimationTime = timeMs;
115
116 firstUpdate = false;
117 }
118
119 // If the camera isn't the active camera, and receiving input, then don't process it.
120 if(!camera->isInputReceiverEnabled())
121 {
122 firstInput = true;
123 return;
124 }
125
126 if ( firstInput )
127 {
128 allKeysUp();
129 firstInput = false;
130 }
131
132 scene::ISceneManager * smgr = camera->getSceneManager();
133 if(smgr && smgr->getActiveCamera() != camera)
134 return;
135
136 // get time
137 f32 timeDiff = (f32) ( timeMs - LastAnimationTime );
138 LastAnimationTime = timeMs;
139
140 // update position
141 core::vector3df pos = camera->getPosition();
142
143 // Update rotation
144 core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
145 core::vector3df relativeRotation = target.getHorizontalAngle();
146
147 if (CursorControl)
148 {
149 if (CursorPos != CenterCursor)
150 {
151 relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed;
152 relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection;
153
154 // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
155
156 if (relativeRotation.X > MaxVerticalAngle*2 &&
157 relativeRotation.X < 360.0f-MaxVerticalAngle)
158 {
159 relativeRotation.X = 360.0f-MaxVerticalAngle;
160 }
161 else
162 if (relativeRotation.X > MaxVerticalAngle &&
163 relativeRotation.X < 360.0f-MaxVerticalAngle)
164 {
165 relativeRotation.X = MaxVerticalAngle;
166 }
167
168 // Do the fix as normal, special case below
169 // reset cursor position to the centre of the window.
170 CursorControl->setPosition(0.5f, 0.5f);
171 CenterCursor = CursorControl->getRelativePosition();
172
173 // needed to avoid problems when the event receiver is disabled
174 CursorPos = CenterCursor;
175 }
176
177 // Special case, mouse is whipped outside of window before it can update.
178 video::IVideoDriver* driver = smgr->getVideoDriver();
179 core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
180 core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
181
182 // Only if we are moving outside quickly.
183 bool reset = !screenRect.isPointInside(mousepos);
184
185 if(reset)
186 {
187 // Force a reset.
188 CursorControl->setPosition(0.5f, 0.5f);
189 CenterCursor = CursorControl->getRelativePosition();
190 CursorPos = CenterCursor;
191 }
192 }
193
194 // set target
195
196 target.set(0,0, core::max_(1.f, pos.getLength()));
197 core::vector3df movedir = target;
198
199 core::matrix4 mat;
200 mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
201 mat.transformVect(target);
202
203 if (NoVerticalMovement)
204 {
205 mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
206 mat.transformVect(movedir);
207 }
208 else
209 {
210 movedir = target;
211 }
212
213 movedir.normalize();
214
215 if (CursorKeys[EKA_MOVE_FORWARD])
216 pos += movedir * timeDiff * MoveSpeed;
217
218 if (CursorKeys[EKA_MOVE_BACKWARD])
219 pos -= movedir * timeDiff * MoveSpeed;
220
221 // strafing
222
223 core::vector3df strafevect = target;
224 strafevect = strafevect.crossProduct(camera->getUpVector());
225
226 if (NoVerticalMovement)
227 strafevect.Y = 0.0f;
228
229 strafevect.normalize();
230
231 if (CursorKeys[EKA_STRAFE_LEFT])
232 pos += strafevect * timeDiff * MoveSpeed;
233
234 if (CursorKeys[EKA_STRAFE_RIGHT])
235 pos -= strafevect * timeDiff * MoveSpeed;
236
237 // For jumping, we find the collision response animator attached to our camera
238 // and if it's not falling, we tell it to jump.
239 if (CursorKeys[EKA_JUMP_UP])
240 {
241 const ISceneNodeAnimatorList& animators = camera->getAnimators();
242 ISceneNodeAnimatorList::ConstIterator it = animators.begin();
243 while(it != animators.end())
244 {
245 if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
246 {
247 ISceneNodeAnimatorCollisionResponse * collisionResponse =
248 static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
249
250 if(!collisionResponse->isFalling())
251 collisionResponse->jump(JumpSpeed);
252 }
253
254 it++;
255 }
256 }
257
258 // write translation
259 camera->setPosition(pos);
260
261 // write right target
262 target += pos;
263 camera->setTarget(target);
264}
265
266
267void CSceneNodeAnimatorCameraFPS::allKeysUp()
268{
269 for (u32 i=0; i<EKA_COUNT; ++i)
270 CursorKeys[i] = false;
271}
272
273
274//! Sets the rotation speed
275void CSceneNodeAnimatorCameraFPS::setRotateSpeed(f32 speed)
276{
277 RotateSpeed = speed;
278}
279
280
281//! Sets the movement speed
282void CSceneNodeAnimatorCameraFPS::setMoveSpeed(f32 speed)
283{
284 MoveSpeed = speed;
285}
286
287
288//! Gets the rotation speed
289f32 CSceneNodeAnimatorCameraFPS::getRotateSpeed() const
290{
291 return RotateSpeed;
292}
293
294
295// Gets the movement speed
296f32 CSceneNodeAnimatorCameraFPS::getMoveSpeed() const
297{
298 return MoveSpeed;
299}
300
301
302//! Sets the keyboard mapping for this animator
303void CSceneNodeAnimatorCameraFPS::setKeyMap(SKeyMap *map, u32 count)
304{
305 // clear the keymap
306 KeyMap.clear();
307
308 // add actions
309 for (u32 i=0; i<count; ++i)
310 {
311 KeyMap.push_back(map[i]);
312 }
313}
314
315void CSceneNodeAnimatorCameraFPS::setKeyMap(const core::array<SKeyMap>& keymap)
316{
317 KeyMap=keymap;
318}
319
320const core::array<SKeyMap>& CSceneNodeAnimatorCameraFPS::getKeyMap() const
321{
322 return KeyMap;
323}
324
325
326//! Sets whether vertical movement should be allowed.
327void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow)
328{
329 NoVerticalMovement = !allow;
330}
331
332
333//! Sets whether the Y axis of the mouse should be inverted.
334void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert)
335{
336 if (invert)
337 MouseYDirection = -1.0f;
338 else
339 MouseYDirection = 1.0f;
340}
341
342
343ISceneNodeAnimator* CSceneNodeAnimatorCameraFPS::createClone(ISceneNode* node, ISceneManager* newManager)
344{
345 CSceneNodeAnimatorCameraFPS * newAnimator =
346 new CSceneNodeAnimatorCameraFPS(CursorControl, RotateSpeed, MoveSpeed, JumpSpeed,
347 0, 0, NoVerticalMovement);
348 newAnimator->setKeyMap(KeyMap);
349 return newAnimator;
350}
351
352
353} // namespace scene
354} // namespace irr
355