1 /*****************************************************************************
2  * $LastChangedDate: 2010-06-24 10:22:48 -0400 (Thu, 24 Jun 2010) $
3  * @file
4  * @author  Jim E. Brooks  http://www.palomino3d.org
5  * @brief   Base Object class.
6  *//*
7  * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
8  *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
9  *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
10  *****************************************************************************/
11 
12 #define OBJECT_OBJECT_CC 1
13 #include "base/module.hh"
14 #include "base/bits.hh"
15 using namespace base;
16 #include "math/module.hh"
17 #include "math/funcs.hh"
18 #include "math/matrix.hh"
19 #include "math/matrix_funcs.hh"
20 using namespace math;
21 #include "graph/module.hh"
22 #include "graph/scene_graph.hh"
23 using namespace graph;
24 #include "world/module.hh"
25 using namespace world;
26 #include "collision/module.hh"
27 using namespace collision;
28 #include "control/module.hh"
29 using namespace control;
30 #include "object/module.hh"
31 #include "object/object.hh"
32 #include "object/zombies.hh"
33 #include "object/events.hh"
34 using namespace object;
35 
36 namespace object {
37 
38 ////////////////////////////////////////////////////////////////////////////////
39 /// @brief Dummy Object.
40 ///
41 class DummyObject : public Object
42 {
43 PREVENT_COPYING(DummyObject)
44 public:
DummyObject(void)45     DummyObject( void )
46     :   Object(Graph::MakeMinimalGraph(),WorldVertex(0,0,0))
47     {
48         mBits.mDummy = true;
49     }
50 
GetName(void)51     virtual const string GetName( void ) { return string("DummyObject"); }
52 };
53 
54 ////////////////////////////////////////////////////////////////////////////////
55 ///////////////////////////////  Object  ///////////////////////////////////////
56 ////////////////////////////////////////////////////////////////////////////////
57 
58 int             Object::msObjectCount = 0;
59 const NodeSort  Object::msDefaultNodeSort;
60 
61 /*****************************************************************************
62  * ctor/dtor.
63  *****************************************************************************/
Object(shptr<Graph> graph,const WorldVertex & pos)64 Object::Object( shptr<Graph> graph, const WorldVertex& pos )
65 :   mGraph(graph),
66     mTransformNode(graph->GetTransformNode()),
67     mRadius(-1.0f),  // -1 means uncomputed
68     mBits()
69 {
70     ++msObjectCount;
71     SET_TYPESIG(this,TYPESIG_OBJECT);
72     CLEAR_BIT_FIELDS(&mBits);
73 
74     SetPosition( pos );
75 }
76 
~Object()77 Object::~Object()
78 {
79     // Object dtor detaches from scene-graph even though Object ctor didn't attach.
80     GET_SCENE_GRAPH().DetachNode( GetRootNode() );
81 
82     --msObjectCount;
83     ASSERT( msObjectCount >= 0 );  // catch double-deletion
84     INVALIDATE_TYPESIG(this,TYPESIG_OBJECT);
85 }
86 
87 /*****************************************************************************
88  * Make a dummy Object.
89  *****************************************************************************/
90 shptr<Object>  // CLASS_METHOD
MakeDummyObject(void)91 Object::MakeDummyObject( void )
92 {
93     // Re-use the same dummy to minimize Object count.
94     PERSISTENT shptr<DummyObject> sDummyObject = new DummyObject;
95     return sDummyObject.PTR();
96 }
97 
98 /*****************************************************************************
99  * Ok to call repeatedly (NOP).
100  * Zombification reduces memory consumption by freeing an Object's Graph.
101  * Some 3D models consume tens of megabytes (which a Graph holds).
102  * Replacing Graph is potentially dangerous but so is manipulating a detached Object.
103  *****************************************************************************/
104 void
Zombify(void)105 Object::Zombify( void )
106 {
107 CHECK_OBJECT();
108 
109     // Omit calling World::Detach().
110     // Let World::Detach() call Object::Zombify().
111     // World::Detach() will release the Object's previous Graph.
112 
113     // Do once.
114     if ( not mBits.mZombie )
115     {
116         // Set zombie bit.
117         mBits.mZombie = true;
118 
119         // First detach the current Graph.
120         GET_SCENE_GRAPH().DetachNode( GetRootNode() );
121 
122         // As step in reducing memory usage, replace Graph with a minimal one.
123         mGraph = Graph::MakeMinimalGraph();
124 
125         // Schedule this Object for destruction.
126         GET_ZOMBIE_OBJECTS().Zombify( this );
127     }
128 }
129 
130 ////////////////////////////////////////////////////////////////////////////////
131 ////////////////////////////  Object : drawing  ////////////////////////////////
132 ////////////////////////////////////////////////////////////////////////////////
133 
134 /*****************************************************************************
135  * Draw Object.
136  *****************************************************************************/
137 void
Draw(void)138 Object::Draw( void )
139 {
140 CHECK_OBJECT();
141 
142     // (NOP on OSG)
143 }
144 
145 ////////////////////////////////////////////////////////////////////////////////
146 ////////////////////////////  Object : spatial  ////////////////////////////////
147 ////////////////////////////////////////////////////////////////////////////////
148 
149 /*****************************************************************************
150  * Set/get position of Object.
151  * Position is defined by the matrix origin.
152  *****************************************************************************/
153 void
SetPosition(const WorldVertex & position)154 Object::SetPosition( const WorldVertex& position )
155 {
156 CHECK_OBJECT();
157 
158     osg::Matrix m = mTransformNode->getMatrix();
159     m.setTrans( position );
160     mTransformNode->setMatrix( m );
161 }
162 
163 WorldVertex
GetPosition(void)164 Object::GetPosition( void )
165 {
166 CHECK_OBJECT();
167 
168     return mTransformNode->getMatrix().getTrans();
169 }
170 
171 /*****************************************************************************
172  * Compute approximate radius of Object.
173  *****************************************************************************/
174 fp
ComputeRadius(void)175 Object::ComputeRadius( void )
176 {
177 CHECK_OBJECT();
178 
179     // Must ensure child of switch node is enabled, or radius will be -1.
180     const bool graphEnabled = GetGraph()->IfEnabled();
181     GetGraph()->Enable( true );
182       //const fp radius = GetRootNode()->computeBoundingBox().radius();
183         const fp radius = GetRootNode()->getBound().radius();  // faster
184         ASSERT( IfZombie() or radius > 0.0f );  // OSG could return -1
185     GetGraph()->Enable( graphEnabled );  // restore
186     return radius;
187 }
188 
189 ////////////////////////////////////////////////////////////////////////////////
190 ///////////////////////////  Object : geometry  ////////////////////////////////
191 ////////////////////////////////////////////////////////////////////////////////
192 
193 /*****************************************************************************
194  * Scale an Object.
195  *****************************************************************************/
196 void
Scale(const Vector3 & v)197 Object::Scale( const Vector3& v )
198 {
199 CHECK_OBJECT();
200 
201     MatrixScale( *mTransformNode, v );
202 }
203 
204 void
Scale(const fp scale)205 Object::Scale( const fp scale )
206 {
207 CHECK_OBJECT();
208 
209     Scale( Vector3( scale, scale, scale ) );
210 }
211 
212 ////////////////////////////////////////////////////////////////////////////////
213 ////////////////////////  Object : transformation  /////////////////////////////
214 ////////////////////////////////////////////////////////////////////////////////
215 
216 /*****************************************************************************
217  * Set matrix.
218  *****************************************************************************/
219 void
SetMatrix(const Matrix & matrix,eMatrixChange)220 Object::SetMatrix( const Matrix& matrix, eMatrixChange /* used by Dyna */ )
221 {
222 CHECK_OBJECT();
223 
224     mTransformNode->setMatrix( matrix );
225 }
226 
227 /*****************************************************************************
228  * Set rotation by quaternion.
229  * Note: Quaternions don't define position.
230  *****************************************************************************/
231 void
SetQuaternion(const Quaternion & quat)232 Object::SetQuaternion( const Quaternion& quat )
233 {
234 CHECK_OBJECT();
235 
236     // Reuse SetMatrix().  But Quaternions don't have a position.
237     SetMatrix( Matrix( quat, GetPosition() ),
238                Object::ROTATION );
239 }
240 
241 Quaternion
GetQuaternion(void)242 Object::GetQuaternion( void )
243 {
244 CHECK_OBJECT();
245 
246     return Quaternion( GetMatrix() );  // discards position
247 }
248 
249 /*****************************************************************************
250  * Move Object along one of its local axis.
251  *****************************************************************************/
252 void
Translate(uint axis,fp inc)253 Object::Translate( uint axis, fp inc )
254 {
255 CHECK_OBJECT();
256 ASSERT_AXIS3( axis );
257 
258     Matrix m = GetMatrix();
259     MatrixTranslateLocal<>( m, axis, inc );
260     SetMatrix( m, Object::TRANSLATION );
261 }
262 
263 /*****************************************************************************
264  * Translate Object by adding a 3D vector offset.
265  *****************************************************************************/
266 void
Translate(const Vector3 & v)267 Object::Translate( const Vector3& v )
268 {
269 CHECK_OBJECT();
270 
271     Matrix m = GetMatrix();
272     MatrixTranslateLocal<>( m, XX, v[XX] );
273     MatrixTranslateLocal<>( m, YY, v[YY] );
274     MatrixTranslateLocal<>( m, ZZ, v[ZZ] );
275     SetMatrix( m, Object::TRANSLATION );
276 }
277 
278 /*****************************************************************************
279  * Rotate Object around one of its local axis.
280  *****************************************************************************/
281 void
Rotate(uint axis,Radian radian)282 Object::Rotate( uint axis, Radian radian )
283 {
284 CHECK_OBJECT();
285 ASSERT_AXIS3(axis);
286 
287     Matrix m = GetMatrix();
288     MatrixRotateLocal<>( m, axis, radian );
289     SetMatrix( m, Object::ROTATION );
290 }
291 
292 ////////////////////////////////////////////////////////////////////////////////
293 ///////////////////  Object : collidable, collision  ///////////////////////////
294 ////////////////////////////////////////////////////////////////////////////////
295 
296 /*****************************************************************************
297  * Set whether an Object is collidable.
298  *****************************************************************************/
299 void
SetCollidable(const bool collidable)300 Object::SetCollidable( const bool collidable )
301 {
302 CHECK_OBJECT();
303 
304     // Has collidable flag changed?
305     if ( collidable != mBits.mCollidable )
306     {
307         mBits.mCollidable = collidable;
308 
309         // Notify Collision to update its container of collidable objects.
310         GET_COLLISION().SetCollidable( this, collidable );
311     }
312 }
313 
314 /*****************************************************************************
315  * Set collision flag.
316  * If COLLISION_FATAL then Object will zombify itself
317  * which will broadcast the DestroyObject event.
318  *****************************************************************************/
319 void
SetCollision(const eCollision collision)320 Object::SetCollision( const eCollision collision )
321 {
322 CHECK_OBJECT();
323 
324     mBits.mCollision = collision;
325 
326     if ( collision == COLLISION_FATAL )
327         Zombify();
328 }
329 
330 } // namespace object
331