/* +---------------------------------------------------------------------------+
   |          The Mobile Robot Programming Toolkit (MRPT) C++ library          |
   |                                                                           |
   |                   http://mrpt.sourceforge.net/                            |
   |                                                                           |
   |   Copyright (C) 2005-2008  University of Malaga                           |
   |                                                                           |
   |    This software was written by the Perception and Robotics               |
   |      research group, University of Malaga (Spain).                        |
   |    Contact: Jose-Luis Blanco  <jlblanco@ctima.uma.es>                     |
   |                                                                           |
   |  This file is part of the MRPT project.                                   |
   |                                                                           |
   |     MRPT is free software: you can redistribute it and/or modify          |
   |     it under the terms of the GNU General Public License as published by  |
   |     the Free Software Foundation, either version 3 of the License, or     |
   |     (at your option) any later version.                                   |
   |                                                                           |
   |   MRPT is distributed in the hope that it will be useful,                 |
   |     but WITHOUT ANY WARRANTY; without even the implied warranty of        |
   |     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         |
   |     GNU General Public License for more details.                          |
   |                                                                           |
   |     You should have received a copy of the GNU General Public License     |
   |     along with MRPT.  If not, see <http://www.gnu.org/licenses/>.         |
   |                                                                           |
   +---------------------------------------------------------------------------+ */
#ifndef COpenGLScene_H
#define COpenGLScene_H

#include <MRPT/UTILS/utils_defs.h>
#include <MRPT/UTILS/CSerializable.h>
#include <MRPT/UTILS/CMRPTImage.h>
#include <MRPT/UTILS/CMRPTImageFloat.h>

#include <MRPT/UTILS/CMatrixD.h>

#include <map>

namespace MRML
{
	class CPointsMap;
	class CPose3D;
}


namespace UTILS
{
	class CStringList;

	/** The namespace for 3D scene representation and rendering.
	  */
	namespace OPENGL
	{
		/** The base class of 3D objects that can be directly rendered through OpenGL.
		  *  In this class there are a set of common properties to all 3D objects, mainly:
		  *		- A name (m_name): A name that can be optionally asigned to objects for easing its reference.
		  *		- 6D coordinates (x,y,z,yaw,pitch,roll), relative to the "current" reference framework. By default, any object is referenced to global scene coordinates.
		  *		- A RGB color: This field will be used in simple elements (points, lines, text,...) but is ignored in more complex objects that carry their own color information (triangle sets,...)
		  *  See the main class UTILS::COpenGLScene
		  *  \sa UTILS::COpenGLScene, UTILS::OPENGL
		  */
		class CRenderizable : public UTILS::CSerializable
		{
			DEFINE_VIRTUAL_SERIALIZABLE( CRenderizable )

 		public:
			std::string				m_name;
			double					m_color_R,m_color_G,m_color_B,m_color_A;    //!< Color components in the range [0,1]
			double					m_x,m_y,m_z;								//!< Translation relative to parent coordinate origin.
			double					m_yaw,m_pitch,m_roll;						//!< Rotation relative to parent coordinate origin, in **DEGREES**.
			bool					m_show_name;

			static void	renderTextBitmap( const char *str, void *fontStyle );

			/** Default constructor:
			  */
			CRenderizable() :
				m_name(),
				m_color_R(1),m_color_G(1),m_color_B(1),m_color_A(1),
				m_x(0),m_y(0),m_z(0),
				m_yaw(0),m_pitch(0),m_roll(0),
				m_show_name(false)
			{
			}

			/** Default virtual destructor
			  */
			virtual ~CRenderizable();

			/** This virtual method in the base class performs common tasks like coordinates transformation,color,...
			  */
			virtual void  render() = 0;

			/** Set the 3D pose from a MRML::CPose3D object */
			void setPose( const MRML::CPose3D &o );

			//This function only are used when show name
			//void  prepareFontLists();

			void  writeToStreamRender(CStream &out) const;
			void  readFromStreamRender(CStream &in);
		};

		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CRenderizable )


		/** A solid sphere
		  *  \sa UTILS::COpenGLScene
		  */
		class CSphere : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CSphere )
		public:

			float			m_radius;
			int				m_nDivsLongitude,m_nDivsLatitude;

			/** Constructor
			  */
			CSphere(
				float				radius = 1.0f,
				int					nDivsLongitude = 20,
				int					nDivsLatitude = 20
				) :
				m_radius(radius),
				m_nDivsLongitude(nDivsLongitude),
				m_nDivsLatitude(nDivsLatitude)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CSphere )

		/** A grid of lines over the XY plane.
		  *  \sa UTILS::COpenGLScene
		  */
		class CGridPlaneXY : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CGridPlaneXY )
		public:
			float	m_xMin, m_xMax;
			float	m_yMin, m_yMax;
			float	m_z;
			float	m_frequency;

			/** Default constructor
			  */
			CGridPlaneXY( ) :
				m_xMin(-10),
				m_xMax(10),
				m_yMin(-10),
				m_yMax(10),
				m_z(0),
				m_frequency(1)
			{
			}

			/** Constructor
			  */
			CGridPlaneXY(
				float				xMin,
				float				xMax,
				float				yMin,
				float				yMax,
				float				z,
				float				frequency
				) :
				m_xMin(xMin),
				m_xMax(xMax),
				m_yMin(yMin),
				m_yMax(yMax),
				m_z(z),
				m_frequency(frequency)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CGridPlaneXY )

		/** A 2D plane in the XY plane with a texture image.
		  *  \sa UTILS::COpenGLScene
		  */
		class CTexturedPlane : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CTexturedPlane )
		protected:
			unsigned int		m_glTextureName;
			bool				m_init;
			CMRPTImage			m_textureImage;
			CMRPTImage			m_textureImageAlpha;
			bool				m_enableTransparency;

			int					r_width,r_height;

		public:
			float				m_tex_x_min,m_tex_x_max;
			float				m_tex_y_min,m_tex_y_max;

			float			m_xMin, m_xMax;
			float			m_yMin, m_yMax;
			/** Destructor
			  */
			virtual ~CTexturedPlane();

			/** Constructor
			  */
			CTexturedPlane(
				float				x_min = -1,
				float				x_max = 1,
				float				y_min = -1,
				float				y_max = 1
				);

			/** Assigns a texture and a transparency image, and enables transparency (If the images are not 2^N x 2^M, they will be internally filled to its dimensions to be powers of two)
			  */
			void  assignImage(
				const CMRPTImage&	img,
				const CMRPTImage&	imgAlpha );

			/** Assigns a texture image, and disable transparency.
			  */
			void  assignImage(
				const CMRPTImage&	img );

			/** Similar to assignImage, but the passed images will be returned as empty: it avoids making a copy of the whole image, just copies a pointer.
			  */
			void  assignImage_fast(
				CMRPTImage&	img,
				CMRPTImage&	imgAlpha );

			/** Similar to assignImage, but the passed images will be returned as empty: it avoids making a copy of the whole image, just copies a pointer.
			  */
			void  assignImage_fast(
				CMRPTImage&	img );

			/** Render
			  */
			void  render();

			/** VERY IMPORTANT: If you use a multi-thread application, you MUST call this from the same thread that will later destruct the object in order to the OpenGL texture memory to be correctly deleted.
			  *  Calling this method more than once has no effects. If you user one thread, this method will be automatically called when rendering, so there is no need to explicitly call it.
			  */
			void 		loadTextureInOpenGL();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CTexturedPlane )

		/** A 2D text to be renderized
		  *  \sa UTILS::COpenGLScene
		  */
		class CText : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CText )
		protected:

		public:
			std::string		m_str;
            std::string		m_fontName;
            int				m_fontHeight, m_fontWidth;

			/** Constructor
			  */
			CText( const std::string &str = std::string("") );

			/** Destructor
			  */
			virtual ~CText();

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CText )

		/** A simple line
		  *  \sa UTILS::COpenGLScene
		  */
		class CSimpleLine : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CSimpleLine )
		public:
			float	m_x0,m_y0,m_z0;
			float	m_x1,m_y1,m_z1;
            float	m_lineWidth;

			/** Constructor
			  */
			CSimpleLine(
				float x0=0,float y0=0, float z0=0,
				float x1=0,float y1=0, float z1=0, float lineWidth = 1.0 ) :
					m_x0(x0),m_y0(y0),m_z0(z0),
					m_x1(x1),m_y1(y1),m_z1(z1),
					m_lineWidth(lineWidth)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CSimpleLine )

		/** A set of independent lines
		  *  \sa UTILS::COpenGLScene
		  */
		class CSetOfLines : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CSetOfLines )
		public:
			vector_float	m_x0,m_y0,m_z0;
			vector_float	m_x1,m_y1,m_z1;

			/** Constructor
			  */
			CSetOfLines( ) :
				m_x0(),m_y0(),m_z0(),
				m_x1(),m_y1(),m_z1()
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CSetOfLines )


		/** A cloud of points
		  *  \sa UTILS::COpenGLScene
		  */
		class CPointCloud : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CPointCloud )
		public:
			bool			m_colorFromZ;
			vector_float	m_xs,m_ys,m_zs;
			float           m_pointSize; //!< By default is 1.0

			/** Constructor
			  */
			CPointCloud( ) :
				m_colorFromZ(false),
				m_xs(),m_ys(),m_zs(),
				m_pointSize(1)
			{
			}

			/** Load the points from a points map
			  */
			void  loadFromPointsMap( const MRML::CPointsMap *map);

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CPointCloud )

		/** A 3D arrow
		  *  \sa UTILS::COpenGLScene
		  */
		class CArrow : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CArrow )
		public:
			float	m_x0,m_y0,m_z0;
			float	m_x1,m_y1,m_z1;
			float	m_headRatio;
			float	m_smallRadius, m_largeRadius;
			//For version 2 in stream
			float	m_arrow_roll;
			float	m_arrow_pitch;
			float	m_arrow_yaw;

			/** Constructor
			  */
			CArrow(
				float	x0 = 0,
				float	y0 = 0,
				float	z0 = 0,
				float	x1 = 1,
				float	y1 = 1,
				float	z1 = 1,
				float	headRatio = 0.2f,
				float	smallRadius = 0.05f,
				float	largeRadius = 0.2f,
				float	arrow_roll = -1.0f,
				float	arrow_pitch = -1.0f,
				float	arrow_yaw = -1.0f
				) :
				m_x0(x0),m_y0(y0),m_z0(z0),
				m_x1(x1),m_y1(y1),m_z1(z1),
				m_headRatio(headRatio),
				m_smallRadius(smallRadius),
				m_largeRadius(largeRadius),
				m_arrow_roll(arrow_roll),
				m_arrow_pitch(arrow_pitch),
				m_arrow_yaw(arrow_yaw)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CArrow )

		/** A planar disk in the XY plane.
		  *  \sa UTILS::COpenGLScene
		  */
		class CDisk : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CDisk )
		public:
			float	m_radiusIn,m_radiusOut;
			int		m_nSlices, m_nLoops;

			/** Constructor
			  */
			CDisk( ) :
				m_radiusIn(0),
				m_radiusOut(1),
				m_nSlices(50),
				m_nLoops(4)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CDisk )


		/** A set of colored triangles.
		  *  This class can be used to draw any solid, arbitrarily complex object (without textures).
		  *  \sa UTILS::COpenGLScene
		  */
		class CSetOfTriangles : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CSetOfTriangles )
		public:
			struct TTriangle
			{
				float	x[3],y[3],z[3];
				float	r[3],g[3],b[3],a[3];
			};

			std::vector<TTriangle>		m_triangles;
			bool						m_enableTransparency;

			/** Constructor
			  */
			CSetOfTriangles( bool enableTransparency = false ) :
				m_triangles(),
				m_enableTransparency(enableTransparency)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CSetOfTriangles )

		/** A 2D ellipse or 3D ellipsoid, depending on the size of the m_cov matrix (2x2 or 3x3).
		  *  The center of the ellipsoid is the "m_x,m_y,m_z" object's coordinates. In the case of
		  *   a 2D ellipse it will be drawn in the XY plane, for z=0.
		  *  The color is determined by the RGBA fields in the class "CRenderizable". Note that a
		  *   transparent ellipsoid can be drawn for "0<alpha<1" values.
		  *  \sa UTILS::COpenGLScene
		  */
		class CEllipsoid : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CEllipsoid )

		private:
			/** Used to store computed values the first time this is rendered, and to avoid recomputing them again.
			 */
			 CMatrixD		m_eigVal,m_eigVec,m_prevComputedCov;

		public:
			/** The 2x2 or 3x3 covariance matrix that will determine the aspect of the ellipsoid.
			  */
			CMatrixD		m_cov;
			/** If set to true (default), a whole ellipsoid surface will be drawn, or if set to "false" it will be drawn as a "wireframe".
			  */
			bool			m_drawSolid3D;
			/** The number of "sigmas" for drawing the ellipse/ellipsoid (default=3)
			  */
			float			m_quantiles;
			/** The number of segments of a 2D ellipse (default=20)
			  */
			unsigned int	m_2D_segments;
			/** The number of segments of a 3D ellipse (in both "axis") (default=20)
			  */
			unsigned int	m_3D_segments;
			/** The line width for 2D ellipses or 3D wireframe ellipsoids (default=1)
			  */
			float			m_lineWidth;

			/** Constructor
			  */
			CEllipsoid() : m_eigVal(),m_eigVec(),m_prevComputedCov(),
				m_cov(2,2),
				m_drawSolid3D(true),
				m_quantiles(3),
				m_2D_segments(20),
				m_3D_segments(20),
				m_lineWidth(1.0)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CEllipsoid )

		/** A list of objects pointers, automatically managing memory free at destructor, and managing copies correctly.
		  */
		class CListOpenGLObjects : public std::deque<UTILS::OPENGL::CRenderizable*>
		{
			typedef std::deque<UTILS::OPENGL::CRenderizable*> BASE;
		public:
			CListOpenGLObjects() : BASE() {  }
			CListOpenGLObjects( const CListOpenGLObjects&o );
			CListOpenGLObjects& operator = (const CListOpenGLObjects & o);

			void clearAndDelete(); //!< Clear the list of objects and free objects themselves.

			virtual ~CListOpenGLObjects() { clearAndDelete(); }
		};

		/** A set of object, which are referenced to the coordinates framework established in this object.
		  *  It can be established a hierarchy of "CSetOfObjects", where the coordinates framework of each
		  *   one will be referenced to the parent's one.
		  *	The list of child objects is accessed directly as in the class "COpenGLScene"
		  *  \sa UTILS::COpenGLScene
		  */
		class CSetOfObjects : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CSetOfObjects )

		protected:
			/** The list of child objects.
			  *  Objects are automatically deleted when calling "clear" or in the destructor.
			  */
			CListOpenGLObjects		m_objects;

		public:

			/** Insert a new object to the list.
			  */
			void insert( UTILS::OPENGL::CRenderizable* newObject );

			/** Render child objects.
			  */
			void  render();

			/** Clear the list of objects in the scene, deleting objects' memory.
			  */
			void  clear();

			/** Returns number of objects.
			  */
			size_t size()  {  return m_objects.size(); }

			/** Default constructor
			  */
			CSetOfObjects( );

			/** Destructor
			  */
			virtual ~CSetOfObjects();

			/** Initializes all textures in the scene (See OPENGL::CTexturedPlane::loadTextureInOpenGL)
			  */
			void  initializeAllTextures();

			/** Returns the first object of a given class, or NULL if not found.
			  */
			UTILS::OPENGL::CRenderizable*	getByClass( const UTILS::TRuntimeClassId * classId );

			/** Retrieves a list of all objects in text form.
			  */
			void dumpListOfObjects( UTILS::CStringList  &lst );

		};

		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CSetOfObjects )


		/** A grid of lines over the XZ plane.
		  *  \sa UTILS::COpenGLScene
		  */
		class CGridPlaneXZ : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CGridPlaneXZ )
		public:
			float	m_xMin, m_xMax;
			float	m_zMin, m_zMax;
			float	m_y;
			float	m_frequency;

			/** Constructor
			  */
			CGridPlaneXZ(
				float				xMin = -10,
				float				xMax = 10,
				float				zMin = -10,
				float				zMax = 10,
				float				y = 0,
				float				frequency = 1
				) :
				m_xMin(xMin),m_xMax(xMax),
				m_zMin(zMin),m_zMax(zMax),
				m_y(y),
				m_frequency(frequency)
			{
			}

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CGridPlaneXZ )

		/** Draw the 3D world axis
		  *  \sa UTILS::COpenGLScene
		  */
		class CAxis : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CAxis )
		protected:

		public:
			float	m_xmin,m_ymin,m_zmin;
			float	m_xmax,m_ymax,m_zmax;
			float	m_frecuency;
            float	m_lineWidth;
			bool	m_marks;

			/** Constructor
			  */
			CAxis(
				float xmin=-1.0f,float ymin=-1.0f, float zmin=-1.0f,
				float xmax=1.0f, float ymax=1.0f,  float zmax=1.0f,
				float frecuency = 0.25f, float lineWidth = 3.0f, bool marks=false) :
				m_xmin(xmin),m_ymin(ymin),m_zmin(zmin),
				m_xmax(xmax),m_ymax(ymax),m_zmax(zmax),
				m_frecuency(frecuency),
                m_lineWidth(lineWidth),
				m_marks(marks)
			{
			}

			/** Destructor
			  */
			virtual ~CAxis();

			/** Render
			  */
			void  render();
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CAxis )

		/** A camera: if added to a scene, the viewpoint defined by this camera will be used instead of the camera parameters set in COpenGLViewport::m_camera.
		  *  \sa UTILS::COpenGLScene
		  */
		class CCamera : public CRenderizable
		{
			DEFINE_SERIALIZABLE( CCamera )
		public:
			float	m_pointingX,m_pointingY,m_pointingZ,
					m_distanceZoom,
					m_azimuthDeg,m_elevationDeg;

			/** If set to true (default), camera model is projective, otherwise, it's orthogonal.
			  */
			bool	m_projectiveModel;

			/** Field-of-View in degs, only when projectiveModel=true (default=30 deg).
			  */
			float	m_projectiveFOVdeg;

			/** Constructor
			  */
			CCamera();

			/** Render does nothing here.
			  */
			void  render() {  }
		};
		// This must be added to any CSerializable derived class:
		DEFINE_SERIALIZABLE_POST( CCamera )

	} // end namespace OPENGL


	class COpenGLScene;

	/** A viewport within a COpenGLScene, containing a set of OpenGL objects to render.
	  *   This class has protected constuctor, thus it cannot be created by users. Use COpenGLScene::createViewport instead.
	  *  Refer to UTILS::COpenGLScene for further details.
	  */
	class COpenGLViewport : public UTILS::CSerializable
	{
		DEFINE_SERIALIZABLE( COpenGLViewport )

		friend class COpenGLScene;
    public:
        /** Set this view as a clone of some other viewport, given its name - as a side effect, current list of internal OpenGL objects is cleared.
		  *  By default, only the objects are cloned, not the camera. See
		  * \sa resetCloneView
          */
		void setCloneView( const std::string &clonedViewport );

		/** Reset the viewport to normal mode: rendering its own objects.
		  * \sa setCloneView
		  */
		void resetCloneView() { m_isCloned=false;m_isClonedCamera=false; }

		/** If set to true, and setCloneView() has been called, this viewport will be rendered using the camera of the cloned viewport.
		  */
		void setCloneCamera(bool enable) { m_isClonedCamera = enable; }


		/** Delete all internal obejcts
		  * \sa insert
		  */
		void clear();

		/** Insert a new object into the list.
		  *  The object MUST NOT be deleted, it will be deleted automatically by this object when not required anymore.
		  */
		void insert( UTILS::OPENGL::CRenderizable* newObject );

		/** Returns the name of the viewport */
		std::string getName() { return m_name; }

		/** Change the viewport position and dimension on the rendering window.
		  *  Coordinates here are alwasys in the range [0,1], relative to the actual
		  *   window sizes (i.e. width=1 means the entire width of the rendering window).
		  * \note (x,y) specify the lower left corner of the viewport rectangle.
		  * \sa getViewportPosition
		  */
		void setViewportPosition(
			const double &x,
			const double &y,
			const double &width,
			const double &height );

		/** Get the current viewport position and dimension on the rendering window.
		  *  Coordinates here are alwasys in the range [0,1], relative to the actual
		  *   window sizes (i.e. width=1 means the entire width of the rendering window).
		  * \note (x,y) specify the lower left corner of the viewport rectangle.
		  * \sa setViewportPosition
		  */
		void getViewportPosition(
			double &x,
			double &y,
			double &width,
			double &height );

        /** Set the border size ("frame") of the viewport (default=0).
          */
        void setBorderSize( unsigned int lineWidth ) { m_borderWidth = lineWidth; }

		/** Return whether the viewport will be rendered transparent over previous viewports.
		  */
		bool isTransparent() { return m_isTransparent; }

		/** Set the transparency, that is, whether the viewport will be rendered transparent over previous viewports (default=false).
		  */
		void setTransparent( bool trans ) { m_isTransparent=trans; }

		virtual ~COpenGLViewport();  //!< Destructor: clears all objects.

		/** Returns the first object with a given name, or NULL if not found.
		  */
		UTILS::OPENGL::CRenderizable*	getByName( const std::string &str );

		/** Returns the first object of a given class, or NULL if not found.
		  */
		UTILS::OPENGL::CRenderizable*	getByClass( const UTILS::TRuntimeClassId * classId );

		/** Number of objects contained. */
		size_t  size() const { return m_objects.size(); }

		/** The camera associated to the viewport */
		OPENGL::CCamera		m_camera;

    protected:
		/** Constructor, invoked from COpenGLScene only.
		  */
		COpenGLViewport( COpenGLScene *parent=NULL, const std::string &name=std::string("") );

		/** Initializes all textures in the scene (See OPENGL::CTexturedPlane::loadTextureInOpenGL)
		  */
		void  initializeAllTextures();

		/** Retrieves a list of all objects in text form.
		  */
		void dumpListOfObjects( UTILS::CStringList  &lst );

		/** Render the objects in this viewport (called from COpenGLScene only) */
		void  render( const int &render_width, const int &render_height );

        safe_ptr<COpenGLScene>  m_parent;   //!< The scene that contains this viewport.

        bool			m_isCloned; //!< Set by setCloneView
		bool			m_isClonedCamera; //!< Set by setCloneCamera
		std::string		m_clonedViewport; //!< Only if m_isCloned=true

		std::string		m_name; //!< The viewport's name

		bool			m_isTransparent; //!< Whether to clear color buffer.

		uint32_t        m_borderWidth;  //!< Default=0, the border around the viewport.

		double			m_view_x, m_view_y,m_view_width,m_view_height; //!< The viewport position [0,1]

		/** The list of objects that comprise the 3D scene.
		  *  Objects are automatically deleted when calling "clear" or in the destructor.
		  */
		OPENGL::CListOpenGLObjects		m_objects;

	};
	// This must be added to any CSerializable derived class:
	DEFINE_SERIALIZABLE_POST( COpenGLViewport )


	/** This class allows the user to create, load, save, and render 3D scenes using OpenGL primitives.
	  *  The class can be understood as a program to be run over OpenGL, containing a sequence of viewport definitions,
	  *   rendering primitives, etc...
	  *
	  *  In MRPT 0.5.5 this class has been re-structured to contain from 1 to any number of <b>Viewports</b>, each one
	  *   associated a set of OpenGL objects and, optionally, a preferred camera position. Both orthogonal (2D/3D) and projection
	  *   camera models can be used for each viewport independently, greatly increasing the possibilities of rendered scenes.
	  *
	  *  An object of COpenGLScene always contains at least one viewport (UTILS::COpenGLViewport), named "main". Optionally, any
	  *   number of other viewports may exist. Viewports are referenced by their names, case-sensitive strings. Each viewport contains
	  *   a different 3D scene (i.e. they render different objects), though a mechanism exist to share the same 3D scene by a number of
	  *   viewports so memory is not wasted replicating the same objects (see COpenGLViewport::setCloneView ).
	  *
	  *  The main rendering method, COpenGLScene::render(), assumes a viewport has been set-up for the entire target window. That
	  *   method will internally make the required calls to opengl for creating the additional viewports. Note that only the depth
	  *   buffer is cleared by default for each (non-main) viewport, to allow transparencies. This can be disabled by the approppriate
	  *   member in COpenGLViewport.
	  *
	  *   An object COpenGLScene can be saved to a ".3Dscene" file using CFileOutputStream, for posterior visualization from
	  *    the standalone application <a href="http://babel.isa.uma.es/mrpt/index.php/Application:SceneViewer">SceneViewer</a>.
	  *    It can be also displayed in real-time using UTILS::CDisplayWindow3D.
	  */
	class COpenGLScene : public UTILS::CSerializable
	{
		DEFINE_SERIALIZABLE( COpenGLScene )
	public:
		/** Constructor
		  */
		COpenGLScene();

		/** Destructor:
		 */
		virtual ~COpenGLScene();

		/** Copy operator:
		  */
		COpenGLScene & operator =( const COpenGLScene &obj );

		/** Copy constructor:
		  */
		COpenGLScene( const COpenGLScene &obj );

		/** Insert a new object into the scene, in the given viewport (by default, into the "main" viewport).
		  *  The viewport must be created previously, an exception will be raised if the given name does not correspond to
		  *   an existing viewport.
		  * \sa createViewport, getViewport
		  */
		void insert( UTILS::OPENGL::CRenderizable* newObject, const std::string &viewportName = std::string("main") );

		/**Creates a new viewport, adding it to the scene and returning a pointer to the new object.
		  *  Names (case-sensitive) cannot be duplicated: if the name provided coincides with an already existing viewport, a pointer to the existing object will be returned. 
		  *  The first, default viewport, is named "main".
		  */
		COpenGLViewport * createViewport( const std::string &viewportName );

		/** Returns the viewport with the given name, or NULL if it does not exist
		  */
		COpenGLViewport * getViewport( const std::string &viewportName );

		/** Render this scene.
		  */
		void  render();

		size_t  viewportsCount() const { return m_viewports.size(); }

		/** Clear the list of objects and viewports in the scene, deleting objects' memory, and leaving just the default viewport with the default values.
		  */
		void  clear( bool createMainViewport = true );

		/** If disabled (default), the SceneViewer application will ignore the camera of the "main" viewport and keep the viewport selected by the user by hand; otherwise, the camera in the "main" viewport prevails.
		  * \sa followCamera
		  */
		void enableFollowCamera( bool enabled ) { m_followCamera = enabled; }

		/** Return the value of "followCamera"
		  * \sa enableFollowCamera
		  */
		bool followCamera() const { return m_followCamera; }

		/** Returns the first object with a given name, or NULL if not found.
		  */
		UTILS::OPENGL::CRenderizable*	getByName( const std::string &str, const std::string &viewportName = std::string("main") );

		/** Returns the first object of a given class, or NULL if not found.
		  */
		UTILS::OPENGL::CRenderizable*	getByClass( const UTILS::TRuntimeClassId * classId, const std::string &viewportName = std::string("main") );

		/** Initializes all textures in the scene (See OPENGL::CTexturedPlane::loadTextureInOpenGL)
		  */
		void  initializeAllTextures();

		/** Retrieves a list of all objects in text form.
		  */
		void dumpListOfObjects( UTILS::CStringList  &lst );

	protected:
		bool		m_followCamera;

		typedef std::vector<COpenGLViewport*> TListViewports;

		/**  The list of viewports, indexed by name.
		  */
		TListViewports		m_viewports;

	};

	// This must be added to any CSerializable derived class:
	DEFINE_SERIALIZABLE_POST( COpenGLScene )


	/** A collection of pre-built 3D objects for quick insertion in UTILS::COpenGLScene objects.
	  */
	namespace StockObjects
	{
		/** Returns a representation of a Pioneer II mobile base.
		  *  The generated object must be inserted in a OPENGL::COpenGLScene or OPENGL::CSetOfObjects, or otherwise the user should delete it manually.
		  */
		OPENGL::CSetOfObjects *RobotPioneer();

		/** Returns three arrows representing a X,Y,Z 3D corner.
		  *  The generated object must be inserted in a OPENGL::COpenGLScene or OPENGL::CSetOfObjects, or otherwise the user should delete it manually.
		  */
		OPENGL::CSetOfObjects *CornerXYZ();

	} // end namespace StockObjects

} // End of namespace


#endif
