]> git.tdb.fi Git - libs/gl.git/blob - source/materials/material.h
Check the flat qualifier from the correct member
[libs/gl.git] / source / materials / 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/dynamicobjectloader.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 /**
17 Base class for materials.  Subclasses provide different shading models.
18 */
19 class Material
20 {
21 private:
22         class Loader: public DataFile::CollectionObjectLoader<Material>
23         {
24         protected:
25                 Loader(Material &, Collection &);
26
27                 virtual void init_actions();
28
29         private:
30                 void sampler(const std::string &);
31         };
32
33 protected:
34         template<typename T>
35         struct Property
36         {
37                 T value;
38                 const Texture *texture;
39
40                 Property(): value(T()), texture(0) { }
41         };
42
43         template<typename C>
44         class PropertyLoader: public DataFile::DerivedObjectLoader<Material, Loader>
45         {
46         protected:
47                 PropertyLoader(C &m, Collection &c): DerivedObjectLoader<Material, Loader>(m, c) { }
48
49                 void add_property(const std::string &, void (C::*)(float), void (C::*)(const Texture *));
50                 void add_property(const std::string &, void (C::*)(const Color &), void (C::*)(const Texture *), bool);
51                 void add_property(const std::string &, void (C::*)(const Texture *));
52
53                 void property_value_scalar(void (C::*)(float), float);
54                 void property_value_rgb(void (C::*)(const Color &), float, float, float);
55                 void property_value_rgba(void (C::*)(const Color &), float, float, float, float);
56                 void property_value_srgb(void (C::*)(const Color &), float, float, float);
57                 void property_value_srgb_alpha(void (C::*)(const Color &), float, float, float, float);
58                 void property_texture(void (C::*)(const Texture *), const std::string &);
59         };
60
61 public:
62         class GenericLoader: public DataFile::DynamicObjectLoader<Material>
63         {
64                 friend class Material;
65
66         public:
67                 GenericLoader(Collection &c): DynamicObjectLoader<Material>(&c) { }
68
69         protected:
70                 virtual const TypeRegistry &get_type_registry() const { return get_material_registry(); }
71         };
72
73 protected:
74         const Sampler *sampler = 0;
75         ProgramData shdata;
76
77         Material() = default;
78 public:
79         virtual ~Material() = default;
80
81         /** Returns a shader appropriate for this material.  The same shader is
82         returned for materials with the same set of features.  Additional
83         specialization values can be passed in to customize the shader. */
84         virtual const Program *create_compatible_shader(const std::map<std::string, int> & = std::map<std::string, int>()) const;
85 protected:
86         virtual void fill_program_info(std::string &, std::map<std::string, int> &) const = 0;
87
88 public:
89         /** Returns the uniform values for the material. */
90         const ProgramData &get_shader_data() const { return shdata; }
91
92         /** Returns texture tags used by the material.  The returned array is
93         terminated by an empty tag. */
94         virtual const Tag *get_texture_tags() const = 0;
95
96         virtual const Texture *get_texture(Tag) const = 0;
97         virtual const Sampler *get_sampler(Tag) const { return sampler; }
98
99         void set_debug_name(const std::string &);
100
101         template<typename T>
102         static void register_type(const std::string &);
103 private:
104         static GenericLoader::TypeRegistry &get_material_registry();
105 };
106
107 template<typename T>
108 void Material::register_type(const std::string &kw)
109 {
110         get_material_registry().register_type<T>(kw);
111 }
112
113
114 template<typename C>
115 void Material::PropertyLoader<C>::add_property(const std::string &kw, void (C::*set_value)(float), void (C::*set_texture)(const Texture *))
116 {
117         add(kw, &PropertyLoader<C>::property_value_scalar, set_value);
118         if(set_texture)
119                 add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
120 }
121
122 template<typename C>
123 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)
124 {
125         add(kw, &PropertyLoader<C>::property_value_rgb, set_value);
126         add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb, set_value);
127         if(allow_alpha)
128         {
129                 add(kw, &PropertyLoader<C>::property_value_rgba, set_value);
130                 add(kw+"_srgb", &PropertyLoader<C>::property_value_srgb_alpha, set_value);
131         }
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_texture)(const Texture *))
138 {
139         add(kw+"_map", &PropertyLoader<C>::property_texture, set_texture);
140 }
141
142 template<typename C>
143 void Material::PropertyLoader<C>::property_value_scalar(void (C::*set_value)(float), float value)
144 {
145         (static_cast<C &>(obj).*set_value)(value);
146 }
147
148 template<typename C>
149 void Material::PropertyLoader<C>::property_value_rgb(void (C::*set_value)(const Color &), float r, float g, float b)
150 {
151         (static_cast<C &>(obj).*set_value)(Color(r, g, b));
152 }
153
154 template<typename C>
155 void Material::PropertyLoader<C>::property_value_rgba(void (C::*set_value)(const Color &), float r, float g, float b, float a)
156 {
157         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a));
158 }
159
160 template<typename C>
161 void Material::PropertyLoader<C>::property_value_srgb(void (C::*set_value)(const Color &), float r, float g, float b)
162 {
163         (static_cast<C &>(obj).*set_value)(Color(r, g, b).to_linear());
164 }
165
166 template<typename C>
167 void Material::PropertyLoader<C>::property_value_srgb_alpha(void (C::*set_value)(const Color &), float r, float g, float b, float a)
168 {
169         (static_cast<C &>(obj).*set_value)(Color(r, g, b, a).to_linear());
170 }
171
172 template<typename C>
173 void Material::PropertyLoader<C>::property_texture(void (C::*set_texture)(const Texture *), const std::string &name)
174 {
175         /* The static_cast around get_collection is needed because otherwise Android
176         SDK's g++ 4.9 fails to parse get<Texture> as a template function call */
177         (static_cast<C &>(obj).*set_texture)(&static_cast<Collection &>(get_collection()).get<Texture>(name));
178 }
179
180 } // namespace GL
181 } // namespace Msp
182
183 #endif