/** \defgroup Rendering Rendering classes */

/** @addtogroup Rendering
    @{
*/

/** @file CRenderObj.h
    \brief This file contains the declaration of the CRenderObj class,
    
    It holds all the necessary data to render the surface.
*/

#ifndef CRENDEROBJ_H
#define CRENDEROBJ_H


// Option constants

/**
   \brief With or without perspective.
*/
#define OPTION_PERSPECTIVE     (1 << 0)

/**
   \brief With or without the bounding box drawn.
*/
#define OPTION_BOUNDINGBOX     (1 << 1)

/**
   \brief With or without knowing that a point is part of the 
   surface is done by the change in the sign of the expression.
*/
#define OPTION_SIGN            (1 << 2)

/**
   \brief With or without OpenGL specular lightning
*/
#define OPTION_OPENGLSPECULAR  (1 << 3)




/**
   \brief This class holds all the necessary data to render the
   mathematical surface.

   It provides functions to get the color of a specific pixel,
   according to what was previously set.
*/
class CRenderObj
{
 public:
  std::string m_FormulaString; /** Expression to be plotted. */

  float m_SignIncrement; /**< Increment using the sign mode. */
  float m_NoSignIncrement; /**< Increment using the no sign mode. */
  float m_NoSignPrecision; /**< Maximal difference between two reel 
                              numbers to consider them equal. */
  float m_Zoom; /**< Distance from the scene of the camera. */

  CVector3f m_MinVector; /**< Vector representing the minimal corner
                            of the bounding box. */
  CVector3f m_MaxVector; /**< Vector representing the maximal corner
                            of the bounding box. */
  CVector3f m_ViewerPos; /**< Position of the viewer. */

  CVector3f m_LightDirection; /**< Direction of the light. */

  CColor m_SurfaceAmbientColor; /**< Ambient color of the surface. */
  CColor m_SurfaceDiffuseColor; /**< Diffuse color of the surface. */
  CColor m_SurfaceSpecularColor; /**< Specular color of the surface. */
  float  m_SurfaceSpecularExponent; /**< Specular exponent of the surface. */

  CColor m_BoxAmbientColor; /**< Ambient color of the bounding box. */
  CColor m_BoxDiffuseColor; /**< Diffuse color of the bounding box. */
  CColor m_BoxSpecularColor; /**< Specular color of the bounding box. */
  float  m_BoxSpecularExponent; /**< Specular exponent of the bouding box. */

  CColor m_BackgroundColor; /**< Background color of the image. */

  unsigned char m_Options; /**< 8 bits representing the options. */
  int m_Width; /**< Width of the rendered picture. */
  int m_Height; /**< Height of the rendered picture. */

  /**
     \brief This is the default constructor.  
  */
  CRenderObj();

  /**
     \brief This is the copy constructor.
  */
  CRenderObj(const CRenderObj& obj)
    {
      m_pFormula   = NULL;
      m_pFormulaDx = NULL;
      m_pFormulaDy = NULL;
      m_pFormulaDz = NULL;
      Copy(obj);
    }

  /**
     \brief This is the assignment operator.
  */
  const CRenderObj& operator = (const CRenderObj& obj)
    {
      if (this != &obj)
        Copy(obj);
      return *this;
    }

  /**
     \brief This function returns the vector base of the space used.
  */
  const CVectBase& getVectorBase() const { return m_VectorBase; }

  /**
     \brief This function updates the vector base of the space used.
  */
  void UpdateVectorBase() { m_VectorBase.Update(); }

  /**
     \brief This function returns the vector representing
     the position of the center of the rendering volume
  */
  const CVector3f getCenterPos() const { return m_CenterPos; }

  /**
     \brief This function makes sure all the parameters
     are valid.
  */
  std::string Validate() const;

  /**
     \brief This function returns the color of a pixel in a given direction.
  */
  CColor GetPixelColor(int x, int y) const;

  /**
     \brief This function recalculates what depends on other parameters.
  */
  void Update(void);

 private:
  CVector3f m_CenterPos; /**< Position of the center of the bounding box. */
  CVectBase m_VectorBase; /**< Vector base used for the rendering. */

  CMathExpression *m_pFormula;  /**< Formula to be plotted. */
  CMathExpression *m_pFormulaDx; /**< Formula of the partial derivative
                                    with respect to x. */
  CMathExpression *m_pFormulaDy; /**< Formula of the partial derivative
                                    with respect to y. */
  CMathExpression *m_pFormulaDz; /**< Formula of the partial derivative
                                    with respect to z. */

  /**
     \brief This function returns the direction of the ray corresponding 
     to a pixel.
  */
  CVector3f GetDirection(int x, int y) const;

  /**
     \brief This function returns the starting point of the ray 
     corresponding to a pixel.
  */
  CVector3f GetStartingPoint(int x, int y) const;

  /**
     \brief This function returns true if the ray is still going towards 
     the bounding box or if it is in it.
  */
  inline bool InBoundingBox(const CVector3f& Pos,
                            const CVector3f& Dir) const
    {
      return ( !(
                 ( (Pos.x < m_MinVector.x) && (Dir.x < 0) ) ||
                 ( (Pos.x > m_MaxVector.x) && (Dir.x > 0) ) ||
                 ( (Pos.y < m_MinVector.y) && (Dir.y < 0) ) ||
                 ( (Pos.y > m_MaxVector.y) && (Dir.y > 0) ) ||
                 ( (Pos.z < m_MinVector.z) && (Dir.z < 0) ) ||
                 ( (Pos.z > m_MaxVector.z) && (Dir.z > 0) ) )
               );
    }

  /**
     \brief This function gets the starting point as close as possible 
     to the bounding box.
  */
  void GetCloseToBoundingBox(CVector3f& StartingPoint,
                             const CVector3f& Direction) const;

  /**
     \brief This function copies a CRenderObj.
  */
  void Copy(const CRenderObj& obj);
};

#endif  // CRENDEROBJ_H

/** @} */
