diff options
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.cpp | 355 |
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 | |||
13 | namespace irr | ||
14 | { | ||
15 | namespace scene | ||
16 | { | ||
17 | |||
18 | //! constructor | ||
19 | CSceneNodeAnimatorCameraFPS::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 | ||
55 | CSceneNodeAnimatorCameraFPS::~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. | ||
67 | bool 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 | |||
98 | void 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 | |||
267 | void CSceneNodeAnimatorCameraFPS::allKeysUp() | ||
268 | { | ||
269 | for (u32 i=0; i<EKA_COUNT; ++i) | ||
270 | CursorKeys[i] = false; | ||
271 | } | ||
272 | |||
273 | |||
274 | //! Sets the rotation speed | ||
275 | void CSceneNodeAnimatorCameraFPS::setRotateSpeed(f32 speed) | ||
276 | { | ||
277 | RotateSpeed = speed; | ||
278 | } | ||
279 | |||
280 | |||
281 | //! Sets the movement speed | ||
282 | void CSceneNodeAnimatorCameraFPS::setMoveSpeed(f32 speed) | ||
283 | { | ||
284 | MoveSpeed = speed; | ||
285 | } | ||
286 | |||
287 | |||
288 | //! Gets the rotation speed | ||
289 | f32 CSceneNodeAnimatorCameraFPS::getRotateSpeed() const | ||
290 | { | ||
291 | return RotateSpeed; | ||
292 | } | ||
293 | |||
294 | |||
295 | // Gets the movement speed | ||
296 | f32 CSceneNodeAnimatorCameraFPS::getMoveSpeed() const | ||
297 | { | ||
298 | return MoveSpeed; | ||
299 | } | ||
300 | |||
301 | |||
302 | //! Sets the keyboard mapping for this animator | ||
303 | void 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 | |||
315 | void CSceneNodeAnimatorCameraFPS::setKeyMap(const core::array<SKeyMap>& keymap) | ||
316 | { | ||
317 | KeyMap=keymap; | ||
318 | } | ||
319 | |||
320 | const core::array<SKeyMap>& CSceneNodeAnimatorCameraFPS::getKeyMap() const | ||
321 | { | ||
322 | return KeyMap; | ||
323 | } | ||
324 | |||
325 | |||
326 | //! Sets whether vertical movement should be allowed. | ||
327 | void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow) | ||
328 | { | ||
329 | NoVerticalMovement = !allow; | ||
330 | } | ||
331 | |||
332 | |||
333 | //! Sets whether the Y axis of the mouse should be inverted. | ||
334 | void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert) | ||
335 | { | ||
336 | if (invert) | ||
337 | MouseYDirection = -1.0f; | ||
338 | else | ||
339 | MouseYDirection = 1.0f; | ||
340 | } | ||
341 | |||
342 | |||
343 | ISceneNodeAnimator* 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 | |||