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 "CCameraSceneNode.h"
6 #include "ISceneManager.h"
7 #include "IVideoDriver.h"
8 #include "os.h"
9
10 namespace irr
11 {
12 namespace scene
13 {
14
15
16 //! constructor
CCameraSceneNode(ISceneNode * parent,ISceneManager * mgr,s32 id,const core::vector3df & position,const core::vector3df & lookat)17 CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,
18 const core::vector3df& position, const core::vector3df& lookat)
19 : ICameraSceneNode(parent, mgr, id, position),
20 Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),
21 InputReceiverEnabled(true), TargetAndRotationAreBound(false)
22 {
23 #ifdef _DEBUG
24 setDebugName("CCameraSceneNode");
25 #endif
26
27 // set default projection
28 Fovy = core::PI / 2.5f; // Field of view, in radians.
29
30 const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0;
31 if (d)
32 Aspect = (f32)d->getCurrentRenderTargetSize().Width /
33 (f32)d->getCurrentRenderTargetSize().Height;
34 else
35 Aspect = 4.0f / 3.0f; // Aspect ratio.
36
37 recalculateProjectionMatrix();
38 recalculateViewArea();
39 }
40
41
42 //! Disables or enables the camera to get key or mouse inputs.
setInputReceiverEnabled(bool enabled)43 void CCameraSceneNode::setInputReceiverEnabled(bool enabled)
44 {
45 InputReceiverEnabled = enabled;
46 }
47
48
49 //! Returns if the input receiver of the camera is currently enabled.
isInputReceiverEnabled() const50 bool CCameraSceneNode::isInputReceiverEnabled() const
51 {
52 _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
53 return InputReceiverEnabled;
54 }
55
56
57 //! Sets the projection matrix of the camera.
58 /** The core::matrix4 class has some methods
59 to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH
60 \param projection: The new projection matrix of the camera. */
setProjectionMatrix(const core::matrix4 & projection,bool isOrthogonal)61 void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)
62 {
63 IsOrthogonal = isOrthogonal;
64 ViewArea.getTransform ( video::ETS_PROJECTION ) = projection;
65 }
66
67
68 //! Gets the current projection matrix of the camera
69 //! \return Returns the current projection matrix of the camera.
getProjectionMatrix() const70 const core::matrix4& CCameraSceneNode::getProjectionMatrix() const
71 {
72 return ViewArea.getTransform ( video::ETS_PROJECTION );
73 }
74
75
76 //! Gets the current view matrix of the camera
77 //! \return Returns the current view matrix of the camera.
getViewMatrix() const78 const core::matrix4& CCameraSceneNode::getViewMatrix() const
79 {
80 return ViewArea.getTransform ( video::ETS_VIEW );
81 }
82
83
84 //! Sets a custom view matrix affector. The matrix passed here, will be
85 //! multiplied with the view matrix when it gets updated.
86 //! This allows for custom camera setups like, for example, a reflection camera.
87 /** \param affector: The affector matrix. */
setViewMatrixAffector(const core::matrix4 & affector)88 void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)
89 {
90 Affector = affector;
91 }
92
93
94 //! Gets the custom view matrix affector.
getViewMatrixAffector() const95 const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const
96 {
97 return Affector;
98 }
99
100
101 //! It is possible to send mouse and key events to the camera. Most cameras
102 //! may ignore this input, but camera scene nodes which are created for
103 //! example with scene::ISceneManager::addMayaCameraSceneNode or
104 //! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input
105 //! for changing their position, look at target or whatever.
OnEvent(const SEvent & event)106 bool CCameraSceneNode::OnEvent(const SEvent& event)
107 {
108 if (!InputReceiverEnabled)
109 return false;
110
111 // send events to event receiving animators
112
113 ISceneNodeAnimatorList::Iterator ait = Animators.begin();
114
115 for (; ait != Animators.end(); ++ait)
116 if ((*ait)->isEventReceiverEnabled() && (*ait)->OnEvent(event))
117 return true;
118
119 // if nobody processed the event, return false
120 return false;
121 }
122
123
124 //! sets the look at target of the camera
125 //! \param pos: Look at target of the camera.
setTarget(const core::vector3df & pos)126 void CCameraSceneNode::setTarget(const core::vector3df& pos)
127 {
128 Target = pos;
129
130 if(TargetAndRotationAreBound)
131 {
132 const core::vector3df toTarget = Target - getAbsolutePosition();
133 ISceneNode::setRotation(toTarget.getHorizontalAngle());
134 }
135 }
136
137
138 //! Sets the rotation of the node.
139 /** This only modifies the relative rotation of the node.
140 If the camera's target and rotation are bound ( @see bindTargetAndRotation() )
141 then calling this will also change the camera's target to match the rotation.
142 \param rotation New rotation of the node in degrees. */
setRotation(const core::vector3df & rotation)143 void CCameraSceneNode::setRotation(const core::vector3df& rotation)
144 {
145 if(TargetAndRotationAreBound)
146 Target = getAbsolutePosition() + rotation.rotationToDirection();
147
148 ISceneNode::setRotation(rotation);
149 }
150
151
152 //! Gets the current look at target of the camera
153 //! \return Returns the current look at target of the camera
getTarget() const154 const core::vector3df& CCameraSceneNode::getTarget() const
155 {
156 return Target;
157 }
158
159
160 //! sets the up vector of the camera
161 //! \param pos: New upvector of the camera.
setUpVector(const core::vector3df & pos)162 void CCameraSceneNode::setUpVector(const core::vector3df& pos)
163 {
164 UpVector = pos;
165 }
166
167
168 //! Gets the up vector of the camera.
169 //! \return Returns the up vector of the camera.
getUpVector() const170 const core::vector3df& CCameraSceneNode::getUpVector() const
171 {
172 return UpVector;
173 }
174
175
getNearValue() const176 f32 CCameraSceneNode::getNearValue() const
177 {
178 return ZNear;
179 }
180
181
getFarValue() const182 f32 CCameraSceneNode::getFarValue() const
183 {
184 return ZFar;
185 }
186
187
getAspectRatio() const188 f32 CCameraSceneNode::getAspectRatio() const
189 {
190 return Aspect;
191 }
192
193
getFOV() const194 f32 CCameraSceneNode::getFOV() const
195 {
196 return Fovy;
197 }
198
199
setNearValue(f32 f)200 void CCameraSceneNode::setNearValue(f32 f)
201 {
202 ZNear = f;
203 recalculateProjectionMatrix();
204 }
205
206
setFarValue(f32 f)207 void CCameraSceneNode::setFarValue(f32 f)
208 {
209 ZFar = f;
210 recalculateProjectionMatrix();
211 }
212
213
setAspectRatio(f32 f)214 void CCameraSceneNode::setAspectRatio(f32 f)
215 {
216 Aspect = f;
217 recalculateProjectionMatrix();
218 }
219
220
setFOV(f32 f)221 void CCameraSceneNode::setFOV(f32 f)
222 {
223 Fovy = f;
224 recalculateProjectionMatrix();
225 }
226
227
recalculateProjectionMatrix()228 void CCameraSceneNode::recalculateProjectionMatrix()
229 {
230 ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar);
231 }
232
233
234 //! prerender
OnRegisterSceneNode()235 void CCameraSceneNode::OnRegisterSceneNode()
236 {
237 if ( SceneManager->getActiveCamera () == this )
238 SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);
239
240 ISceneNode::OnRegisterSceneNode();
241 }
242
243
244 //! render
render()245 void CCameraSceneNode::render()
246 {
247 core::vector3df pos = getAbsolutePosition();
248 core::vector3df tgtv = Target - pos;
249 tgtv.normalize();
250
251 // if upvector and vector to the target are the same, we have a
252 // problem. so solve this problem:
253 core::vector3df up = UpVector;
254 up.normalize();
255
256 f32 dp = tgtv.dotProduct(up);
257
258 if ( core::equals(core::abs_<f32>(dp), 1.f) )
259 {
260 up.X += 0.5f;
261 }
262
263 ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up);
264 ViewArea.getTransform(video::ETS_VIEW) *= Affector;
265 recalculateViewArea();
266
267 video::IVideoDriver* driver = SceneManager->getVideoDriver();
268 if ( driver)
269 {
270 driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) );
271 driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) );
272 }
273 }
274
275
276 //! returns the axis aligned bounding box of this node
getBoundingBox() const277 const core::aabbox3d<f32>& CCameraSceneNode::getBoundingBox() const
278 {
279 return ViewArea.getBoundingBox();
280 }
281
282
283 //! returns the view frustum. needed sometimes by bsp or lod render nodes.
getViewFrustum() const284 const SViewFrustum* CCameraSceneNode::getViewFrustum() const
285 {
286 return &ViewArea;
287 }
288
289
recalculateViewArea()290 void CCameraSceneNode::recalculateViewArea()
291 {
292 ViewArea.cameraPosition = getAbsolutePosition();
293
294 core::matrix4 m(core::matrix4::EM4CONST_NOTHING);
295 m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION),
296 ViewArea.getTransform(video::ETS_VIEW));
297 ViewArea.setFrom(m);
298 }
299
300
301 //! Writes attributes of the scene node.
serializeAttributes(io::IAttributes * out,io::SAttributeReadWriteOptions * options) const302 void CCameraSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
303 {
304 ICameraSceneNode::serializeAttributes(out, options);
305
306 out->addVector3d("Target", Target);
307 out->addVector3d("UpVector", UpVector);
308 out->addFloat("Fovy", Fovy);
309 out->addFloat("Aspect", Aspect);
310 out->addFloat("ZNear", ZNear);
311 out->addFloat("ZFar", ZFar);
312 out->addBool("Binding", TargetAndRotationAreBound);
313 out->addBool("ReceiveInput", InputReceiverEnabled);
314 }
315
316 //! Reads attributes of the scene node.
deserializeAttributes(io::IAttributes * in,io::SAttributeReadWriteOptions * options)317 void CCameraSceneNode::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
318 {
319 ICameraSceneNode::deserializeAttributes(in, options);
320
321 Target = in->getAttributeAsVector3d("Target");
322 UpVector = in->getAttributeAsVector3d("UpVector");
323 Fovy = in->getAttributeAsFloat("Fovy");
324 Aspect = in->getAttributeAsFloat("Aspect");
325 ZNear = in->getAttributeAsFloat("ZNear");
326 ZFar = in->getAttributeAsFloat("ZFar");
327 TargetAndRotationAreBound = in->getAttributeAsBool("Binding");
328 if ( in->findAttribute("ReceiveInput") )
329 InputReceiverEnabled = in->getAttributeAsBool("InputReceiverEnabled");
330
331 recalculateProjectionMatrix();
332 recalculateViewArea();
333 }
334
335
336 //! Set the binding between the camera's rotation adn target.
bindTargetAndRotation(bool bound)337 void CCameraSceneNode::bindTargetAndRotation(bool bound)
338 {
339 TargetAndRotationAreBound = bound;
340 }
341
342
343 //! Gets the binding between the camera's rotation and target.
getTargetAndRotationBinding(void) const344 bool CCameraSceneNode::getTargetAndRotationBinding(void) const
345 {
346 return TargetAndRotationAreBound;
347 }
348
349
350 //! Creates a clone of this scene node and its children.
clone(ISceneNode * newParent,ISceneManager * newManager)351 ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)
352 {
353 ICameraSceneNode::clone(newParent, newManager);
354
355 if (!newParent)
356 newParent = Parent;
357 if (!newManager)
358 newManager = SceneManager;
359
360 CCameraSceneNode* nb = new CCameraSceneNode(newParent,
361 newManager, ID, RelativeTranslation, Target);
362
363 nb->ISceneNode::cloneMembers(this, newManager);
364 nb->ICameraSceneNode::cloneMembers(this);
365
366 nb->Target = Target;
367 nb->UpVector = UpVector;
368 nb->Fovy = Fovy;
369 nb->Aspect = Aspect;
370 nb->ZNear = ZNear;
371 nb->ZFar = ZFar;
372 nb->ViewArea = ViewArea;
373 nb->Affector = Affector;
374 nb->InputReceiverEnabled = InputReceiverEnabled;
375 nb->TargetAndRotationAreBound = TargetAndRotationAreBound;
376
377 if ( newParent )
378 nb->drop();
379 return nb;
380 }
381
382
383 } // end namespace
384 } // end namespace
385
386