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