1 // =============================================================================
2 // PROJECT CHRONO - http://projectchrono.org
3 //
4 // Copyright (c) 2014 projectchrono.org
5 // All rights reserved.
6 //
7 // Use of this source code is governed by a BSD-style license that can be found
8 // in the LICENSE file at the top level of the distribution and at
9 // http://projectchrono.org/license-chrono.txt.
10 //
11 // =============================================================================
12 
13 #include <iostream>
14 #include "chrono_irrlicht/ChIrrCamera.h"
15 
16 namespace chrono {
17 namespace irrlicht {
18 
19 using namespace irr;
20 using namespace irr::scene;
21 
RTSCamera(IrrlichtDevice * devicepointer,ISceneNode * parent,ISceneManager * smgr,s32 id,f32 rs,f32 zs,f32 ts)22 RTSCamera::RTSCamera(IrrlichtDevice* devicepointer,
23                      ISceneNode* parent,
24                      ISceneManager* smgr,
25                      s32 id,
26                      f32 rs,
27                      f32 zs,
28                      f32 ts)
29     : ICameraSceneNode(parent,
30                        smgr,
31                        id,
32                        core::vector3df(1.0f, 1.0f, 1.0f),
33                        core::vector3df(0.0f, 0.0f, 0.0f),
34                        core::vector3df(1.0f, 1.0f, 1.0f)),
35       InputReceiverEnabled(true) {
36     device = devicepointer;
37     BBox.reset(0, 0, 0);
38 
39     UpVector.set(0.0f, 1.0f, 0.0f);
40     y_up = true;
41 
42     Fovy = core::PI / 2.5f;
43     Aspect = 4.0f / 3.0f;
44     ZNear = 1.0f;
45     ZFar = 3000.0f;
46 
47     atMinDistance = false;
48 
49     video::IVideoDriver* d = smgr->getVideoDriver();
50     if (d) {
51         screenDim.Width = (f32)d->getCurrentRenderTargetSize().Width;
52         screenDim.Height = (f32)d->getCurrentRenderTargetSize().Height;
53         Aspect = screenDim.Width / screenDim.Height;
54     }
55 
56     zooming = false;
57     rotating = false;
58     moving = false;
59     translating = false;
60     zoomSpeed = zs;
61     rotateSpeed = rs;
62     translateSpeed = ts;
63     currentZoom = 100.0f;
64     targetMinDistance = 1.0f;
65     targetMaxDistance = 2000.0f;
66     Target.set(0.0f, 0.0f, 0.0f);
67     rotX = 0;
68     rotY = 0;
69     oldTarget = Target;
70 
71     atMinDistance = false;
72     atMaxDistance = false;
73 
74     allKeysUp();
75     allMouseKeysUp();
76 
77     recalculateProjectionMatrix();
78     recalculateViewArea();
79 
80     smgr->setActiveCamera(this);
81 }
82 
OnEvent(const SEvent & event)83 bool RTSCamera::OnEvent(const SEvent& event) {
84     if (!InputReceiverEnabled)
85         return false;
86 
87     core::dimension2d<u32> ssize = SceneManager->getVideoDriver()->getScreenSize();
88 
89     if (event.EventType == EET_MOUSE_INPUT_EVENT) {
90         switch (event.MouseInput.Event) {
91             case EMIE_LMOUSE_PRESSED_DOWN:
92                 // selectednode =
93                 // SceneManager->getSceneCollisionManager()->getSceneNodeFromScreenCoordinatesBB(device->getCursorControl()->getPosition(),0xFF,false);
94 
95                 // if(selectednode)
96                 //   pointCameraAtNode(selectednode);
97                 // else
98                 {
99                     selectednode = NULL;
100                     MouseKeys[0] = true;
101                 }
102                 break;
103             case EMIE_RMOUSE_PRESSED_DOWN:
104                 MouseKeys[2] = true;
105                 break;
106             case EMIE_MMOUSE_PRESSED_DOWN:
107                 MouseKeys[1] = true;
108                 break;
109             case EMIE_LMOUSE_LEFT_UP:
110                 MouseKeys[0] = false;
111                 break;
112             case EMIE_RMOUSE_LEFT_UP:
113                 MouseKeys[2] = false;
114                 break;
115             case EMIE_MMOUSE_LEFT_UP:
116                 MouseKeys[1] = false;
117                 break;
118             case EMIE_MOUSE_MOVED:
119                 MousePos.X = event.MouseInput.X / (f32)ssize.Width;
120                 MousePos.Y = event.MouseInput.Y / (f32)ssize.Height;
121                 break;
122             case EMIE_MOUSE_WHEEL:
123                 currentZoom -= event.MouseInput.Wheel * 0.05f * zoomSpeed;  //***ALEX
124 
125                 if (currentZoom <= targetMinDistance)
126                     atMinDistance = true;
127                 else if (currentZoom >= targetMaxDistance)
128                     atMaxDistance = true;
129                 else {
130                     atMinDistance = false;
131                     atMaxDistance = false;
132                 }
133 
134                 break;
135             default:
136                 break;
137         }
138         return true;
139     }
140 
141     if (event.EventType == EET_KEY_INPUT_EVENT) {
142         Keys[event.KeyInput.Key] = event.KeyInput.PressedDown;
143         return true;
144     }
145 
146     return false;
147 }
148 
OnRegisterSceneNode()149 void RTSCamera::OnRegisterSceneNode() {
150     video::IVideoDriver* driver = SceneManager->getVideoDriver();
151     if (!driver)
152         return;
153 
154     if (SceneManager->getActiveCamera() == this) {
155         screenDim.Width = (f32)driver->getCurrentRenderTargetSize().Width;
156         screenDim.Height = (f32)driver->getCurrentRenderTargetSize().Height;
157 
158         driver->setTransform(video::ETS_PROJECTION, Projection);
159 
160         // If UpVector and Vector to Target are the same, we have a problem.
161         // Correct it.
162         core::vector3df pos = getAbsolutePosition();
163         core::vector3df tgtv = Target - pos;
164         tgtv.normalize();
165 
166         core::vector3df up = UpVector;
167         up.normalize();
168 
169         f32 dp = tgtv.dotProduct(up);
170         if ((dp > -1.0001f && dp < -0.9999f) || (dp < 1.0001f && dp > 0.9999f))
171             up.X += 1.0f;
172 
173         View.buildCameraLookAtMatrixLH(pos, Target, up);  // Right hand camera: use "..RH" here and in the following
174         recalculateViewArea();
175 
176         SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);
177     }
178 
179     if (IsVisible)
180         ISceneNode::OnRegisterSceneNode();
181 }
182 
render()183 void RTSCamera::render() {
184     video::IVideoDriver* driver = SceneManager->getVideoDriver();
185     if (!driver)
186         return;
187 
188     driver->setTransform(video::ETS_VIEW, View);
189 }
190 
OnAnimate(u32 timeMs)191 void RTSCamera::OnAnimate(u32 timeMs) {
192     animate();
193 
194     ISceneNode::setPosition(Pos);
195     updateAbsolutePosition();
196 
197     // TODO Add Animators
198 }
199 
isInputReceiverEnabled() const200 bool RTSCamera::isInputReceiverEnabled() const {
201     _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
202     return InputReceiverEnabled;
203 }
204 
setNearValue(f32 f)205 void RTSCamera::setNearValue(f32 f) {
206     ZNear = f;
207     recalculateProjectionMatrix();
208 }
209 
setFarValue(f32 f)210 void RTSCamera::setFarValue(f32 f) {
211     ZFar = f;
212     recalculateProjectionMatrix();
213 }
214 
setAspectRatio(f32 f)215 void RTSCamera::setAspectRatio(f32 f) {
216     Aspect = f;
217     recalculateProjectionMatrix();
218 }
219 
setFOV(f32 f)220 void RTSCamera::setFOV(f32 f) {
221     Fovy = f;
222     recalculateProjectionMatrix();
223 }
224 
setViewMatrixAffector(const core::matrix4 & affector)225 void RTSCamera::setViewMatrixAffector(const core::matrix4& affector) {
226     Affector = affector;
227 }
228 
setZUp()229 void RTSCamera::setZUp() {
230     UpVector.set(0.0f, 0.0f, 1.0f);
231     y_up = false;
232 }
233 
setProjectionMatrix(const core::matrix4 & projection,bool isOrthogonal)234 void RTSCamera::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal) {
235     Projection = projection;
236 }
237 
setPosition(const core::vector3df & pos)238 void RTSCamera::setPosition(const core::vector3df& pos) {
239     Pos = pos;
240     updateAnimationState();
241 
242     ISceneNode::setPosition(pos);
243 }
244 
setTarget(const core::vector3df & pos)245 void RTSCamera::setTarget(const core::vector3df& pos) {
246     Target = oldTarget = pos;
247     updateAnimationState();
248 }
249 
setZoomSpeed(f32 value)250 void RTSCamera::setZoomSpeed(f32 value) {
251     zoomSpeed = value;
252 }
253 
setTranslateSpeed(f32 value)254 void RTSCamera::setTranslateSpeed(f32 value) {
255     translateSpeed = value;
256 }
257 
setRotationSpeed(f32 value)258 void RTSCamera::setRotationSpeed(f32 value) {
259     rotateSpeed = value;
260 }
261 
pointCameraAtNode(ISceneNode * selectednode)262 void RTSCamera::pointCameraAtNode(ISceneNode* selectednode) {
263     core::vector3df totarget = getPosition() - getTarget();
264     setPosition(selectednode->getPosition() + (totarget.normalize() * 100));
265     setTarget(selectednode->getPosition());
266     updateAnimationState();
267 }
268 
setMinZoom(f32 amount)269 void RTSCamera::setMinZoom(f32 amount) {
270     targetMinDistance = amount;
271 }
272 
setMaxZoom(f32 amount)273 void RTSCamera::setMaxZoom(f32 amount) {
274     targetMaxDistance = amount;
275 }
276 
recalculateProjectionMatrix()277 void RTSCamera::recalculateProjectionMatrix() {
278     Projection.buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear,
279                                                      ZFar);  // Right hand camera: use "..RH" here and in the following
280 }
281 
recalculateViewArea()282 void RTSCamera::recalculateViewArea() {
283     core::matrix4 mat = Projection * View;
284     ViewArea = SViewFrustum(mat);
285 
286     ViewArea.cameraPosition = getAbsolutePosition();
287     ViewArea.recalculateBoundingBox();
288 }
289 
allKeysUp()290 void RTSCamera::allKeysUp() {
291     for (int i = 0; i < KEY_KEY_CODES_COUNT; i++)
292         Keys[i] = false;
293 }
294 
allMouseKeysUp()295 void RTSCamera::allMouseKeysUp() {
296     for (s32 i = 0; i < 3; ++i)
297         MouseKeys[i] = false;
298 }
299 
isKeyDown(s32 key)300 bool RTSCamera::isKeyDown(s32 key) {
301     return Keys[key];
302 }
303 
isMouseKeyDown(s32 key)304 bool RTSCamera::isMouseKeyDown(s32 key) {
305     return MouseKeys[key];
306 }
307 
animate()308 void RTSCamera::animate() {
309     // Rotation Vals
310     f32 nRotX = rotX;
311     f32 nRotY = rotY;
312     f32 nZoom = currentZoom;
313 
314     // Translation Vals
315     core::vector3df translate(oldTarget);
316     core::vector3df tvectX = Pos - Target;
317     tvectX = tvectX.crossProduct(UpVector);
318     tvectX.normalize();
319 
320     // Zoom
321     if (isMouseKeyDown(MOUSE_BUTTON_RIGHT) && isMouseKeyDown(MOUSE_BUTTON_LEFT)) {
322         if (!zooming) {
323             zoomStartX = MousePos.X;
324             zoomStartY = MousePos.Y;
325             zooming = true;
326             nZoom = currentZoom;
327         } else {
328             f32 old = nZoom;
329             nZoom += (zoomStartX - MousePos.X) * zoomSpeed * 100;
330 
331             if (nZoom < targetMinDistance)
332                 nZoom = targetMinDistance;
333             else if (nZoom > targetMaxDistance)
334                 nZoom = targetMaxDistance;
335 
336             if (nZoom < 0)
337                 nZoom = old;
338         }
339     } else {
340         if (zooming) {
341             f32 old = currentZoom;
342             currentZoom = currentZoom + (zoomStartX - MousePos.X) * zoomSpeed;
343             nZoom = currentZoom;
344 
345             if (nZoom < 0)
346                 nZoom = currentZoom = old;
347         }
348         zooming = false;
349     }
350 
351     // Rotation
352     if (isMouseKeyDown(MOUSE_BUTTON_LEFT) && !zooming) {
353         if (!rotating) {
354             rotateStartX = MousePos.X;
355             rotateStartY = MousePos.Y;
356             rotating = true;
357             nRotX = rotX;
358             nRotY = rotY;
359         } else {
360             if (y_up)
361                 nRotX += (rotateStartX - MousePos.X) * rotateSpeed;
362             else
363                 nRotX -= (rotateStartX - MousePos.X) * rotateSpeed;
364             nRotY += (rotateStartY - MousePos.Y) * rotateSpeed;
365         }
366     } else {
367         if (rotating) {
368             if (y_up)
369                 rotX = rotX + (rotateStartX - MousePos.X) * rotateSpeed;
370             else
371                 rotX = rotX - (rotateStartX - MousePos.X) * rotateSpeed;
372             rotY = rotY + (rotateStartY - MousePos.Y) * rotateSpeed;
373             nRotX = rotX;
374             nRotY = rotY;
375         }
376 
377         rotating = false;
378     }
379 
380     // Translate
381     if (isMouseKeyDown(MOUSE_BUTTON_RIGHT) && !zooming) {
382         if (!translating) {
383             translateStartX = MousePos.X;
384             translateStartY = MousePos.Y;
385             translating = true;
386         } else {
387             translate += tvectX * (translateStartX - MousePos.X) * translateSpeed;
388             translate.X += tvectX.Z * (translateStartY - MousePos.Y) * translateSpeed;
389             translate.Z -= tvectX.X * (translateStartY - MousePos.Y) * translateSpeed;
390 
391             oldTarget = translate;
392         }
393     }
394 
395     else if (isKeyDown(KEY_UP) && !zooming) {
396         if (!translating)
397             translating = true;
398         else {
399             core::vector3df movevector = getPosition() - getTarget();
400             if (y_up)
401                 movevector.Y = 0;
402             else
403                 movevector.Z = 0;
404             movevector.normalize();
405 
406             setPosition(getPosition() - movevector * translateSpeed);
407             setTarget(getTarget() - movevector * translateSpeed);
408             updateAbsolutePosition();
409         }
410     } else if (isKeyDown(KEY_DOWN) && !zooming) {
411         if (!translating)
412             translating = true;
413         else {
414             core::vector3df movevector = getPosition() - getTarget();
415             if (y_up)
416                 movevector.Y = 0;
417             else
418                 movevector.Z = 0;
419             movevector.normalize();
420 
421             setPosition(getPosition() + movevector * translateSpeed);
422             setTarget(getTarget() + movevector * translateSpeed);
423             updateAbsolutePosition();
424         }
425     } else if (isKeyDown(KEY_LEFT) && !zooming) {
426         if (!translating)
427             translating = true;
428         else {
429             core::vector3df totargetvector = getPosition() - getTarget();
430             totargetvector.normalize();
431             core::vector3df crossvector = totargetvector.crossProduct(getUpVector());
432             core::vector3df strafevector = crossvector.normalize();
433 
434             setPosition(getPosition() - strafevector * translateSpeed);
435             setTarget(getTarget() - strafevector * translateSpeed);
436             updateAbsolutePosition();
437         }
438     } else if (isKeyDown(KEY_RIGHT) && !zooming) {
439         if (!translating)
440             translating = true;
441         else {
442             core::vector3df totargetvector = getPosition() - getTarget();
443             totargetvector.normalize();
444             core::vector3df crossvector = totargetvector.crossProduct(getUpVector());
445             core::vector3df strafevector = crossvector.normalize();
446 
447             setPosition(getPosition() + strafevector * translateSpeed);
448             setTarget(getTarget() + strafevector * translateSpeed);
449             updateAbsolutePosition();
450         }
451     } else if (isKeyDown(KEY_PRIOR) && !zooming)  // ALE
452     {
453         if (!translating)
454             translating = true;
455         else {
456             core::vector3df movevector;
457             if (y_up)
458                 movevector.Y = 1;
459             else
460                 movevector.Z = 1;
461 
462             setPosition(getPosition() + movevector * translateSpeed);
463             setTarget(getTarget() + movevector * translateSpeed);
464             updateAbsolutePosition();
465         }
466     } else if (isKeyDown(KEY_NEXT) && !zooming)  // ALE
467     {
468         if (!translating)
469             translating = true;
470         else {
471             core::vector3df movevector;
472             if (y_up)
473                 movevector.Y = -1;
474             else
475                 movevector.Z = -1;
476 
477             setPosition(getPosition() + movevector * translateSpeed);
478             setTarget(getTarget() + movevector * translateSpeed);
479             updateAbsolutePosition();
480         }
481     }
482 
483     // Set Position
484     Target = translate;
485 
486     Pos.X = nZoom + Target.X;
487     Pos.Y = Target.Y;
488     Pos.Z = Target.Z;
489 
490     if (y_up) {
491         Pos.rotateXYBy(nRotY, Target);
492         Pos.rotateXZBy(-nRotX, Target);
493     } else {
494         Pos.rotateXZBy(nRotY, Target);
495         Pos.rotateXYBy(-nRotX, Target);
496     }
497 
498     // Correct Rotation Error
499     if (y_up) {
500         UpVector.set(0, 1, 0);
501         UpVector.rotateXYBy(-nRotY, core::vector3df(0, 0, 0));
502         UpVector.rotateXZBy(-nRotX + 180.f, core::vector3df(0, 0, 0));
503     } else {
504         UpVector.set(0, 0, 1);
505         UpVector.rotateXZBy(-nRotY, core::vector3df(0, 0, 0));
506         UpVector.rotateXYBy(-nRotX + 180.f, core::vector3df(0, 0, 0));
507     }
508 }
509 
updateAnimationState()510 void RTSCamera::updateAnimationState() {
511     core::vector3df pos(Pos - Target);
512 
513     if (y_up) {
514         // X rotation
515         core::vector2df vec2d(pos.X, pos.Z);
516         rotX = (f32)vec2d.getAngle();
517 
518         // Y rotation
519         pos.rotateXZBy(rotX, core::vector3df());
520         vec2d.set(pos.X, pos.Y);
521         rotY = -(f32)vec2d.getAngle();
522     } else {
523         // X rotation
524         core::vector2df vec2d(pos.X, pos.Y);
525         rotX = (f32)vec2d.getAngle();
526 
527         // Y rotation
528         pos.rotateXYBy(rotX, core::vector3df());
529         vec2d.set(pos.X, pos.Z);
530         rotY = -(f32)vec2d.getAngle();
531     }
532 
533     // Zoom
534     currentZoom = (f32)Pos.getDistanceFrom(Target);
535 }
536 
updateMatrices()537 void RTSCamera::updateMatrices() {}
538 
539 }  // end namespace irrlicht
540 }  // end namespace chrono
541