text: /**************************************************************************\
   * Copyright (c) Kongsberg Oil & Gas Technologies AS
   * All rights reserved.
   * 
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   * 
   * Redistributions of source code must retain the above copyright notice,
   * this list of conditions and the following disclaimer.
   * 
   * Redistributions in binary form must reproduce the above copyright
   * notice, this list of conditions and the following disclaimer in the
   * documentation and/or other materials provided with the distribution.
   * 
   * Neither the name of the copyright holder nor the names of its
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   * 
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  \**************************************************************************/
  
  /*!
    \class SmHeadlight SmHeadlight.h SmallChange/nodes/SmHeadlight.h
    \brief The SmHeadlight class is a node type for specifying a viewer headlight.
  
    \ingroup nodes
  
    See also documentation of parent class for important information
    regarding light sources in general.
  */
  
  #ifdef HAVE_CONFIG_H
  #include <config.h>
  #endif // HAVE_CONFIG_H
  
  #include <SmallChange/nodes/SmHeadlight.h>
  
  #include <Inventor/SbColor4f.h>
  #include <Inventor/SbVec4f.h>
  #include <Inventor/actions/SoGLRenderAction.h>
  #include <Inventor/actions/SoCallbackAction.h>
  #include <Inventor/elements/SoEnvironmentElement.h>
  #include <Inventor/elements/SoGLLightIdElement.h>
  #include <Inventor/elements/SoViewVolumeElement.h>
  #include <Inventor/elements/SoModelMatrixElement.h>
  #include <Inventor/elements/SoViewingMatrixElement.h>
  #include <Inventor/elements/SoLightElement.h>
  
  #include <Inventor/system/gl.h>
  
  #if COIN_DEBUG
  #include <Inventor/errors/SoDebugError.h>
  #endif // COIN_DEBUG
  
  // *************************************************************************
  
  SO_NODE_SOURCE(SmHeadlight);
  
  /*!
    Constructor.
  */
  SmHeadlight::SmHeadlight(void)
  {
    SO_NODE_CONSTRUCTOR(SmHeadlight);
    // needed to pass a standard light source to SoLightElement
    this->dummy = new SoDirectionalLight;
    this->dummy->ref();
  }
  
  /*!
    Destructor.
  */
  SmHeadlight::~SmHeadlight()
  {
    this->dummy->unref();
  }
  
  // Doc from superclass.
  void
  SmHeadlight::initClass(void)
  {
    static int initialized = 0;
    if (!initialized) {
      initialized = 1;
      SO_NODE_INIT_CLASS(SmHeadlight, SoLight, "Light");
    }
  }
  
  void
  SmHeadlight::callback(SoCallbackAction * action)
  {
    if (!this->on.getValue()) return;
  
    SoState * state = action->getState();
  
    SbVec3f dir = - SoViewVolumeElement::get(state).getProjectionDirection();
  
    // update internal light and pass it to SoLightElement
    this->dummy->intensity = this->intensity.getValue();
    this->dummy->color = this->color.getValue();
    this->dummy->direction = -dir;
  
    SoLightElement::add(state, dummy, SoModelMatrixElement::get(state) *
                        SoViewingMatrixElement::get(state));
  
  }
  
  // Doc from superclass.
  void
  SmHeadlight::GLRender(SoGLRenderAction * action)
  {
    if (!this->on.getValue()) return;
  
    SoState * state = action->getState();
    int idx = SoGLLightIdElement::increment(state);
  
    if (idx < 0) {
  #if COIN_DEBUG
      SoDebugError::postWarning("SmHeadlight::GLRender",
                                "Max # of OpenGL lights exceeded :(");
  #endif // COIN_DEBUG
      return;
    }
  
    GLenum light = (GLenum) (idx + GL_LIGHT0);
  
    SbColor4f lightcolor(0.0f, 0.0f, 0.0f, 1.0f);
    // disable ambient contribution from this light source
    glLightfv(light, GL_AMBIENT, lightcolor.getValue());
  
    lightcolor.setRGB(this->color.getValue());
    lightcolor *= this->intensity.getValue();
  
    glLightfv(light, GL_DIFFUSE, lightcolor.getValue());
    glLightfv(light, GL_SPECULAR, lightcolor.getValue());
  
    // GL directional light is specified towards light source
    SbVec3f dir = - SoViewVolumeElement::get(state).getProjectionDirection();
    dir.normalize();
  
    // directional when w = 0.0
    SbVec4f dirvec(dir[0], dir[1], dir[2], 0.0f);
    glLightfv(light, GL_POSITION, dirvec.getValue());
  
    glLightf(light, GL_SPOT_EXPONENT, 0.0);
    glLightf(light, GL_SPOT_CUTOFF, 180.0);
    glLightf(light, GL_CONSTANT_ATTENUATION, 1);
    glLightf(light, GL_LINEAR_ATTENUATION, 0);
    glLightf(light, GL_QUADRATIC_ATTENUATION, 0);
  
    // update internal light and pass it to SoLightElement
    this->dummy->intensity = this->intensity.getValue();
    this->dummy->color = this->color.getValue();
    this->dummy->direction = -dir;
  
    SoLightElement::add(state, dummy, SoModelMatrixElement::get(state) *
                        SoViewingMatrixElement::get(state));
  
  }
  