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