#include "Base.h" #include "Light.h" #include "DAESceneEncoder.h" namespace gameplay { Light::Light(void) : _lightType(0), _constantAttenuation(0.0f), _linearAttenuation(0.0f), _quadraticAttenuation(0.0f), _falloffAngle(0.0f), _falloffExponent(0.0f), _range(-1.0f), _innerAngle(-1.0f), _outerAngle(0.0f) { fillArray(_color, 0.0f, COLOR_SIZE); } Light::~Light(void) { } unsigned int Light::getTypeId(void) const { return LIGHT_ID; } const char* Light::getElementName(void) const { return "Light"; } float Light::computeRange(float constantAttenuation, float linearAttenuation, float quadraticAttenuation) { if (constantAttenuation == 0.0f && linearAttenuation == 0.0f && quadraticAttenuation == 0.0f) { return 0.0f; } // Constant Attenuation is currently not supported. if (constantAttenuation == 1.0f) { return 1.0f; } const float step = 0.01f; float range = 0.01f; float att = 1.0f; while (att > 0.01f) { att = 1 / (constantAttenuation + (range * linearAttenuation) + (range * range * quadraticAttenuation)); range += step; } return range; } float lerpstep( float lower, float upper, float s) { float lerpstep = ( s - lower ) / ( upper - lower ); if (lerpstep < 0.0f) lerpstep = 0.0f; else if (lerpstep > 1.0f) lerpstep = 1.0f; return lerpstep; } float Light::computeInnerAngle(float outerAngle) { const float epsilon = 0.15f; // Set inner angle to half of outer angle. float innerAngle = outerAngle / 2.0f; // Try to find the inner angle by sampling the attenuation with steps of angle. for (float angle = 0.0; angle < outerAngle; angle += epsilon) { float outerCosAngle = cos(MATH_DEG_TO_RAD(outerAngle)); float innerCosAngle = cos(MATH_DEG_TO_RAD(innerAngle)); float cosAngle = cos(MATH_DEG_TO_RAD(angle)); float att = lerpstep(outerCosAngle, innerCosAngle, cosAngle); if (att < 1.0f) { innerAngle = angle; break; } } return innerAngle; } void Light::writeBinary(FILE* file) { Object::writeBinary(file); write(_lightType, file); write(_color, COLOR_SIZE, file); // Compute an approximate light range with Collada's attenuation parameters. // This facilitates bringing in the light nodes directly from maya to gameplay. if (_range == -1.0f) { _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation); } if (_lightType == SpotLight) { // Compute an approximate inner angle of the spot light using Collada's outer angle. _outerAngle = _falloffAngle / 2.0f; if (_innerAngle == -1.0f) { _innerAngle = computeInnerAngle(_outerAngle); } write(_range, file); write(MATH_DEG_TO_RAD(_innerAngle), file); write(MATH_DEG_TO_RAD(_outerAngle), file); } else if (_lightType == PointLight) { write(_range, file); } } void Light::writeText(FILE* file) { fprintElementStart(file); fprintfElement(file, "lightType", _lightType); fprintfElement(file, "color", _color, COLOR_SIZE); // Compute an approximate light range with Collada's attenuation parameters. // This facilitates bringing in the light nodes directly from maya to gameplay. if (_range == -1.0f) { _range = computeRange(_constantAttenuation, _linearAttenuation, _quadraticAttenuation); } if (_lightType == SpotLight) { // Compute an approximate inner angle of the spot light using Collada's outer angle. _outerAngle = _falloffAngle / 2.0f; if (_innerAngle == -1.0f) { _innerAngle = computeInnerAngle(_outerAngle); } fprintfElement(file, "range", _range); fprintfElement(file, "innerAngle", MATH_DEG_TO_RAD(_innerAngle)); fprintfElement(file, "outerAngle", MATH_DEG_TO_RAD(_outerAngle)); } else if (_lightType == PointLight) { fprintfElement(file, "range", _range); } fprintElementEnd(file); } float Light::getRed() const { return _color[0]; } float Light::getGreen() const { return _color[1]; } float Light::getBlue() const { return _color[2]; } bool Light::isAmbient() const { return _lightType == AmbientLight; } void Light::setAmbientLight() { _lightType = AmbientLight; } void Light::setDirectionalLight() { _lightType = DirectionalLight; } void Light::setPointLight() { _lightType = PointLight; } void Light::setSpotLight() { _lightType = SpotLight; } void Light::setColor(float r, float g, float b) { _color[0] = r; _color[1] = g; _color[2] = b; } void Light::setConstantAttenuation(float value) { _constantAttenuation = value; } void Light::setLinearAttenuation(float value) { _linearAttenuation = value; } void Light::setQuadraticAttenuation(float value) { _quadraticAttenuation = value; } void Light::setFalloffAngle(float value) { _falloffAngle = value; } void Light::setFalloffExponent(float value) { _falloffExponent = value; if ( value != 1.0) { LOG(1, "Warning: spot light falloff_exponent must be 1.0. \n"); } } }