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