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 "CSceneNodeAnimatorCameraMaya.h"
6 #include "ICursorControl.h"
7 #include "ICameraSceneNode.h"
8 #include "SViewFrustum.h"
9 #include "ISceneManager.h"
10 
11 namespace irr
12 {
13 namespace scene
14 {
15 
16 //! constructor
CSceneNodeAnimatorCameraMaya(gui::ICursorControl * cursor,f32 rotateSpeed,f32 zoomSpeed,f32 translateSpeed,f32 distance)17 CSceneNodeAnimatorCameraMaya::CSceneNodeAnimatorCameraMaya(gui::ICursorControl* cursor,
18 	f32 rotateSpeed, f32 zoomSpeed, f32 translateSpeed, f32 distance)
19 	: CursorControl(cursor), OldCamera(0), MousePos(0.5f, 0.5f),
20 	ZoomSpeed(zoomSpeed), RotateSpeed(rotateSpeed), TranslateSpeed(translateSpeed),
21 	CurrentZoom(distance), RotX(0.0f), RotY(0.0f),
22 	Zooming(false), Rotating(false), Moving(false), Translating(false)
23 {
24 	#ifdef _DEBUG
25 	setDebugName("CSceneNodeAnimatorCameraMaya");
26 	#endif
27 
28 	if (CursorControl)
29 	{
30 		CursorControl->grab();
31 		MousePos = CursorControl->getRelativePosition();
32 	}
33 
34 	allKeysUp();
35 }
36 
37 
38 //! destructor
~CSceneNodeAnimatorCameraMaya()39 CSceneNodeAnimatorCameraMaya::~CSceneNodeAnimatorCameraMaya()
40 {
41 	if (CursorControl)
42 		CursorControl->drop();
43 }
44 
45 
46 //! It is possible to send mouse and key events to the camera. Most cameras
47 //! may ignore this input, but camera scene nodes which are created for
48 //! example with scene::ISceneManager::addMayaCameraSceneNode or
49 //! scene::ISceneManager::addMeshViewerCameraSceneNode, may want to get this input
50 //! for changing their position, look at target or whatever.
OnEvent(const SEvent & event)51 bool CSceneNodeAnimatorCameraMaya::OnEvent(const SEvent& event)
52 {
53 	if (event.EventType != EET_MOUSE_INPUT_EVENT)
54 		return false;
55 
56 	switch(event.MouseInput.Event)
57 	{
58 	case EMIE_LMOUSE_PRESSED_DOWN:
59 		MouseKeys[0] = true;
60 		break;
61 	case EMIE_RMOUSE_PRESSED_DOWN:
62 		MouseKeys[2] = true;
63 		break;
64 	case EMIE_MMOUSE_PRESSED_DOWN:
65 		MouseKeys[1] = true;
66 		break;
67 	case EMIE_LMOUSE_LEFT_UP:
68 		MouseKeys[0] = false;
69 		break;
70 	case EMIE_RMOUSE_LEFT_UP:
71 		MouseKeys[2] = false;
72 		break;
73 	case EMIE_MMOUSE_LEFT_UP:
74 		MouseKeys[1] = false;
75 		break;
76 	case EMIE_MOUSE_MOVED:
77 		MousePos = CursorControl->getRelativePosition();
78 		break;
79 	case EMIE_MOUSE_WHEEL:
80 	case EMIE_LMOUSE_DOUBLE_CLICK:
81 	case EMIE_RMOUSE_DOUBLE_CLICK:
82 	case EMIE_MMOUSE_DOUBLE_CLICK:
83 	case EMIE_LMOUSE_TRIPLE_CLICK:
84 	case EMIE_RMOUSE_TRIPLE_CLICK:
85 	case EMIE_MMOUSE_TRIPLE_CLICK:
86 	case EMIE_COUNT:
87 		return false;
88 	}
89 	return true;
90 }
91 
92 
93 //! OnAnimate() is called just before rendering the whole scene.
animateNode(ISceneNode * node,u32 timeMs)94 void CSceneNodeAnimatorCameraMaya::animateNode(ISceneNode *node, u32 timeMs)
95 {
96 	//Alt + LM = Rotate around camera pivot
97 	//Alt + LM + MM = Dolly forth/back in view direction (speed % distance camera pivot - max distance to pivot)
98 	//Alt + MM = Move on camera plane (Screen center is about the mouse pointer, depending on move speed)
99 
100 	if (!node || node->getType() != ESNT_CAMERA)
101 		return;
102 
103 	ICameraSceneNode* camera = static_cast<ICameraSceneNode*>(node);
104 
105 	// If the camera isn't the active camera, and receiving input, then don't process it.
106 	if (!camera->isInputReceiverEnabled())
107 		return;
108 
109 	scene::ISceneManager * smgr = camera->getSceneManager();
110 	if (smgr && smgr->getActiveCamera() != camera)
111 		return;
112 
113 	if (OldCamera != camera)
114 	{
115 		LastCameraTarget = OldTarget = camera->getTarget();
116 		OldCamera = camera;
117 	}
118 	else
119 	{
120 		OldTarget += camera->getTarget() - LastCameraTarget;
121 	}
122 
123 	f32 nRotX = RotX;
124 	f32 nRotY = RotY;
125 	f32 nZoom = CurrentZoom;
126 
127 	if ( (isMouseKeyDown(0) && isMouseKeyDown(2)) || isMouseKeyDown(1) )
128 	{
129 		if (!Zooming)
130 		{
131 			ZoomStart = MousePos;
132 			Zooming = true;
133 		}
134 		else
135 		{
136 			const f32 targetMinDistance = 0.1f;
137 			nZoom += (ZoomStart.X - MousePos.X) * ZoomSpeed;
138 
139 			if (nZoom < targetMinDistance) // jox: fixed bug: bounce back when zooming to close
140 				nZoom = targetMinDistance;
141 		}
142 	}
143 	else if (Zooming)
144 	{
145 		const f32 old = CurrentZoom;
146 		CurrentZoom = CurrentZoom + (ZoomStart.X - MousePos.X ) * ZoomSpeed;
147 		nZoom = CurrentZoom;
148 
149 		if (nZoom < 0)
150 			nZoom = CurrentZoom = old;
151 		Zooming = false;
152 	}
153 
154 	// Translation ---------------------------------
155 
156 	core::vector3df translate(OldTarget);
157 	const core::vector3df upVector(camera->getUpVector());
158 	const core::vector3df target = camera->getTarget();
159 
160 	core::vector3df pos = camera->getPosition();
161 	core::vector3df tvectX = pos - target;
162 	tvectX = tvectX.crossProduct(upVector);
163 	tvectX.normalize();
164 
165 	const SViewFrustum* const va = camera->getViewFrustum();
166 	core::vector3df tvectY = (va->getFarLeftDown() - va->getFarRightDown());
167 	tvectY = tvectY.crossProduct(upVector.Y > 0 ? pos - target : target - pos);
168 	tvectY.normalize();
169 
170 	if (isMouseKeyDown(2) && !Zooming)
171 	{
172 		if (!Translating)
173 		{
174 			TranslateStart = MousePos;
175 			Translating = true;
176 		}
177 		else
178 		{
179 			translate +=  tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed +
180 			              tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed;
181 		}
182 	}
183 	else if (Translating)
184 	{
185 		translate += tvectX * (TranslateStart.X - MousePos.X)*TranslateSpeed +
186 		             tvectY * (TranslateStart.Y - MousePos.Y)*TranslateSpeed;
187 		OldTarget = translate;
188 		Translating = false;
189 	}
190 
191 	// Rotation ------------------------------------
192 
193 	if (isMouseKeyDown(0) && !Zooming)
194 	{
195 		if (!Rotating)
196 		{
197 			RotateStart = MousePos;
198 			Rotating = true;
199 			nRotX = RotX;
200 			nRotY = RotY;
201 		}
202 		else
203 		{
204 			nRotX += (RotateStart.X - MousePos.X) * RotateSpeed;
205 			nRotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;
206 		}
207 	}
208 	else if (Rotating)
209 	{
210 		RotX += (RotateStart.X - MousePos.X) * RotateSpeed;
211 		RotY += (RotateStart.Y - MousePos.Y) * RotateSpeed;
212 		nRotX = RotX;
213 		nRotY = RotY;
214 		Rotating = false;
215 	}
216 
217 	// Set pos ------------------------------------
218 
219 	pos = translate;
220 	pos.X += nZoom;
221 
222 	pos.rotateXYBy(nRotY, translate);
223 	pos.rotateXZBy(-nRotX, translate);
224 
225 	camera->setPosition(pos);
226 	camera->setTarget(translate);
227 
228 	// Rotation Error ----------------------------
229 
230 	// jox: fixed bug: jitter when rotating to the top and bottom of y
231 	pos.set(0,1,0);
232 	pos.rotateXYBy(-nRotY);
233 	pos.rotateXZBy(-nRotX+180.f);
234 	camera->setUpVector(pos);
235 	LastCameraTarget = camera->getTarget();
236 }
237 
238 
isMouseKeyDown(s32 key) const239 bool CSceneNodeAnimatorCameraMaya::isMouseKeyDown(s32 key) const
240 {
241 	return MouseKeys[key];
242 }
243 
244 
allKeysUp()245 void CSceneNodeAnimatorCameraMaya::allKeysUp()
246 {
247 	for (s32 i=0; i<3; ++i)
248 		MouseKeys[i] = false;
249 }
250 
251 
252 //! Sets the rotation speed
setRotateSpeed(f32 speed)253 void CSceneNodeAnimatorCameraMaya::setRotateSpeed(f32 speed)
254 {
255 	RotateSpeed = speed;
256 }
257 
258 
259 //! Sets the movement speed
setMoveSpeed(f32 speed)260 void CSceneNodeAnimatorCameraMaya::setMoveSpeed(f32 speed)
261 {
262 	TranslateSpeed = speed;
263 }
264 
265 
266 //! Sets the zoom speed
setZoomSpeed(f32 speed)267 void CSceneNodeAnimatorCameraMaya::setZoomSpeed(f32 speed)
268 {
269 	ZoomSpeed = speed;
270 }
271 
272 
273 //! Set the distance
setDistance(f32 distance)274 void CSceneNodeAnimatorCameraMaya::setDistance(f32 distance)
275 {
276 	CurrentZoom=distance;
277 }
278 
279 
280 //! Gets the rotation speed
getRotateSpeed() const281 f32 CSceneNodeAnimatorCameraMaya::getRotateSpeed() const
282 {
283 	return RotateSpeed;
284 }
285 
286 
287 // Gets the movement speed
getMoveSpeed() const288 f32 CSceneNodeAnimatorCameraMaya::getMoveSpeed() const
289 {
290 	return TranslateSpeed;
291 }
292 
293 
294 //! Gets the zoom speed
getZoomSpeed() const295 f32 CSceneNodeAnimatorCameraMaya::getZoomSpeed() const
296 {
297 	return ZoomSpeed;
298 }
299 
300 
301 //! Returns the current distance, i.e. orbit radius
getDistance() const302 f32 CSceneNodeAnimatorCameraMaya::getDistance() const
303 {
304 	return CurrentZoom;
305 }
306 
307 
createClone(ISceneNode * node,ISceneManager * newManager)308 ISceneNodeAnimator* CSceneNodeAnimatorCameraMaya::createClone(ISceneNode* node, ISceneManager* newManager)
309 {
310 	CSceneNodeAnimatorCameraMaya * newAnimator =
311 		new CSceneNodeAnimatorCameraMaya(CursorControl, RotateSpeed, ZoomSpeed, TranslateSpeed);
312 	return newAnimator;
313 }
314 
315 } // end namespace
316 } // end namespace
317 
318