]> git.tdb.fi Git - libs/gl.git/blob - source/material.h
Redesign the material system
[libs/gl.git] / source / material.h
1 #ifndef MSP_GL_MATERIAL_H_
2 #define MSP_GL_MATERIAL_H_
3
4 #include <msp/datafile/collection.h>
5 #include <msp/datafile/loadabletyperegistry.h>
6 #include <msp/datafile/objectloader.h>
7 #include "color.h"
8 #include "programdata.h"
9
10 namespace Msp {
11 namespace GL {
12
13 class Texture;
14 class Texturing;
15
16 class Material
17 {
18 protected:
19         template<typename T>
20         struct Property
21         {
22                 T value;
23                 const Texture *texture;
24
25                 Property(): value(T()), texture(0) { }
26         };
27
28         template<typename C>
29         class LoaderBase: public DataFile::CollectionObjectLoader<Material>
30         {
31         protected:
32                 LoaderBase(C &m): CollectionObjectLoader<Material>(m, 0) { }
33                 LoaderBase(C &m, Collection &c): CollectionObjectLoader<Material>(m, &c) { }
34
35                 void add_property(const std::string &, void (C::*)(float), void (C::*)(const Texture *));
36                 void add_property(const std::string &, void (C::*)(const Color &), void (C::*)(const Texture *), bool);
37                 void add_property(const std::string &, void (C::*)(const Texture *));
38
39                 void property_value_scalar(void (C::*)(float), float);
40                 void property_value_rgb(void (C::*)(const Color &), float, float, float);
41                 void property_value_rgba(void (C::*)(const Color &), float, float, float, float);
42                 void property_value_srgb(void (C::*)(const Color &), float, float, float);
43                 void property_value_srgb_alpha(void (C::*)(const Color &), float, float, float, float);
44                 void property_texture(void (C::*)(const Texture *), const std::string &);
45         };
46
47 public:
48         class GenericLoader: public DataFile::Loader
49         {
50         private:
51                 template<typename T>
52                 struct AddType
53                 {
54                         static void add(GenericLoader &ldr, const std::string &kw) { ldr.add(kw, &GenericLoader::typed_material<T>); }
55                 };
56
57                 DataFile::Collection *coll;
58                 RefPtr<Material> material;
59
60                 static ActionMap shared_actions;
61
62         public:
63                 GenericLoader(DataFile::Collection * = 0);
64
65                 Material *get_material() { return material.release(); }
66         private:
67                 virtual void init_actions();
68
69                 template<typename T>
70                 void typed_material();
71
72                 friend class Material;
73         };
74
75 private:
76         typedef DataFile::LoadableTypeRegistry<GenericLoader, GenericLoader::AddType> MaterialRegistry;
77
78 protected:
79         ProgramData shdata;
80
81         Material() { }
82 public:
83         virtual ~Material() { }
84
85 public:
86         /** Returns the uniforms for the material. */
87         const ProgramData &get_shader_data() const { return shdata; }
88
89 protected:
90         void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const;
91 public:
92         virtual void attach_textures_to(Texturing &, ProgramData &) const = 0;
93
94         template<typename T>
95         static void register_type(const std::string &);
96 private:
97         static MaterialRegistry &get_material_registry();
98 };
99
100 template<typename T>
101 void Material::register_type(const std::string &kw)
102 {
103         get_material_registry().register_type<T>(kw);
104 }
105
106
107 template<typename C>
108 void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
109 {
110         add(kw, &LoaderBase<C>::property_value_scalar, set_value);
111         add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
112 }
113
114 template<typename C>
115 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)
116 {
117         add(kw, &LoaderBase<C>::property_value_rgb, set_value);
118         add(kw+"_srgb", &LoaderBase<C>::property_value_srgb, set_value);
119         if(allow_alpha)
120         {
121                 add(kw, &LoaderBase<C>::property_value_rgba, set_value);
122                 add(kw+"_srgb", &LoaderBase<C>::property_value_srgb_alpha, set_value);
123         }
124         add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
125 }
126
127 template<typename C>
128 void Material::LoaderBase<C>::add_property(const std::string &kw, void (C::*set_texture)(const Texture *))
129 {
130         add(kw+"_map", &LoaderBase<C>::property_texture, set_texture);
131 }
132
133 template<typename C>
134 void Material::LoaderBase<C>::property_value_scalar(void (C::*set_value)(float), float value)
135 {
136         (static_cast<C &>(obj).*set_value)(value);
137 }
138
139 template<typename C>
140 void Material::LoaderBase<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
141 {
142         (static_cast<C &>(obj).*set_value)(Color(r, g, b));
143 }
144
145 template<typename C>
146 void Material::LoaderBase<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
147 {
148         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
149 }
150
151 template<typename C>
152 void Material::LoaderBase<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
153 {
154         (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
155 }
156
157 template<typename C>
158 void Material::LoaderBase<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
159 {
160         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
161 }
162
163 template<typename C>
164 void Material::LoaderBase<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
165 {
166         (static_cast<C &>(obj).*set_texture)(&get_collection().get<GL::Texture>(name));
167 }
168
169
170 template<typename T>
171 void Material::GenericLoader::typed_material()
172 {
173         if(material)
174                 throw std::logic_error("Material was already loaded");
175         RefPtr<T> mat = new T;
176         if(coll)
177                 load_sub(*mat, *coll);
178         else
179                 load_sub(*mat);
180         material = mat;
181 }
182
183 } // namespace GL
184 } // namespace Msp
185
186 #endif