// __author__ = Juan Carlos De Abreu (jcabreur@gmail.com)

#include "geometry_node.h"
#include "../scene_inl.h"
#include "../../Model/Model.h"
#include "../../Includes/OpenGL.h"
#include "../../Material/Material.h"

BEGIN_TEG_NAMESPACE();

GeometryNode::GeometryNode() : ISceneNode(GEOMETRY_NODE),
                               model_(NULL),
                               draw_(true),
                               custom_material_(NULL), 
                               use_default_material_(true),
                               cast_shadows_(true) {}

GeometryNode::GeometryNode(SmartPointer<IModel> model,
                           bool draw,
                           bool cast_shadows)
    : ISceneNode(GEOMETRY_NODE),
      model_(model),
      draw_(draw),
      custom_material_(NULL), 
      use_default_material_(true),
      cast_shadows_(cast_shadows) {}

GeometryNode::~GeometryNode() {
  model_ = NULL;
  custom_material_ = NULL;
}

void GeometryNode::apply() {
  // Retrieve modelView matrix, before check to can do collision detection.
  glGetFloatv(GL_MODELVIEW_MATRIX, model_view_.m);

  // Check if the geometry will be displayed.
  if(!draw_) return; // The geometry don't will be displayed.

  // Calculate the distance to the eye.
  const Mat4f kModelViewTranspose = math::transpose(model_view_);
  const Vec3f kV0 = vec3(kModelViewTranspose * Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
  const Vec3f kV1 = vec3(kModelViewTranspose * Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
  dist_ = kV0.module() - (kV0 - kV1).module();

  // Add the geometry to the list of display.
  Scene::GetInstance().AddSceneGeometry(this);
}

void GeometryNode::render(int render_mode) {
  // Load the modelview for the geometry and dispaly the geometry.
  glLoadMatrixf(model_view_.m);
  if (!use_default_material_ && custom_material_ != NULL)
    model_->drawSurface(render_mode, custom_material_);
  else
    model_->drawSurface(render_mode);
}

SmartPointer<ISceneNode> GeometryNode::copy() {
  // Create a new instance of geometry node with the same values.
  SmartPointer<GeometryNode> geometry_node_copy = 
      new GeometryNode(model_, draw_, cast_shadows_);
  geometry_node_copy->use_default_material_ = use_default_material_;
  if (custom_material_ != NULL)
	geometry_node_copy->custom_material_ = custom_material_->copy();
  return SmartPointer<ISceneNode>(
      dynamic_cast<ISceneNode*>((GeometryNode*) geometry_node_copy));
}

END_TEG_NAMESPACE();
