/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This file contains the declaration of the CSurface class.           //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
#ifndef __CSURFACE_HPP__
#define __CSURFACE_HPP__


#include "real.hpp"
#include "CVector.hpp"
#include "CSquareMatrix.hpp"
#include "CPropertyObject.hpp"
#include <iostream>
#include <string>
#include <vector>

class CConcreteSurface;
class CRay;


/////////////////////////////////////////////////////////////////////////
//                                                                     //
// This class is an interface that must be implemented by any object   //
// that is to be rendered in a scene.                                  //
//                                                                     //
/////////////////////////////////////////////////////////////////////////
class CSurface : public CPropertyObject
{
public:
  virtual ~CSurface();

  // Apply translation to transformation matrix
  virtual void Translate(const CVector& v);
  // Apply scale to transformation matrix
  virtual void Scale(const CVector& v);
  // Apply rotation to transformation matrix
  virtual void Rotate(real_t angle, const CVector& v);

  // Push matrix and load current transformation matrix
  void PushMatrixState() const;
  // Pop matrix
  void PopMatrixState() const;



  // Type representing what will hold hit values for a ray
  typedef std::vector<real_t> hitcontainer;



  ///////////////////////////////////////////////////////
  // Interface that must be implemented to be rendered //
  ///////////////////////////////////////////////////////

  // Return a copy of the surface
  virtual CSurface* Copy()                                        const = 0;

  // Do the necessary preprocessing that a surface needs
  virtual void      Preprocess()                                        = 0;

  // Compute the intersections of the surface with a ray
  virtual int       Intersect(const CRay&              ray,
                              hitcontainer&            hits,
                              const CConcreteSurface **pFirstHit) const = 0;

  // Do the necessary preprocessing that a surface needs the be
  // rendered in OpenGL
  virtual void      PreprocessGL()                                      = 0;

  // Render the surface in OpenGL
  virtual void      DrawGL()                                      const = 0;

  // Generate the shader code
  virtual void      GenerateShaderForObject(std::ostream& o)      const = 0;




  // Transformation matrix
  CSquareMatrix<real_t,4> m_Transformation;
  // Inverse of the transformation matrix
  CSquareMatrix<real_t,4> m_InverseTransformation;




  ////////////////
  // Properties //
  ////////////////

  // Refraction index inside the surface
  real_t  m_PropRefractionIndex;


protected:
  CSurface(const std::string& strName);
};


#endif // __CSURFACE_HPP__
