99aeb3e72eeb6ff7585d92926ee945f3a1b0f915
[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 {
60 }
61
62 SG_Spatial::
63 SG_Spatial(
64         const SG_Spatial& other
65 ) : 
66         SG_IObject(other),
67         m_localPosition(other.m_localPosition),
68         m_localRotation(other.m_localRotation),
69         m_localScaling(other.m_localScaling),
70         
71         m_worldPosition(other.m_worldPosition),
72         m_worldRotation(other.m_worldRotation),
73         m_worldScaling(other.m_worldScaling),
74         
75         m_parent_relation(NULL),
76         
77         m_bbox(other.m_bbox),
78         m_radius(other.m_radius)
79 {
80         // duplicate the parent relation for this object
81         m_parent_relation = other.m_parent_relation->NewCopy();
82 }
83         
84 SG_Spatial::
85 ~SG_Spatial()
86 {
87         delete (m_parent_relation);
88 }
89
90         SG_ParentRelation *
91 SG_Spatial::
92 GetParentRelation(
93 ){
94         return m_parent_relation;
95 }
96
97         void
98 SG_Spatial::
99 SetParentRelation(
100         SG_ParentRelation *relation
101 ){
102         delete (m_parent_relation);
103         m_parent_relation = relation;
104 }
105
106
107 /**
108  * Update Spatial Data.
109  * Calculates WorldTransform., (either doing itsself or using the linked SGControllers)
110  */
111
112
113         bool 
114 SG_Spatial::
115 UpdateSpatialData(
116         const SG_Spatial *parent,
117         double time
118 ){
119
120     bool bComputesWorldTransform = false;
121
122         // update spatial controllers
123         
124         SGControllerList::iterator cit = GetSGControllerList().begin();
125         SGControllerList::const_iterator c_end = GetSGControllerList().end();
126
127         for (;cit!=c_end;++cit)
128         {
129                 if ((*cit)->Update(time))
130                         bComputesWorldTransform = true;
131         }
132
133         // If none of the objects updated our values then we ask the
134         // parent_relation object owned by this class to update 
135         // our world coordinates.
136
137         if (!bComputesWorldTransform)
138                 bComputesWorldTransform = ComputeWorldTransforms(parent);
139
140         return bComputesWorldTransform;
141 }
142
143 bool    SG_Spatial::ComputeWorldTransforms(const SG_Spatial *parent)
144 {
145         return m_parent_relation->UpdateChildCoordinates(this,parent);
146 }
147
148 /**
149  * Position and translation methods
150  */
151
152
153         void 
154 SG_Spatial::
155 RelativeTranslate(
156         const MT_Vector3& trans,
157         const SG_Spatial *parent,
158         bool local
159 ){
160         if (local) {
161                         m_localPosition += m_localRotation * trans;
162         } else {
163                 if (parent) {
164                         m_localPosition += trans * parent->GetWorldOrientation();
165                 } else {
166                         m_localPosition += trans;
167                 }
168         }
169 }       
170         
171         void 
172 SG_Spatial::
173 SetLocalPosition(
174         const MT_Point3& trans
175 ){
176         m_localPosition = trans;
177 }
178
179         void                            
180 SG_Spatial::
181 SetWorldPosition(
182         const MT_Point3& trans
183 ) {
184         m_worldPosition = trans;
185 }
186
187 /**
188  * Scaling methods.
189  */ 
190
191         void 
192 SG_Spatial::
193 RelativeScale(
194         const MT_Vector3& scale
195 ){
196         m_localScaling = m_localScaling * scale;
197 }
198
199         void 
200 SG_Spatial::
201 SetLocalScale(
202         const MT_Vector3& scale
203 ){
204         m_localScaling = scale;
205 }
206
207
208         void                            
209 SG_Spatial::
210 SetWorldScale(
211         const MT_Vector3& scale
212 ){ 
213         m_worldScaling = scale;
214 }
215
216 /**
217  * Orientation and rotation methods.
218  */
219
220
221         void 
222 SG_Spatial::
223 RelativeRotate(
224         const MT_Matrix3x3& rot,
225         bool local
226 ){
227         m_localRotation = m_localRotation * (
228         local ? 
229                 rot 
230         :
231         (GetWorldOrientation().inverse() * rot * GetWorldOrientation()));
232 }
233
234         void 
235 SG_Spatial::
236 SetLocalOrientation(const MT_Matrix3x3& rot)
237 {
238         m_localRotation = rot;
239 }
240
241
242
243         void                            
244 SG_Spatial::
245 SetWorldOrientation(
246         const MT_Matrix3x3& rot
247 ) {
248         m_worldRotation = rot;
249 }
250
251 const 
252         MT_Point3&
253 SG_Spatial::
254 GetLocalPosition(
255 ) const {
256          return m_localPosition;
257 }
258
259 const 
260         MT_Matrix3x3&
261 SG_Spatial::
262 GetLocalOrientation(
263 ) const {
264         return m_localRotation;
265 }
266
267 const 
268         MT_Vector3&     
269 SG_Spatial::
270 GetLocalScale(
271 ) const{
272         return m_localScaling;
273 }
274
275
276 const 
277         MT_Point3&
278 SG_Spatial::
279 GetWorldPosition(
280 ) const {
281         return m_worldPosition;
282 }
283
284 const 
285         MT_Matrix3x3&   
286 SG_Spatial::
287 GetWorldOrientation(
288 ) const {
289         return m_worldRotation;
290 }
291
292 const 
293         MT_Vector3&     
294 SG_Spatial::
295 GetWorldScaling(
296 ) const {
297         return m_worldScaling;
298 }
299
300 void SG_Spatial::SetWorldFromLocalTransform()
301 {
302         m_worldPosition= m_localPosition;
303         m_worldScaling= m_localScaling;
304         m_worldRotation= m_localRotation;
305 }
306
307 SG_BBox& SG_Spatial::BBox()
308 {
309         return m_bbox;
310 }
311
312 void SG_Spatial::SetBBox(SG_BBox& bbox)
313 {
314         m_bbox = bbox;
315 }
316
317 MT_Transform SG_Spatial::GetWorldTransform() const
318 {
319         return MT_Transform(m_worldPosition, 
320                 m_worldRotation.scaled(
321                 m_worldScaling[0], m_worldScaling[1], m_worldScaling[2]));
322 }
323
324 bool SG_Spatial::inside(const MT_Point3 &point) const
325 {
326         MT_Scalar radius = m_worldScaling[m_worldScaling.closestAxis()]*m_radius;
327         return (m_worldPosition.distance2(point) <= radius*radius) ?
328                 m_bbox.transform(GetWorldTransform()).inside(point) :
329                 false;
330 }
331
332 void SG_Spatial::getBBox(MT_Point3 *box) const
333 {
334         m_bbox.get(box, GetWorldTransform());
335 }
336
337 void SG_Spatial::getAABBox(MT_Point3 *box) const
338 {
339         m_bbox.getaa(box, GetWorldTransform());
340 }
341