aboutsummaryrefslogtreecommitdiff
path: root/dep/g3dlite/source/GLight.cpp
diff options
context:
space:
mode:
authorclick <none@none>2010-08-27 01:52:05 +0200
committerclick <none@none>2010-08-27 01:52:05 +0200
commit7686d6ee57038e848f75130563fc78c1adebc1a2 (patch)
tree258a7a6db03e3479a0219ace8cfc3ec3ba53a1be /dep/g3dlite/source/GLight.cpp
parent1d3deae555f0ec523d77875bd5a307ab9bd19742 (diff)
Core/Dependency: Upgrade G3d-library to v8.0-release (patched version!)
Note: Due to issues with G3D (normally requiring X11 and the ZIP-library), the sourcetree version contains a modified version. The applied patch is commited to the repository for future reference. --HG-- branch : trunk
Diffstat (limited to 'dep/g3dlite/source/GLight.cpp')
-rw-r--r--dep/g3dlite/source/GLight.cpp275
1 files changed, 275 insertions, 0 deletions
diff --git a/dep/g3dlite/source/GLight.cpp b/dep/g3dlite/source/GLight.cpp
new file mode 100644
index 00000000000..553b493c1a3
--- /dev/null
+++ b/dep/g3dlite/source/GLight.cpp
@@ -0,0 +1,275 @@
+/**
+ @file GLight.cpp
+
+ @maintainer Morgan McGuire, http://graphics.cs.williams.edu
+
+ @created 2003-11-12
+ @edited 2009-11-16
+*/
+#include "G3D/GLight.h"
+#include "G3D/Sphere.h"
+#include "G3D/CoordinateFrame.h"
+#include "G3D/Any.h"
+#include "G3D/stringutils.h"
+
+namespace G3D {
+
+GLight::GLight(const Any& any) {
+ any.verifyName("GLight");
+
+ if (any.type() == Any::TABLE) {
+ *this = GLight();
+ Vector3 spotTarget;
+ bool hasSpotTarget = false;
+ for (Any::AnyTable::Iterator it = any.table().begin(); it.hasMore(); ++it) {
+ const std::string& key = toLower(it->key);
+ if (key == "position") {
+ position = it->value;
+ } else if (key == "rightdirection") {
+ rightDirection = it->value;
+ } else if (key == "spotdirection") {
+ spotDirection = Vector3(it->value).directionOrZero();
+ } else if (key == "spottarget") {
+ spotTarget = it->value;
+ hasSpotTarget = true;
+ } else if (key == "spotcutoff") {
+ spotCutoff = it->value.number();
+ } else if (key == "spotsquare") {
+ spotSquare = it->value.boolean();
+ } else if (key == "attenuation") {
+ attenuation[0] = it->value[0].number();
+ attenuation[1] = it->value[1].number();
+ attenuation[2] = it->value[2].number();
+ } else if (key == "color") {
+ color = it->value;
+ } else if (key == "enabled") {
+ enabled = it->value.boolean();
+ } else if (key == "specular") {
+ specular = it->value.boolean();
+ } else if (key == "diffuse") {
+ diffuse = it->value.boolean();
+ } else {
+ any.verify(false, "Illegal key: " + it->key);
+ }
+ }
+ if (hasSpotTarget) {
+ spotDirection = (spotTarget - position.xyz()).direction();
+ }
+ } else if (toLower(any.name()) == "glight::directional") {
+
+ *this = directional(any[0], any[1],
+ (any.size() > 2) ? any[2] : Any(true),
+ (any.size() > 3) ? any[3] : Any(true));
+
+ } else if (toLower(any.name()) == "glight::point") {
+
+ *this = point(any[0], any[1],
+ (any.size() > 2) ? any[2] : Any(1),
+ (any.size() > 3) ? any[3] : Any(0),
+ (any.size() > 4) ? any[4] : Any(0.5f),
+ (any.size() > 5) ? any[5] : Any(true),
+ (any.size() > 6) ? any[6] : Any(true));
+
+ } else if (toLower(any.name()) == "glight::spot") {
+
+ *this = spot(any[0], any[1], any[2], any[3],
+ (any.size() > 4) ? any[4] : Any(1),
+ (any.size() > 5) ? any[5] : Any(0),
+ (any.size() > 6) ? any[6] : Any(0),
+ (any.size() > 7) ? any[7] : Any(true),
+ (any.size() > 8) ? any[8] : Any(true));
+ } else {
+ any.verify(false, "Unrecognized name");
+ }
+}
+
+
+GLight::operator Any() const {
+ Any a(Any::TABLE, "GLight");
+ a.set("position", position.operator Any());
+ a.set("rightDirection", rightDirection.operator Any());
+ a.set("spotDirection", spotDirection.operator Any());
+ a.set("spotCutoff", spotCutoff);
+ a.set("spotSquare", spotSquare);
+
+ Any att(Any::ARRAY);
+ att.append(attenuation[0], attenuation[1], attenuation[2]);
+ a.set("attenuation", att);
+ a.set("color", color.operator Any());
+ a.set("enabled", enabled);
+ a.set("specular", specular);
+ a.set("diffuse", diffuse);
+ return a;
+}
+
+
+GLight::GLight() :
+ position(0, 0, 0, 0),
+ rightDirection(0,0,0),
+ spotDirection(0, 0, -1),
+ spotCutoff(180),
+ spotSquare(false),
+ color(Color3::white()),
+ enabled(false),
+ specular(true),
+ diffuse(true) {
+
+ attenuation[0] = 1.0;
+ attenuation[1] = 0.0;
+ attenuation[2] = 0.0;
+}
+
+
+GLight GLight::directional(const Vector3& toLight, const Color3& color, bool s, bool d) {
+ GLight L;
+ L.position = Vector4(toLight.direction(), 0);
+ L.color = color;
+ L.specular = s;
+ L.diffuse = d;
+ return L;
+}
+
+
+GLight GLight::point(const Vector3& pos, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
+ GLight L;
+ L.position = Vector4(pos, 1);
+ L.color = color;
+ L.attenuation[0] = constAtt;
+ L.attenuation[1] = linAtt;
+ L.attenuation[2] = quadAtt;
+ L.specular = s;
+ L.diffuse = d;
+ return L;
+}
+
+
+GLight GLight::spot(const Vector3& pos, const Vector3& pointDirection, float cutOffAngleDegrees, const Color3& color, float constAtt, float linAtt, float quadAtt, bool s, bool d) {
+ GLight L;
+ L.position = Vector4(pos, 1.0f);
+ L.spotDirection = pointDirection.direction();
+ debugAssert(cutOffAngleDegrees <= 90);
+ L.spotCutoff = cutOffAngleDegrees;
+ L.color = color;
+ L.attenuation[0] = constAtt;
+ L.attenuation[1] = linAtt;
+ L.attenuation[2] = quadAtt;
+ L.specular = s;
+ L.diffuse = d;
+ return L;
+}
+
+
+bool GLight::operator==(const GLight& other) const {
+ return (position == other.position) &&
+ (rightDirection == other.rightDirection) &&
+ (spotDirection == other.spotDirection) &&
+ (spotCutoff == other.spotCutoff) &&
+ (spotSquare == other.spotSquare) &&
+ (attenuation[0] == other.attenuation[0]) &&
+ (attenuation[1] == other.attenuation[1]) &&
+ (attenuation[2] == other.attenuation[2]) &&
+ (color == other.color) &&
+ (enabled == other.enabled) &&
+ (specular == other.specular) &&
+ (diffuse == other.diffuse);
+}
+
+
+bool GLight::operator!=(const GLight& other) const {
+ return !(*this == other);
+}
+
+
+Sphere GLight::effectSphere(float cutoff) const {
+ if (position.w == 0) {
+ // Directional light
+ return Sphere(Vector3::zero(), finf());
+ } else {
+ // Avoid divide by zero
+ cutoff = max(cutoff, 0.00001f);
+ float maxIntensity = max(color.r, max(color.g, color.b));
+
+ float radius = finf();
+
+ if (attenuation[2] != 0) {
+
+ // Solve I / attenuation.dot(1, r, r^2) < cutoff for r
+ //
+ // a[0] + a[1] r + a[2] r^2 > I/cutoff
+ //
+
+ float a = attenuation[2];
+ float b = attenuation[1];
+ float c = attenuation[0] - maxIntensity / cutoff;
+
+ float discrim = square(b) - 4 * a * c;
+
+ if (discrim >= 0) {
+ discrim = sqrt(discrim);
+
+ float r1 = (-b + discrim) / (2 * a);
+ float r2 = (-b - discrim) / (2 * a);
+
+ if (r1 < 0) {
+ if (r2 > 0) {
+ radius = r2;
+ }
+ } else if (r2 > 0) {
+ radius = min(r1, r2);
+ } else {
+ radius = r1;
+ }
+ }
+
+ } else if (attenuation[1] != 0) {
+
+ // Solve I / attenuation.dot(1, r) < cutoff for r
+ //
+ // r * a[1] + a[0] = I / cutoff
+ // r = (I / cutoff - a[0]) / a[1]
+
+ float radius = (maxIntensity / cutoff - attenuation[0]) / attenuation[1];
+ radius = max(radius, 0.0f);
+ }
+
+ return Sphere(position.xyz(), radius);
+
+ }
+}
+
+
+CoordinateFrame GLight::frame() const {
+ CoordinateFrame f;
+ if (rightDirection == Vector3::zero()) {
+ // No specified right direction; choose one automatically
+ if (position.w == 0) {
+ // Directional light
+ f.lookAt(-position.xyz());
+ } else {
+ // Spot light
+ f.lookAt(spotDirection);
+ }
+ } else {
+ const Vector3& Z = -spotDirection.direction();
+ Vector3 X = rightDirection.direction();
+
+ // Ensure the vectors are not too close together
+ while (abs(X.dot(Z)) > 0.9f) {
+ X = Vector3::random();
+ }
+
+ // Ensure perpendicular
+ X -= Z * Z.dot(X);
+ const Vector3& Y = Z.cross(X);
+
+ f.rotation.setColumn(Vector3::X_AXIS, X);
+ f.rotation.setColumn(Vector3::Y_AXIS, Y);
+ f.rotation.setColumn(Vector3::Z_AXIS, Z);
+ }
+ f.translation = position.xyz();
+
+ return f;
+}
+
+
+} // G3D