BGE Scenegraph and View frustrum culling improvement.
[blender-staging.git] / source / gameengine / SceneGraph / SG_Spatial.cpp
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "SG_Node.h"
31 #include "SG_Spatial.h"
32 #include "SG_Controller.h"
33 #include "SG_ParentRelation.h"
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 SG_Spatial::
40 SG_Spatial(
41         void* clientobj,
42         void* clientinfo,
43         SG_Callbacks callbacks
44 ): 
45
46         SG_IObject(clientobj,clientinfo,callbacks),
47         m_localPosition(0.0,0.0,0.0),
48         m_localRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0),
49         m_localScaling(1.f,1.f,1.f),
50         
51         m_worldPosition(0.0,0.0,0.0),
52         m_worldRotation(1.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0),
53         m_worldScaling(1.f,1.f,1.f),
54
55         m_parent_relation (NULL),
56         
57         m_bbox(MT_Point3(-1.0, -1.0, -1.0), MT_Point3(1.0, 1.0, 1.0)),
58         m_radius(1.0),
59         m_modified(true)
60 {
61 }
62
63 SG_Spatial::
64 SG_Spatial(
65         const SG_Spatial& other
66 ) : 
67         SG_IObject(other),
68         m_localPosition(other.m_localPosition),
69         m_localRotation(other.m_localRotation),
70         m_localScaling(other.m_localScaling),
71         
72         m_worldPosition(other.m_worldPosition),
73         m_worldRotation(other.m_worldRotation),
74         m_worldScaling(other.m_worldScaling),
75         
76         m_parent_relation(NULL),
77         
78         m_bbox(other.m_bbox),
79         m_radius(other.m_radius)
80 {
81         // duplicate the parent relation for this object
82         m_parent_relation = other.m_parent_relation->NewCopy();
83 }
84         
85 SG_Spatial::
86 ~SG_Spatial()
87 {
88         delete (m_parent_relation);
89 }
90
91         SG_ParentRelation *
92 SG_Spatial::
93 GetParentRelation(
94 ){
95         return m_parent_relation;
96 }
97
98         void
99 SG_Spatial::
100 SetParentRelation(
101         SG_ParentRelation *relation
102 ){
103         delete (m_parent_relation);
104         m_parent_relation = relation;
105         m_modified = true;
106 }
107
108
109 /**
110  * Update Spatial Data.
111  * Calculates WorldTransform., (either doing itsself or using the linked SGControllers)
112  */
113
114
115         bool 
116 SG_Spatial::
117 UpdateSpatialData(
118         const SG_Spatial *parent,
119         double time,
120         bool& parentUpdated
121 ){
122
123     bool bComputesWorldTransform = false;
124
125         // update spatial controllers
126         
127         SGControllerList::iterator cit = GetSGControllerList().begin();
128         SGControllerList::const_iterator c_end = GetSGControllerList().end();
129
130         for (;cit!=c_end;++cit)
131         {
132                 if ((*cit)->Update(time))
133                         bComputesWorldTransform = true;
134         }
135
136         // If none of the objects updated our values then we ask the
137         // parent_relation object owned by this class to update 
138         // our world coordinates.
139
140         if (!bComputesWorldTransform)
141                 bComputesWorldTransform = ComputeWorldTransforms(parent, parentUpdated);
142
143         return bComputesWorldTransform;
144 }
145
146 bool    SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent, bool& parentUpdated)
147 {
148         return m_parent_relation->UpdateChildCoordinates(this,parent,parentUpdated);
149 }
150
151 /**
152  * Position and translation methods
153  */
154
155
156         void 
157 SG_Spatial::
158 RelativeTranslate(
159         const MT_Vector3& trans,
160         const SG_Spatial *parent,
161         bool local
162 ){
163         if (local) {
164                         m_localPosition += m_localRotation * trans;
165         } else {
166                 if (parent) {
167                         m_localPosition += trans * parent->GetWorldOrientation();
168                 } else {
169                         m_localPosition += trans;
170                 }
171         }
172         m_modified = true;
173 }       
174         
175         void 
176 SG_Spatial::
177 SetLocalPosition(
178         const MT_Point3& trans
179 ){
180         m_localPosition = trans;
181         m_modified = true;
182 }
183
184         void                            
185 SG_Spatial::
186 SetWorldPosition(
187         const MT_Point3& trans
188 ) {
189         m_worldPosition = trans;
190 }
191
192 /**
193  * Scaling methods.
194  */ 
195
196         void 
197 SG_Spatial::
198 RelativeScale(
199         const MT_Vector3& scale
200 ){
201         m_localScaling = m_localScaling * scale;
202         m_modified = true;
203 }
204
205         void 
206 SG_Spatial::
207 SetLocalScale(
208         const MT_Vector3& scale
209 ){
210         m_localScaling = scale;
211         m_modified = true;
212 }
213
214
215         void                            
216 SG_Spatial::
217 SetWorldScale(
218         const MT_Vector3& scale
219 ){ 
220         m_worldScaling = scale;
221 }
222
223 /**
224  * Orientation and rotation methods.
225  */
226
227
228         void 
229 SG_Spatial::
230 RelativeRotate(
231         const MT_Matrix3x3& rot,
232         bool local
233 ){
234         m_localRotation = m_localRotation * (
235         local ? 
236                 rot 
237         :
238         (GetWorldOrientation().inverse() * rot * GetWorldOrientation()));
239         m_modified = true;
240 }
241
242         void 
243 SG_Spatial::
244 SetLocalOrientation(const MT_Matrix3x3& rot)
245 {
246         m_localRotation = rot;
247         m_modified = true;
248 }
249
250
251
252         void                            
253 SG_Spatial::
254 SetWorldOrientation(
255         const MT_Matrix3x3& rot
256 ) {
257         m_worldRotation = rot;
258 }
259
260 const 
261         MT_Point3&
262 SG_Spatial::
263 GetLocalPosition(
264 ) const {
265          return m_localPosition;
266 }
267
268 const 
269         MT_Matrix3x3&
270 SG_Spatial::
271 GetLocalOrientation(
272 ) const {
273         return m_localRotation;
274 }
275
276 const 
277         MT_Vector3&     
278 SG_Spatial::
279 GetLocalScale(
280 ) const{
281         return m_localScaling;
282 }
283
284
285 const 
286         MT_Point3&
287 SG_Spatial::
288 GetWorldPosition(
289 ) const {
290         return m_worldPosition;
291 }
292
293 const 
294         MT_Matrix3x3&   
295 SG_Spatial::
296 GetWorldOrientation(
297 ) const {
298         return m_worldRotation;
299 }
300
301 const 
302         MT_Vector3&     
303 SG_Spatial::
304 GetWorldScaling(
305 ) const {
306         return m_worldScaling;
307 }
308
309 void SG_Spatial::SetWorldFromLocalTransform()
310 {
311         m_worldPosition= m_localPosition;
312         m_worldScaling= m_localScaling;
313         m_worldRotation= m_localRotation;
314 }
315
316 SG_BBox& SG_Spatial::BBox()
317 {
318         return m_bbox;
319 }
320
321 void SG_Spatial::SetBBox(SG_BBox& bbox)
322 {
323         m_bbox = bbox;
324 }
325
326 MT_Transform SG_Spatial::GetWorldTransform() const
327 {
328         return MT_Transform(m_worldPosition, 
329                 m_worldRotation.scaled(
330                 m_worldScaling[0], m_worldScaling[1], m_worldScaling[2]));
331 }
332
333 bool SG_Spatial::inside(const MT_Point3 &point) const
334 {
335         MT_Scalar radius = m_worldScaling[m_worldScaling.closestAxis()]*m_radius;
336         return (m_worldPosition.distance2(point) <= radius*radius) ?
337                 m_bbox.transform(GetWorldTransform()).inside(point) :
338                 false;
339 }
340
341 void SG_Spatial::getBBox(MT_Point3 *box) const
342 {
343         m_bbox.get(box, GetWorldTransform());
344 }
345
346 void SG_Spatial::getAABBox(MT_Point3 *box) const
347 {
348         m_bbox.getaa(box, GetWorldTransform());
349 }
350