]> git.lizzy.rs Git - irrlicht.git/blob - source/Irrlicht/CCameraSceneNode.cpp
aaa752f433a2f118e537fab48d5957d331abed39
[irrlicht.git] / source / Irrlicht / CCameraSceneNode.cpp
1 // Copyright (C) 2002-2012 Nikolaus Gebhardt\r
2 // This file is part of the "Irrlicht Engine".\r
3 // For conditions of distribution and use, see copyright notice in irrlicht.h\r
4 \r
5 #include "CCameraSceneNode.h"\r
6 #include "ISceneManager.h"\r
7 #include "IVideoDriver.h"\r
8 #include "os.h"\r
9 \r
10 namespace irr\r
11 {\r
12 namespace scene\r
13 {\r
14 \r
15 \r
16 //! constructor\r
17 CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id,\r
18         const core::vector3df& position, const core::vector3df& lookat)\r
19         : ICameraSceneNode(parent, mgr, id, position),\r
20         BoundingBox(core::vector3df(0, 0, 0)),  // Camera has no size. Still not sure if FLT_MAX might be the better variant\r
21         Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f),\r
22         InputReceiverEnabled(true), TargetAndRotationAreBound(false),\r
23         HasD3DStyleProjectionMatrix(true)\r
24 {\r
25         #ifdef _DEBUG\r
26         setDebugName("CCameraSceneNode");\r
27         #endif\r
28 \r
29         // set default projection\r
30         Fovy = core::PI / 2.5f; // Field of view, in radians.\r
31 \r
32         const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0;\r
33         if (d)\r
34         {\r
35                 Aspect = (f32)d->getCurrentRenderTargetSize().Width /\r
36                         (f32)d->getCurrentRenderTargetSize().Height;\r
37                 HasD3DStyleProjectionMatrix = d->getDriverType() != video::EDT_OPENGL;\r
38         }\r
39         else\r
40                 Aspect = 4.0f / 3.0f;   // Aspect ratio.\r
41 \r
42         ViewArea.setFarNearDistance(ZFar - ZNear);\r
43         recalculateProjectionMatrix();\r
44         recalculateViewArea();\r
45 }\r
46 \r
47 \r
48 //! Disables or enables the camera to get key or mouse inputs.\r
49 void CCameraSceneNode::setInputReceiverEnabled(bool enabled)\r
50 {\r
51         InputReceiverEnabled = enabled;\r
52 }\r
53 \r
54 \r
55 //! Returns if the input receiver of the camera is currently enabled.\r
56 bool CCameraSceneNode::isInputReceiverEnabled() const\r
57 {\r
58         return InputReceiverEnabled;\r
59 }\r
60 \r
61 \r
62 //! Sets the projection matrix of the camera.\r
63 /** The core::matrix4 class has some methods\r
64 to build a projection matrix. e.g: core::matrix4::buildProjectionMatrixPerspectiveFovLH\r
65 \param projection: The new projection matrix of the camera. */\r
66 void CCameraSceneNode::setProjectionMatrix(const core::matrix4& projection, bool isOrthogonal)\r
67 {\r
68         IsOrthogonal = isOrthogonal;\r
69         ViewArea.getTransform ( video::ETS_PROJECTION ) = projection;\r
70 }\r
71 \r
72 \r
73 //! Gets the current projection matrix of the camera\r
74 //! \return Returns the current projection matrix of the camera.\r
75 const core::matrix4& CCameraSceneNode::getProjectionMatrix() const\r
76 {\r
77         return ViewArea.getTransform ( video::ETS_PROJECTION );\r
78 }\r
79 \r
80 \r
81 //! Gets the current view matrix of the camera\r
82 //! \return Returns the current view matrix of the camera.\r
83 const core::matrix4& CCameraSceneNode::getViewMatrix() const\r
84 {\r
85         return ViewArea.getTransform ( video::ETS_VIEW );\r
86 }\r
87 \r
88 \r
89 //! Sets a custom view matrix affector. The matrix passed here, will be\r
90 //! multiplied with the view matrix when it gets updated.\r
91 //! This allows for custom camera setups like, for example, a reflection camera.\r
92 /** \param affector: The affector matrix. */\r
93 void CCameraSceneNode::setViewMatrixAffector(const core::matrix4& affector)\r
94 {\r
95         Affector = affector;\r
96 }\r
97 \r
98 \r
99 //! Gets the custom view matrix affector.\r
100 const core::matrix4& CCameraSceneNode::getViewMatrixAffector() const\r
101 {\r
102         return Affector;\r
103 }\r
104 \r
105 \r
106 //! It is possible to send mouse and key events to the camera. Most cameras\r
107 //! may ignore this input, but camera scene nodes which are created for\r
108 //! example with scene::ISceneManager::addMayaCameraSceneNode or\r
109 //! scene::ISceneManager::addFPSCameraSceneNode, may want to get this input\r
110 //! for changing their position, look at target or whatever.\r
111 bool CCameraSceneNode::OnEvent(const SEvent& event)\r
112 {\r
113         // animators have been deleted; nothing happens here now!\r
114         return false;\r
115 }\r
116 \r
117 \r
118 //! sets the look at target of the camera\r
119 //! \param pos: Look at target of the camera.\r
120 void CCameraSceneNode::setTarget(const core::vector3df& pos)\r
121 {\r
122         Target = pos;\r
123 \r
124         if(TargetAndRotationAreBound)\r
125         {\r
126                 const core::vector3df toTarget = Target - getAbsolutePosition();\r
127                 ISceneNode::setRotation(toTarget.getHorizontalAngle());\r
128         }\r
129 }\r
130 \r
131 \r
132 //! Sets the rotation of the node.\r
133 /** This only modifies the relative rotation of the node.\r
134 If the camera's target and rotation are bound ( @see bindTargetAndRotation() )\r
135 then calling this will also change the camera's target to match the rotation.\r
136 \param rotation New rotation of the node in degrees. */\r
137 void CCameraSceneNode::setRotation(const core::vector3df& rotation)\r
138 {\r
139         if(TargetAndRotationAreBound)\r
140                 Target = getAbsolutePosition() + rotation.rotationToDirection();\r
141 \r
142         ISceneNode::setRotation(rotation);\r
143 }\r
144 \r
145 \r
146 //! Gets the current look at target of the camera\r
147 //! \return Returns the current look at target of the camera\r
148 const core::vector3df& CCameraSceneNode::getTarget() const\r
149 {\r
150         return Target;\r
151 }\r
152 \r
153 \r
154 //! sets the up vector of the camera\r
155 //! \param pos: New upvector of the camera.\r
156 void CCameraSceneNode::setUpVector(const core::vector3df& pos)\r
157 {\r
158         UpVector = pos;\r
159 }\r
160 \r
161 \r
162 //! Gets the up vector of the camera.\r
163 //! \return Returns the up vector of the camera.\r
164 const core::vector3df& CCameraSceneNode::getUpVector() const\r
165 {\r
166         return UpVector;\r
167 }\r
168 \r
169 \r
170 f32 CCameraSceneNode::getNearValue() const\r
171 {\r
172         return ZNear;\r
173 }\r
174 \r
175 \r
176 f32 CCameraSceneNode::getFarValue() const\r
177 {\r
178         return ZFar;\r
179 }\r
180 \r
181 \r
182 f32 CCameraSceneNode::getAspectRatio() const\r
183 {\r
184         return Aspect;\r
185 }\r
186 \r
187 \r
188 f32 CCameraSceneNode::getFOV() const\r
189 {\r
190         return Fovy;\r
191 }\r
192 \r
193 \r
194 void CCameraSceneNode::setNearValue(f32 f)\r
195 {\r
196         ZNear = f;\r
197         recalculateProjectionMatrix();\r
198         ViewArea.setFarNearDistance(ZFar - ZNear);\r
199 }\r
200 \r
201 \r
202 void CCameraSceneNode::setFarValue(f32 f)\r
203 {\r
204         ZFar = f;\r
205         recalculateProjectionMatrix();\r
206         ViewArea.setFarNearDistance(ZFar - ZNear);\r
207 }\r
208 \r
209 \r
210 void CCameraSceneNode::setAspectRatio(f32 f)\r
211 {\r
212         Aspect = f;\r
213         recalculateProjectionMatrix();\r
214 }\r
215 \r
216 \r
217 void CCameraSceneNode::setFOV(f32 f)\r
218 {\r
219         Fovy = f;\r
220         recalculateProjectionMatrix();\r
221 }\r
222 \r
223 \r
224 void CCameraSceneNode::recalculateProjectionMatrix()\r
225 {\r
226         ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar, HasD3DStyleProjectionMatrix);\r
227         IsOrthogonal = false;\r
228 }\r
229 \r
230 \r
231 //! prerender\r
232 void CCameraSceneNode::OnRegisterSceneNode()\r
233 {\r
234         if ( SceneManager->getActiveCamera () == this )\r
235                 SceneManager->registerNodeForRendering(this, ESNRP_CAMERA);\r
236 \r
237         ISceneNode::OnRegisterSceneNode();\r
238 }\r
239 \r
240 \r
241 //! render\r
242 void CCameraSceneNode::render()\r
243 {\r
244         updateMatrices();\r
245 \r
246         video::IVideoDriver* driver = SceneManager->getVideoDriver();\r
247         if ( driver)\r
248         {\r
249                 driver->setTransform(video::ETS_PROJECTION, ViewArea.getTransform ( video::ETS_PROJECTION) );\r
250                 driver->setTransform(video::ETS_VIEW, ViewArea.getTransform ( video::ETS_VIEW) );\r
251         }\r
252 }\r
253 \r
254 //! update\r
255 void CCameraSceneNode::updateMatrices()\r
256 {\r
257         core::vector3df pos = getAbsolutePosition();\r
258         core::vector3df tgtv = Target - pos;\r
259         tgtv.normalize();\r
260 \r
261         // if upvector and vector to the target are the same, we have a\r
262         // problem. so solve this problem:\r
263         core::vector3df up = UpVector;\r
264         up.normalize();\r
265 \r
266         f32 dp = tgtv.dotProduct(up);\r
267 \r
268         if ( core::equals(core::abs_<f32>(dp), 1.f) )\r
269         {\r
270                 up.X += 0.5f;\r
271         }\r
272 \r
273         ViewArea.getTransform(video::ETS_VIEW).buildCameraLookAtMatrixLH(pos, Target, up);\r
274         ViewArea.getTransform(video::ETS_VIEW) *= Affector;\r
275         recalculateViewArea();\r
276 }\r
277 \r
278 //! returns the axis aligned bounding box of this node\r
279 const core::aabbox3d<f32>& CCameraSceneNode::getBoundingBox() const\r
280 {\r
281         return BoundingBox;\r
282 }\r
283 \r
284 \r
285 //! returns the view frustum.\r
286 const SViewFrustum* CCameraSceneNode::getViewFrustum() const\r
287 {\r
288         return &ViewArea;\r
289 }\r
290 \r
291 \r
292 void CCameraSceneNode::recalculateViewArea()\r
293 {\r
294         ViewArea.cameraPosition = getAbsolutePosition();\r
295 \r
296         core::matrix4 m(core::matrix4::EM4CONST_NOTHING);\r
297         m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION),\r
298                                                 ViewArea.getTransform(video::ETS_VIEW));\r
299         ViewArea.setFrom(m, HasD3DStyleProjectionMatrix);\r
300 }\r
301 \r
302 \r
303 //! Set the binding between the camera's rotation adn target.\r
304 void CCameraSceneNode::bindTargetAndRotation(bool bound)\r
305 {\r
306         TargetAndRotationAreBound = bound;\r
307 }\r
308 \r
309 \r
310 //! Gets the binding between the camera's rotation and target.\r
311 bool CCameraSceneNode::getTargetAndRotationBinding(void) const\r
312 {\r
313         return TargetAndRotationAreBound;\r
314 }\r
315 \r
316 \r
317 //! Creates a clone of this scene node and its children.\r
318 ISceneNode* CCameraSceneNode::clone(ISceneNode* newParent, ISceneManager* newManager)\r
319 {\r
320         ICameraSceneNode::clone(newParent, newManager);\r
321 \r
322         if (!newParent)\r
323                 newParent = Parent;\r
324         if (!newManager)\r
325                 newManager = SceneManager;\r
326 \r
327         CCameraSceneNode* nb = new CCameraSceneNode(newParent,\r
328                 newManager, ID, RelativeTranslation, Target);\r
329 \r
330         nb->ISceneNode::cloneMembers(this, newManager);\r
331         nb->ICameraSceneNode::cloneMembers(this);\r
332 \r
333         nb->Target = Target;\r
334         nb->UpVector = UpVector;\r
335         nb->Fovy = Fovy;\r
336         nb->Aspect = Aspect;\r
337         nb->ZNear = ZNear;\r
338         nb->ZFar = ZFar;\r
339         nb->ViewArea = ViewArea;\r
340         nb->Affector = Affector;\r
341         nb->InputReceiverEnabled = InputReceiverEnabled;\r
342         nb->TargetAndRotationAreBound = TargetAndRotationAreBound;\r
343 \r
344         if ( newParent )\r
345                 nb->drop();\r
346         return nb;\r
347 }\r
348 \r
349 \r
350 } // end namespace\r
351 } // end namespace\r
352 \r