]> git.tdb.fi Git - libs/gl.git/blob - source/materials/material.h
4f8e23ccc972001c892bb6e37a65f9448e3f1c9d
[libs/gl.git] / source / materials / material.h
1 #ifndef MSP_GL_MATERIAL_H_
2 #define MSP_GL_MATERIAL_H_
3
4 #include <msp/core/typeregistry.h>
5 #include <msp/datafile/collection.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 Sampler;
15
16 class Material
17 {
18 private:
19         class Loader: public DataFile::CollectionObjectLoader<Material>
20         {
21         protected:
22                 Loader(Material &);
23                 Loader(Material &, Collection &);
24
25                 virtual void init_actions();
26
27         private:
28                 void sampler(const std::string &);
29         };
30
31 protected:
32         template<typename T>
33         struct Property
34         {
35                 T value;
36                 const Texture *texture;
37
38                 Property(): value(T()), texture(0) { }
39         };
40
41         template<typename C>
42         class PropertyLoader: public DataFile::DerivedObjectLoader<Material, Loader>
43         {
44         protected:
45                 PropertyLoader(C &m): DerivedObjectLoader<Material, Loader>(m) { }
46                 PropertyLoader(C &m, Collection &c): DerivedObjectLoader<Material, Loader>(m, c) { }
47
48                 void add_property(const std::string &, void (C::*)(float), void (C::*)(const Texture *));
49                 void add_property(const std::string &, void (C::*)(const Color &), void (C::*)(const Texture *), bool);
50                 void add_property(const std::string &, void (C::*)(const Texture *));
51
52                 void property_value_scalar(void (C::*)(float), float);
53                 void property_value_rgb(void (C::*)(const Color &), float, float, float);
54                 void property_value_rgba(void (C::*)(const Color &), float, float, float, float);
55                 void property_value_srgb(void (C::*)(const Color &), float, float, float);
56                 void property_value_srgb_alpha(void (C::*)(const Color &), float, float, float, float);
57                 void property_texture(void (C::*)(const Texture *), const std::string &);
58         };
59
60 public:
61         class GenericLoader: public DataFile::Loader
62         {
63         private:
64                 template<typename T>
65                 struct CreateMaterial
66                 {
67                         void operator()(const std::string &, GenericLoader &) const;
68                 };
69
70                 DataFile::Collection *coll;
71                 Material *material;
72                 Loader *mat_loader;
73
74                 static ActionMap shared_actions;
75
76         public:
77                 GenericLoader();
78                 GenericLoader(DataFile::Collection &);
79                 ~GenericLoader();
80
81                 Material *get_object() { Material *m = material; material = 0; return m; }
82         private:
83                 virtual void init_actions();
84
85                 void type(const DataFile::Symbol &);
86
87                 friend class Material;
88         };
89
90 private:
91         typedef TypeRegistry<GenericLoader::CreateMaterial, GenericLoader &> MaterialRegistry;
92
93 protected:
94         const Sampler *sampler;
95         ProgramData shdata;
96
97         Material(): sampler(0) { }
98 public:
99         virtual ~Material() { }
100
101         virtual const Program *create_compatible_shader(const std::map<std::string, int> & = std::map<std::string, int>()) const;
102 protected:
103         virtual void fill_program_info(std::string &, std::map<std::string, int> &) const = 0;
104
105 public:
106         /** Returns the uniforms for the material. */
107         const ProgramData &get_shader_data() const { return shdata; }
108
109         virtual const Tag *get_texture_tags() const = 0;
110         virtual const Texture *get_texture(Tag) const = 0;
111         virtual const Sampler *get_sampler(Tag) const { return sampler; }
112
113         void set_debug_name(const std::string &);
114
115         template<typename T>
116         static void register_type(const std::string &);
117 private:
118         static MaterialRegistry &get_material_registry();
119 };
120
121 template<typename T>
122 void Material::register_type(const std::string &kw)
123 {
124         get_material_registry().register_type<T>(kw);
125 }
126
127
128 template<typename C>
129 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
130 {
131         add(kw, &PropertyLoader<C>::property_value_scalar, set_value);
132         if(set_texture)
133                 add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
134 }
135
136 template<typename C>
137 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)
138 {
139         add(kw, &PropertyLoader<C>::property_value_rgb, set_value);
140         add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb, set_value);
141         if(allow_alpha)
142         {
143                 add(kw, &PropertyLoader<C>::property_value_rgba, set_value);
144                 add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb_alpha, set_value);
145         }
146         if(set_texture)
147                 add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
148 }
149
150 template<typename C>
151 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_texture)(const Texture *))
152 {
153         add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
154 }
155
156 template<typename C>
157 void Material::PropertyLoader<C>::property_value_scalar(void (C::*set_value)(float), float value)
158 {
159         (static_cast<C &>(obj).*set_value)(value);
160 }
161
162 template<typename C>
163 void Material::PropertyLoader<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
164 {
165         (static_cast<C &>(obj).*set_value)(Color(r, g, b));
166 }
167
168 template<typename C>
169 void Material::PropertyLoader<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
170 {
171         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
172 }
173
174 template<typename C>
175 void Material::PropertyLoader<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
176 {
177         (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
178 }
179
180 template<typename C>
181 void Material::PropertyLoader<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
182 {
183         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
184 }
185
186 template<typename C>
187 void Material::PropertyLoader<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
188 {
189         /* The static_cast around get_collection is needed because otherwise Android
190         SDK's g++ 4.9 fails to parse get<Texture> as a template function call */
191         (static_cast<C &>(obj).*set_texture)(&static_cast<Collection &>(get_collection()).get<Texture>(name));
192 }
193
194
195 template<typename T>
196 void Material::GenericLoader::CreateMaterial<T>::operator()(const std::string &, GenericLoader &ldr) const
197 {
198         if(ldr.material)
199                 throw std::logic_error("Material type was already specified");
200
201         T *mat = new T;
202         ldr.material = mat;
203         if(ldr.coll)
204                 ldr.mat_loader = new typename T::Loader(*mat, *ldr.coll);
205         else
206                 ldr.mat_loader = new typename T::Loader(*mat);
207         ldr.add_auxiliary_loader(*ldr.mat_loader);
208 }
209
210 } // namespace GL
211 } // namespace Msp
212
213 #endif