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