// Author: Juan Carlos De Abreu (jcabreur@gmail.com)

#include "light_node.h"
#include "../scene_inl.h"
#include "../../Includes/OpenGL.h"
#include "../../Math/Matrix.h"

BEGIN_TEG_NAMESPACE();

LightNode::LightNode() : ISceneNode(LIGHT_NODE), use_light_(true) {
  ambient_.set(0.0f, 0.0f, 0.0f, 1.0f);
  diffuse_.set(1.0f, 1.0f, 1.0f, 1.0f);
  specular_.set(1.0f, 1.0f, 1.0f, 1.0f);
  attenuation_.set(1.0f, 0.0f, 0.0f);
}

LightNode::LightNode(const Vec4f& ambient,
                     const Vec4f& diffuse,
                     const Vec4f& specular)
    : ISceneNode(LIGHT_NODE),
      use_light_(true),
      ambient_(ambient),
      diffuse_(diffuse),
      specular_(specular) {}

LightNode::~LightNode() {}

void LightNode::apply() {
  // Retrieve modelview matrix and update the position.
  Mat4f model_view; glGetFloatv(GL_MODELVIEW_MATRIX, model_view.m);
  position_ = math::transpose(model_view) * Vec4f(0, 0, 0 ,1);

  // Add the light to the list of lights in the scene.
  if (use_light_) Scene::GetInstance().AddSceneLight(this);
}

void LightNode::render(int lightNumber) {
  // Set the properties of the light in the active graphics API.
  glLightfv(GL_LIGHT0 + lightNumber, GL_AMBIENT, ambient_.values);
  glLightfv(GL_LIGHT0 + lightNumber, GL_DIFFUSE, diffuse_.values);
  glLightfv(GL_LIGHT0 + lightNumber, GL_SPECULAR, specular_.values);
  glLightfv(GL_LIGHT0 + lightNumber, GL_POSITION, position_.values);
  glLightf(GL_LIGHT0 + lightNumber, GL_CONSTANT_ATTENUATION, attenuation_.x);
  glLightf(GL_LIGHT0 + lightNumber, GL_LINEAR_ATTENUATION, attenuation_.y);
  glLightf(GL_LIGHT0 + lightNumber, GL_QUADRATIC_ATTENUATION, attenuation_.z);
}

SmartPointer<ISceneNode> LightNode::copy(void) {
  // Create a new instance of LightNode with the same values.
  return SmartPointer<ISceneNode>(new LightNode(ambient_, diffuse_, specular_));
}

END_TEG_NAMESPACE();
