Euphoria
compiledmesh.cc
Go to the documentation of this file.
1 #include "render/compiledmesh.h"
2 
3 #include <set>
4 #include <utility>
5 #include <numeric>
6 
7 #include "base/cint.h"
8 #include "base/rgb.h"
9 #include "assert/assert.h"
10 #include "core/enum.h"
11 #include "core/texturetypes.h"
12 #include "log/log.h"
13 #include "io/vfs_path.h"
14 
15 #include "render/materialshader.h"
17 #include "render/attributebinder.h"
19 #include "render/texturecache.h"
20 #include "render/texture.h"
21 #include "render/actor.h"
22 
23 namespace eu::render
24 {
26  : ambient(NamedColor::white)
27  , diffuse(NamedColor::white)
28  , specular(NamedColor::white)
29  , shininess(135.0f)
30  {
31  }
32 
33 
34  void
36  (
37  const core::EnumValue& name,
38  std::shared_ptr<Texture2> texture
39  )
40  {
41  if(textures.find(name) != textures.end())
42  {
43  LOG_WARN("{0} is already assigned, overwriting...", name.to_string());
44  }
45  textures[name] = std::move(texture);
46  }
47 
48 
49  void
51  (
52  const mat4f& model_matrix,
53  const mat4f& projection_matrix,
54  const mat4f& view_matrix,
55  const vec3f& camera,
56  const Light& light
57  ) const
58  {
59  shader->use_shader();
60 
61  // set common constants
62  shader->set_model(model_matrix);
63  shader->set_projection(projection_matrix);
64  shader->set_view(view_matrix);
65  shader->setup_light(light, camera);
66 
67  shader->set_colors(ambient, diffuse, specular, shininess);
68 
69  // bind all textures
70  int texture_index = 0;
71  for(const auto& binding: shader->bindings)
72  {
73  auto texture = textures.find(binding.name);
74  if(texture == textures.end())
75  {
76  // todo(Gustav): this is a error and should have been caught by the Validate,
77  // abort?
78  continue;
79  }
80 
81  // todo(Gustav): refactor to material shader
83  texture->second.get(),
84  &shader->shader,
85  binding.uniform,
86  texture_index);
87  texture_index += 1;
88  }
89  }
90 
91 
92  void
94  {
95  for(const auto& default_texture: shader->default_textures)
96  {
97  const bool missing
98  = textures.find(default_texture.name) == textures.end();
99  if(missing)
100  {
101  textures[default_texture.name]
102  = cache->get_texture(default_texture.path);
103  }
104  }
105  }
106 
107 
108  bool
110  {
111  std::set<core::EnumValue> shader_values;
112 
113  ASSERT(shader);
114 
115  bool ok = true;
116 
117  for(const auto& binding: shader->bindings)
118  {
119  shader_values.insert(binding.name);
120  const bool missing = textures.find(binding.name) == textures.end();
121  if(missing)
122  {
123  LOG_ERROR
124  (
125  "Material is missing shader-required texture: {0}",
126  binding.name.to_string()
127  );
128  ok = false;
129  }
130  }
131 
132  for(const auto& texture: textures)
133  {
134  const auto name = texture.first;
135  const bool missing
136  = shader_values.find(name) == shader_values.end();
137  if(missing)
138  {
139  LOG_ERROR
140  (
141  "Texture {0} is specified but is missing in shader",
142  name.to_string()
143  );
144  ok = false;
145  }
146  }
147 
148  return ok;
149  }
150 
151 
153 
154  namespace
155  {
156  DEFINE_ENUM_VALUE(core::texture_type, DiffuseType, "Diffuse"); // NOLINT
157  }
158 
159 
160  void
162  (
163  const std::vector<core::MeshPoint>& points,
164  const std::vector<ShaderAttribute>& attributes,
165  VertexBuffer* vb
166  )
167  {
168  constexpr auto add_float2 = [](std::vector<float>* dst, const vec2f& src)
169  {
170  dst->emplace_back(src.x);
171  dst->emplace_back(src.y);
172  };
173  constexpr auto add_float3 = [](std::vector<float>* dst, const vec3f& src)
174  {
175  dst->emplace_back(src.x);
176  dst->emplace_back(src.y);
177  dst->emplace_back(src.z);
178  };
179  std::vector<float> data;
180  const auto total_attributes = std::accumulate
181  (
182  attributes.begin(), attributes.end(), 0,
183  [](int count, const ShaderAttribute& att) -> int
184  {
185  return count + att.get_element_count();
186  }
187  );
188  data.reserve(total_attributes * points.size());
189  for(const auto& point: points)
190  {
191  for(const auto& att: attributes)
192  {
193  switch(att.source)
194  {
197  add_float3(&data, point.vertex);
198  break;
201  add_float3(&data, point.normal);
202  break;
205  add_float2(&data, point.uv);
206  break;
207  default: DIE("Unhandled case");
208  }
209  }
210  }
211  vb->set_data(data);
212  }
213 
214 
215  void
216  convert_tris_to_index_buffer(const std::vector<core::MeshFace>& faces, IndexBuffer* b)
217  {
218  std::vector<unsigned int> data;
219  data.reserve(faces.size() * 3);
220  for(const auto& f: faces)
221  {
222  data.emplace_back(c_int_to_unsigned_int(f.a));
223  data.emplace_back(c_int_to_unsigned_int(f.b));
224  data.emplace_back(c_int_to_unsigned_int(f.c));
225  }
226  b->set_data(data);
227  }
228 
229  std::shared_ptr<CompiledMesh>
231  (
232  const core::Mesh& mesh,
233  MaterialShaderCache* shader_cache,
234  TextureCache* texture_cache,
235  const io::DirPath& texture_folder,
236  const std::string& debug_name
237  )
238  {
239  std::shared_ptr<CompiledMesh> ret {new CompiledMesh {}};
240 
241  // todo(Gustav): add default material if there are 0 materials
242 
243  int material_index = 0;
244 
245  for(const auto& material_src: mesh.materials)
246  {
247  material_index += 1;
249  mat.ambient = material_src.ambient;
250  mat.diffuse = material_src.diffuse;
251  mat.specular = material_src.specular;
252  mat.shininess = material_src.shininess;
253 
254  // todo(Gustav): determine a better default shader name
255  // perhaps by setting a few default shaders on a "project" and
256  // we try to match a shader to the object
257  const auto shader_name = material_src.shader.value_or
258  (
259  io::FilePath("~/default_shader")
260  );
261  mat.shader = shader_cache->get(shader_name);
262  for(const auto& texture_src: material_src.textures)
263  {
264  const auto texture_path = io::resolve_relative
265  (
266  io::FilePath{texture_src.path},
267  texture_folder
268  );
269  if(texture_path.has_value() == false)
270  {
271  LOG_WARN
272  (
273  "Invalid texture path {0} with root {1}",
274  texture_src.path,
275  texture_folder.path
276  );
277  }
278  else
279  {
280  auto texture = texture_cache->get_texture(texture_path);
281  if(texture->width <= 0)
282  {
283  LOG_WARN
284  (
285  "Failed to load {0} for {1}",
286  texture_src.path,
287  debug_name
288  );
289  }
290  mat.set_texture(texture_src.type, texture);
291  }
292  }
293 
294  mat.load_default_materials_from_shader(texture_cache);
295 
296  if(!mat.validate())
297  {
298  LOG_WARN
299  (
300  "Material {0}({1}) failed validation.",
301  material_src.name,
302  material_index
303  );
304  }
305 
306  ret->materials.push_back(mat);
307  }
308 
309  const auto material_count = ret->materials.size();
310 
311  // todo(Gustav): move this to a data file, load the mesh dynamically
312  const auto attributes = std::vector<ShaderAttribute>
313  {
317  };
318 
319  for(const auto& part_src: mesh.parts)
320  {
321  std::shared_ptr<CompiledMeshPart> part {new CompiledMeshPart()};
322 
323  PointLayout::bind(&part->config);
324  VertexBuffer::bind(&part->data);
325  IndexBuffer::bind(&part->tris);
326 
328  (
329  part_src.points,
330  attributes,
331  &part->data
332  );
333  bind_attributes(attributes, &part->config);
334 
335  convert_tris_to_index_buffer(part_src.faces, &part->tris);
336  part->tri_count = c_sizet_to_int(part_src.faces.size());
337 
338  IndexBuffer::bind(nullptr);
339  VertexBuffer::bind(nullptr);
340  PointLayout::bind(nullptr);
341 
342  part->material = part_src.material;
343 
344  if(part->material >= material_count)
345  {
346  LOG_ERROR("Mesh part is using a invalid material, defaulting to first.");
347  part->material = 0;
348  }
349 
350  ret->parts.push_back(part);
351  }
352 
353  return ret;
354  }
355 
356 
357  void
359  (
360  const mat4f& model_matrix,
361  const mat4f& projection_matrix,
362  const mat4f& view_matrix,
363  const vec3f& camera,
364  const Light& light,
365  const std::shared_ptr<MaterialOverride>& overridden_materials
366  )
367  {
368  ASSERT
369  (
370  overridden_materials == nullptr ||
371  materials.size() == overridden_materials->materials.size()
372  );
373 
374  for(const auto& part: parts)
375  {
376  const auto& material
377  = overridden_materials == nullptr
378  ? materials[part->material]
379  : overridden_materials->materials[part->material];
380 
381  material.apply
382  (
383  model_matrix,
384  projection_matrix,
385  view_matrix,
386  camera,
387  light
388  );
389 
390  PointLayout::bind(&part->config);
391  IndexBuffer::bind(&part->tris);
392  part->tris.draw(RenderMode::triangles, part->tri_count);
393  IndexBuffer::bind(nullptr);
394  PointLayout::bind(nullptr);
395  }
396  }
397 
398 }
#define ASSERT(x)
Definition: assert.h:29
#define DIE(message)
Definition: assert.h:67
#define DEFINE_ENUM_VALUE(TYPE, NAME, STRING)
Definition: enum.h:95
#define LOG_ERROR(...)
Definition: log.h:9
#define LOG_WARN(...)
Definition: log.h:8
constexpr ParseResult ok
all ok
Definition: argparse.h:76
std::optional< DirPath > resolve_relative(const DirPath &base)
Definition: vfs_path.cc:349
constexpr ShaderAttribute tex_coord
constexpr ShaderAttribute normal
constexpr ShaderAttribute vertex
void bind_attributes(const std::vector< ShaderAttribute > &attributes, PointLayout *layout)
void convert_tris_to_index_buffer(const std::vector< core::MeshFace > &faces, IndexBuffer *b)
void convert_points_to_vertex_buffer(const std::vector< core::LinePoint > &points, const std::vector< ShaderAttribute > &attributes, VertexBuffer *vb)
void bind_texture_to_shader(Texture2 *texture, ShaderProgram *shader, const ShaderUniform &attribute, gl::Int index)
Definition: shader.cc:488
std::shared_ptr< CompiledMesh > compile_mesh(const core::Mesh &mesh, MaterialShaderCache *shader_cache, TextureCache *texture_cache, const io::DirPath &texture_folder, const std::string &debug_name)
int c_sizet_to_int(size_t t)
Definition: cint.cc:11
NamedColor
Definition: colors.h:12
unsigned int c_int_to_unsigned_int(int i)
Definition: cint.cc:27
TPoints * points
Definition: polybezier.cc:41
std::shared_ptr< TData > get(const TKey &key)
Definition: cache.h:18
std::string to_string() const
Definition: enum.cc:139
std::vector< MeshPart > parts
Definition: mesh.h:103
std::vector< Material > materials
Definition: mesh.h:102
std::string path
contains either . or ~ at the start, / at the end
Definition: vfs_path.h:69
std::string path
contains either .
Definition: vfs_path.h:39
Definition: mat4.h:14
bool validate() const
Asks the shader if all the textures are set, and if more than necessary are set.
void apply(const mat4f &model_matrix, const mat4f &projection_matrix, const mat4f &view_matrix, const vec3f &camera, const Light &light) const
Definition: compiledmesh.cc:51
void load_default_materials_from_shader(TextureCache *cache)
Gets the default materials from the shader if they are null/not set.
Definition: compiledmesh.cc:93
std::map< core::EnumValue, std::shared_ptr< Texture2 > > textures
Definition: compiledmesh.h:48
std::shared_ptr< MaterialShader > shader
Definition: compiledmesh.h:47
void set_texture(const core::EnumValue &name, std::shared_ptr< Texture2 > texture)
Definition: compiledmesh.cc:36
A collection of parts making up a mesh.
Definition: compiledmesh.h:82
std::vector< std::shared_ptr< CompiledMeshPart > > parts
Definition: compiledmesh.h:83
std::vector< CompiledMeshMaterial > materials
Definition: compiledmesh.h:84
void render(const mat4f &model_matrix, const mat4f &projection_matrix, const mat4f &view_matrix, const vec3f &camera, const Light &light, const std::shared_ptr< MaterialOverride > &overridden_materials)
Reuses points.
Definition: buffer.h:64
static void bind(const IndexBuffer *ebo)
Definition: buffer.cc:216
static void bind(const PointLayout *vao)
Definition: buffer.cc:130
Represents a shader attribute like vertex, normal or uv coord.
ShaderAttributeType type
the type of the attribute
ShaderAttributeSource source
the source of the shader attribute
std::shared_ptr< Texture2 > get_texture(const io::FilePath &path) const
Definition: texturecache.cc:47
Stores vertices, uv, etc.
Definition: buffer.h:13
void set_data(const std::vector< float > &data)
Definition: buffer.cc:29
static void bind(const VertexBuffer *vbo)
Definition: buffer.cc:38
Definition: vec2.h:33
Definition: vec3.h:48