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