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