/*****************************************************************************
 * $LastChangedDate: 2011-04-09 21:58:06 -0400 (Sat, 09 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Base Object class.
 *//*
 * LEGAL:   COPYRIGHT (C) 2007 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef OBJECT_OBJECT_HH
#define OBJECT_OBJECT_HH 1

#define CHECK_OBJECT() {{ CHECK_TYPESIG(this,TYPESIG_OBJECT); }}

#include "graph/module.hh"
#include "graph/graph.hh"
#include "graph/node_sort.hh"
using namespace graph;

namespace object {

////////////////////////////////////////////////////////////////////////////////
/// @brief 3D Object class.
///
class Object : public Shared
{
PREVENT_COPYING(Object)

//------------------------------------------------------------------------------
// Interface:
// Construction, identity:
public: CLASS_METHOD shptr<Object>  MakeDummyObject( void );
public:                             Object( shptr<Graph> graph, const WorldVertex& pos );
public:     virtual                 ~Object();
public:     virtual const string    GetName( void ) { return string("Object"); }
public:     virtual bool            IfDyna( void ) { CHECK_OBJECT(); return false; }
public:     void                    Zombify( void );  // schedule destruction
public:     virtual void            Reset( void ) { }

// Status:
public:     virtual bool            IfReproducible( void ) { CHECK_OBJECT(); return false; }
public:     bool                    IfDisabled( void ) { CHECK_OBJECT(); return mBits.mZombie | mBits.mDummy | mBits.mCollision; }
public:     bool                    IfZombie( void ) { CHECK_OBJECT(); return mBits.mZombie; }
public:     bool                    IfDummy( void ) { CHECK_OBJECT(); return mBits.mDummy; }

// Drawing:
public:     virtual void            Draw( void );

// Spatial:
public:     virtual void            SetPosition( const WorldVertex& position );
public:     virtual WorldVertex     GetPosition( void );
public:     virtual fp              GetRadius( void )
                                    {
                                    CHECK_OBJECT();
                                        // Was radius computed before?
                                        if ( EX( mRadius > 0.0f ) )  // initially -1 (invalid)
                                            return mRadius;
                                        else
                                            return (mRadius = ComputeRadius());
                                    }
private:    fp                      ComputeRadius( void );

// Geometry:
public:     shptr<Graph>            GetGraph( void )
                                    { CHECK_OBJECT(); return mGraph; }
public:     void                    Scale( const Vector3& v );
public:     void                    Scale( const fp scale );
public:     RefPtr<Node>            GetRootNode( void )
                                    { CHECK_OBJECT(); return GetGraph()->GetRootNode(); }
// Transformation:
public:     enum eMatrixChange { PLACEMENT, ROTATION, TRANSLATION };  // see Dyna class
public:     virtual void            SetMatrix( const Matrix& matrix, Object::eMatrixChange change = PLACEMENT );
public:     virtual Matrix          GetMatrix( void )
                                    { CHECK_OBJECT(); return mTransformNode->getMatrix(); }
public:     virtual void            SetQuaternion( const Quaternion& quat );
public:     virtual Quaternion      GetQuaternion( void );
public:     virtual void            Translate( uint axis, fp inc );
public:     virtual void            Translate( const Vector3& v );
public:     virtual void            Rotate( uint axis, Radian rad );

// Collidable/indestructible:
public:     void                    SetCollidable( const bool collidable );
public:     bool                    IfCollidable( void )
                                    { CHECK_OBJECT(); return mBits.mCollidable and not mBits.mZombie; }
// Collision flag:
// Object merely defines this flag while Dyna does collision-detection.
// This split lets any Object to be affected by other kinds of collision-detection tests.
public:     enum eCollision { COLLISION_NONE, COLLISION, COLLISION_FATAL };  // 2 bits
public:     virtual void            SetCollision( const eCollision collision );
public:     bool                    IfCollision( void )
                                    { CHECK_OBJECT(); return mBits.mCollision != COLLISION_NONE; }
public:     bool                    IfCollisionFatal( void )
                                    { CHECK_OBJECT(); return mBits.mCollision == COLLISION_FATAL; }
// Info:
public:     virtual NodeSort        GetNodeSort( void ) { return msDefaultNodeSort; }
public:     CLASS_METHOD int        GetObjectCount( void ) { return msObjectCount; }

//------------------------------------------------------------------------------
// Data:

protected:  struct Bits
            {
                uint mDummy         : 1;
                uint mZombie        : 1;
                uint mCollidable    : 1;
                uint mCollision     : 2;
            };
private:    CLASS_VAR int                   msObjectCount;
private:    CLASS_CONST NodeSort            msDefaultNodeSort;  /// for state-sorting
protected:  shptr<Graph>                    mGraph;
private:    RefPtr<osg::MatrixTransform>    mTransformNode;     ///< force derivatives to use SetMatrix() which can intercept incorrect positions
protected:  fp                              mRadius;            ///< approximate
protected:  Bits                            mBits;
public:     DECLARE_TYPESIG( TYPESIG_OBJECT )
};

} // namespace object

#endif // OBJECT_OBJECT_HH
