//
//  Vrml 97 library
//  Copyright (C) 1998 Chris Morley
//
//  %W% %G%
//  VrmlNodeSpotLight.cpp

#include "VrmlNodeSpotLight.h"
#include "MathUtils.h"
#include "VrmlNodeType.h"
#include "VrmlScene.h"
#include "Viewer.h"

// Return a new VrmlNodeSpotLight
static VrmlNode *creator( VrmlScene *s ) { return new VrmlNodeSpotLight(s); }


// Define the built in VrmlNodeType:: "SpotLight" fields

VrmlNodeType *VrmlNodeSpotLight::defineType(VrmlNodeType *t)
{
  static VrmlNodeType *st = 0;

  if (! t)
    {
      if (st) return st;
      t = st = new VrmlNodeType("SpotLight", creator);
    }

  VrmlNodeLight::defineType(t);	// Parent class
  t->addExposedField("attenuation", VrmlField::SFVEC3F);
  t->addExposedField("beamWidth", VrmlField::SFFLOAT);
  t->addExposedField("cutOffAngle", VrmlField::SFFLOAT);
  t->addExposedField("direction", VrmlField::SFVEC3F);
  t->addExposedField("location", VrmlField::SFVEC3F);
  t->addExposedField("radius", VrmlField::SFFLOAT);

  return t;
}


VrmlNodeType *VrmlNodeSpotLight::nodeType() const { return defineType(0); }


VrmlNodeSpotLight::VrmlNodeSpotLight(VrmlScene *scene) :
  VrmlNodeLight(scene),
  d_attenuation(1.0, 0.0, 0.0),
  d_beamWidth(1.570796),
  d_cutOffAngle(0.785398),
  d_direction(0.0, 0.0, -1.0),
  d_location(0.0, 0.0, 0.0),
  d_radius(100)
{
  if (d_scene) d_scene->addScopedLight(this);
}

VrmlNodeSpotLight::~VrmlNodeSpotLight()
{
  if (d_scene) d_scene->removeScopedLight(this);
}


VrmlNode *VrmlNodeSpotLight::cloneMe() const
{
  return new VrmlNodeSpotLight(*this);
}


VrmlNodeSpotLight* VrmlNodeSpotLight::toSpotLight() const
{ return (VrmlNodeSpotLight*) this; }


void VrmlNodeSpotLight::addToScene(VrmlScene *s, const char *)
{ if (d_scene != s && (d_scene = s) != 0) d_scene->addScopedLight(this); }


ostream& VrmlNodeSpotLight::printFields(ostream& os, int indent)
{
  VrmlNodeLight::printFields(os, indent);
  if (! FPEQUAL(d_attenuation.x(), 1.0) ||
      ! FPZERO(d_attenuation.y()) ||
      ! FPZERO(d_attenuation.z()) )
    PRINT_FIELD(attenuation);
  if (! FPEQUAL(d_beamWidth.get(), 1.570796))
    PRINT_FIELD(beamWidth);

  if (! FPEQUAL(d_cutOffAngle.get(), 1.570796))
    PRINT_FIELD(cutOffAngle);
  if (! FPZERO(d_direction.x()) ||
      ! FPZERO(d_direction.y()) ||
      ! FPEQUAL(d_direction.z(), -1.0) )
    PRINT_FIELD(direction);

  if (! FPZERO(d_location.x()) ||
      ! FPZERO(d_location.y()) ||
      ! FPZERO(d_location.z()) )
    PRINT_FIELD(location);

  if (! FPEQUAL(d_radius.get(), 100.0))
    PRINT_FIELD(radius);

  return os;
}


// This should be called before rendering any geometry in the scene.
// Since this is called from Scene::render() before traversing the
// scene graph, the proper transformation matrix hasn't been set up.
// Somehow it needs to figure out the accumulated xforms of its
// parents and apply them before rendering. This is not easy with
// DEF/USEd nodes...
void VrmlNodeSpotLight::renderScoped(Viewer *viewer)
{
  if ( d_on.get() && d_radius.get() > 0.0 )
    viewer->insertSpotLight( d_ambientIntensity.get(),
			     d_attenuation.get(),
			     d_beamWidth.get(),
			     d_color.get(),
			     d_cutOffAngle.get(),
			     d_direction.get(),
			     d_intensity.get(),
			     d_location.get(),
			     d_radius.get() );
  clearModified();
}

// Set the value of one of the node fields.

void VrmlNodeSpotLight::setField(const char *fieldName,
				 const VrmlField &fieldValue)
{
  if TRY_FIELD(attenuation, SFVec3f)
  else if TRY_FIELD(beamWidth, SFFloat)
  else if TRY_FIELD(cutOffAngle, SFFloat)
  else if TRY_FIELD(direction, SFVec3f)
  else if TRY_FIELD(location, SFVec3f)
  else if TRY_FIELD(radius, SFFloat)
  else 
    VrmlNodeLight::setField(fieldName, fieldValue);
}

const VrmlSFVec3f& VrmlNodeSpotLight::getAttenuation() const   // LarryD Mar 04/99
{  return d_attenuation; }

const VrmlSFVec3f& VrmlNodeSpotLight::getDirection() const   // LarryD Mar 04/99
{  return d_direction; }

const VrmlSFVec3f& VrmlNodeSpotLight::getLocation() const   // LarryD Mar 04/99
{  return d_location; }
