/* (c) 1999-2000 Tino Schwarze, see COPYING for details */
/**@pkg cObject.cVisibleObject*/
/**
 * base class for any visible object (like a cube, a light, etc.)
 *
 * #include "cObject.hh"
 *
 * -lMesaGL or -lGL
 *
 * @pkgdoc cObject.cVisibleObject
 */

#ifndef cVisibleObject_hh
#define cVisibleObject_hh

// include OpenGL functions
#include <GL/gl.h>

// PROJECT INCLUDES (used classes)
#include "cVertex.hh"
#include "cMatrix.hh"
#include "cQuaternion.hh"
#include "cObject.hh"
#include "cMaterial.hh"

/**
 * This object provides anything neccessary to build viewable objects.
 *
 * It is intended to derive from it, overloading the DrawTheObject() and 
 * probably Init() methods.
 *
 * This is already OpenGL specific!
 *
 * If we talk about a position, it's OpenGL's notion of a
 * translation via glTranslatef, that means, that not the object
 * but the object's coordinate system is translated!
 * Take care of that!
 */
class cVisibleObject : public cObject
{

// LIFECYCLE
public:
	/**
	 * constructor with initialization for name (default constructor)
		* @param name name to identify the object (optional)
		*/
	cVisibleObject (const char *name = NULL);

	/**
	 * copy constructor
	 	*/
	cVisibleObject (const cVisibleObject &);

	/**
	 * constructor with initialization for position and name
	 	* @param pos initial object position
		* @param name name to identify the object (optional)
		*/
	cVisibleObject (const cVertex &pos, const char *name = NULL);

	/**
	 * constructor with initialization for position, rotation and name
	 	* @param pos initial object position
		* @param rot initial object rotation
		* @param name name to identify the object (optional)
		*/
	cVisibleObject (const cVertex &pos, const cQuaternion &rot, const char *name = NULL);

	/**
	 * destructor
	 	*/
	virtual ~cVisibleObject ();

// ACCESS
	/**
	 * initialize object and it's childs
	 	*
		* (partially inherited from cObject)
		*/
	virtual int Init ();

	/**
	 * move object to given position
	 	* @param pos new absolute center of objects coordinate system
		*/
	virtual void MoveTo (const cVertex &pos);

	/**
	 * move object by given amount
	 	* @param pos new center of objects coordinate system relative to
		         actual
		*/
	virtual void MoveBy (const cVertex &pos);

	/**
	 * rotate object angle degrees around given vector 
	 * ("adds" to current rotation)
	 	* @param angle angle in degree
		* @param axis vector to rotate around
		*/
	virtual void RotateBy (
		const GLfloat angle,
		const cVertex &axis);

	/**
	 * rotate object by applying a quaternion
	 * ("adds" to current rotation)
	 	* @param quaternion quaternion to apply
		*/
	virtual void RotateBy (const cQuaternion &quaternion);

	/**
	 * set rotation to given values (replaces current rotation)
	 	* @param angle angle in degree
		* @param axis vector to rotate around
		*/
	virtual void SetRotation (
		const GLfloat angle,
		const cVertex &axis);

	/**
	 * set rotation to given value (replaces current rotation)
	 	* @param new_rotation quaternion representing rotation
		*/
	virtual void SetRotation (const cQuaternion &new_rotation);

	/**
	 * set material to use for this object (store reference only!)
	 	*
	 	* @param material pointer to cMaterial to use
	 	*/
	virtual void UseMaterial (cMaterial *material);

	/**
	 * disable use of material for this object
	 	* @param material const reference to cMaterial to use
	 	*/
	virtual void DontUseMaterial ();

	/**
	 * set visibility
	 	* @param visible visibility
		*/
	void SetVisible (bool visible)
	{
		mVisible = visible;
	};

	/**
	 * get visibility
		*/
	bool IsVisible () const
	{
		return mVisible;
	};


protected:	// protected functions
// INTERNAL OPERATIONS

	/**
	 * Activate the object. (here: draw it if visible)
	 *
	 * The scene is drawn by pre-oder traversing the scene graph (an n-ary 
	 * tree). Drawing is started by invoking Activate() which takes care that 
	 * all childs are drawn as well.
	 *
	 * Activate() works as follows: (see implementation for details)
	 * <ol>
	 * <li>- perform any steps neccessary to prepare for drawing
	 *                  (inherited, overloaded, may be overloaded)</li>
	 * <li>Transform () - apply rotation and translation
	 *                  (might be overloaded to prefent transformation)
	 * <li>DrawThisObject () - perform actual drawing if object is visible
	 *					(usually has to be overloaded)</li>
	 * <li>call cObject::Activate() to activate all siblings</li>
	 * <li>Deactivate () called by cObject::Activate() - undo special things 
	 *                   done in Activate(), call cObject::Deactivate ()
	 *                  (inherited, overloaded, may be overloaded)</li>
	 * </ol>
	 *
	 * You may overwrite this but make sure to call cVisibleObject::Activate()
	 * to get transformations right!
	 */
	virtual void Activate ();

	/**
	 * perform transformation neccessary before drawing
	 	*
		* might be overloaded e.g. to prevent transformation
	 	*/
	virtual void Transform ();

	/**
	 * perform actual drawing of the object
	 * (has to be overloaded)
	 	*/
	virtual void DrawThisObject () = 0;

	/**
	 * actions to perform after drawing the object and it's siblings
	 * (might be overloaded)
	 	*/
	virtual void Deactivate ();

	/**
	 * return default name of object (the poor man's RTTI)
	 *
	 * Every object within the scene graph can be associated a name.
	 * By default, the class of the object is used.
	 */
	virtual const char *GetDefaultName () const
	{
		return "cVisibleObject";
	};

// protected data - it may only be accessed after deriving from this class

	/** actual rotation of the object
	 * @see cVisibleObject::Activate */
	cQuaternion mRotation;
	/** actual position of the object
	 * @see cVisibleObject::Activate */
	cVertex mPosition;

	/**
	 * Visibility of object
	 *
	 * is the object visible (read: call DrawThisObject()) 
	 * @see #DrawThisObject */
	bool mVisible;

	/**
	 * the material to use for this object
	 *
	 * NULL == do not use a material
	 */
	cMaterial *mMaterial;

	/**
	 * The resulting _global_ transformation of this object.
	 * 
	 * It is aquired via glGetFloatv (GL_MODELVIEW_MATRIX). It's purpose
	 * is to simplify interaction.
	 * @see #Activate 
	 */
	cMatrix mGlobalTransformation;

};

#endif	// ifndef cVisibleObject_hh

