Simulant  21.12-194
A portable game engine for Windows, OSX, Linux, Dreamcast, and PSP
material.h
1 /* * Copyright (c) 2011-2017 Luke Benstead https://simulant-engine.appspot.com
2  *
3  * This file is part of Simulant.
4  *
5  * Simulant is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * Simulant is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with Simulant. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #ifndef MATERIAL_H
20 #define MATERIAL_H
21 
22 
23 #include <unordered_map>
24 #include <set>
25 
26 #include "../asset.h"
27 #include "../generic/identifiable.h"
28 #include "../generic/managed.h"
29 #include "../types.h"
30 #include "../loadable.h"
31 #include "../interfaces/updateable.h"
32 
33 #include "materials/material_object.h"
34 #include "materials/constants.h"
35 
36 namespace smlt {
37 
38 class Renderer;
39 
40 enum IterationType {
41  ITERATION_TYPE_ONCE,
42  ITERATION_TYPE_N,
43  ITERATION_TYPE_ONCE_PER_LIGHT
44 };
45 
47  public MaterialObject {
48 public:
49  friend class Material;
50 
51  MaterialPass();
52 
53  MaterialPass(Material* material);
54 
55  void set_iteration_type(IterationType iteration) {
56  iteration_type_ = iteration;
57  }
58 
59  IterationType iteration_type() const {
60  return iteration_type_;
61  }
62 
63  GPUProgramID gpu_program_id() const;
64 
65  void set_gpu_program(GPUProgramID program) {
66  // If the renderer doesn't support GPU programs then this
67  // will be an empty ID
68  if(program) {
69  program_ = program.fetch();
70  }
71  }
72 
73  uint8_t max_iterations() const {
74  return max_iterations_;
75  }
76 
77  const Material* material() const;
78 
79 private:
80  IterationType iteration_type_ = ITERATION_TYPE_ONCE;
81  uint8_t max_iterations_ = 1;
82 
83  GPUProgramPtr program_;
84 };
85 
86 typedef uint8_t PropertyIndex;
87 
88 class Material:
89  public Asset,
90  public Loadable,
91  public generic::Identifiable<MaterialID>,
92  public RefCounted<Material>,
93  public Updateable,
94  public MaterialObject,
95  public ChainNameable<Material> {
96 
97 public:
98  friend class GenericRenderer;
99 
100  struct BuiltIns {
101  static const std::string DEFAULT;
102  static const std::string TEXTURE_ONLY;
103  static const std::string DIFFUSE_ONLY;
104  };
105 
106  static const std::unordered_map<std::string, std::string> BUILT_IN_NAMES;
107 
108  Material(MaterialID id, AssetManager *asset_manager);
109  virtual ~Material();
110 
111 // ---------- Passes ------------------------
112  bool set_pass_count(uint8_t pass_count);
113 
114  uint8_t pass_count() const {
115  return passes_.size();
116  }
117 
118  MaterialPass* pass(uint8_t pass);
119 
120  void each(std::function<void (uint32_t, MaterialPass*)> callback) {
121  for(std::size_t i = 0; i != passes_.size(); ++i) {
122  callback(i, &passes_[i]);
123  }
124  }
125 
126  void update(float dt) override;
127 
128  const std::unordered_map<MaterialPropertyNameHash, MaterialPropertyType>& custom_properties() const {
129  return custom_properties_;
130  }
131 
132  const std::set<MaterialPropertyNameHash>& texture_properties() const {
133  return texture_properties_;
134  }
135 
136  /* Return the string name of a property, given its name hash */
137  bool property_name(MaterialPropertyNameHash hsh, std::string& name) const {
138  auto it = hashes_to_names_.find(hsh);
139  if(it != hashes_to_names_.end()) {
140  name = it->second.name;
141  return true;
142  } else {
143  return false;
144  }
145  }
146 
147 private:
148  Renderer* renderer_ = nullptr;
149  std::vector<MaterialPass> passes_;
150 
151  struct PropertyName {
152  std::string name;
153  uint8_t ref_count = 0;
154  };
155 
156  static std::unordered_map<
157  MaterialPropertyNameHash,
158  PropertyName
159  > hashes_to_names_;
160 
161  static uint32_t _name_refcount(const char* name) {
162  auto hsh = material_property_hash(name);
163 
164  auto it = hashes_to_names_.find(hsh);
165  if(it != hashes_to_names_.end()) {
166  return it->second.ref_count;
167  } else {
168  return 0;
169  }
170  }
171 
172  /* Push a name onto the hash lookup */
173  static PropertyName* push_name(const char* name, MaterialPropertyNameHash hsh) {
174  auto it = hashes_to_names_.find(hsh);
175  if(it != hashes_to_names_.end()) {
176  it->second.ref_count++;
177  return &it->second;
178  } else {
179  PropertyName pn;
180  pn.name = name;
181  pn.ref_count = 1;
182  hashes_to_names_[hsh] = pn;
183  return &hashes_to_names_[hsh];
184  }
185  }
186 
187  /* Reduce the refcount of hsh. Returns true if this was the
188  * last hsh entry */
189  static bool pop_name(MaterialPropertyNameHash hsh) {
190  auto it = hashes_to_names_.find(hsh);
191  if(it != hashes_to_names_.end()) {
192  it->second.ref_count--;
193  if(!it->second.ref_count) {
194  hashes_to_names_.erase(it);
195  return true;
196  }
197  }
198 
199  return false;
200  }
201 
202  std::set<MaterialPropertyNameHash> texture_properties_;
203 
204  std::unordered_map<
205  MaterialPropertyNameHash,
206  MaterialPropertyType
207  > custom_properties_;
208 
209  virtual void on_override(
210  MaterialPropertyNameHash hsh,
211  const char *name,
212  MaterialPropertyType type) override {
213 
214  push_name(name, hsh);
215 
216  if(type == MATERIAL_PROPERTY_TYPE_TEXTURE) {
217  texture_properties_.insert(hsh);
218  }
219 
220  if(!is_core_property(hsh)) {
221  custom_properties_[hsh] = type;
222  }
223  }
224 
225  virtual void on_clear_override(MaterialPropertyNameHash hsh) override {
226  pop_name(hsh);
227  }
228 
229 protected:
230  /* Assignment operator and copy constructor must be private
231  * to prevent accidental copying. However the object manager needs
232  * to be able to clone materials, hence the friendship.
233  */
234 
235  friend class _object_manager_impl::ObjectManagerBase<
236  MaterialID, Material, std::shared_ptr<smlt::Material>,
237  _object_manager_impl::ToSharedPtr<smlt::Material>
238  >;
239 
240  Material(const Material& rhs) = delete;
241 
242  Material& operator=(const Material& rhs);
243 };
244 
245 
246 }
247 
248 #endif // MATERIAL_H
smlt::Material
Definition: material.h:95
smlt::Updateable
The Updateable class.
Definition: updateable.h:13
smlt::RefCounted
Definition: managed.h:65
smlt
Definition: animation.cpp:25
smlt::generic::Identifiable
Definition: identifiable.h:26
smlt::UniqueID< GPUProgramPtr >
smlt::MaterialPass
Definition: material.h:47
smlt::MaterialObject
Definition: material_object.h:12
smlt::Loadable
Definition: loadable.h:26
smlt::ChainNameable
Definition: nameable.h:34
smlt::GenericRenderer
Definition: generic_renderer.h:76
smlt::Material::BuiltIns
Definition: material.h:100
std
Extensions to the C++ standard library.
Definition: unique_id.h:200
smlt::Asset
Definition: asset.h:37
smlt::AssetManager
Definition: asset_manager.h:100