256 lines
5.9 KiB
C++
256 lines
5.9 KiB
C++
/**
|
|
* PANDA 3D SOFTWARE
|
|
* Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
*
|
|
* All use of this software is subject to the terms of the revised BSD
|
|
* license. You should have received a copy of this license along
|
|
* with this source code in a file named "LICENSE."
|
|
*
|
|
* @file light.cxx
|
|
* @author mike
|
|
* @date 1997-01-09
|
|
*/
|
|
|
|
#include "light.h"
|
|
#include "bamWriter.h"
|
|
#include "bamReader.h"
|
|
#include "datagram.h"
|
|
#include "datagramIterator.h"
|
|
|
|
UpdateSeq Light::_sort_seq;
|
|
|
|
TypeHandle Light::_type_handle;
|
|
|
|
|
|
/**
|
|
*
|
|
*/
|
|
CycleData *Light::CData::
|
|
make_copy() const {
|
|
return new CData(*this);
|
|
}
|
|
|
|
/**
|
|
* Writes the contents of this object to the datagram for shipping out to a
|
|
* Bam file.
|
|
*/
|
|
void Light::CData::
|
|
write_datagram(BamWriter *, Datagram &dg) const {
|
|
_color.write_datagram(dg);
|
|
}
|
|
|
|
/**
|
|
* This internal function is called by make_from_bam to read in all of the
|
|
* relevant data from the BamFile for the new Light.
|
|
*/
|
|
void Light::CData::
|
|
fillin(DatagramIterator &scan, BamReader *) {
|
|
_color.read_datagram(scan);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*/
|
|
Light::
|
|
~Light() {
|
|
}
|
|
|
|
/**
|
|
* Returns true if this is an AmbientLight, false if it is some other kind of
|
|
* light.
|
|
*/
|
|
bool Light::
|
|
is_ambient_light() const {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Sets the color temperature of the light in kelvins. This will recalculate
|
|
* the light's color.
|
|
*
|
|
* The default value is 6500 K, corresponding to a perfectly white light
|
|
* assuming a D65 white point.
|
|
*
|
|
* @since 1.10.0
|
|
*/
|
|
void Light::
|
|
set_color_temperature(PN_stdfloat temperature) {
|
|
if (_has_color_temperature && _color_temperature == temperature) {
|
|
return;
|
|
}
|
|
|
|
_has_color_temperature = true;
|
|
_color_temperature = temperature;
|
|
|
|
// Recalculate the color.
|
|
PN_stdfloat x, y;
|
|
|
|
if (temperature == 6500) {
|
|
// sRGB D65 white point.
|
|
x = 0.31271;
|
|
y = 0.32902;
|
|
|
|
} else {
|
|
PN_stdfloat mm = 1000.0 / temperature;
|
|
PN_stdfloat mm2 = mm * mm;
|
|
PN_stdfloat mm3 = mm2 * mm;
|
|
|
|
if (temperature < 4000) {
|
|
x = -0.2661239 * mm3 - 0.2343580 * mm2 + 0.8776956 * mm + 0.179910;
|
|
} else {
|
|
x = -3.0258469 * mm3 + 2.1070379 * mm2 + 0.2226347 * mm + 0.240390;
|
|
}
|
|
|
|
PN_stdfloat x2 = x * x;
|
|
PN_stdfloat x3 = x2 * x;
|
|
if (temperature < 2222) {
|
|
y = -1.1063814 * x3 - 1.34811020 * x2 + 2.18555832 * x - 0.20219683;
|
|
} else if (temperature < 4000) {
|
|
y = -0.9549476 * x3 - 1.37418593 * x2 + 2.09137015 * x - 0.16748867;
|
|
} else {
|
|
y = 3.0817580 * x3 - 5.87338670 * x2 + 3.75112997 * x - 0.37001483;
|
|
}
|
|
}
|
|
|
|
// xyY to XYZ, assuming Y=1.
|
|
LVecBase3 xyz(x / y, 1, (1 - x - y) / y);
|
|
|
|
// Convert XYZ to linearized sRGB.
|
|
const static LMatrix3 xyz_to_rgb(
|
|
3.2406255, -0.9689307, 0.0557101,
|
|
-1.537208, 1.8757561, -0.2040211,
|
|
-0.4986286, 0.0415175, 1.0569959);
|
|
|
|
LColor color(xyz_to_rgb.xform(xyz), 1);
|
|
|
|
CDWriter cdata(_cycler);
|
|
cdata->_color = color;
|
|
mark_viz_stale();
|
|
}
|
|
|
|
/**
|
|
* For spotlights, returns the exponent that controls the amount of light
|
|
* falloff from the center of the spotlight. For other kinds of lights,
|
|
* returns 0.
|
|
*/
|
|
PN_stdfloat Light::
|
|
get_exponent() const {
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Returns the color of specular highlights generated by the light. This
|
|
* value is meaningless for ambient lights.
|
|
*/
|
|
const LColor &Light::
|
|
get_specular_color() const {
|
|
static const LColor white(1, 1, 1, 1);
|
|
return white;
|
|
}
|
|
|
|
/**
|
|
* Returns the terms of the attenuation equation for the light. These are, in
|
|
* order, the constant, linear, and quadratic terms based on the distance from
|
|
* the point to the vertex.
|
|
*/
|
|
const LVecBase3 &Light::
|
|
get_attenuation() const {
|
|
static const LVecBase3 no_atten(1, 0, 0);
|
|
return no_atten;
|
|
}
|
|
|
|
/**
|
|
* This is called when the light is added to a LightAttrib.
|
|
*/
|
|
void Light::
|
|
attrib_ref() {
|
|
}
|
|
|
|
/**
|
|
* This is called when the light is removed from a LightAttrib.
|
|
*/
|
|
void Light::
|
|
attrib_unref() {
|
|
}
|
|
|
|
/**
|
|
* Computes the vector from a particular vertex to this light. The exact
|
|
* vector depends on the type of light (e.g. point lights return a different
|
|
* result than directional lights).
|
|
*
|
|
* The input parameters are the vertex position in question, expressed in
|
|
* object space, and the matrix which converts from light space to object
|
|
* space. The result is expressed in object space.
|
|
*
|
|
* The return value is true if the result is successful, or false if it cannot
|
|
* be computed (e.g. for an ambient light).
|
|
*/
|
|
bool Light::
|
|
get_vector_to_light(LVector3 &, const LPoint3 &, const LMatrix4 &) {
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns a GeomNode that may be rendered to visualize the Light. This is
|
|
* used during the cull traversal to render the Lights that have been made
|
|
* visible.
|
|
*/
|
|
GeomNode *Light::
|
|
get_viz() {
|
|
CDLockedReader cdata(_cycler);
|
|
if (cdata->_viz_geom_stale) {
|
|
CDWriter cdata_w(_cycler, cdata);
|
|
|
|
cdata_w->_viz_geom = new GeomNode("viz");
|
|
fill_viz_geom(cdata_w->_viz_geom);
|
|
cdata_w->_viz_geom_stale = false;
|
|
}
|
|
return cdata->_viz_geom;
|
|
}
|
|
|
|
/**
|
|
* Fills the indicated GeomNode up with Geoms suitable for rendering this
|
|
* light.
|
|
*/
|
|
void Light::
|
|
fill_viz_geom(GeomNode *) {
|
|
}
|
|
|
|
/**
|
|
* Writes the contents of this object to the datagram for shipping out to a
|
|
* Bam file.
|
|
*/
|
|
void Light::
|
|
write_datagram(BamWriter *manager, Datagram &dg) {
|
|
if (manager->get_file_minor_ver() >= 39) {
|
|
dg.add_bool(_has_color_temperature);
|
|
if (_has_color_temperature) {
|
|
dg.add_stdfloat(_color_temperature);
|
|
} else {
|
|
manager->write_cdata(dg, _cycler);
|
|
}
|
|
} else {
|
|
manager->write_cdata(dg, _cycler);
|
|
}
|
|
dg.add_int32(_priority);
|
|
}
|
|
|
|
/**
|
|
* This internal function is called by make_from_bam to read in all of the
|
|
* relevant data from the BamFile for the new Light.
|
|
*/
|
|
void Light::
|
|
fillin(DatagramIterator &scan, BamReader *manager) {
|
|
if (manager->get_file_minor_ver() >= 39) {
|
|
_has_color_temperature = scan.get_bool();
|
|
} else {
|
|
_has_color_temperature = false;
|
|
}
|
|
if (_has_color_temperature) {
|
|
set_color_temperature(scan.get_stdfloat());
|
|
} else {
|
|
manager->read_cdata(scan, _cycler);
|
|
}
|
|
_priority = scan.get_int32();
|
|
}
|