]> git.tdb.fi Git - libs/gl.git/commitdiff
Split the Light class into subclasses by light type
authorMikko Rasa <tdb@tdb.fi>
Wed, 6 Oct 2021 08:15:42 +0000 (11:15 +0300)
committerMikko Rasa <tdb@tdb.fi>
Wed, 6 Oct 2021 21:13:22 +0000 (00:13 +0300)
There are some cases where it would be inconvenient for a light to
suddenly change type.

18 files changed:
blender/io_mspgl/export_light.py
demos/desertpillars/source/desertpillars.cpp
shaderlib/cooktorrance.glsl
shaderlib/msp_interface.glsl
shaderlib/phong.glsl
source/effects/shadowmap.cpp
source/effects/shadowmap.h
source/effects/sky.cpp
source/effects/sky.h
source/materials/directionallight.cpp [new file with mode: 0644]
source/materials/directionallight.h [new file with mode: 0644]
source/materials/light.cpp
source/materials/light.h
source/materials/lighting.cpp
source/materials/pointlight.cpp [new file with mode: 0644]
source/materials/pointlight.h [new file with mode: 0644]
source/resources/resources.cpp
tools/viewer.cpp

index 4da2ba29a717c6b7bf6ac9417d4157b4ddc12302..2fc8c8dd02bd3dbccec4b0204dd75ed0930c378e 100644 (file)
@@ -6,15 +6,19 @@ class LightExporter:
                        raise ValueError("Object {} is not a light".format(obj.name))
                light = obj.data
 
-               from .datafile import Resource, Statement
+               from .datafile import Resource, Statement, Token
                light_res = Resource(light.name+".light", "light")
 
                if light.type=='SUN':
-                       pos = obj.matrix_world@mathutils.Vector((0.0, 0.0, 1.0, 0.0))
-               else:
+                       light_res.statements.append(Statement("type", Token("directional")))
+                       light_res.statements.append(Statement("direction", *(-obj.matrix_world.col[2])[0:3]))
+               elif light.type=='POINT':
+                       light_res.statements.append(Statement("type", Token("point")))
                        pos = obj.matrix_world@mathutils.Vector((0.0, 0.0, 0.0, 1.0))
+                       light_res.statements.append(Statement("position", *obj.matrix_world.col[3][0:3]))
+               else:
+                       raise Exception("Can't export light {} of unknown type {}".format(light.name, light.type))
 
-               light_res.statements.append(Statement("position", *tuple(pos)))
                c = light.color*light.energy
                light_res.statements.append(Statement("color", *tuple(c)))
 
index 016cc95d12bb878ee38dfbe11866a9f143cff5c6..5932e56968be16851469fd045e58b96708b30dc6 100644 (file)
@@ -1,4 +1,5 @@
 #include <msp/fs/dir.h>
+#include <msp/gl/directionallight.h>
 #include <msp/gl/sequencebuilder.h>
 #include <msp/gl/renderer.h>
 #include <msp/gl/tests.h>
@@ -34,7 +35,7 @@ DesertPillars::DesertPillars(int, char **):
        window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &DesertPillars::exit), 0));
        keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &DesertPillars::key_press), false));
 
-       GL::Light &sun = resources.get<GL::Light>("Sun.light");
+       GL::DirectionalLight &sun = resources.get<GL::DirectionalLight>("Sun.light");
        sky = make_unique<GL::Sky>(content, sun);
        sky->set_debug_name("Sky");
 
index 7eefbf60eb52e96a9ab320e6c9c42e1ccc4d1e40..f441a6d392088fe05f8152dc3430d2de1b701c3a 100644 (file)
@@ -153,7 +153,7 @@ vec3 cooktorrance_lighting(vec3 normal, vec3 look, vec3 base_color, float metaln
 {
        vec3 color = vec3(0.0);
        for(int i=0; i<max_lights; ++i)
-               if(light_sources[i].enabled!=0)
+               if(light_sources[i].type!=0)
                {
                        vec3 light = get_light_direction(i);
                        float shadow = get_shadow_factor(i);
index 23c612051248281c9a3bc9795cf11163e2b2f5d1..d8de5d240b90f6c416cac9a7b7cc37a361debe1c 100644 (file)
@@ -2,7 +2,7 @@ struct LightSourceParameters
 {
        vec4 position;
        vec3 color;
-       int enabled;
+       int type;
 };
 
 struct ClipPlane
index 87eba5eadf38bce9ba1c6873a4dd18b2dcb2f841..004232acd503e4c76c607ca6206f2f4e228cdef1 100644 (file)
@@ -96,7 +96,7 @@ vec3 phong_lighting(vec3 normal, vec3 look, vec3 surface_diffuse, vec3 surface_s
 {
        vec3 color = phong_ambient(surface_diffuse);
        for(int i=0; i<max_lights; ++i)
-               if(light_sources[i].enabled!=0)
+               if(light_sources[i].type!=0)
                {
                        vec3 light = get_light_direction(i);
                        float shadow = get_shadow_factor(i);
index 49dfa36de0bb636d101900dc78e47ca42f03f723..1b5f531b913c2d339f8e1aee3830775d576aed58 100644 (file)
@@ -1,6 +1,6 @@
 #include <msp/strings/format.h>
+#include "directionallight.h"
 #include "error.h"
-#include "light.h"
 #include "lighting.h"
 #include "renderer.h"
 #include "resources.h"
@@ -38,7 +38,7 @@ ShadowMap::ShadowMap(unsigned w, unsigned h, Renderable &r, const Lighting *l, R
        }
 }
 
-ShadowMap::ShadowMap(unsigned s, Renderable &r, const Light &l, Renderable &c):
+ShadowMap::ShadowMap(unsigned s, Renderable &r, const DirectionalLight &l, Renderable &c):
        ShadowMap(s, s, r, 0, c)
 {
        add_light(l, s);
@@ -48,7 +48,7 @@ ShadowMap::ShadowMap(unsigned w, unsigned h, Renderable &r, const Lighting &l, R
        ShadowMap(w, h, r, &l, c)
 { }
 
-void ShadowMap::add_light(const Light &light, unsigned s)
+void ShadowMap::add_light(const DirectionalLight &light, unsigned s)
 {
        if(!lighting && !lights.empty())
                throw invalid_operation("ShadowMap::add_light");
index c3c7bd55a7f53430937cce8faf6f6955b220f61d..cb6229935a81806dc3bad9af00b72bed47e739b7 100644 (file)
@@ -12,6 +12,7 @@
 namespace Msp {
 namespace GL {
 
+class DirectionalLight;
 class Light;
 
 /**
@@ -49,10 +50,10 @@ private:
 
        ShadowMap(unsigned, unsigned, Renderable &, const Lighting *, Renderable &);
 public:
-       ShadowMap(unsigned, Renderable &, const Light &, Renderable &);
+       ShadowMap(unsigned, Renderable &, const DirectionalLight &, Renderable &);
        ShadowMap(unsigned, unsigned, Renderable &, const Lighting &, Renderable &);
 
-       void add_light(const Light &, unsigned);
+       void add_light(const DirectionalLight &, unsigned);
 
        /** Sets the ShadowMap target point and radius.  The transformation matrix is
        computed so that a sphere with the specified parameters will be completely
index d9c95b3bd79839fed84d1ad3f06235a4f5ac626e..fcb465b8bb71960fc480086ff263baeb73119fd7 100644 (file)
@@ -1,6 +1,6 @@
 #include <msp/geometry/hypersphere.h>
 #include <msp/geometry/ray.h>
-#include "light.h"
+#include "directionallight.h"
 #include "mesh.h"
 #include "renderer.h"
 #include "resources.h"
@@ -12,7 +12,7 @@ using namespace std;
 namespace Msp {
 namespace GL {
 
-Sky::Sky(Renderable &r, Light &s):
+Sky::Sky(Renderable &r, DirectionalLight &s):
        Effect(r),
        sun(s),
        transmittance_lookup(128, 64, (COLOR_ATTACHMENT,RGB16F)),
@@ -97,8 +97,8 @@ void Sky::setup_frame(Renderer &renderer)
        rendered = true;
 
        shdata.uniform("light_color", sun.get_color());
-       shdata.uniform("light_dir", sun.get_position().slice<3>(0));
-       sun.set_transmittance(get_transmittance(normalize(sun.get_position().slice<3>(0))));
+       shdata.uniform("light_dir", -sun.get_direction());
+       sun.set_transmittance(get_transmittance(-sun.get_direction()));
 
        Renderer::Push push(renderer);
 
index be31b3085625001c9603adb1c28f4232e64862da..782aef1ceb1d0b0faa2c5e58a6407118834b0457 100644 (file)
@@ -8,8 +8,8 @@
 namespace Msp {
 namespace GL {
 
+class DirectionalLight;
 class Mesh;
-class Light;
 class Program;
 
 /**
@@ -41,7 +41,7 @@ public:
 
 private:
        Planet planet;
-       Light &sun;
+       DirectionalLight &sun;
        RenderTarget transmittance_lookup;
        const Program &transmittance_shprog;
        bool transmittance_lookup_dirty;
@@ -56,7 +56,7 @@ private:
        bool rendered;
 
 public:
-       Sky(Renderable &, Light &);
+       Sky(Renderable &, DirectionalLight &);
 
        void set_planet(const Planet &);
        void set_view_height(float);
diff --git a/source/materials/directionallight.cpp b/source/materials/directionallight.cpp
new file mode 100644 (file)
index 0000000..a306196
--- /dev/null
@@ -0,0 +1,81 @@
+#include "directionallight.h"
+#include "programdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+DirectionalLight::DirectionalLight():
+       transmittance(1.0f),
+       direction(0.0f, 0.0f, -1.0f)
+{ }
+
+void DirectionalLight::update_matrix()
+{
+       Vector3 up_dir;
+       if(20*abs(direction.z)>abs(direction.x)+abs(direction.y))
+               up_dir.y = 1;
+       else
+               up_dir.z = 1;
+       Vector3 right_dir = normalize(cross(direction, up_dir));
+
+       Vector4 columns[4];
+       columns[0] = compose(right_dir, 0.0f);
+       columns[1] = compose(cross(right_dir, direction), 0.0f);
+       columns[2] = compose(-direction, 0.0f);
+       columns[3] = Vector4(0.0f, 0.0f, 0.0f, 1.0f);
+       matrix = Matrix::from_columns(columns);
+}
+
+void DirectionalLight::set_matrix(const Matrix &m)
+{
+       Placeable::set_matrix(m);
+       direction = normalize(-matrix.column(2).slice<3>(0));
+       update_matrix();
+       ++generation;
+}
+
+void DirectionalLight::set_direction(const Vector3 &d)
+{
+       direction = normalize(d);
+       update_matrix();
+       ++generation;
+}
+
+void DirectionalLight::set_transmittance(const Color &t)
+{
+       transmittance = t;
+       ++generation;
+}
+
+void DirectionalLight::update_shader_data(ProgramData &shdata, const string &base) const
+{
+       shdata.uniform(base+".type", 1);
+       shdata.uniform(base+".position", -direction.x, -direction.y, -direction.z, 0.0f);
+       shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
+       shdata.uniform(base+".attenuation", 1.0f, 0.0f, 0.0f);
+}
+
+
+DataFile::Loader::ActionMap DirectionalLight::Loader::shared_actions;
+
+DirectionalLight::Loader::Loader(DirectionalLight &l):
+       DerivedObjectLoader<DirectionalLight, Light::Loader>(l)
+{
+       set_actions(shared_actions);
+}
+
+void DirectionalLight::Loader::init_actions()
+{
+       Light::Loader::init_actions();
+       add("direction", &Loader::direction);
+}
+
+void DirectionalLight::Loader::direction(float x, float y, float z)
+{
+       obj.set_direction(Vector3(x, y, z));
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/materials/directionallight.h b/source/materials/directionallight.h
new file mode 100644 (file)
index 0000000..8bde91c
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef MSP_GL_DIRECTIONALLIGHT_H_
+#define MSP_GL_DIRECTIONALLIGHT_H_
+
+#include "light.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+A light source which has uniform direction and strength everywhere.
+*/
+class DirectionalLight: public Light
+{
+public:
+       class Loader: public DataFile::DerivedObjectLoader<DirectionalLight, Light::Loader>
+       {
+       private:
+               static ActionMap shared_actions;
+
+       public:
+               Loader(DirectionalLight &);
+
+       private:
+               virtual void init_actions();
+
+               void direction(float, float, float);
+       };
+
+private:
+       Color transmittance;
+       Vector3 direction;
+
+public:
+       DirectionalLight();
+
+private:
+       void update_matrix();
+
+public:
+       /** Sets the light's direction from a matrix.  The negative Z axis is used
+       as the direction.  Other axes and translation are ignored. */
+       virtual void set_matrix(const Matrix &);
+
+       void set_direction(const Vector3 &);
+
+       const Vector3 &get_direction() const { return direction; }
+
+       /** Sets a multiplier on how much light actually reaches the target.  Used
+       when modeling an atmosphere. */
+       void set_transmittance(const Color &);
+
+protected:
+       virtual void update_shader_data(ProgramData &, const std::string &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 7c78b393fc32431b43904ed1dcdd14409446bb94..24bd8fa9c443483f581a8ed72b59a5df6e00445d 100644 (file)
@@ -1,7 +1,8 @@
 #include <stdexcept>
 #include <msp/strings/format.h>
+#include "directionallight.h"
 #include "light.h"
-#include "programdata.h"
+#include "pointlight.h"
 
 using namespace std;
 
@@ -9,35 +10,9 @@ namespace Msp {
 namespace GL {
 
 Light::Light():
-       color(1),
-       transmittance(1),
-       position(0, 0, 1, 0),
-       spot_dir(0, 0, -1),
-       spot_exp(0),
-       spot_cutoff(Geometry::Angle<float>::straight()),
+       color(1.0f),
        generation(0)
-{
-       attenuation[0] = 1;
-       attenuation[1] = 0;
-       attenuation[2] = 0;
-}
-
-void Light::update_matrix()
-{
-       Vector3 up_dir;
-       if(20*abs(direction.z)>abs(direction.x)+abs(direction.y))
-               up_dir.y = 1;
-       else
-               up_dir.z = 1;
-       Vector3 right_dir = normalize(cross(direction, up_dir));
-
-       Vector4 columns[4];
-       columns[0] = compose(right_dir, 0.0f);
-       columns[1] = compose(cross(right_dir, direction), 0.0f);
-       columns[2] = compose(-direction, 0.0f);
-       columns[3] = position;
-       matrix = Matrix::from_columns(columns);
-}
+{ }
 
 void Light::set_color(const Color &c)
 {
@@ -45,95 +20,32 @@ void Light::set_color(const Color &c)
        ++generation;
 }
 
-void Light::set_transmittance(const Color &t)
-{
-       transmittance = t;
-       ++generation;
-}
-
-void Light::set_matrix(const Matrix &m)
-{
-       Placeable::set_matrix(m);
-       position = matrix.column(3);
-       spot_dir = normalize(-matrix.column(2).slice<3>(0));
-       direction = (position.w ? spot_dir : normalize(-position.slice<3>(0)));
-       update_matrix();
-       ++generation;
-}
-
-void Light::set_position(const Vector4 &p)
-{
-       position = p;
-       if(!position.w)
-               direction = normalize(-position.slice<3>(0));
-       update_matrix();
-       ++generation;
-}
-
-void Light::set_spot_direction(const Vector3 &d)
-{
-       spot_dir = normalize(d);
-       if(position.w)
-               direction = spot_dir;
-       update_matrix();
-       ++generation;
-}
-
-void Light::set_spot_exponent(float e)
-{
-       if(e<0)
-               throw invalid_argument("Light::set_spot_exponent");
-
-       spot_exp = e;
-       ++generation;
-}
-
-void Light::set_spot_cutoff(const Geometry::Angle<float> &c)
-{
-       if(c<Geometry::Angle<float>::zero() || (c>Geometry::Angle<float>::right() && c!=Geometry::Angle<float>::straight()))
-               throw invalid_argument("Light::set_spot_cutoff");
-
-       spot_cutoff = c;
-       ++generation;
-}
-
-void Light::disable_spot_cutoff()
-{
-       set_spot_cutoff(Geometry::Angle<float>::straight());
-       ++generation;
-}
-
-void Light::set_attenuation(float c, float l, float q)
+void Light::update_shader_data(ProgramData &shdata, unsigned i) const
 {
-       attenuation[0] = c;
-       attenuation[1] = l;
-       attenuation[2] = q;
-       ++generation;
+       update_shader_data(shdata, format("light_sources[%d]", i));
 }
 
-void Light::update_shader_data(ProgramData &shdata, unsigned i) const
+Light::GenericLoader::TypeRegistry &Light::get_light_registry()
 {
-       string base = format("light_sources[%d]", i);
-       shdata.uniform(base+".position", position);
-       shdata.uniform(base+".color", color.r*transmittance.r, color.g*transmittance.g, color.b*transmittance.b);
-       shdata.uniform(base+".enabled", 1);
+       static GenericLoader::TypeRegistry registry;
+       static bool initialized = false;
+       if(!initialized)
+       {
+               initialized = true;
+               registry.register_type<DirectionalLight>("directional");
+               registry.register_type<PointLight>("point");
+       }
+       return registry;
 }
 
 
 Light::Loader::Loader(Light &l):
        DataFile::ObjectLoader<Light>(l)
-{
-       add("attenuation", &Loader::attenuation);
-       add("color", &Loader::color);
-       add("position", &Loader::position);
-       add("spot_direction", &Loader::spot_direction);
-       add("spot_exponent", &Loader::spot_exponent);
-       add("spot_cutoff", &Loader::spot_cutoff);
-}
+{ }
 
-void Light::Loader::attenuation(float c, float l, float q)
+void Light::Loader::init_actions()
 {
-       obj.set_attenuation(c, l, q);
+       add("color", &Loader::color);
 }
 
 void Light::Loader::color(float r, float g, float b)
@@ -141,25 +53,5 @@ void Light::Loader::color(float r, float g, float b)
        obj.set_color(Color(r, g, b));
 }
 
-void Light::Loader::position(float x, float y, float z, float w)
-{
-       obj.set_position(Vector4(x, y, z, w));
-}
-
-void Light::Loader::spot_direction(float x, float y, float z)
-{
-       obj.set_spot_direction(Vector3(x, y, z));
-}
-
-void Light::Loader::spot_exponent(float e)
-{
-       obj.set_spot_exponent(e);
-}
-
-void Light::Loader::spot_cutoff(float c)
-{
-       obj.set_spot_cutoff(Geometry::Angle<float>::from_degrees(c));
-}
-
 } // namespace GL
 } // namespace Msp
index 05a05aa90040a65bbf1017a070fdc9ab85cb75c0..606ec67325812d535d305c5756ca82bcfb439528 100644 (file)
@@ -1,11 +1,11 @@
 #ifndef MSP_GL_LIGHT_H_
 #define MSP_GL_LIGHT_H_
 
+#include <string>
+#include <msp/datafile/dynamicobjectloader.h>
 #include <msp/datafile/objectloader.h>
-#include <msp/geometry/angle.h>
 #include "color.h"
 #include "placeable.h"
-#include "vector.h"
 
 namespace Msp {
 namespace GL {
@@ -13,12 +13,8 @@ namespace GL {
 class ProgramData;
 
 /**
-Stores properties of a single light source.  Lights can be directional, point
-lights or spotlights.  No explicit type parameter is provided; rather the
-other parameters determine what kind of light it is.  If the fourth component
-of position is zero, it's a directional light.  Otherwise, if the spot cutoff
-is not 180 degrees, it's a spotlight.  Otherwise it's an omnidirectional point
-light.
+Base class for light sources.  The DirectionalLight and PointLight classes
+implement different types of lights.
 
 Lights are usually grouped with a Lighting object, which can be used in a
 Sequence::Step.
@@ -27,87 +23,53 @@ Lights do not cast shadows by themselves.  See ShadowMap for that.
 */
 class Light: public Placeable
 {
-public:
+protected:
        class Loader: public DataFile::ObjectLoader<Light>
        {
-       public:
+       protected:
                Loader(Light &);
 
+               virtual void init_actions();
+
        private:
-               void attenuation(float, float, float);
                void color(float, float, float);
-               void position(float, float, float, float);
-               void spot_direction(float, float, float);
-               void spot_exponent(float);
-               void spot_cutoff(float);
        };
 
-private:
+public:
+       class GenericLoader: public DataFile::DynamicObjectLoader<Light>
+       {
+               friend class Light;
+
+       public:
+               GenericLoader(Collection &c): DynamicObjectLoader<Light>(&c) { }
+
+       protected:
+               virtual const TypeRegistry &get_type_registry() const { return Light::get_light_registry(); }
+       };
+
+protected:
        Color color;
-       Color transmittance;
-       Vector4 position;
-       Vector3 spot_dir;
-       Vector3 direction;
-       float spot_exp;
-       Geometry::Angle<float> spot_cutoff;
-       float attenuation[3];
        unsigned generation;
 
 public:
        Light();
 
-private:
-       void update_matrix();
-
-public:
-       /** Sets the color of the Light.  Provided
-       to shaders as light_sources[i].color. */
+       /** Sets the color of the Light. */
        void set_color(const Color &);
 
-       /** Sets a multiplier on how much light actually reaches the target.  Used
-       when modeling an atmosphere. */
-       void set_transmittance(const Color &);
-
        const Color &get_color() const { return color; }
-       const Color &get_transmittance() const { return transmittance; }
-
-       /** Sets the postion and orientation of the Light from a matrix.  Negative Z
-       axis is used as the spot direction, other axes are ignored. */
-       virtual void set_matrix(const Matrix &);
-
-       /** Sets the position of the Light.  For a directional light, set the xyz
-       components to a vector pointing towards the light and the w component to 0. */
-       void set_position(const Vector4 &);
-
-       const Vector4 &get_position() const { return position; }
-
-       /** Sets the direction of a spotlight.  Has no effect if spotlight cutoff is
-       not set. */
-       void set_spot_direction(const Vector3 &);
-
-       /** Sets the angular falloff exponent of the spotlight.  Must be >= 0. */
-       void set_spot_exponent(float);
-
-       /** Sets the cutoff angle of a spotlight.  Beyond this angle from its axis
-       the spotlight provides no illumination.  Must be between 0 and 90 degrees,
-       or exactly 180 degrees to indicate a non-spotlight. */
-       void set_spot_cutoff(const Geometry::Angle<float> &);
-
-       /** Disables spotlight, reverting to an omnidirectional point light.
-       Equivalent to setting the spot cutoff to 180 degrees. */
-       void disable_spot_cutoff();
-
-       const Vector3 &get_spot_direction() const { return spot_dir; }
-       float get_spot_exponent() const { return spot_exp; }
-       const Geometry::Angle<float> &get_spot_cutoff() const { return spot_cutoff; }
-       void set_attenuation(float, float, float);
-       const float *get_attenuation() const { return attenuation; }
 
        unsigned get_generation() const { return generation; }
 
        /** Updates a ProgramData object with the uniforms for the Light.  A light
        source index must be passed in.  Primarily used by Lighting. */
        void update_shader_data(ProgramData &, unsigned) const;
+
+protected:
+       virtual void update_shader_data(ProgramData &, const std::string &) const = 0;
+
+private:
+       static GenericLoader::TypeRegistry &get_light_registry();
 };
 
 } // namespace GL
index c1b2e2aaf0a02619fb17f9a1e06f456bc27fdd1a..3057d20d77baaccd1e00804ad37521868ff5c342 100644 (file)
@@ -23,7 +23,7 @@ Lighting::Lighting()
                string base = format("light_sources[%d]", i);
                shdata.uniform(base+".position", Vector4(0, 0, 1, 0));
                shdata.uniform(base+".color", 0.0f, 0.0f, 0.0f);
-               shdata.uniform(base+".enabled", 0);
+               shdata.uniform(base+".type", 0);
        }
 }
 
@@ -142,8 +142,9 @@ void Lighting::Loader::light(const string &name)
 
 void Lighting::Loader::light_inline()
 {
-       RefPtr<Light> lgt = new Light;
-       load_sub(*lgt);
+       Light::GenericLoader ldr(get_collection());
+       load_sub_with(ldr);
+       RefPtr<Light> lgt = ldr.get_object();
        get_collection().add(format("%s/%d.light", FS::basename(get_source()), obj.lights.size()), lgt.get());
        obj.attach(*lgt.release());
 }
diff --git a/source/materials/pointlight.cpp b/source/materials/pointlight.cpp
new file mode 100644 (file)
index 0000000..4bbf413
--- /dev/null
@@ -0,0 +1,76 @@
+#include "pointlight.h"
+#include "programdata.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+PointLight::PointLight():
+       position(0.0f, 0.0f, 0.0f),
+       attenuation{1.0f, 0.0f, 0.1f}
+{ }
+
+void PointLight::update_matrix()
+{
+       matrix = Matrix::translation(position);
+}
+
+void PointLight::set_matrix(const Matrix &m)
+{
+       Placeable::set_matrix(m);
+       position = matrix.column(3).slice<3>(0);
+       update_matrix();
+       ++generation;
+}
+
+void PointLight::set_position(const Vector3 &p)
+{
+       position = p;
+       update_matrix();
+       ++generation;
+}
+
+void PointLight::set_attenuation(float c, float l, float q)
+{
+       attenuation[0] = c;
+       attenuation[1] = l;
+       attenuation[2] = q;
+       ++generation;
+}
+
+void PointLight::update_shader_data(ProgramData &shdata, const string &base) const
+{
+       shdata.uniform(base+".type", 2);
+       shdata.uniform(base+".position", position.x, position.y, position.z, 1.0f);
+       shdata.uniform(base+".color", color.r, color.g, color.b);
+}
+
+
+DataFile::Loader::ActionMap PointLight::Loader::shared_actions;
+
+PointLight::Loader::Loader(PointLight &l):
+       DerivedObjectLoader<PointLight, Light::Loader>(l)
+{
+       set_actions(shared_actions);
+}
+
+void PointLight::Loader::init_actions()
+{
+       Light::Loader::init_actions();
+       add("attenuation", &Loader::attenuation);
+       add("position", &Loader::position);
+}
+
+void PointLight::Loader::attenuation(float c, float l, float q)
+{
+       obj.set_attenuation(c, l, q);
+}
+
+void PointLight::Loader::position(float x, float y, float z)
+{
+       obj.set_position(Vector3(x, y, z));
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/materials/pointlight.h b/source/materials/pointlight.h
new file mode 100644 (file)
index 0000000..074c8c3
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef MSP_GL_POINTLIGHT_H_
+#define MSP_GL_POINTLIGHT_H_
+
+#include "light.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+/**
+A positional, omnidirectional light source.  The light's strength can be
+attenuated based on distance.
+*/
+class PointLight: public Light
+{
+public:
+       class Loader: public DataFile::DerivedObjectLoader<PointLight, Light::Loader>
+       {
+       private:
+               static ActionMap shared_actions;
+
+       public:
+               Loader(PointLight &);
+
+       private:
+               virtual void init_actions();
+
+               void attenuation(float, float, float);
+               void position(float, float, float);
+       };
+
+private:
+       Vector3 position;
+       float attenuation[3];
+
+public:
+       PointLight();
+
+private:
+       void update_matrix();
+
+public:
+       /** Sets the light's position from a matrix.  Only the translation part is
+       used. */
+       virtual void set_matrix(const Matrix &);
+
+       void set_position(const Vector3 &);
+       const Vector3 &get_position();
+
+       void set_attenuation(float, float, float);
+       const float *get_attenuation() const { return attenuation; }
+
+protected:
+       virtual void update_shader_data(ProgramData &, const std::string &) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
index 32f59d93d6e5a85f0bea998fd6bc446deb3fe88f..fa20a0bf2e38d5cc072908480ce0bf3a62008257 100644 (file)
@@ -4,10 +4,10 @@
 #include "armature.h"
 #include "basicmaterial.h"
 #include "camera.h"
+#include "directionallight.h"
 #include "error.h"
 #include "font.h"
 #include "keyframe.h"
-#include "light.h"
 #include "lighting.h"
 #include "mesh.h"
 #include "module.h"
@@ -16,6 +16,7 @@
 #include "orderedscene.h"
 #include "pbrmaterial.h"
 #include "sequencetemplate.h"
+#include "pointlight.h"
 #include "pose.h"
 #include "program.h"
 #include "resourcemanager.h"
@@ -52,9 +53,10 @@ Resources::Resources(bool set_as_global):
                .notify(&set_debug_name<Material>);
        add_type<Camera>().keyword("camera")
                .notify(&set_debug_name<Camera>);
+       add_type<DirectionalLight>().base<Light>().suffix(".light")
+               .creator([this](const string &n) -> DirectionalLight * { create_generic<Light>(n); return 0; });
        add_type<Font>().keyword("font");
        add_type<KeyFrame>().suffix(".kframe").keyword("keyframe");
-       add_type<Light>().keyword("light");
        add_type<Lighting>().suffix(".lightn").keyword("lighting")
                .notify(&set_debug_name<Lighting>);
        add_type<Mesh>().keyword("mesh")
@@ -70,6 +72,8 @@ Resources::Resources(bool set_as_global):
        add_type<PbrMaterial>().base<Material>().suffix(".mat")
                .creator([this](const string &n) -> PbrMaterial * { create_generic<Material>(n); return 0; })
                .notify(&set_debug_name<Material>);
+       add_type<PointLight>().base<Light>().suffix(".light")
+               .creator([this](const string &n) -> PointLight * { create_generic<Light>(n); return 0; });
        add_type<SequenceTemplate>().suffix(".seq").keyword("sequence");
        add_type<Pose>().keyword("pose");
        add_type<Program>().keyword("shader")
index b0e3420dab0395394f02ec0aa8525a8b04bff089..c54d7278c4cba0a23a4a935850a2eb25ead4d816 100644 (file)
@@ -11,8 +11,8 @@
 #include <msp/gl/animationplayer.h>
 #include <msp/gl/blend.h>
 #include <msp/gl/camera.h>
+#include <msp/gl/directionallight.h>
 #include <msp/gl/framebuffer.h>
-#include <msp/gl/light.h>
 #include <msp/gl/lighting.h>
 #include <msp/gl/mesh.h>
 #include <msp/gl/object.h>
@@ -71,7 +71,7 @@ private:
        GL::Renderable *renderable;
        GL::AnimatedObject *anim_object;
        GL::AnimationPlayer *anim_player;
-       GL::Light light;
+       GL::DirectionalLight light;
        GL::Lighting lighting;
        GL::Camera camera;
        float yaw;
@@ -226,7 +226,7 @@ Viewer::Viewer(int argc, char **argv):
        mouse.signal_button_release.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::button_release), false));
        mouse.signal_axis_motion.connect(sigc::bind_return(sigc::mem_fun(this, &Viewer::axis_motion), false));
 
-       light.set_position(GL::Vector4(0, 0, 1, 0));
+       light.set_direction(GL::Vector3(0, 0, -1));
        lighting.attach(light);
 
        camera.set_up_direction(GL::Vector3(0, 0, 1));
@@ -368,7 +368,7 @@ void Viewer::update_light()
        float sy = sin(light_yaw);
        float cp = cos(light_pitch);
        float sp = sin(light_pitch);
-       light.set_position(GL::Vector4(-cy*cp, -sy*cp, -sp, 0));
+       light.set_direction(GL::Vector3(cy*cp, sy*cp, sp));
 }