]> git.tdb.fi Git - libs/gl.git/blob - source/material.h
Rename Material::LoaderBase to PropertyLoader
[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 #include "texture.h"
10
11 namespace Msp {
12 namespace GL {
13
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 PropertyLoader: public DataFile::CollectionObjectLoader<Material>
30         {
31         protected:
32                 PropertyLoader(C &m): CollectionObjectLoader<Material, Loader>(m, 0) { }
33                 PropertyLoader(C &m, Collection &c): CollectionObjectLoader<Material, Loader>(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         virtual Program *create_compatible_shader() const;
86         virtual const Program *create_compatible_shader(DataFile::Collection &) const;
87 protected:
88         virtual std::string create_program_source() const = 0;
89
90 public:
91         /** Returns the uniforms for the material. */
92         const ProgramData &get_shader_data() const { return shdata; }
93
94 protected:
95         void attach_texture_to(const Texture *, Texturing &, ProgramData &, const std::string &) const;
96 public:
97         virtual void attach_textures_to(Texturing &, ProgramData &) const = 0;
98
99         template<typename T>
100         static void register_type(const std::string &);
101 private:
102         static MaterialRegistry &get_material_registry();
103 };
104
105 template<typename T>
106 void Material::register_type(const std::string &kw)
107 {
108         get_material_registry().register_type<T>(kw);
109 }
110
111
112 template<typename C>
113 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
114 {
115         add(kw, &PropertyLoader<C>::property_value_scalar, set_value);
116         add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
117 }
118
119 template<typename C>
120 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_value)(const Color &), void (C::*set_texture)(const Texture *), bool allow_alpha)
121 {
122         add(kw, &PropertyLoader<C>::property_value_rgb, set_value);
123         add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb, set_value);
124         if(allow_alpha)
125         {
126                 add(kw, &PropertyLoader<C>::property_value_rgba, set_value);
127                 add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb_alpha, set_value);
128         }
129         add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
130 }
131
132 template<typename C>
133 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_texture)(const Texture *))
134 {
135         add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
136 }
137
138 template<typename C>
139 void Material::PropertyLoader<C>::property_value_scalar(void (C::*set_value)(float), float value)
140 {
141         (static_cast<C &>(obj).*set_value)(value);
142 }
143
144 template<typename C>
145 void Material::PropertyLoader<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
146 {
147         (static_cast<C &>(obj).*set_value)(Color(r, g, b));
148 }
149
150 template<typename C>
151 void Material::PropertyLoader<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
152 {
153         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
154 }
155
156 template<typename C>
157 void Material::PropertyLoader<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
158 {
159         (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
160 }
161
162 template<typename C>
163 void Material::PropertyLoader<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
164 {
165         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
166 }
167
168 template<typename C>
169 void Material::PropertyLoader<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
170 {
171         /* The static_cast around get_collection is needed because otherwise Android
172         SDK's g++ 4.9 fails to parse get<Texture> as a template function call */
173         (static_cast<C &>(obj).*set_texture)(&static_cast<Collection &>(get_collection()).get<Texture>(name));
174 }
175
176
177 template<typename T>
178 void Material::GenericLoader::typed_material()
179 {
180         if(material)
181                 throw std::logic_error("Material was already loaded");
182         RefPtr<T> mat = new T;
183         if(coll)
184                 load_sub(*mat, *coll);
185         else
186                 load_sub(*mat);
187         material = mat;
188 }
189
190 } // namespace GL
191 } // namespace Msp
192
193 #endif