]> git.tdb.fi Git - libs/gl.git/blobdiff - source/material.h
Redesign the material system
[libs/gl.git] / source / material.h
index ead11618c2c9abdf8d82ca29b63d7e241bfd7beb..df55a56767c6318ad9f6f3effed314520604fcd7 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef MSP_GL_MATERIAL_H_
 #define MSP_GL_MATERIAL_H_
 
+#include <msp/datafile/collection.h>
+#include <msp/datafile/loadabletyperegistry.h>
 #include <msp/datafile/objectloader.h>
 #include "color.h"
 #include "programdata.h"
 namespace Msp {
 namespace GL {
 
-/**
-Stores basic material properties.  This includes color and reflection
-parameters, but does not include texturing.  Materials interact with light
-sources and ambient lighting to produce the base color of a surface.  Textures
-can be used to add detail.
+class Texture;
+class Texturing;
 
-Material provides a set of uniform variables for use with shaders.
-*/
 class Material
 {
+protected:
+       template<typename T>
+       struct Property
+       {
+               T value;
+               const Texture *texture;
+
+               Property(): value(T()), texture(0) { }
+       };
+
+       template<typename C>
+       class LoaderBase: public DataFile::CollectionObjectLoader<Material>
+       {
+       protected:
+               LoaderBase(C &m): CollectionObjectLoader<Material>(m, 0) { }
+               LoaderBase(C &m, Collection &c): CollectionObjectLoader<Material>(m, &c) { }
+
+               void add_property(const std::string &, void (C::*)(float), void (C::*)(const Texture *));
+               void add_property(const std::string &, void (C::*)(const Color &), void (C::*)(const Texture *), bool);
+               void add_property(const std::string &, void (C::*)(const Texture *));
+
+               void property_value_scalar(void (C::*)(float), float);
+               void property_value_rgb(void (C::*)(const Color &), float, float, float);
+               void property_value_rgba(void (C::*)(const Color &), float, float, float, float);
+               void property_value_srgb(void (C::*)(const Color &), float, float, float);
+               void property_value_srgb_alpha(void (C::*)(const Color &), float, float, float, float);
+               void property_texture(void (C::*)(const Texture *), const std::string &);
+       };
+
 public:
-       class Loader: public DataFile::CollectionObjectLoader<Material>
+       class GenericLoader: public DataFile::Loader
        {
        private:
-               bool srgb;
+               template<typename T>
+               struct AddType
+               {
+                       static void add(GenericLoader &ldr, const std::string &kw) { ldr.add(kw, &GenericLoader::typed_material<T>); }
+               };
+
+               DataFile::Collection *coll;
+               RefPtr<Material> material;
+
+               static ActionMap shared_actions;
 
        public:
-               Loader(Material &);
-               Loader(Material &, Collection &);
+               GenericLoader(DataFile::Collection * = 0);
+
+               Material *get_material() { return material.release(); }
        private:
-               void init();
-
-               Color make_color(float, float, float, float);
-               void ambient(float, float, float, float);
-               void diffuse(float, float, float, float);
-               void specular(float, float, float, float);
-               void emission(float, float, float, float);
-               void shininess(float);
-               void reflectivity(float);
+               virtual void init_actions();
+
+               template<typename T>
+               void typed_material();
+
+               friend class Material;
        };
 
 private:
-       Color ambient;
-       Color diffuse;
-       Color specular;
-       Color emission;
-       float shininess;
-       float reflectivity;
+       typedef DataFile::LoadableTypeRegistry<GenericLoader, GenericLoader::AddType> MaterialRegistry;
+
+protected:
        ProgramData shdata;
 
+       Material() { }
+public:
+       virtual ~Material() { }
+
+public:
+       /** Returns the uniforms for the material. */
+       const ProgramData &get_shader_data() const { return shdata; }
+
+protected:
+       void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const;
 public:
-       Material();
+       virtual void attach_textures_to(Texturing &, ProgramData &) const = 0;
+
+       template<typename T>
+       static void register_type(const std::string &);
+private:
+       static MaterialRegistry &get_material_registry();
+};
 
-       /** Sets the ambient color of the material.  Provided to shaders with the
-       name material.ambient. */
-       void set_ambient(const Color &);
+template<typename T>
+void Material::register_type(const std::string &kw)
+{
+       get_material_registry().register_type<T>(kw);
+}
 
-       /** Sets the diffuse (direction-independent) color of the material.
-       Provided to shaders with the name material.diffuse. */
-       void set_diffuse(const Color &);
 
-       /** Sets the specular (direction-dependent) color of the material.  Provided
-       to shaders with the name material.specular. */
-       void set_specular(const Color &);
-       void set_emission(const Color &);
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
+{
+       add(kw, &LoaderBase<C>::property_value_scalar, set_value);
+       add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
 
-       /** Sets the specular exponent of the material.  Provided to shaders with
-       the name material.shininess. */
-       void set_shininess(float);
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_value)(const Color &), void (C::*set_texture)(const Texture *), bool allow_alpha)
+{
+       add(kw, &LoaderBase<C>::property_value_rgb, set_value);
+       add(kw+"_srgb", &LoaderBase<C>::property_value_srgb, set_value);
+       if(allow_alpha)
+       {
+               add(kw, &LoaderBase<C>::property_value_rgba, set_value);
+               add(kw+"_srgb", &LoaderBase<C>::property_value_srgb_alpha, set_value);
+       }
+       add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
+
+template<typename C>
+void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_texture)(const Texture *))
+{
+       add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
+}
 
-       /** Sets the reflectivity of the material.  Provided to shaders with the
-       name reflectivity.  Has no effect when shaders are not used. */
-       void set_reflectivity(float);
+template<typename C>
+void Material::LoaderBase<C>::property_value_scalar(void (C::*set_value)(float), float value)
+{
+       (static_cast<C &>(obj).*set_value)(value);
+}
 
-       const Color &get_ambient() const { return ambient; }
-       const Color &get_diffuse() const { return diffuse; }
-       const Color &get_specular() const { return specular; }
-       const Color &get_emission() const { return emission; }
-       float get_shininess() const { return shininess; }
-       float get_reflectivity() const { return reflectivity; }
+template<typename C>
+void Material::LoaderBase<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
+{
+       (static_cast<C &>(obj).*set_value)(Color(r, g, b));
+}
 
-       /** Returns the uniforms for the material. */
-       const ProgramData &get_shader_data() const { return shdata; }
-};
+template<typename C>
+void Material::LoaderBase<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
+{
+       (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
+{
+       (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
+{
+       (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
+}
+
+template<typename C>
+void Material::LoaderBase<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
+{
+       (static_cast<C &>(obj).*set_texture)(&get_collection().get<GL::Texture>(name));
+}
+
+
+template<typename T>
+void Material::GenericLoader::typed_material()
+{
+       if(material)
+               throw std::logic_error("Material was already loaded");
+       RefPtr<T> mat = new T;
+       if(coll)
+               load_sub(*mat, *coll);
+       else
+               load_sub(*mat);
+       material = mat;
+}
 
 } // namespace GL
 } // namespace Msp