]> git.tdb.fi Git - libs/gl.git/commitdiff
Support effects and subordinate sequences inside sequence templates
authorMikko Rasa <tdb@tdb.fi>
Tue, 19 Oct 2021 13:02:57 +0000 (16:02 +0300)
committerMikko Rasa <tdb@tdb.fi>
Tue, 19 Oct 2021 13:02:57 +0000 (16:02 +0300)
source/builders/sequencebuilder.cpp
source/builders/sequencetemplate.cpp
source/builders/sequencetemplate.h
source/effects/effect.cpp
source/effects/effect.h
source/effects/environmentmap.cpp
source/effects/environmentmap.h
source/effects/shadowmap.cpp
source/effects/shadowmap.h
source/effects/sky.cpp
source/effects/sky.h

index f007350eeaa0e76ad023055f59d133bd407e368a..dbb675acf2a7925a3ddf1e4b6b3969f04faaf8be 100644 (file)
@@ -49,6 +49,48 @@ void SequenceBuilder::build(Sequence &sequence) const
                sequence.set_debug_name(debug_name);
 #endif
 
+       map<string, Renderable *> final_renderables = renderables;
+       vector<const SequenceTemplate::Renderable *> sequences;
+       for(const SequenceTemplate::Renderable &r: tmpl.get_renderables())
+       {
+               Renderable *&ptr = final_renderables[r.slot_name];
+               if(!ptr)
+               {
+                       if(r.effect_template)
+                       {
+                               Effect *effect = r.effect_template->create(final_renderables);
+#ifdef DEBUG
+                               if(!debug_name.empty())
+                                       effect->set_debug_name(format("%s/%s", debug_name, r.slot_name));
+#endif
+                               ptr = effect;
+                       }
+                       else if(r.sequence_template)
+                       {
+                               Sequence *seq = new Sequence;
+#ifdef DEBUG
+                               if(!debug_name.empty())
+                                       seq->set_debug_name(format("%s/%s", debug_name, r.slot_name));
+#endif
+                               ptr = seq;
+                               sequences.push_back(&r);
+                       }
+                       else
+                               throw invalid_operation("SequenceBuilder::build");
+
+                       sequence.add_owned(ptr);
+               }
+       }
+
+       for(const SequenceTemplate::Renderable *s: sequences)
+       {
+               SequenceBuilder bld(*s->sequence_template);
+               for(const auto &kvp: s->sequence_renderables)
+                       if(Renderable *r = get_item(final_renderables, kvp.second))
+                               bld.set_renderable(kvp.first, *r);
+               bld.build(*static_cast<Sequence *>(get_item(final_renderables, s->slot_name)));
+       }
+
        sequence.set_clear_enabled(tmpl.is_clear_enabled());
        if(tmpl.is_clear_enabled())
        {
@@ -59,11 +101,9 @@ void SequenceBuilder::build(Sequence &sequence) const
 
        for(const SequenceTemplate::Step &s: tmpl.get_steps())
        {
-               Renderable *renderable = get_item(renderables, s.renderable_name);
-               if(!renderable)
-                       throw missing_renderable(s.renderable_name);
-
-               Sequence::Step &step = sequence.add_step(s.tag, *renderable);
+               // Existence is already ensured above
+               Renderable &renderable = *get_item(final_renderables, s.renderable_name);
+               Sequence::Step &step = sequence.add_step(s.tag, renderable);
                step.set_depth_test(s.depth_test);
                step.set_stencil_test(s.stencil_test);
                step.set_lighting(s.lighting);
index 03c8c7fe1cafa0b26f3fc20e37080e94c8fafe0a..999d2ae7693baaeea5e0c37229dd54d5b84f5a75 100644 (file)
@@ -5,11 +5,14 @@
 #include "blend.h"
 #include "bloom.h"
 #include "colorcurve.h"
+#include "environmentmap.h"
 #include "lighting.h"
 #include "object.h"
 #include "resources.h"
 #include "scene.h"
 #include "sequencetemplate.h"
+#include "shadowmap.h"
+#include "sky.h"
 
 using namespace std;
 
@@ -18,6 +21,8 @@ namespace GL {
 
 SequenceTemplate::~SequenceTemplate()
 {
+       for(const Renderable &r: renderables)
+               delete r.effect_template;
        for(const PostProcessor &p: postprocessors)
                delete p.postprocessor_template;
 }
@@ -37,6 +42,21 @@ SequenceTemplate::TemplateRegistry<GL::PostProcessor> &SequenceTemplate::get_reg
        return registry;
 }
 
+template<>
+SequenceTemplate::TemplateRegistry<Effect> &SequenceTemplate::get_registry<Effect>()
+{
+       static TemplateRegistry<Effect> registry;
+       static bool initialized = false;
+       if(!initialized)
+       {
+               registry.register_type<EnvironmentMap::Template>("environment_map");
+               registry.register_type<ShadowMap::Template>("shadow_map");
+               registry.register_type<Sky::Template>("sky");
+               initialized = true;
+       }
+       return registry;
+}
+
 
 SequenceTemplate::PostProcessor::PostProcessor(GL::PostProcessor::Template *ppt):
        postprocessor_template(ppt)
@@ -56,12 +76,14 @@ void SequenceTemplate::Loader::init_actions()
        add("hdr", &SequenceTemplate::hdr);
        add("alpha", &SequenceTemplate::alpha);
        add("clear", &Loader::clear);
+       add("effect", &Loader::effect);
        add("multisample", &Loader::multisample);
        add("multisample", &Loader::multisample_range);
        add("postprocessor", &Loader::postprocessor);
        add("postprocessor", &Loader::postprocessor_with_slot);
        add("renderable", &Loader::renderable);
        add("renderable", &Loader::renderable_with_default);
+       add("sequence", &Loader::sequence);
        add("step", &Loader::step);
 }
 
@@ -72,6 +94,16 @@ void SequenceTemplate::Loader::clear()
        obj.clear_enabled = true;
 }
 
+void SequenceTemplate::Loader::effect(const string &slot)
+{
+       TemplateLoader<Effect> ldr(get_collection());
+       load_sub_with(ldr);
+       Renderable rend;
+       rend.slot_name = slot;
+       rend.effect_template = ldr.get_object();
+       obj.renderables.push_back(rend);
+}
+
 void SequenceTemplate::Loader::multisample(unsigned samples)
 {
        obj.required_multisample = samples;
@@ -114,6 +146,16 @@ void SequenceTemplate::Loader::renderable_with_default(const string &slot, const
        obj.renderables.push_back(rend);
 }
 
+void SequenceTemplate::Loader::sequence(const string &slot, const string &name)
+{
+       Renderable rend;
+       rend.sequence_template = &get_collection().get<SequenceTemplate>(name);
+       rend.slot_name = slot;
+       SequenceLoader ldr(rend);
+       load_sub_with(ldr);
+       obj.renderables.push_back(rend);
+}
+
 void SequenceTemplate::Loader::step(const string &tag, const string &rend)
 {
        Step stp;
@@ -158,6 +200,25 @@ void SequenceTemplate::ClearLoader::stencil(int s)
 }
 
 
+DataFile::Loader::ActionMap SequenceTemplate::SequenceLoader::shared_actions;
+
+SequenceTemplate::SequenceLoader::SequenceLoader(Renderable &r):
+       ObjectLoader<Renderable>(r)
+{
+       set_actions(shared_actions);
+}
+
+void SequenceTemplate::SequenceLoader::init_actions()
+{
+       add("renderable", &SequenceLoader::renderable);
+}
+
+void SequenceTemplate::SequenceLoader::renderable(const string &slot, const string &name)
+{
+       obj.sequence_renderables[slot] = name;
+}
+
+
 DataFile::Loader::ActionMap SequenceTemplate::Step::Loader::shared_actions;
 
 SequenceTemplate::Step::Loader::Loader(Step &p, Collection &c):
index 3f4b86b956d3499ee1020a96595cbf78818db106..5c13aebebc2263677447e93e33ab96de25883cf0 100644 (file)
@@ -7,6 +7,7 @@
 #include <msp/datafile/dynamicobjectloader.h>
 #include <msp/datafile/objectloader.h>
 #include "depthtest.h"
+#include "effect.h"
 #include "postprocessor.h"
 #include "resources.h"
 #include "stenciltest.h"
@@ -47,18 +48,23 @@ public:
                virtual void init_actions();
 
                void clear();
+               void effect(const std::string &);
                void multisample(unsigned);
                void multisample_range(unsigned, unsigned);
                void postprocessor();
                void postprocessor_with_slot(const std::string &);
                void renderable(const std::string &);
                void renderable_with_default(const std::string &, const std::string &);
+               void sequence(const std::string &, const std::string &);
                void step(const std::string &, const std::string &);
        };
 
        struct Renderable
        {
+               Effect::Template *effect_template = 0;
                GL::Renderable *renderable = 0;
+               SequenceTemplate *sequence_template = 0;
+               std::map<std::string, std::string> sequence_renderables;
                std::string slot_name;
        };
 
@@ -118,6 +124,19 @@ private:
                void stencil(int);
        };
 
+       class SequenceLoader: public DataFile::ObjectLoader<Renderable>
+       {
+       private:
+               static ActionMap shared_actions;
+
+       public:
+               SequenceLoader(Renderable &);
+       private:
+               virtual void init_actions();
+
+               void renderable(const std::string &, const std::string &);
+       };
+
        bool hdr = false;
        bool alpha = false;
        unsigned required_multisample = 0;
@@ -145,6 +164,9 @@ public:
        float get_clear_depth() const { return clear_depth; }
        int get_clear_stencil() const { return clear_stencil; }
 
+       template<typename T>
+       static void register_effect(const std::string &);
+
        template<typename T>
        static void register_postprocessor(const std::string &);
 
@@ -153,6 +175,12 @@ private:
        static TemplateRegistry<T> &get_registry();
 };
 
+template<typename T>
+void SequenceTemplate::register_effect(const std::string &kw)
+{
+       get_registry<Effect>().register_type<typename T::Template>(kw);
+}
+
 template<typename T>
 void SequenceTemplate::register_postprocessor(const std::string &kw)
 {
index 4ab867ff23f538a0a52fbb08e4dbe0dc750691be..05ef5a10f1c2acee31f801053ffe94fc50259d5a 100644 (file)
@@ -19,5 +19,15 @@ void Effect::disable_for_method(Tag tag)
        enabled_methods.erase(tag);
 }
 
+
+Effect::Template::Loader::Loader(Template &t, Collection &c):
+       CollectionObjectLoader<Template>(t, &c)
+{ }
+
+void Effect::Template::Loader::init_actions()
+{
+       add("content", &Template::content_name);
+}
+
 } // namespace GL
 } // namespace Msp
index 9bf49c22b812a585200a0c28890932dcadadf093..eadb4dc845984a3d8e04d83e93d6a819df81bdf0 100644 (file)
@@ -2,6 +2,7 @@
 #define MSP_GL_EFFECT_H_
 
 #include <set>
+#include <msp/datafile/objectloader.h>
 #include "renderable.h"
 
 namespace Msp {
@@ -14,6 +15,24 @@ the wrapped Renderable's render method, and clean up after itself.
 */
 class Effect: public Renderable
 {
+public:
+       struct Template
+       {
+               class Loader: public DataFile::CollectionObjectLoader<Template>
+               {
+               public:
+                       Loader(Template &, Collection &);
+               protected:
+                       virtual void init_actions();
+               };
+
+               std::string content_name;
+
+               virtual ~Template() = default;
+
+               virtual Effect *create(const std::map<std::string, Renderable *> &) const = 0;
+       };
+
 protected:
        Renderable &renderable;
        std::set<Tag> enabled_methods;
index 782a3d2ab0845b4815520852de8436b8b86c0fb5..419f402b8d22287c89bfb89549190ed6a5ae8b07 100644 (file)
@@ -2,6 +2,7 @@
 #include <cmath>
 #include <msp/strings/format.h>
 #include "environmentmap.h"
+#include "error.h"
 #include "mesh.h"
 #include "renderer.h"
 #include "resources.h"
@@ -199,5 +200,47 @@ void EnvironmentMap::set_debug_name(const string &name)
 #endif
 }
 
+
+EnvironmentMap *EnvironmentMap::Template::create(const map<string, Renderable *> &renderables) const
+{
+       Renderable *content = get_item(renderables, content_name);
+       Renderable *environment = get_item(renderables, environment_name);
+       if(!content || !environment)
+               throw invalid_operation("EnvironmentMap::Template::create");
+
+       RefPtr<EnvironmentMap> env_map = new EnvironmentMap(size, format, roughness_levels, *content, *environment);
+       if(use_fixed_position)
+               env_map->set_fixed_position(fixed_position);
+       env_map->set_depth_clip(near_clip, far_clip);
+
+       return env_map.release();
+}
+
+
+DataFile::Loader::ActionMap EnvironmentMap::Template::Loader::shared_actions;
+
+EnvironmentMap::Template::Loader::Loader(Template &t, Collection &c):
+       DerivedObjectLoader<Template, Effect::Template::Loader>(t, c)
+{
+       set_actions(shared_actions);
+}
+
+void EnvironmentMap::Template::Loader::init_actions()
+{
+       Effect::Template::Loader::init_actions();
+       add("depth_clip", &Template::near_clip, &Template::far_clip);
+       add("environment", &Template::environment_name);
+       add("fixed_position", &Loader::fixed_position);
+       add("format", &Template::format);
+       add("roughness_levels", &Template::roughness_levels);
+       add("size", &Template::size);
+}
+
+void EnvironmentMap::Template::Loader::fixed_position(float x, float y, float z)
+{
+       obj.fixed_position = Vector3(x, y, z);
+       obj.use_fixed_position = true;
+}
+
 } // namespace GL
 } // namespace Msp
index f9f4cf5306e3af142be170b3714ad84c91800e8e..0c80012501baab724ae5845aab1b786363c32996 100644 (file)
@@ -26,7 +26,35 @@ environment.
 */
 class EnvironmentMap: public Effect
 {
-private:
+public:
+       struct Template: Effect::Template
+       {
+               class Loader: public DataFile::DerivedObjectLoader<Template, Effect::Template::Loader>
+               {
+               private:
+                       static ActionMap shared_actions;
+
+               public:
+                       Loader(Template &, Collection &);
+               private:
+                       virtual void init_actions();
+
+                       void fixed_position(float, float, float);
+               };
+
+               unsigned size = 512;
+               PixelFormat format = RGB16F;
+               std::string environment_name;
+               unsigned roughness_levels = 5;
+               Vector3 fixed_position;
+               bool use_fixed_position = false;
+               float near_clip = 0.1f;
+               float far_clip = 100.0f;
+
+               virtual EnvironmentMap *create(const std::map<std::string, Renderable *> &) const;
+       };
+
+protected:
        struct Face
        {
                Framebuffer fbo;
index 6c49f79fc9a70ba1fc97be427197a6054b24651b..27b695443341c860337242d5c2908d0479b502d7 100644 (file)
@@ -273,5 +273,89 @@ void ShadowMap::set_debug_name(const string &name)
 #endif
 }
 
+
+ShadowMap *ShadowMap::Template::create(const map<string, Renderable *> &renderables) const
+{
+       Renderable *content = get_item(renderables, content_name);
+       if(!content || !lighting)
+               throw invalid_operation("ShadowMap::Template::create");
+
+       RefPtr<ShadowMap> shadow_map = new ShadowMap(width, height, *content, *lighting);
+       shadow_map->set_target(target, radius);
+       shadow_map->set_depth_bias(depth_bias);
+       shadow_map->set_darkness(darkness);
+
+       for(const ShadowedLight &l: lights)
+       {
+               Renderable *shadow_caster = get_item(renderables, l.shadow_caster_name);
+               if(!l.light || !shadow_caster)
+                       throw invalid_operation("ShadowMap::Template::create");
+               if(const DirectionalLight *dir_light = dynamic_cast<const DirectionalLight *>(l.light))
+                       shadow_map->add_light(*dir_light, l.size, *shadow_caster);
+               else if(const PointLight *point_light = dynamic_cast<const PointLight *>(l.light))
+                       shadow_map->add_light(*point_light, l.size, *shadow_caster);
+               else
+                       throw invalid_operation("ShadowMap::Template::create");
+       }
+
+       return shadow_map.release();
+}
+
+
+DataFile::Loader::ActionMap ShadowMap::Template::Loader::shared_actions;
+
+ShadowMap::Template::Loader::Loader(Template &t, Collection &c):
+       DerivedObjectLoader<Template, Effect::Template::Loader>(t, c)
+{
+       set_actions(shared_actions);
+}
+
+void ShadowMap::Template::Loader::init_actions()
+{
+       Effect::Template::Loader::init_actions();
+       add("darkness", &Template::darkness);
+       add("depth_bias", &Template::depth_bias);
+       add("light", &Loader::light);
+       add("lighting", &Template::lighting);
+       add("radius", &Template::radius);
+       add("size", &Loader::size_square);
+       add("size", &Template::width, &Template::height);
+       add("target", &Loader::target);
+}
+
+void ShadowMap::Template::Loader::light(const string &name)
+{
+       ShadowedLight light;
+       light.light = &get_collection().get<Light>(name);
+       load_sub(light);
+       obj.lights.push_back(light);
+}
+
+void ShadowMap::Template::Loader::size_square(unsigned s)
+{
+       obj.width = s;
+       obj.height = s;
+}
+
+void ShadowMap::Template::Loader::target(float x, float y, float z)
+{
+       obj.target = Vector3(x, y, z);
+}
+
+
+DataFile::Loader::ActionMap ShadowMap::Template::ShadowedLight::Loader::shared_actions;
+
+ShadowMap::Template::ShadowedLight::Loader::Loader(ShadowedLight &l):
+       ObjectLoader<ShadowedLight>(l)
+{
+       set_actions(shared_actions);
+}
+
+void ShadowMap::Template::ShadowedLight::Loader::init_actions()
+{
+       add("size", &ShadowedLight::size);
+       add("shadow_caster", &ShadowedLight::shadow_caster_name);
+}
+
 } // namespace GL
 } // namespace Msp
index 0acb1b64657bc2cc0c5d0837717883fb0bd1b77f..502480122fc68354e45c85adec5b8a3d22c328de 100644 (file)
@@ -24,6 +24,54 @@ texture coordinate generation to determine whether each fragment is lit.
 */
 class ShadowMap: public Effect
 {
+public:
+       struct Template: Effect::Template
+       {
+               class Loader: public DataFile::DerivedObjectLoader<Template, Effect::Template::Loader>
+               {
+               private:
+                       static ActionMap shared_actions;
+
+               public:
+                       Loader(Template &, Collection &);
+               private:
+                       virtual void init_actions();
+
+                       void light(const std::string &);
+                       void size_square(unsigned);
+                       void target(float, float, float);
+               };
+
+               struct ShadowedLight
+               {
+                       class Loader: public DataFile::ObjectLoader<ShadowedLight>
+                       {
+                       private:
+                               static ActionMap shared_actions;
+
+                       public:
+                               Loader(ShadowedLight &);
+                       private:
+                               virtual void init_actions();
+                       };
+
+                       const Light *light = 0;
+                       unsigned size;
+                       std::string shadow_caster_name;
+               };
+
+               unsigned width = 2048;
+               unsigned height = 2048;
+               const Lighting *lighting = 0;
+               std::vector<ShadowedLight> lights;
+               Vector3 target;
+               float radius = 1.0f;
+               float depth_bias = 4.0f;
+               float darkness = 1.0f;
+
+               virtual ShadowMap *create(const std::map<std::string, Renderable *> &) const;
+       };
+
 private:
        enum ShadowType
        {
index 855509d15a3c1affb3dcc61dd41986f4decd3ae4..ab322f230e34365e6363c3ea9c867b2be251d79c 100644 (file)
@@ -1,6 +1,7 @@
 #include <msp/geometry/hypersphere.h>
 #include <msp/geometry/ray.h>
 #include "directionallight.h"
+#include "error.h"
 #include "mesh.h"
 #include "renderer.h"
 #include "resources.h"
@@ -183,5 +184,29 @@ Sky::Planet Sky::Planet::earth()
        return planet;
 }
 
+
+Sky *Sky::Template::create(const map<string, Renderable *> &renderables) const
+{
+       Renderable *content = get_item(renderables, content_name);
+       if(!content || !sun)
+               throw invalid_operation("Sky::Template::create");
+       return new Sky(*content, *sun);
+}
+
+
+DataFile::Loader::ActionMap Sky::Template::Loader::shared_actions;
+
+Sky::Template::Loader::Loader(Template &t, Collection &c):
+       DerivedObjectLoader<Template, Effect::Template::Loader>(t, c)
+{
+       set_actions(shared_actions);
+}
+
+void Sky::Template::Loader::init_actions()
+{
+       Effect::Template::Loader::init_actions();
+       add("sun", &Template::sun);
+}
+
 } // namespace GL
 } // namespace Msp
index 782aef1ceb1d0b0faa2c5e58a6407118834b0457..0152729a0ec8cf8dbb5ba88c5fc529ad5fd895c2 100644 (file)
@@ -39,6 +39,24 @@ public:
                static Planet earth();
        };
 
+       struct Template: Effect::Template
+       {
+               class Loader: public DataFile::DerivedObjectLoader<Template, Effect::Template::Loader>
+               {
+               private:
+                       static ActionMap shared_actions;
+
+               public:
+                       Loader(Template &, Collection &);
+               private:
+                       virtual void init_actions();
+               };
+
+               DirectionalLight *sun = 0;
+
+               virtual Sky *create(const std::map<std::string, Renderable *> &) const;
+       };
+
 private:
        Planet planet;
        DirectionalLight &sun;