Simulant  21.12-574
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
material_property_overrider.h
1 #pragma once
2 
3 #include <unordered_map>
4 #include <list>
5 #include <string>
6 
7 #include "../property_value.h"
8 #include "core_material.h"
9 #include "../../../generic/containers/contiguous_map.h"
10 
11 namespace smlt {
12 
13 /* All materials and passes inherit the properties and
14  * values of the core material. Overriders allow two things:
15  *
16  * 1. Overriding the value of the core material
17  * 2. Adding additional property values (e.g. shader uniforms)
18  */
19 
20 bool valid_name(const char* name);
21 
23 public:
24  MaterialPropertyOverrider() = default;
26  parent_(parent) {}
27 
28  template<typename T>
29  bool set_property_value(MaterialPropertyNameHash hsh, const char* name, const T& value) {
30  if(auto v = find_core_property_value(hsh)) {
31  v->set(value);
32  } else {
33  clear_override(hsh);
34 
35  properties_.insert(std::make_pair(hsh, PropertyValue<void>(value)));
36  on_override(hsh, name, _impl::material_property_lookup<T>::type);
37  }
38 
39  return true;
40  }
41 
42  template<typename T>
43  bool set_property_value(const char* name, const T& value) {
44  if(!valid_name(name)) {
45  S_WARN("Ignoring invalid property name: {0}", name);
46  return false;
47  }
48 
49  if(parent_ && !parent_->check_existance(name)) {
50  S_WARN("Ignoring unknown property override for {0}", name);
51  return false;
52  }
53 
54  return set_property_value(material_property_hash(name), name, value);
55  }
56 
57  bool set_property_value(const char* name, const Colour& value) {
58  if(!valid_name(name)) {
59  S_WARN("Ignoring invalid property name: {0}", name);
60  return false;
61  }
62 
63  if(parent_ && !parent_->check_existance(name)) {
64  S_WARN("Ignoring unknown property override for {0}", name);
65  return false;
66  }
67 
68  return set_property_value(material_property_hash(name), name, (const Vec4&) value);
69  }
70 
71  template<typename T>
72  bool property_value(const MaterialPropertyNameHash hsh, const T*& out) const {
73  /* Core property fast-path. If it's a core property, check locally
74  * then check the parent without doing a hash lookup on the properties
75  * list (which is for non-core properties) */
76  auto mem_ptr = find_core_property(hsh);
77  if(mem_ptr) {
78  auto v = &(this->*mem_ptr);
79  auto p = (parent_) ? &(parent_->*mem_ptr) : nullptr;
80  if(v->has_value()) {
81  out = v->get<T>();
82  return true;
83  } else if(p && p->has_value()) {
84  out = p->get<T>();
85  return true;
86  } else {
87  return core_material_property_value(hsh, out);
88  }
89  } else {
90  auto it = properties_.find(hsh);
91  if(it != properties_.end()) {
92  out = it->second.get<T>();
93  return true;
94  } else if(parent_) {
95  return parent_->property_value(hsh, out);
96  }
97  }
98 
99  return false;
100  }
101 
102  /* Helpers for std::string */
103  template<typename T>
104  void set_property_value(const std::string& str, const T& v) {
105  set_property_value(str.c_str(), v);
106  }
107 
108  template<typename T>
109  bool property_value(const std::string& str, const T*& out) const {
110  return property_value(str.c_str(), out);
111  }
112 
113  template<typename T>
114  bool property_value(const char* name, const T*& out) const {
115  auto hsh = material_property_hash(name);
116  return property_value(hsh, out);
117  }
118 
119  bool clear_override(const char* name) {
120  return clear_override(material_property_hash(name));
121  }
122 
123  bool property_type(const char* property_name, MaterialPropertyType* type) const;
124 
125 
126 protected:
127  /* It would be nice if we could treat core properties and
128  * custom properties identically. Unfortunately that leads to
129  * poor performance due to lack of cache locality and the
130  * hash table lookups. So instead we keep a list of core properties
131  * directly embedded in the material and use a massive switch
132  * statement to find them. */
133  PropertyValue<Vec4> diffuse_property_;
134  PropertyValue<Vec4> ambient_property_;
135  PropertyValue<Vec4> emission_property_;
136  PropertyValue<Vec4> specular_property_;
137  PropertyValue<float> shininess_property_;
138  PropertyValue<float> point_size_property_;
139  PropertyValue<bool> depth_write_enabled_property_;
140  PropertyValue<bool> depth_test_enabled_property_;
141  PropertyValue<bool> lighting_enabled_property_;
142  PropertyValue<int32_t> textures_enabled_property_;
143  PropertyValue<TexturePtr> diffuse_map_property_;
144  PropertyValue<TexturePtr> specular_map_property_;
145  PropertyValue<TexturePtr> light_map_property_;
146  PropertyValue<TexturePtr> normal_map_property_;
147  PropertyValue<Mat4> diffuse_map_matrix_property_;
148  PropertyValue<Mat4> specular_map_matrix_property_;
149  PropertyValue<Mat4> light_map_matrix_property_;
150  PropertyValue<Mat4> normal_map_matrix_property_;
151  PropertyValue<int32_t> blend_func_property_;
152  PropertyValue<int32_t> polygon_mode_property_;
153  PropertyValue<int32_t> shade_model_property_;
154  PropertyValue<bool> colour_material_property_;
155  PropertyValue<int32_t> cull_mode_property_;
156  PropertyValue<Vec4> fog_colour_property_;
157  PropertyValue<float> fog_density_property_;
158  PropertyValue<float> fog_start_property_;
159  PropertyValue<float> fog_end_property_;
160  PropertyValue<int32_t> fog_mode_property_;
161 
162  BasePropertyValue* find_core_property_value(const MaterialPropertyNameHash& hsh) {
163  return const_cast<BasePropertyValue*>(static_cast<const MaterialPropertyOverrider*>(this)->find_core_property_value(hsh));
164  }
165 
166  typedef BasePropertyValue MaterialPropertyOverrider::* PropertyValueMemberPtr;
167 
168  PropertyValueMemberPtr find_core_property(const MaterialPropertyNameHash& hsh) const {
169  switch(hsh) {
170  case DIFFUSE_PROPERTY_HASH:
171  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::diffuse_property_;
172  case AMBIENT_PROPERTY_HASH:
173  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::ambient_property_;
174  case EMISSION_PROPERTY_HASH:
175  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::emission_property_;
176  case SPECULAR_PROPERTY_HASH:
177  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::specular_property_;
178  case SHININESS_PROPERTY_HASH:
179  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::shininess_property_;
180  case POINT_SIZE_PROPERTY_HASH:
181  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::point_size_property_;
182  case DEPTH_WRITE_ENABLED_PROPERTY_HASH:
183  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::depth_write_enabled_property_;
184  case DEPTH_TEST_ENABLED_PROPERTY_HASH:
185  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::depth_test_enabled_property_;
186  case LIGHTING_ENABLED_PROPERTY_HASH:
187  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::lighting_enabled_property_;
188  case TEXTURES_ENABLED_PROPERTY_HASH:
189  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::textures_enabled_property_;
190  case DIFFUSE_MAP_PROPERTY_HASH:
191  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::diffuse_map_property_;
192  case SPECULAR_MAP_PROPERTY_HASH:
193  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::specular_map_property_;
194  case LIGHT_MAP_PROPERTY_HASH:
195  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::light_map_property_;
196  case NORMAL_MAP_PROPERTY_HASH:
197  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::normal_map_property_;
198  case DIFFUSE_MAP_MATRIX_PROPERTY_HASH:
199  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::diffuse_map_matrix_property_;
200  case SPECULAR_MAP_MATRIX_PROPERTY_HASH:
201  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::specular_map_matrix_property_;
202  case LIGHT_MAP_MATRIX_PROPERTY_HASH:
203  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::light_map_matrix_property_;
204  case NORMAL_MAP_MATRIX_PROPERTY_HASH:
205  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::normal_map_matrix_property_;
206  case BLEND_FUNC_PROPERTY_HASH:
207  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::blend_func_property_;
208  case POLYGON_MODE_PROPERTY_HASH:
209  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::polygon_mode_property_;
210  case SHADE_MODEL_PROPERTY_HASH:
211  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::shade_model_property_;
212  case COLOUR_MATERIAL_PROPERTY_HASH:
213  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::colour_material_property_;
214  case CULL_MODE_PROPERTY_HASH:
215  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::cull_mode_property_;
216  case FOG_COLOUR_PROPERTY_HASH:
217  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::fog_colour_property_;
218  case FOG_DENSITY_PROPERTY_HASH:
219  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::fog_density_property_;
220  case FOG_START_PROPERTY_HASH:
221  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::fog_start_property_;
222  case FOG_END_PROPERTY_HASH:
223  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::fog_end_property_;
224  case FOG_MODE_PROPERTY_HASH:
225  return (PropertyValueMemberPtr) &MaterialPropertyOverrider::fog_mode_property_;
226  default:
227  return nullptr;
228  }
229  }
230 
231  const BasePropertyValue* find_core_property_value(const MaterialPropertyNameHash& hsh) const {
232  auto ptr = find_core_property(hsh);
233  if(!ptr) {
234  return nullptr;
235  }
236 
237  return &(this->*ptr);
238  }
239 
240 
241  virtual void on_override(
242  MaterialPropertyNameHash hsh,
243  const char* name,
244  MaterialPropertyType type
245  ) {
246  _S_UNUSED(hsh);
247  _S_UNUSED(name);
248  _S_UNUSED(type);
249  }
250 
251  virtual void on_clear_override(MaterialPropertyNameHash hsh) { _S_UNUSED(hsh); }
252 
253  /* If we have a parent, then we can't override unless the property has
254  * been defined on the parent - or it's a core property */
255  bool check_existance(const MaterialPropertyNameHash hsh) const;
256  bool check_existance(const char* property_name) const;
257  bool clear_override(const unsigned hsh);
258 
259  const MaterialPropertyOverrider* parent_ = nullptr;
260 
261  std::unordered_map<MaterialPropertyNameHash, PropertyValue<void>> properties_;
262 };
263 
264 }
smlt::PropertyValue< void >
Definition: property_value.h:170
smlt::BasePropertyValue
Definition: property_value.h:79
smlt
Definition: animation.cpp:25
smlt::_impl::material_property_lookup
Definition: property_value.h:29
smlt::MaterialPropertyOverrider
Definition: material_property_overrider.h:22
smlt::PropertyValue
Definition: property_value.h:134
smlt::Colour
Definition: colour.h:29
smlt::Vec4
Definition: vec4.h:12