1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 // Interface header.
31 #include "meshobject.h"
32
33 // appleseed.renderer headers.
34 #include "renderer/kernel/rasterization/objectrasterizer.h"
35 #include "renderer/modeling/object/meshobjectprimitives.h"
36 #include "renderer/modeling/object/meshobjectreader.h"
37 #include "renderer/modeling/object/triangle.h"
38
39 // appleseed.foundation headers.
40 #include "foundation/utility/api/apiarray.h"
41 #include "foundation/utility/api/specializedapiarrays.h"
42 #include "foundation/utility/containers/dictionary.h"
43 #include "foundation/utility/foreach.h"
44
45 // Standard headers.
46 #include <cassert>
47 #include <string>
48 #include <vector>
49
50 using namespace foundation;
51 using namespace std;
52
53 namespace renderer
54 {
55
56 //
57 // MeshObject class implementation.
58 //
59
60 namespace
61 {
62 const char* Model = "mesh_object";
63 }
64
65 struct MeshObject::Impl
66 {
67 StaticTriangleTess m_tess;
68 vector<string> m_material_slots;
69 };
70
MeshObject(const char * name,const ParamArray & params)71 MeshObject::MeshObject(
72 const char* name,
73 const ParamArray& params)
74 : Object(name, params)
75 , impl(new Impl())
76 {
77 m_inputs.declare("alpha_map", InputFormatFloat, "");
78 }
79
~MeshObject()80 MeshObject::~MeshObject()
81 {
82 delete impl;
83 }
84
release()85 void MeshObject::release()
86 {
87 delete this;
88 }
89
get_model() const90 const char* MeshObject::get_model() const
91 {
92 return Model;
93 }
94
get_uncached_alpha_map() const95 const Source* MeshObject::get_uncached_alpha_map() const
96 {
97 return m_inputs.source("alpha_map");
98 }
99
compute_local_bbox() const100 GAABB3 MeshObject::compute_local_bbox() const
101 {
102 return impl->m_tess.compute_local_bbox();
103 }
104
get_static_triangle_tess() const105 const StaticTriangleTess& MeshObject::get_static_triangle_tess() const
106 {
107 return impl->m_tess;
108 }
109
rasterize(ObjectRasterizer & rasterizer) const110 void MeshObject::rasterize(ObjectRasterizer& rasterizer) const
111 {
112 rasterizer.begin_object(impl->m_tess.m_primitives.size());
113
114 for (const auto& prim : impl->m_tess.m_primitives)
115 {
116 const auto& v0 = impl->m_tess.m_vertices[prim.m_v0];
117 const auto& v1 = impl->m_tess.m_vertices[prim.m_v1];
118 const auto& v2 = impl->m_tess.m_vertices[prim.m_v2];
119
120 // todo: check that vertex normals are available.
121 const auto& n0 = impl->m_tess.m_vertex_normals[prim.m_n0];
122 const auto& n1 = impl->m_tess.m_vertex_normals[prim.m_n1];
123 const auto& n2 = impl->m_tess.m_vertex_normals[prim.m_n2];
124
125 ObjectRasterizer::Triangle triangle;
126
127 triangle.m_v0[0] = v0[0];
128 triangle.m_v0[1] = v0[1];
129 triangle.m_v0[2] = v0[2];
130
131 triangle.m_v1[0] = v1[0];
132 triangle.m_v1[1] = v1[1];
133 triangle.m_v1[2] = v1[2];
134
135 triangle.m_v2[0] = v2[0];
136 triangle.m_v2[1] = v2[1];
137 triangle.m_v2[2] = v2[2];
138
139 triangle.m_n0[0] = n0[0];
140 triangle.m_n0[1] = n0[1];
141 triangle.m_n0[2] = n0[2];
142
143 triangle.m_n1[0] = n1[0];
144 triangle.m_n1[1] = n1[1];
145 triangle.m_n1[2] = n1[2];
146
147 triangle.m_n2[0] = n2[0];
148 triangle.m_n2[1] = n2[1];
149 triangle.m_n2[2] = n2[2];
150
151 rasterizer.rasterize(triangle);
152 }
153
154 rasterizer.end_object();
155 }
156
reserve_vertices(const size_t count)157 void MeshObject::reserve_vertices(const size_t count)
158 {
159 impl->m_tess.m_vertices.reserve(count);
160 }
161
push_vertex(const GVector3 & vertex)162 size_t MeshObject::push_vertex(const GVector3& vertex)
163 {
164 const size_t index = impl->m_tess.m_vertices.size();
165 impl->m_tess.m_vertices.push_back(vertex);
166 return index;
167 }
168
get_vertex_count() const169 size_t MeshObject::get_vertex_count() const
170 {
171 return impl->m_tess.m_vertices.size();
172 }
173
get_vertex(const size_t index) const174 const GVector3& MeshObject::get_vertex(const size_t index) const
175 {
176 return impl->m_tess.m_vertices[index];
177 }
178
reserve_vertex_normals(const size_t count)179 void MeshObject::reserve_vertex_normals(const size_t count)
180 {
181 impl->m_tess.m_vertex_normals.reserve(count);
182 }
183
push_vertex_normal(const GVector3 & normal)184 size_t MeshObject::push_vertex_normal(const GVector3& normal)
185 {
186 assert(is_normalized(normal));
187
188 const size_t index = impl->m_tess.m_vertex_normals.size();
189 impl->m_tess.m_vertex_normals.push_back(normal);
190 return index;
191 }
192
get_vertex_normal_count() const193 size_t MeshObject::get_vertex_normal_count() const
194 {
195 return impl->m_tess.m_vertex_normals.size();
196 }
197
get_vertex_normal(const size_t index) const198 const GVector3& MeshObject::get_vertex_normal(const size_t index) const
199 {
200 return impl->m_tess.m_vertex_normals[index];
201 }
202
clear_vertex_normals()203 void MeshObject::clear_vertex_normals()
204 {
205 impl->m_tess.m_vertex_normals.clear();
206 }
207
reserve_vertex_tangents(const size_t count)208 void MeshObject::reserve_vertex_tangents(const size_t count)
209 {
210 impl->m_tess.reserve_vertex_tangents(count);
211 }
212
push_vertex_tangent(const GVector3 & tangent)213 size_t MeshObject::push_vertex_tangent(const GVector3& tangent)
214 {
215 return impl->m_tess.push_vertex_tangent(tangent);
216 }
217
get_vertex_tangent_count() const218 size_t MeshObject::get_vertex_tangent_count() const
219 {
220 return impl->m_tess.get_vertex_tangent_count();
221 }
222
get_vertex_tangent(const size_t index) const223 GVector3 MeshObject::get_vertex_tangent(const size_t index) const
224 {
225 return impl->m_tess.get_vertex_tangent(index);
226 }
227
reserve_tex_coords(const size_t count)228 void MeshObject::reserve_tex_coords(const size_t count)
229 {
230 impl->m_tess.reserve_tex_coords(count);
231 }
232
push_tex_coords(const GVector2 & tex_coords)233 size_t MeshObject::push_tex_coords(const GVector2& tex_coords)
234 {
235 return impl->m_tess.push_tex_coords(tex_coords);
236 }
237
get_tex_coords_count() const238 size_t MeshObject::get_tex_coords_count() const
239 {
240 return impl->m_tess.get_tex_coords_count();
241 }
242
get_tex_coords(const size_t index) const243 GVector2 MeshObject::get_tex_coords(const size_t index) const
244 {
245 return impl->m_tess.get_tex_coords(index);
246 }
247
reserve_triangles(const size_t count)248 void MeshObject::reserve_triangles(const size_t count)
249 {
250 impl->m_tess.m_primitives.reserve(count);
251 }
252
push_triangle(const Triangle & triangle)253 size_t MeshObject::push_triangle(const Triangle& triangle)
254 {
255 const size_t index = impl->m_tess.m_primitives.size();
256 impl->m_tess.m_primitives.push_back(triangle);
257 return index;
258 }
259
get_triangle_count() const260 size_t MeshObject::get_triangle_count() const
261 {
262 return impl->m_tess.m_primitives.size();
263 }
264
get_triangle(const size_t index) const265 const Triangle& MeshObject::get_triangle(const size_t index) const
266 {
267 return impl->m_tess.m_primitives[index];
268 }
269
get_triangle(const size_t index)270 Triangle& MeshObject::get_triangle(const size_t index)
271 {
272 return impl->m_tess.m_primitives[index];
273 }
274
clear_triangles()275 void MeshObject::clear_triangles()
276 {
277 impl->m_tess.m_primitives.clear();
278 }
279
set_motion_segment_count(const size_t count)280 void MeshObject::set_motion_segment_count(const size_t count)
281 {
282 impl->m_tess.set_motion_segment_count(count);
283 }
284
get_motion_segment_count() const285 size_t MeshObject::get_motion_segment_count() const
286 {
287 return impl->m_tess.get_motion_segment_count();
288 }
289
set_vertex_pose(const size_t vertex_index,const size_t motion_segment_index,const GVector3 & vertex)290 void MeshObject::set_vertex_pose(
291 const size_t vertex_index,
292 const size_t motion_segment_index,
293 const GVector3& vertex)
294 {
295 impl->m_tess.set_vertex_pose(vertex_index, motion_segment_index, vertex);
296 }
297
get_vertex_pose(const size_t vertex_index,const size_t motion_segment_index) const298 GVector3 MeshObject::get_vertex_pose(
299 const size_t vertex_index,
300 const size_t motion_segment_index) const
301 {
302 return impl->m_tess.get_vertex_pose(vertex_index, motion_segment_index);
303 }
304
clear_vertex_poses()305 void MeshObject::clear_vertex_poses()
306 {
307 impl->m_tess.clear_vertex_poses();
308 }
309
set_vertex_normal_pose(const size_t normal_index,const size_t motion_segment_index,const GVector3 & normal)310 void MeshObject::set_vertex_normal_pose(
311 const size_t normal_index,
312 const size_t motion_segment_index,
313 const GVector3& normal)
314 {
315 impl->m_tess.set_vertex_normal_pose(normal_index, motion_segment_index, normal);
316 }
317
get_vertex_normal_pose(const size_t normal_index,const size_t motion_segment_index) const318 GVector3 MeshObject::get_vertex_normal_pose(
319 const size_t normal_index,
320 const size_t motion_segment_index) const
321 {
322 return impl->m_tess.get_vertex_normal_pose(normal_index, motion_segment_index);
323 }
324
clear_vertex_normal_poses()325 void MeshObject::clear_vertex_normal_poses()
326 {
327 impl->m_tess.clear_vertex_normal_poses();
328 }
329
set_vertex_tangent_pose(const size_t tangent_index,const size_t motion_segment_index,const GVector3 & tangent)330 void MeshObject::set_vertex_tangent_pose(
331 const size_t tangent_index,
332 const size_t motion_segment_index,
333 const GVector3& tangent)
334 {
335 impl->m_tess.set_vertex_tangent_pose(tangent_index, motion_segment_index, tangent);
336 }
337
get_vertex_tangent_pose(const size_t tangent_index,const size_t motion_segment_index) const338 GVector3 MeshObject::get_vertex_tangent_pose(
339 const size_t tangent_index,
340 const size_t motion_segment_index) const
341 {
342 return impl->m_tess.get_vertex_tangent_pose(tangent_index, motion_segment_index);
343 }
344
clear_vertex_tangent_poses()345 void MeshObject::clear_vertex_tangent_poses()
346 {
347 impl->m_tess.clear_vertex_tangent_poses();
348 }
349
reserve_material_slots(const size_t count)350 void MeshObject::reserve_material_slots(const size_t count)
351 {
352 impl->m_material_slots.reserve(count);
353 }
354
push_material_slot(const char * name)355 size_t MeshObject::push_material_slot(const char* name)
356 {
357 const size_t index = impl->m_material_slots.size();
358 impl->m_material_slots.emplace_back(name);
359 return index;
360 }
361
get_material_slot_count() const362 size_t MeshObject::get_material_slot_count() const
363 {
364 return impl->m_material_slots.size();
365 }
366
get_material_slot(const size_t index) const367 const char* MeshObject::get_material_slot(const size_t index) const
368 {
369 return impl->m_material_slots[index].c_str();
370 }
371
collect_asset_paths(StringArray & paths) const372 void MeshObject::collect_asset_paths(StringArray& paths) const
373 {
374 if (m_params.strings().exist("filename"))
375 paths.push_back(m_params.get("filename"));
376 else if (m_params.dictionaries().exist("filename"))
377 {
378 const StringDictionary& filepaths = m_params.dictionaries().get("filename").strings();
379 for (const_each<StringDictionary> i = filepaths; i; ++i)
380 paths.push_back(i->value());
381 }
382 }
383
update_asset_paths(const StringDictionary & mappings)384 void MeshObject::update_asset_paths(const StringDictionary& mappings)
385 {
386 if (m_params.strings().exist("filename"))
387 m_params.set("filename", mappings.get(m_params.get("filename")));
388 else if (m_params.dictionaries().exist("filename"))
389 {
390 StringDictionary& filepaths = m_params.dictionaries().get("filename").strings();
391 for (const_each<StringDictionary> i = filepaths; i; ++i)
392 filepaths.set(i->key(), mappings.get(i->value()));
393 }
394 }
395
396
397 //
398 // MeshObjectFactory class implementation.
399 //
400
release()401 void MeshObjectFactory::release()
402 {
403 delete this;
404 }
405
get_model() const406 const char* MeshObjectFactory::get_model() const
407 {
408 return Model;
409 }
410
get_model_metadata() const411 Dictionary MeshObjectFactory::get_model_metadata() const
412 {
413 return
414 Dictionary()
415 .insert("name", Model)
416 .insert("label", "Mesh Object");
417 }
418
get_input_metadata() const419 DictionaryArray MeshObjectFactory::get_input_metadata() const
420 {
421 DictionaryArray metadata;
422
423 metadata.push_back(
424 Dictionary()
425 .insert("name", "alpha_map")
426 .insert("label", "Alpha Map")
427 .insert("type", "colormap")
428 .insert("entity_types",
429 Dictionary()
430 .insert("color", "Colors")
431 .insert("texture_instance", "Texture Instances"))
432 .insert("min",
433 Dictionary()
434 .insert("value", "0.0")
435 .insert("type", "hard"))
436 .insert("max",
437 Dictionary()
438 .insert("value", "1.0")
439 .insert("type", "hard"))
440 .insert("use", "optional"));
441
442 return metadata;
443 }
444
create(const char * name,const ParamArray & params) const445 auto_release_ptr<Object> MeshObjectFactory::create(
446 const char* name,
447 const ParamArray& params) const
448 {
449 return auto_release_ptr<Object>(new MeshObject(name, params));
450 }
451
create(const char * name,const ParamArray & params,const SearchPaths & search_paths,const bool omit_loading_assets,ObjectArray & objects) const452 bool MeshObjectFactory::create(
453 const char* name,
454 const ParamArray& params,
455 const SearchPaths& search_paths,
456 const bool omit_loading_assets,
457 ObjectArray& objects) const
458 {
459 if (params.strings().exist("primitive"))
460 {
461 auto_release_ptr<MeshObject> mesh = create_primitive_mesh(name, params);
462 if (mesh.get() == nullptr)
463 return false;
464
465 objects.push_back(mesh.release());
466 return true;
467 }
468
469 if (omit_loading_assets)
470 {
471 objects.push_back(create(name, params).release());
472 return true;
473 }
474
475 MeshObjectArray object_array;
476 if (!MeshObjectReader::read(
477 search_paths,
478 name,
479 params,
480 object_array))
481 return false;
482
483 objects = array_vector<ObjectArray>(object_array);
484 return true;
485 }
486
487 } // namespace renderer
488