~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2002-2011 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), 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(SCamKeyMap(EKA_MOVE_FORWARD, irr::KEY_UP));
 
41
                KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, irr::KEY_DOWN));
 
42
                KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, irr::KEY_LEFT));
 
43
                KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, irr::KEY_RIGHT));
 
44
                KeyMap.push_back(SCamKeyMap(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 && camera)
 
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
                return;
 
122
 
 
123
        scene::ISceneManager * smgr = camera->getSceneManager();
 
124
        if(smgr && smgr->getActiveCamera() != camera)
 
125
                return;
 
126
 
 
127
        // get time
 
128
        f32 timeDiff = (f32) ( timeMs - LastAnimationTime );
 
129
        LastAnimationTime = timeMs;
 
130
 
 
131
        // update position
 
132
        core::vector3df pos = camera->getPosition();
 
133
 
 
134
        // Update rotation
 
135
        core::vector3df target = (camera->getTarget() - camera->getAbsolutePosition());
 
136
        core::vector3df relativeRotation = target.getHorizontalAngle();
 
137
 
 
138
        if (CursorControl)
 
139
        {
 
140
                if (CursorPos != CenterCursor)
 
141
                {
 
142
                        relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed;
 
143
                        relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection;
 
144
 
 
145
                        // X < MaxVerticalAngle or X > 360-MaxVerticalAngle
 
146
 
 
147
                        if (relativeRotation.X > MaxVerticalAngle*2 &&
 
148
                                relativeRotation.X < 360.0f-MaxVerticalAngle)
 
149
                        {
 
150
                                relativeRotation.X = 360.0f-MaxVerticalAngle;
 
151
                        }
 
152
                        else
 
153
                        if (relativeRotation.X > MaxVerticalAngle &&
 
154
                                relativeRotation.X < 360.0f-MaxVerticalAngle)
 
155
                        {
 
156
                                relativeRotation.X = MaxVerticalAngle;
 
157
                        }
 
158
 
 
159
                        // Do the fix as normal, special case below
 
160
                        // reset cursor position to the centre of the window.
 
161
                        CursorControl->setPosition(0.5f, 0.5f);
 
162
                        CenterCursor = CursorControl->getRelativePosition();
 
163
 
 
164
                        // needed to avoid problems when the event receiver is disabled
 
165
                        CursorPos = CenterCursor;
 
166
                }
 
167
 
 
168
                // Special case, mouse is whipped outside of window before it can update.
 
169
                video::IVideoDriver* driver = smgr->getVideoDriver();
 
170
                core::vector2d<u32> mousepos(u32(CursorControl->getPosition().X), u32(CursorControl->getPosition().Y));
 
171
                core::rect<u32> screenRect(0, 0, driver->getScreenSize().Width, driver->getScreenSize().Height);
 
172
 
 
173
                // Only if we are moving outside quickly.
 
174
                bool reset = !screenRect.isPointInside(mousepos);
 
175
 
 
176
                if(reset)
 
177
                {
 
178
                        // Force a reset.
 
179
                        CursorControl->setPosition(0.5f, 0.5f);
 
180
                        CenterCursor = CursorControl->getRelativePosition();
 
181
                        CursorPos = CenterCursor;
 
182
                }
 
183
        }
 
184
 
 
185
        // set target
 
186
 
 
187
        target.set(0,0, core::max_(1.f, pos.getLength()));
 
188
        core::vector3df movedir = target;
 
189
 
 
190
        core::matrix4 mat;
 
191
        mat.setRotationDegrees(core::vector3df(relativeRotation.X, relativeRotation.Y, 0));
 
192
        mat.transformVect(target);
 
193
 
 
194
        if (NoVerticalMovement)
 
195
        {
 
196
                mat.setRotationDegrees(core::vector3df(0, relativeRotation.Y, 0));
 
197
                mat.transformVect(movedir);
 
198
        }
 
199
        else
 
200
        {
 
201
                movedir = target;
 
202
        }
 
203
 
 
204
        movedir.normalize();
 
205
 
 
206
        if (CursorKeys[EKA_MOVE_FORWARD])
 
207
                pos += movedir * timeDiff * MoveSpeed;
 
208
 
 
209
        if (CursorKeys[EKA_MOVE_BACKWARD])
 
210
                pos -= movedir * timeDiff * MoveSpeed;
 
211
 
 
212
        // strafing
 
213
 
 
214
        core::vector3df strafevect = target;
 
215
        strafevect = strafevect.crossProduct(camera->getUpVector());
 
216
 
 
217
        if (NoVerticalMovement)
 
218
                strafevect.Y = 0.0f;
 
219
 
 
220
        strafevect.normalize();
 
221
 
 
222
        if (CursorKeys[EKA_STRAFE_LEFT])
 
223
                pos += strafevect * timeDiff * MoveSpeed;
 
224
 
 
225
        if (CursorKeys[EKA_STRAFE_RIGHT])
 
226
                pos -= strafevect * timeDiff * MoveSpeed;
 
227
 
 
228
        // For jumping, we find the collision response animator attached to our camera
 
229
        // and if it's not falling, we tell it to jump.
 
230
        if (CursorKeys[EKA_JUMP_UP])
 
231
        {
 
232
                const ISceneNodeAnimatorList& animators = camera->getAnimators();
 
233
                ISceneNodeAnimatorList::ConstIterator it = animators.begin();
 
234
                while(it != animators.end())
 
235
                {
 
236
                        if(ESNAT_COLLISION_RESPONSE == (*it)->getType())
 
237
                        {
 
238
                                ISceneNodeAnimatorCollisionResponse * collisionResponse =
 
239
                                        static_cast<ISceneNodeAnimatorCollisionResponse *>(*it);
 
240
 
 
241
                                if(!collisionResponse->isFalling())
 
242
                                        collisionResponse->jump(JumpSpeed);
 
243
                        }
 
244
 
 
245
                        it++;
 
246
                }
 
247
        }
 
248
 
 
249
        // write translation
 
250
        camera->setPosition(pos);
 
251
 
 
252
        // write right target
 
253
        target += pos;
 
254
        camera->setTarget(target);
 
255
}
 
256
 
 
257
 
 
258
void CSceneNodeAnimatorCameraFPS::allKeysUp()
 
259
{
 
260
        for (u32 i=0; i<6; ++i)
 
261
                CursorKeys[i] = false;
 
262
}
 
263
 
 
264
 
 
265
//! Sets the rotation speed
 
266
void CSceneNodeAnimatorCameraFPS::setRotateSpeed(f32 speed)
 
267
{
 
268
        RotateSpeed = speed;
 
269
}
 
270
 
 
271
 
 
272
//! Sets the movement speed
 
273
void CSceneNodeAnimatorCameraFPS::setMoveSpeed(f32 speed)
 
274
{
 
275
        MoveSpeed = speed;
 
276
}
 
277
 
 
278
 
 
279
//! Gets the rotation speed
 
280
f32 CSceneNodeAnimatorCameraFPS::getRotateSpeed() const
 
281
{
 
282
        return RotateSpeed;
 
283
}
 
284
 
 
285
 
 
286
// Gets the movement speed
 
287
f32 CSceneNodeAnimatorCameraFPS::getMoveSpeed() const
 
288
{
 
289
        return MoveSpeed;
 
290
}
 
291
 
 
292
 
 
293
//! Sets the keyboard mapping for this animator
 
294
void CSceneNodeAnimatorCameraFPS::setKeyMap(SKeyMap *map, u32 count)
 
295
{
 
296
        // clear the keymap
 
297
        KeyMap.clear();
 
298
 
 
299
        // add actions
 
300
        for (u32 i=0; i<count; ++i)
 
301
        {
 
302
                switch(map[i].Action)
 
303
                {
 
304
                case EKA_MOVE_FORWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_FORWARD, map[i].KeyCode));
 
305
                        break;
 
306
                case EKA_MOVE_BACKWARD: KeyMap.push_back(SCamKeyMap(EKA_MOVE_BACKWARD, map[i].KeyCode));
 
307
                        break;
 
308
                case EKA_STRAFE_LEFT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_LEFT, map[i].KeyCode));
 
309
                        break;
 
310
                case EKA_STRAFE_RIGHT: KeyMap.push_back(SCamKeyMap(EKA_STRAFE_RIGHT, map[i].KeyCode));
 
311
                        break;
 
312
                case EKA_JUMP_UP: KeyMap.push_back(SCamKeyMap(EKA_JUMP_UP, map[i].KeyCode));
 
313
                        break;
 
314
                default:
 
315
                        break;
 
316
                }
 
317
        }
 
318
}
 
319
 
 
320
 
 
321
//! Sets whether vertical movement should be allowed.
 
322
void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow)
 
323
{
 
324
        NoVerticalMovement = !allow;
 
325
}
 
326
 
 
327
 
 
328
//! Sets whether the Y axis of the mouse should be inverted.
 
329
void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert)
 
330
{
 
331
        if (invert)
 
332
                MouseYDirection = -1.0f;
 
333
        else
 
334
                MouseYDirection = 1.0f;
 
335
}
 
336
 
 
337
 
 
338
ISceneNodeAnimator* CSceneNodeAnimatorCameraFPS::createClone(ISceneNode* node, ISceneManager* newManager)
 
339
{
 
340
        CSceneNodeAnimatorCameraFPS * newAnimator =
 
341
                new CSceneNodeAnimatorCameraFPS(CursorControl,  RotateSpeed, MoveSpeed, JumpSpeed,
 
342
                                                                                        0, 0, NoVerticalMovement);
 
343
        newAnimator->setKeyMap(KeyMap);
 
344
        return newAnimator;
 
345
}
 
346
 
 
347
 
 
348
void CSceneNodeAnimatorCameraFPS::setKeyMap(const core::array<SCamKeyMap>& keymap)
 
349
{
 
350
        KeyMap=keymap;
 
351
}
 
352
 
 
353
 
 
354
} // namespace scene
 
355
} // namespace irr
 
356