• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "gltf/gltf2_importer.h"
17 
18 #include <chrono>
19 #include <cstring>
20 #include <functional>
21 
22 #include <3d/ecs/components/animation_component.h>
23 #include <3d/ecs/components/animation_input_component.h>
24 #include <3d/ecs/components/animation_output_component.h>
25 #include <3d/ecs/components/animation_track_component.h>
26 #include <3d/ecs/components/camera_component.h>
27 #include <3d/ecs/components/environment_component.h>
28 #include <3d/ecs/components/light_component.h>
29 #include <3d/ecs/components/local_matrix_component.h>
30 #include <3d/ecs/components/material_component.h>
31 #include <3d/ecs/components/morph_component.h>
32 #include <3d/ecs/components/name_component.h>
33 #include <3d/ecs/components/node_component.h>
34 #include <3d/ecs/components/render_configuration_component.h>
35 #include <3d/ecs/components/render_handle_component.h>
36 #include <3d/ecs/components/render_mesh_component.h>
37 #include <3d/ecs/components/rsdz_model_id_component.h>
38 #include <3d/ecs/components/skin_ibm_component.h>
39 #include <3d/ecs/components/skin_joints_component.h>
40 #include <3d/ecs/components/transform_component.h>
41 #include <3d/ecs/components/uri_component.h>
42 #include <3d/ecs/components/world_matrix_component.h>
43 #include <3d/ecs/systems/intf_skinning_system.h>
44 #include <3d/implementation_uids.h>
45 #include <3d/intf_graphics_context.h>
46 #include <3d/render/default_material_constants.h>
47 #include <3d/util/intf_mesh_builder.h>
48 #include <base/containers/fixed_string.h>
49 #include <base/containers/string.h>
50 #include <base/containers/unique_ptr.h>
51 #include <base/containers/unordered_map.h>
52 #include <base/containers/vector.h>
53 #include <base/math/matrix_util.h>
54 #include <base/math/vector_util.h>
55 #include <core/ecs/intf_ecs.h>
56 #include <core/ecs/intf_entity_manager.h>
57 #include <core/image/intf_image_container.h>
58 #include <core/image/intf_image_loader_manager.h>
59 #include <core/implementation_uids.h>
60 #include <core/intf_engine.h>
61 #include <core/log.h>
62 #include <core/namespace.h>
63 #include <core/perf/cpu_perf_scope.h>
64 #include <core/perf/intf_performance_data_manager.h>
65 #include <core/plugin/intf_class_register.h>
66 #include <core/property/intf_property_handle.h>
67 #include <core/property/property_types.h>
68 #include <render/datastore/intf_render_data_store_default_staging.h>
69 #include <render/datastore/intf_render_data_store_manager.h>
70 #include <render/device/intf_gpu_resource_manager.h>
71 #include <render/device/intf_shader_manager.h>
72 #include <render/implementation_uids.h>
73 #include <render/intf_render_context.h>
74 
75 #include "gltf/gltf2_util.h"
76 #include "util/log.h"
77 #include "util/mesh_builder.h"
78 #include "util/mesh_util.h"
79 #include "util/string_util.h"
80 #include "util/uri_lookup.h"
81 
82 CORE3D_BEGIN_NAMESPACE()
83 using namespace BASE_NS;
84 using namespace CORE_NS;
85 using namespace RENDER_NS;
86 
87 namespace {
88 // How many threads the GLTF2Importer will use to run tasks.
89 constexpr const uint32_t IMPORTER_THREADS = 2u;
90 
91 // Helper class for running lambda as a ThreadPool task.
92 template<typename Fn>
93 class FunctionTask final : public IThreadPool::ITask {
94 public:
FunctionTask(Fn && func)95     explicit FunctionTask(Fn&& func) : func_(BASE_NS::move(func)) {};
96 
operator ()()97     void operator()() override
98     {
99         func_();
100     }
101 
102 protected:
Destroy()103     void Destroy() override
104     {
105         delete this;
106     }
107 
108 private:
109     Fn func_;
110 };
111 
112 template<typename Fn>
CreateFunctionTask(Fn && func)113 inline IThreadPool::ITask::Ptr CreateFunctionTask(Fn&& func)
114 {
115     return IThreadPool::ITask::Ptr { new FunctionTask<Fn>(BASE_NS::move(func)) };
116 }
117 
118 template<class T>
FindIndex(const vector<unique_ptr<T>> & container,T const * item)119 size_t FindIndex(const vector<unique_ptr<T>>& container, T const* item)
120 {
121     for (size_t i = 0; i < container.size(); ++i) {
122         if (container[i].get() == item) {
123             return i;
124         }
125     }
126     return GLTF2::GLTF_INVALID_INDEX;
127 }
128 
129 constexpr auto MAX_COMPONENTS = 4U;
130 constexpr Format BYTE_FORMATS[2U][MAX_COMPONENTS] = {
131     { BASE_FORMAT_R8_SINT, BASE_FORMAT_R8G8_SINT, BASE_FORMAT_R8G8B8_SINT, BASE_FORMAT_R8G8B8A8_SINT },
132     { BASE_FORMAT_R8_SNORM, BASE_FORMAT_R8G8_SNORM, BASE_FORMAT_R8G8B8_SNORM, BASE_FORMAT_R8G8B8A8_SNORM },
133 };
134 constexpr Format UNSIGNED_BYTE_FORMATS[2U][MAX_COMPONENTS] = {
135     { BASE_FORMAT_R8_UINT, BASE_FORMAT_R8G8_UINT, BASE_FORMAT_R8G8B8_UINT, BASE_FORMAT_R8G8B8A8_UINT },
136     { BASE_FORMAT_R8_UNORM, BASE_FORMAT_R8G8_UNORM, BASE_FORMAT_R8G8B8_UNORM, BASE_FORMAT_R8G8B8A8_UNORM },
137 };
138 
139 constexpr Format SHORT_FORMATS[2U][MAX_COMPONENTS] = {
140     { BASE_FORMAT_R16_SINT, BASE_FORMAT_R16G16_SINT, BASE_FORMAT_R16G16B16_SINT, BASE_FORMAT_R16G16B16A16_SINT },
141     { BASE_FORMAT_R16_SNORM, BASE_FORMAT_R16G16_SNORM, BASE_FORMAT_R16G16B16_SNORM, BASE_FORMAT_R16G16B16A16_SNORM },
142 };
143 constexpr Format UNSIGNED_SHORT_FORMATS[2U][MAX_COMPONENTS] = {
144     { BASE_FORMAT_R16_UINT, BASE_FORMAT_R16G16_UINT, BASE_FORMAT_R16G16B16_UINT, BASE_FORMAT_R16G16B16A16_UINT },
145     { BASE_FORMAT_R16_UNORM, BASE_FORMAT_R16G16_UNORM, BASE_FORMAT_R16G16B16_UNORM, BASE_FORMAT_R16G16B16A16_UNORM },
146 };
147 
148 constexpr Format INT_FORMATS[MAX_COMPONENTS] = { BASE_FORMAT_R32_SINT, BASE_FORMAT_R32G32_SINT,
149     BASE_FORMAT_R32G32B32_SINT, BASE_FORMAT_R32G32B32A32_SINT };
150 constexpr Format UNSIGNED_INT_FORMATS[MAX_COMPONENTS] = { BASE_FORMAT_R32_UINT, BASE_FORMAT_R32G32_UINT,
151     BASE_FORMAT_R32G32B32_UINT, BASE_FORMAT_R32G32B32A32_UINT };
152 
153 constexpr Format FLOAT_FORMATS[MAX_COMPONENTS] = { BASE_FORMAT_R32_SFLOAT, BASE_FORMAT_R32G32_SFLOAT,
154     BASE_FORMAT_R32G32B32_SFLOAT, BASE_FORMAT_R32G32B32A32_SFLOAT };
155 
Convert(GLTF2::ComponentType componentType,size_t componentCount,bool normalized)156 constexpr Format Convert(GLTF2::ComponentType componentType, size_t componentCount, bool normalized)
157 {
158     if (componentCount <= MAX_COMPONENTS) {
159         switch (componentType) {
160             case GLTF2::ComponentType::INVALID:
161                 break;
162 
163             case GLTF2::ComponentType::BYTE:
164                 return BYTE_FORMATS[normalized ? 1U : 0U][componentCount - 1];
165 
166             case GLTF2::ComponentType::UNSIGNED_BYTE:
167                 return UNSIGNED_BYTE_FORMATS[normalized ? 1U : 0U][componentCount - 1];
168 
169             case GLTF2::ComponentType::SHORT:
170                 return SHORT_FORMATS[normalized ? 1U : 0U][componentCount - 1];
171 
172             case GLTF2::ComponentType::UNSIGNED_SHORT:
173                 return UNSIGNED_SHORT_FORMATS[normalized ? 1U : 0U][componentCount - 1];
174 
175             case GLTF2::ComponentType::INT:
176                 return INT_FORMATS[componentCount - 1];
177 
178             case GLTF2::ComponentType::UNSIGNED_INT:
179                 return UNSIGNED_INT_FORMATS[componentCount - 1];
180 
181             case GLTF2::ComponentType::FLOAT:
182                 return FLOAT_FORMATS[componentCount - 1];
183         }
184     }
185     return BASE_FORMAT_UNDEFINED;
186 }
187 
ConvertGltf2InputAssembly(const GLTF2::RenderMode renderMode)188 constexpr GraphicsState::InputAssembly ConvertGltf2InputAssembly(const GLTF2::RenderMode renderMode)
189 {
190     GraphicsState::InputAssembly ia;
191     switch (renderMode) {
192         case GLTF2::RenderMode::POINTS:
193             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_POINT_LIST;
194             break;
195         case GLTF2::RenderMode::LINES:
196             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_LINE_LIST;
197             break;
198         case GLTF2::RenderMode::LINE_STRIP:
199             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_LINE_STRIP;
200             break;
201         case GLTF2::RenderMode::TRIANGLES:
202             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
203             break;
204         case GLTF2::RenderMode::TRIANGLE_STRIP:
205             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP;
206             break;
207         case GLTF2::RenderMode::TRIANGLE_FAN:
208             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN;
209             break;
210         default:
211             // PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY
212             // would need to be handled with line_strip with some additions
213             ia.primitiveTopology = PrimitiveTopology::CORE_PRIMITIVE_TOPOLOGY_MAX_ENUM;
214             break;
215     }
216     return ia;
217 }
218 
ConvertNormalizedDataToFloat(GLTF2::GLTFLoadDataResult const & result,float * destination,size_t dstComponentCount=0,float paddingValue=0.0f,float scale=0.f)219 void ConvertNormalizedDataToFloat(GLTF2::GLTFLoadDataResult const& result, float* destination,
220     size_t dstComponentCount = 0, float paddingValue = 0.0f, float scale = 0.f)
221 {
222     uint8_t const* source = reinterpret_cast<const uint8_t*>(result.data.data());
223 
224     if (dstComponentCount == 0) {
225         // By default, use the source component count.
226         dstComponentCount = result.componentCount;
227     }
228 
229     CORE_ASSERT_MSG(dstComponentCount >= result.componentCount,
230         "Padding count cannot be negative. Make sure expected component count is equal or greater than source "
231         "component count.");
232 
233     // Amount of padding.
234     const size_t paddingCount = dstComponentCount - result.componentCount;
235 
236     for (size_t i = 0; i < result.elementCount; ++i) {
237         for (size_t j = 0; j < result.componentCount; ++j) {
238             switch (result.componentType) {
239                 case GLTF2::ComponentType::BYTE:
240                     *destination = std::max((reinterpret_cast<const int8_t*>(source))[j] / 127.0f, -1.0f);
241                     break;
242 
243                 case GLTF2::ComponentType::UNSIGNED_BYTE:
244                     *destination = source[j] / 255.0f;
245                     break;
246 
247                 case GLTF2::ComponentType::SHORT:
248                     *destination = std::max(
249                         (reinterpret_cast<const int16_t*>(source))[j] / ((scale != 0.f) ? scale : 32767.0f), -1.0f);
250                     break;
251 
252                 case GLTF2::ComponentType::UNSIGNED_SHORT:
253                     *destination = (reinterpret_cast<const uint16_t*>(source))[j] / 65535.0f;
254                     break;
255 
256                 case GLTF2::ComponentType::FLOAT: {
257                     *destination = (reinterpret_cast<const float*>(reinterpret_cast<uintptr_t>(source)))[j];
258                     break;
259                 }
260 
261                 default:
262                 case GLTF2::ComponentType::UNSIGNED_INT:
263                 case GLTF2::ComponentType::INT:
264                     CORE_ASSERT(false);
265                     *destination = 0.0f;
266                     break;
267             }
268 
269             destination++;
270         }
271 
272         // Apply padding.
273         for (size_t padding = 0; padding < paddingCount; ++padding) {
274             *destination = paddingValue;
275             destination++;
276         }
277 
278         source += result.elementSize;
279     }
280 }
281 
ConvertDataToFloat(GLTF2::GLTFLoadDataResult const & result,float * destination,size_t dstComponentCount=0,float paddingValue=0.0f,float scale=0.f)282 void ConvertDataToFloat(GLTF2::GLTFLoadDataResult const& result, float* destination, size_t dstComponentCount = 0,
283     float paddingValue = 0.0f, float scale = 0.f)
284 {
285     uint8_t const* source = reinterpret_cast<const uint8_t*>(result.data.data());
286 
287     if (dstComponentCount == 0) {
288         // By default, use the source component count.
289         dstComponentCount = result.componentCount;
290     }
291 
292     CORE_ASSERT_MSG(dstComponentCount >= result.componentCount,
293         "Padding count cannot be negative. Make sure expected component count is equal or greater than source "
294         "component count.");
295 
296     // Amount of padding.
297     const size_t paddingCount = dstComponentCount - result.componentCount;
298 
299     for (size_t i = 0; i < result.elementCount; ++i) {
300         for (size_t j = 0; j < result.componentCount; ++j) {
301             switch (result.componentType) {
302                 case GLTF2::ComponentType::BYTE:
303                     *destination = reinterpret_cast<const int8_t*>(source)[j];
304                     break;
305 
306                 case GLTF2::ComponentType::UNSIGNED_BYTE:
307                     *destination = source[j];
308                     break;
309 
310                 case GLTF2::ComponentType::SHORT:
311                     *destination = reinterpret_cast<const int16_t*>(source)[j];
312                     break;
313 
314                 case GLTF2::ComponentType::UNSIGNED_SHORT:
315                     *destination = reinterpret_cast<const uint16_t*>(source)[j];
316                     break;
317 
318                 case GLTF2::ComponentType::FLOAT: {
319                     *destination = (reinterpret_cast<const float*>(reinterpret_cast<uintptr_t>(source)))[j];
320                     break;
321                 }
322 
323                 default:
324                 case GLTF2::ComponentType::UNSIGNED_INT:
325                 case GLTF2::ComponentType::INT:
326                     CORE_ASSERT(false);
327                     *destination = 0.0f;
328                     break;
329             }
330 
331             destination++;
332         }
333 
334         // Apply padding.
335         for (size_t padding = 0; padding < paddingCount; ++padding) {
336             *destination = paddingValue;
337             destination++;
338         }
339 
340         source += result.elementSize;
341     }
342 }
343 
ConvertDataToBool(GLTF2::GLTFLoadDataResult const & result,bool * destination)344 void ConvertDataToBool(GLTF2::GLTFLoadDataResult const& result, bool* destination)
345 {
346     uint8_t const* source = reinterpret_cast<const uint8_t*>(result.data.data());
347 
348     for (size_t i = 0; i < result.elementCount; ++i) {
349         for (size_t j = 0; j < result.componentCount; ++j) {
350             switch (result.componentType) {
351                 case GLTF2::ComponentType::BYTE:
352                     *destination = reinterpret_cast<const int8_t*>(source)[j] != 0;
353                     break;
354 
355                 case GLTF2::ComponentType::UNSIGNED_BYTE:
356                     *destination = source[j] != 0u;
357                     break;
358 
359                 case GLTF2::ComponentType::SHORT:
360                     *destination = reinterpret_cast<const int16_t*>(source)[j] != 0;
361                     break;
362 
363                 case GLTF2::ComponentType::UNSIGNED_SHORT:
364                     *destination = reinterpret_cast<const uint16_t*>(source)[j] != 0u;
365                     break;
366 
367                 case GLTF2::ComponentType::FLOAT: {
368                     *destination = reinterpret_cast<const float*>(reinterpret_cast<uintptr_t>(source))[j] != 0.f;
369                     break;
370                 }
371 
372                 default:
373                 case GLTF2::ComponentType::UNSIGNED_INT:
374                 case GLTF2::ComponentType::INT:
375                     CORE_ASSERT(false);
376                     *destination = false;
377                     break;
378             }
379 
380             destination++;
381         }
382 
383         source += result.elementSize;
384     }
385 }
386 
GetImportedTextureHandle(const GLTFImportResult & importResult,uint32_t index)387 EntityReference GetImportedTextureHandle(const GLTFImportResult& importResult, uint32_t index)
388 {
389     if (index != GLTF2::GLTF_INVALID_INDEX && index < importResult.data.textures.size()) {
390         return importResult.data.textures[index];
391     }
392 
393     return EntityReference();
394 }
395 
GetImageExtension(GLTF2::MimeType type)396 string_view GetImageExtension(GLTF2::MimeType type)
397 {
398     switch (type) {
399         case GLTF2::MimeType::JPEG:
400             return "jpg";
401         case GLTF2::MimeType::PNG:
402             return "png";
403         case GLTF2::MimeType::KTX:
404             return "ktx";
405         case GLTF2::MimeType::DDS:
406             return "dds";
407 
408         case GLTF2::MimeType::INVALID:
409         default:
410             return "";
411     }
412 }
413 
ConvertToCoreLightType(GLTF2::LightType lightType)414 LightComponent::Type ConvertToCoreLightType(GLTF2::LightType lightType)
415 {
416     switch (lightType) {
417         case GLTF2::LightType::DIRECTIONAL:
418             return LightComponent::Type::DIRECTIONAL;
419 
420         case GLTF2::LightType::POINT:
421             return LightComponent::Type::POINT;
422 
423         case GLTF2::LightType::SPOT:
424             return LightComponent::Type::SPOT;
425 
426         default:
427         case GLTF2::LightType::INVALID:
428         case GLTF2::LightType::AMBIENT:
429             return LightComponent::Type::DIRECTIONAL;
430     }
431 }
432 
433 struct GatherMeshDataResult {
434     GatherMeshDataResult() = default;
435     ~GatherMeshDataResult() = default;
436     GatherMeshDataResult(const GatherMeshDataResult& aOther) = delete;
GatherMeshDataResult__anonf7ef52ed0111::GatherMeshDataResult437     explicit GatherMeshDataResult(const string& error) : success(false), error(error) {}
GatherMeshDataResult__anonf7ef52ed0111::GatherMeshDataResult438     GatherMeshDataResult(GatherMeshDataResult&& other) noexcept
439         : success(other.success), error(move(other.error)), meshBuilder(move(other.meshBuilder))
440     {}
441 
operator =__anonf7ef52ed0111::GatherMeshDataResult442     GatherMeshDataResult& operator=(GatherMeshDataResult&& other) noexcept
443     {
444         success = other.success;
445         error = move(other.error);
446         meshBuilder = move(other.meshBuilder);
447         return *this;
448     }
449 
450     /** Indicates, whether the load operation is successful. */
451     bool success { true };
452 
453     /** In case of import error, contains the description of the error. */
454     string error;
455 
456     BASE_NS::refcnt_ptr<MeshBuilder> meshBuilder;
457 };
458 
ConvertLoadResultToFloat(GLTF2::GLTFLoadDataResult & data,float scale=0.f)459 void ConvertLoadResultToFloat(GLTF2::GLTFLoadDataResult& data, float scale = 0.f)
460 {
461     vector<uint8_t> converted;
462     auto const componentCount = data.elementCount * data.componentCount;
463     converted.resize(componentCount * sizeof(float));
464     if (data.normalized) {
465         ConvertNormalizedDataToFloat(data, reinterpret_cast<float*>(converted.data()), 0u, 0.f, scale);
466     } else {
467         ConvertDataToFloat(data, reinterpret_cast<float*>(converted.data()), 0u, 0.f, scale);
468     }
469 
470     data.componentType = GLTF2::ComponentType::FLOAT;
471     data.componentByteSize = sizeof(float);
472     data.elementSize = data.componentByteSize * data.componentCount;
473     data.data = move(converted);
474 }
475 
476 template<typename T>
Validate(GLTF2::GLTFLoadDataResult & indices,uint32_t vertexCount,bool & primitiveRestart)477 void Validate(GLTF2::GLTFLoadDataResult& indices, uint32_t vertexCount, bool& primitiveRestart)
478 {
479     const auto elementCount = Math::min(indices.elementCount, indices.data.size_in_bytes() / sizeof(T));
480     auto source = array_view(static_cast<const T*>(static_cast<const void*>(indices.data.data())), elementCount);
481     primitiveRestart = false;
482     if (std::any_of(source.begin(), source.end(), [vertexCount, &primitiveRestart](const auto& value) {
483             // spec prohibits "maximum possible value for component type", but still some models use it for primitive
484             // restart.
485             if (value == std::numeric_limits<T>::max()) {
486                 primitiveRestart = true;
487                 return false;
488             }
489             return (value >= vertexCount);
490         })) {
491         indices.success = false;
492         indices.error += "Indices out-of-range.\n";
493     }
494 }
495 
ValidateIndices(GLTF2::GLTFLoadDataResult & indices,uint32_t vertexCount,bool & primitiveRestart)496 void ValidateIndices(GLTF2::GLTFLoadDataResult& indices, uint32_t vertexCount, bool& primitiveRestart)
497 {
498     switch (indices.componentType) {
499         case GLTF2::ComponentType::UNSIGNED_BYTE: {
500             Validate<uint8_t>(indices, vertexCount, primitiveRestart);
501             break;
502         }
503         case GLTF2::ComponentType::UNSIGNED_SHORT: {
504             Validate<uint16_t>(indices, vertexCount, primitiveRestart);
505             break;
506         }
507         case GLTF2::ComponentType::UNSIGNED_INT: {
508             Validate<uint32_t>(indices, vertexCount, primitiveRestart);
509             break;
510         }
511 
512         default:
513         case GLTF2::ComponentType::BYTE:
514         case GLTF2::ComponentType::SHORT:
515         case GLTF2::ComponentType::FLOAT:
516         case GLTF2::ComponentType::INT:
517             indices.success = false;
518             indices.error += "Invalid componentType for indices.\n";
519             CORE_ASSERT(false);
520             break;
521     }
522 }
523 
LoadPrimitiveAttributeData(const GLTF2::MeshPrimitive & primitive,GLTF2::GLTFLoadDataResult & positions,GLTF2::GLTFLoadDataResult & normals,array_view<GLTF2::GLTFLoadDataResult> texcoords,GLTF2::GLTFLoadDataResult & tangents,GLTF2::GLTFLoadDataResult & joints,GLTF2::GLTFLoadDataResult & weights,GLTF2::GLTFLoadDataResult & colors,const uint32_t & flags)524 bool LoadPrimitiveAttributeData(const GLTF2::MeshPrimitive& primitive, GLTF2::GLTFLoadDataResult& positions,
525     GLTF2::GLTFLoadDataResult& normals, array_view<GLTF2::GLTFLoadDataResult> texcoords,
526     GLTF2::GLTFLoadDataResult& tangents, GLTF2::GLTFLoadDataResult& joints, GLTF2::GLTFLoadDataResult& weights,
527     GLTF2::GLTFLoadDataResult& colors, const uint32_t& flags)
528 {
529     bool success = true;
530     for (const auto& attribute : primitive.attributes) {
531         if ((attribute.attribute.type != GLTF2::AttributeType::TEXCOORD && attribute.attribute.index > 0) ||
532             (attribute.attribute.type == GLTF2::AttributeType::TEXCOORD &&
533                 attribute.attribute.index >= texcoords.size())) {
534             continue;
535         }
536 
537         GLTF2::GLTFLoadDataResult loadDataResult = GLTF2::LoadData(*attribute.accessor);
538         success = success && loadDataResult.success;
539         switch (attribute.attribute.type) {
540             case GLTF2::AttributeType::POSITION:
541                 positions = move(loadDataResult);
542                 break;
543 
544             case GLTF2::AttributeType::NORMAL:
545                 normals = move(loadDataResult);
546                 break;
547 
548             case GLTF2::AttributeType::TEXCOORD:
549                 texcoords[attribute.attribute.index] = move(loadDataResult);
550                 break;
551 
552             case GLTF2::AttributeType::TANGENT:
553                 tangents = move(loadDataResult);
554                 break;
555 
556             case GLTF2::AttributeType::JOINTS:
557                 if (flags & CORE_GLTF_IMPORT_RESOURCE_SKIN) {
558                     joints = move(loadDataResult);
559                 }
560                 break;
561 
562             case GLTF2::AttributeType::WEIGHTS:
563                 if (flags & CORE_GLTF_IMPORT_RESOURCE_SKIN) {
564                     weights = move(loadDataResult);
565                 }
566                 break;
567 
568             case GLTF2::AttributeType::COLOR:
569                 colors = move(loadDataResult);
570                 break;
571 
572             case GLTF2::AttributeType::INVALID:
573             default:
574                 break;
575         }
576     }
577     return success;
578 }
579 
ProcessMorphTargetData(const IMeshBuilder::Submesh & importInfo,size_t targets,GLTF2::GLTFLoadDataResult & loadDataResult,GLTF2::GLTFLoadDataResult & finalDataResult)580 void ProcessMorphTargetData(const IMeshBuilder::Submesh& importInfo, size_t targets,
581     GLTF2::GLTFLoadDataResult& loadDataResult, GLTF2::GLTFLoadDataResult& finalDataResult)
582 {
583 #if !defined(GLTF2_EXTENSION_KHR_MESH_QUANTIZATION)
584     // Spec says POSITION,NORMAL and TANGENT must be FLOAT & VEC3
585     // NOTE: ASSERT for now, if the types don't match, they need to be converted. (or we should fail
586     // since out-of-spec)
587     CORE_ASSERT(loadDataResult.componentType == GLTF2::ComponentType::FLOAT);
588     CORE_ASSERT(loadDataResult.componentCount == 3U);
589     CORE_ASSERT(loadDataResult.elementCount == importInfo.vertexCount);
590 #endif
591     if (finalDataResult.componentCount > 0U) {
592         finalDataResult.data.append(loadDataResult.data.begin(), loadDataResult.data.end());
593         for (size_t i = 0; i < finalDataResult.min.size(); i++) {
594             finalDataResult.min[i] = std::min(finalDataResult.min[i], loadDataResult.min[i]);
595         }
596         for (size_t i = 0; i < finalDataResult.max.size(); i++) {
597             finalDataResult.max[i] = std::max(finalDataResult.max[i], loadDataResult.max[i]);
598         }
599     } else {
600         finalDataResult = move(loadDataResult);
601         finalDataResult.data.reserve(finalDataResult.data.size() * targets);
602     }
603 }
604 
GenerateMorphTargets(const GLTF2::MeshPrimitive & primitive,const IMeshBuilder::Submesh & importInfo,GLTF2::GLTFLoadDataResult & targetPositions,GLTF2::GLTFLoadDataResult & targetNormals,GLTF2::GLTFLoadDataResult & targetTangents)605 void GenerateMorphTargets(const GLTF2::MeshPrimitive& primitive, const IMeshBuilder::Submesh& importInfo,
606     GLTF2::GLTFLoadDataResult& targetPositions, GLTF2::GLTFLoadDataResult& targetNormals,
607     GLTF2::GLTFLoadDataResult& targetTangents)
608 {
609     // All targets collected to single buffer.
610     for (const auto& target : primitive.targets) {
611         for (const auto& targetAttribute : target.target) {
612             GLTF2::GLTFLoadDataResult loadDataResult = GLTF2::LoadData(*targetAttribute.accessor);
613             if (loadDataResult.success) {
614                 switch (targetAttribute.attribute.type) {
615                     case GLTF2::AttributeType::POSITION:
616 #if defined(GLTF2_EXTENSION_IGFX_COMPRESSED)
617                         // This is for the IGFX_compressed extension. Morph target offsets were multiplied by 10000(!)
618                         // and cast to int16.
619                         if (target.iGfxCompressed && loadDataResult.componentType == GLTF2::ComponentType::SHORT) {
620                             loadDataResult.normalized = true;
621                             ConvertLoadResultToFloat(loadDataResult, 10000.f);
622                         }
623 #endif
624                         ProcessMorphTargetData(importInfo, primitive.targets.size(), loadDataResult, targetPositions);
625                         break;
626 
627                     case GLTF2::AttributeType::NORMAL:
628                         ProcessMorphTargetData(importInfo, primitive.targets.size(), loadDataResult, targetNormals);
629                         break;
630 
631                     case GLTF2::AttributeType::TANGENT:
632                         ProcessMorphTargetData(importInfo, primitive.targets.size(), loadDataResult, targetTangents);
633                         break;
634 
635                     case GLTF2::AttributeType::TEXCOORD:
636                     case GLTF2::AttributeType::JOINTS:
637                     case GLTF2::AttributeType::WEIGHTS:
638                     case GLTF2::AttributeType::COLOR:
639                     case GLTF2::AttributeType::INVALID:
640                     default:
641                         // NOTE: Technically there could be custom attributes, but those are not supported at all
642                         // currently!
643                         break;
644                 }
645             }
646         }
647     }
648 }
649 
GetPrimitiveIndexType(const GLTF2::MeshPrimitive & primitive)650 IndexType GetPrimitiveIndexType(const GLTF2::MeshPrimitive& primitive)
651 {
652     switch (primitive.indices->componentType) {
653         case GLTF2::ComponentType::UNSIGNED_BYTE:
654             return CORE_INDEX_TYPE_UINT16;
655 
656         case GLTF2::ComponentType::UNSIGNED_SHORT:
657             return CORE_INDEX_TYPE_UINT16;
658 
659         case GLTF2::ComponentType::UNSIGNED_INT:
660             return CORE_INDEX_TYPE_UINT32;
661 
662         case GLTF2::ComponentType::INVALID:
663         case GLTF2::ComponentType::BYTE:
664         case GLTF2::ComponentType::SHORT:
665         case GLTF2::ComponentType::INT:
666         case GLTF2::ComponentType::FLOAT:
667             break;
668         default:
669             break;
670     }
671 
672     CORE_ASSERT_MSG(false, "Not supported index type.");
673 
674     return CORE_INDEX_TYPE_UINT32;
675 }
676 
ContainsAttribute(const GLTF2::MeshPrimitive & primitive,GLTF2::AttributeType type)677 bool ContainsAttribute(const GLTF2::MeshPrimitive& primitive, GLTF2::AttributeType type)
678 {
679     return std::any_of(primitive.attributes.begin(), primitive.attributes.end(),
680         [type](const GLTF2::Attribute& attribute) { return attribute.attribute.type == type; });
681 }
682 
CreatePrimitiveImportInfo(const GLTFImportResult & importResult,const IMaterialComponentManager & materialManager,const GLTF2::MeshPrimitive & primitive)683 IMeshBuilder::Submesh CreatePrimitiveImportInfo(const GLTFImportResult& importResult,
684     const IMaterialComponentManager& materialManager, const GLTF2::MeshPrimitive& primitive)
685 {
686     IMeshBuilder::Submesh info;
687     bool hasNormalMap = false;
688 
689     // Get material, if one assigned.
690     if (primitive.materialIndex != GLTF2::GLTF_INVALID_INDEX &&
691         primitive.materialIndex < importResult.data.materials.size()) {
692         info.material = importResult.data.materials[primitive.materialIndex];
693         hasNormalMap = (primitive.material->normalTexture.textureInfo.index != GLTF2::GLTF_INVALID_INDEX ||
694                         primitive.material->clearcoat.normalTexture.textureInfo.index != GLTF2::GLTF_INVALID_INDEX);
695     }
696 
697     info.colors = ContainsAttribute(primitive, GLTF2::AttributeType::COLOR);
698     info.joints = ContainsAttribute(primitive, GLTF2::AttributeType::JOINTS);
699     info.tangents = ContainsAttribute(primitive, GLTF2::AttributeType::TANGENT);
700     if (!info.tangents) {
701         // If material has normal map assigned, then always make sure that we have normals.
702         info.tangents = hasNormalMap;
703     }
704 
705     if (!info.tangents) {
706         // NOTE. Currenty morph render node always writes tangent data to output buffer.
707         // Therefore we must have tangents defined for this primitive.
708         info.tangents = primitive.targets.size() > 0;
709     }
710     if (const auto pos = std::find_if(primitive.attributes.begin(), primitive.attributes.end(),
711         [](const GLTF2::Attribute& attribute) {
712             return attribute.attribute.type == GLTF2::AttributeType::POSITION;
713         });
714         pos != primitive.attributes.end()) {
715         info.vertexCount = pos->accessor->count;
716     }
717 
718     if (primitive.indices) {
719         info.indexCount = primitive.indices->count;
720         info.indexType = GetPrimitiveIndexType(primitive);
721     }
722 
723     info.morphTargetCount = (uint32_t)primitive.targets.size();
724 
725     // setting values only for the ones which do not use default
726     if (primitive.mode != GLTF2::DEFAULT_RENDER_MODE) {
727         info.inputAssembly = ConvertGltf2InputAssembly(primitive.mode);
728     }
729 
730     return info;
731 }
732 
GatherErrorStrings(size_t primitiveIndex,const GLTF2::GLTFLoadDataResult & position,const GLTF2::GLTFLoadDataResult & normal,array_view<const GLTF2::GLTFLoadDataResult> texcoords,const GLTF2::GLTFLoadDataResult & tangent,const GLTF2::GLTFLoadDataResult & color,const GLTF2::GLTFLoadDataResult & joint,const GLTF2::GLTFLoadDataResult & weight)733 string GatherErrorStrings(size_t primitiveIndex, const GLTF2::GLTFLoadDataResult& position,
734     const GLTF2::GLTFLoadDataResult& normal, array_view<const GLTF2::GLTFLoadDataResult> texcoords,
735     const GLTF2::GLTFLoadDataResult& tangent, const GLTF2::GLTFLoadDataResult& color,
736     const GLTF2::GLTFLoadDataResult& joint, const GLTF2::GLTFLoadDataResult& weight)
737 {
738     string error = "Failed to load primitive " + to_string(primitiveIndex) + '\n' + position.error + normal.error;
739     for (const auto& tc : texcoords) {
740         error += tc.error;
741     }
742     error += tangent.error + color.error + joint.error + weight.error + '\n';
743     return error;
744 }
745 
746 struct IndicesResult {
747     GLTF2::GLTFLoadDataResult loadDataResult;
748     bool primitiveRestart { false };
749 };
750 
LoadIndices(GatherMeshDataResult & result,const GLTF2::MeshPrimitive & primitive,IndexType indexType,uint32_t loadedVertexCount)751 IndicesResult LoadIndices(GatherMeshDataResult& result, const GLTF2::MeshPrimitive& primitive, IndexType indexType,
752     uint32_t loadedVertexCount)
753 {
754     IndicesResult indicesLoadResult;
755     GLTF2::GLTFLoadDataResult loadDataResult;
756     if (primitive.indices) {
757         if (indicesLoadResult.loadDataResult = LoadData(*primitive.indices); indicesLoadResult.loadDataResult.success) {
758             ValidateIndices(indicesLoadResult.loadDataResult, loadedVertexCount, indicesLoadResult.primitiveRestart);
759         }
760         if (!indicesLoadResult.loadDataResult.success) {
761             result.error += indicesLoadResult.loadDataResult.error;
762             result.success = false;
763             indicesLoadResult.loadDataResult = {};
764         }
765     }
766     return indicesLoadResult;
767 }
768 
ProcessPrimitives(GatherMeshDataResult & result,uint32_t flags,array_view<const GLTF2::MeshPrimitive> primitives)769 void ProcessPrimitives(GatherMeshDataResult& result, uint32_t flags, array_view<const GLTF2::MeshPrimitive> primitives)
770 {
771     // Feed primitive data for builder.
772     for (size_t primitiveIndex = 0, count = primitives.size(); primitiveIndex < count; ++primitiveIndex) {
773         const auto& primitive = primitives[primitiveIndex];
774         const auto& importInfo = result.meshBuilder->GetSubmesh(primitiveIndex);
775 
776         // Load data.
777         GLTF2::GLTFLoadDataResult position, normal, tangent, color, joint, weight;
778         GLTF2::GLTFLoadDataResult texcoords[2];
779         if (!LoadPrimitiveAttributeData(primitive, position, normal, texcoords, tangent, joint, weight, color, flags)) {
780             result.error +=
781                 GatherErrorStrings(primitiveIndex, position, normal, texcoords, tangent, color, joint, weight);
782             result.success = false;
783             break;
784         }
785 
786         uint32_t const loadedVertexCount = static_cast<uint32_t>(position.elementCount);
787 
788         auto fillDataBuffer = [](GLTF2::GLTFLoadDataResult& attribute) {
789             return IMeshBuilder::DataBuffer {
790                 Convert(attribute.componentType, attribute.componentCount, attribute.normalized),
791                 static_cast<uint32_t>(attribute.elementSize),
792                 attribute.data,
793             };
794         };
795         const IMeshBuilder::DataBuffer positions = fillDataBuffer(position);
796         const IMeshBuilder::DataBuffer normals = fillDataBuffer(normal);
797         const IMeshBuilder::DataBuffer texcoords0 = fillDataBuffer(texcoords[0]);
798         const IMeshBuilder::DataBuffer texcoords1 = fillDataBuffer(texcoords[1]);
799         const IMeshBuilder::DataBuffer tangents = fillDataBuffer(tangent);
800         const IMeshBuilder::DataBuffer colors = fillDataBuffer(color);
801 
802         result.meshBuilder->SetVertexData(primitiveIndex, positions, normals, texcoords0, texcoords1, tangents, colors);
803 
804         // Process indices.
805         IndicesResult indices = LoadIndices(result, primitive, importInfo.indexType, loadedVertexCount);
806         if (!indices.loadDataResult.data.empty()) {
807             const auto elementSize = indices.loadDataResult.elementSize;
808             const IMeshBuilder::DataBuffer data {
809                 (elementSize == sizeof(uint32_t))
810                     ? BASE_FORMAT_R32_UINT
811                     : ((elementSize == sizeof(uint16_t)) ? BASE_FORMAT_R16_UINT : BASE_FORMAT_R8_UINT),
812                 static_cast<uint32_t>(elementSize), { indices.loadDataResult.data }
813             };
814             result.meshBuilder->SetIndexData(primitiveIndex, data);
815             if (indices.primitiveRestart) {
816                 result.meshBuilder->EnablePrimitiveRestart(primitiveIndex);
817             }
818         }
819 
820         // Set AABB.
821         if (position.min.size() == 3 && position.max.size() == 3) { // 3: size
822             const Math::Vec3 min = { position.min[0], position.min[1], position.min[2] };
823             const Math::Vec3 max = { position.max[0], position.max[1], position.max[2] };
824             result.meshBuilder->SetAABB(primitiveIndex, min, max);
825         } else {
826             result.meshBuilder->CalculateAABB(primitiveIndex, positions);
827         }
828 
829         // Process joints.
830         if (!joint.data.empty() && (flags & CORE_GLTF_IMPORT_RESOURCE_SKIN)) {
831             const IMeshBuilder::DataBuffer joints = fillDataBuffer(joint);
832             const IMeshBuilder::DataBuffer weights = fillDataBuffer(weight);
833             result.meshBuilder->SetJointData(primitiveIndex, joints, weights, positions);
834         }
835         // Process morphs.
836         if (primitive.targets.size()) {
837             GLTF2::GLTFLoadDataResult targetPosition, targetNormal, targetTangent;
838             GenerateMorphTargets(primitive, importInfo, targetPosition, targetNormal, targetTangent);
839             const IMeshBuilder::DataBuffer targetPositions = fillDataBuffer(targetPosition);
840             const IMeshBuilder::DataBuffer targetNormals = fillDataBuffer(targetNormal);
841             const IMeshBuilder::DataBuffer targetTangents = fillDataBuffer(targetTangent);
842 
843             result.meshBuilder->SetMorphTargetData(
844                 primitiveIndex, positions, normals, tangents, targetPositions, targetNormals, targetTangents);
845         }
846     }
847 }
848 
GatherMeshData(const GLTF2::Mesh & mesh,const GLTFImportResult & importResult,uint32_t flags,const IMaterialComponentManager & materialManager,const IDevice & device,IEngine & engine)849 GatherMeshDataResult GatherMeshData(const GLTF2::Mesh& mesh, const GLTFImportResult& importResult, uint32_t flags,
850     const IMaterialComponentManager& materialManager, const IDevice& device, IEngine& engine)
851 {
852     GatherMeshDataResult result;
853     auto context = GetInstance<IRenderContext>(*engine.GetInterface<IClassRegister>(), UID_RENDER_CONTEXT);
854     if (!context) {
855         result.success = false;
856         result.error = "RenderContext not found.";
857         return result;
858     }
859     auto& shaderManager = device.GetShaderManager();
860     const VertexInputDeclarationView vertexInputDeclaration =
861         shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
862             DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
863 
864     result.meshBuilder.reset(static_cast<MeshBuilder*>(CreateInstance<IMeshBuilder>(*context, UID_MESH_BUILDER).get()));
865     result.meshBuilder->Initialize(vertexInputDeclaration, mesh.primitives.size());
866 
867     // Create primitive import info for mesh builder.
868     for (const auto& primitive : mesh.primitives) {
869         // Add to builder.
870         result.meshBuilder->AddSubmesh(CreatePrimitiveImportInfo(importResult, materialManager, primitive));
871     }
872 
873     // Allocate memory for builder.
874     result.meshBuilder->Allocate();
875 
876     // Feed primitive data for builder.
877     ProcessPrimitives(result, flags, mesh.primitives);
878 
879     if (result.meshBuilder->GetVertexCount()) {
880         result.meshBuilder->CreateGpuResources();
881     }
882 
883     return result;
884 }
885 
ImportMesh(IEcs & ecs,const GatherMeshDataResult & gatherResult)886 Entity ImportMesh(IEcs& ecs, const GatherMeshDataResult& gatherResult)
887 {
888     // No vertices, which means we can't import mesh.
889     if (gatherResult.meshBuilder->GetVertexCount() == 0) {
890         return {};
891     }
892     auto meshEntity = gatherResult.meshBuilder->CreateMesh(ecs);
893     return meshEntity;
894 }
895 
ResolveNodePath(GLTF2::Node const & node)896 string ResolveNodePath(GLTF2::Node const& node)
897 {
898     string path;
899 
900     auto length = node.name.size();
901     GLTF2::Node* parent = node.parent;
902     while (parent) {
903         length += parent->name.size() + 1U;
904         parent = parent->parent;
905     }
906 
907     path.resize(length);
908     length -= node.name.size();
909     const auto begin = path.begin();
910     path.replace(begin + static_cast<string::difference_type>(length),
911         begin + static_cast<string::difference_type>(length + node.name.size()), node.name);
912 
913     parent = node.parent;
914     while (parent) {
915         length -= 1U;
916         path[length] = '/';
917         length -= parent->name.size();
918         path.replace(begin + static_cast<string::difference_type>(length),
919             begin + static_cast<string::difference_type>(length + parent->name.size()), parent->name);
920         parent = parent->parent;
921     }
922 
923     return path;
924 }
925 
BuildSkinIbmComponent(GLTF2::Skin const & skin,SkinIbmComponent & skinIbm)926 bool BuildSkinIbmComponent(GLTF2::Skin const& skin, SkinIbmComponent& skinIbm)
927 {
928     skinIbm.matrices.reserve(skin.joints.size());
929     bool failed = false;
930     bool useIdentityMatrix = true;
931     if (skin.inverseBindMatrices) {
932         GLTF2::GLTFLoadDataResult loadDataResult = GLTF2::LoadData(*skin.inverseBindMatrices);
933         if (loadDataResult.success) {
934             useIdentityMatrix = false;
935             auto ibls = array_view(
936                 reinterpret_cast<Math::Mat4X4 const*>(loadDataResult.data.data()), loadDataResult.elementCount);
937             skinIbm.matrices.append(ibls.begin(), ibls.end());
938         }
939     }
940     if (failed) {
941         return false;
942     }
943 
944     if (useIdentityMatrix) {
945         skinIbm.matrices.append(skin.joints.size(), Math::IDENTITY_4X4);
946     }
947 
948     return true;
949 }
950 
951 enum ImporterImageUsageFlags : uint32_t {
952     IMAGE_USAGE_BASE_COLOR_BIT = (1 << 1),
953     IMAGE_USAGE_METALLIC_ROUGHNESS_BIT = (1 << 2),
954     IMAGE_USAGE_NORMAL_BIT = (1 << 3),
955     IMAGE_USAGE_EMISSIVE_BIT = (1 << 4),
956     IMAGE_USAGE_OCCLUSION_BIT = (1 << 5),
957     IMAGE_USAGE_SPECULAR_GLOSSINESS_BIT = (1 << 6),
958     IMAGE_USAGE_CLEARCOAT_BIT = (1 << 7),
959     IMAGE_USAGE_CLEARCOAT_ROUGHNESS_BIT = (1 << 8),
960     IMAGE_USAGE_SHEEN_COLOR_BIT = (1 << 9),
961     IMAGE_USAGE_SHEEN_ROUGHNESS_BIT = (1 << 10),
962     IMAGE_USAGE_SPECULAR_BIT = (1 << 11),
963     IMAGE_USAGE_TRANSMISSION_BIT = (1 << 12),
964     IMAGE_USAGE_SINGLE_CHANNEL = IMAGE_USAGE_OCCLUSION_BIT | IMAGE_USAGE_TRANSMISSION_BIT
965 };
966 
operator ==(const GLTF2::TextureInfo & info,const GLTF2::Image & image)967 inline bool operator==(const GLTF2::TextureInfo& info, const GLTF2::Image& image) noexcept
968 {
969     return info.texture && info.texture->image == &image;
970 }
971 
BaseColorFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)972 inline void BaseColorFlags(
973     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
974 {
975     if (material.metallicRoughness.baseColorTexture == image) {
976         result |= (IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT |
977                    IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_PREMULTIPLY_ALPHA);
978         usage |= IMAGE_USAGE_BASE_COLOR_BIT;
979     }
980 }
981 
MetallicRoughnessFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)982 inline void MetallicRoughnessFlags(
983     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
984 {
985     if (material.metallicRoughness.metallicRoughnessTexture == image) {
986         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
987         usage |= IMAGE_USAGE_METALLIC_ROUGHNESS_BIT;
988     }
989 }
990 
NormalFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)991 inline void NormalFlags(const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
992 {
993     if (material.normalTexture.textureInfo == image) {
994         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
995         usage |= IMAGE_USAGE_NORMAL_BIT;
996     }
997 }
998 
EmissiveFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)999 inline void EmissiveFlags(const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1000 {
1001     if (material.emissiveTexture == image) {
1002         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT;
1003         usage |= IMAGE_USAGE_EMISSIVE_BIT;
1004     }
1005 }
1006 
OcclusionFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1007 inline void OcclusionFlags(
1008     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1009 {
1010     if (material.occlusionTexture.textureInfo == image) {
1011         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1012         usage |= IMAGE_USAGE_OCCLUSION_BIT;
1013     }
1014 }
1015 
1016 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_PBRSPECULARGLOSSINESS)
SpecularGlossinessFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1017 inline void SpecularGlossinessFlags(
1018     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1019 {
1020     if (material.specularGlossiness.specularGlossinessTexture == image) {
1021         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT;
1022         usage |= IMAGE_USAGE_SPECULAR_GLOSSINESS_BIT;
1023     }
1024 }
1025 #endif
1026 
1027 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_CLEARCOAT)
ClearcoatFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1028 inline void ClearcoatFlags(
1029     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1030 {
1031     if (material.clearcoat.texture == image) {
1032         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1033         usage |= IMAGE_USAGE_CLEARCOAT_BIT;
1034     }
1035 }
1036 
ClearcoatRoughnessFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1037 inline void ClearcoatRoughnessFlags(
1038     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1039 {
1040     if (material.clearcoat.roughnessTexture == image) {
1041         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1042         usage |= IMAGE_USAGE_CLEARCOAT_ROUGHNESS_BIT;
1043     }
1044 }
1045 
ClearcoatNormalFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1046 inline void ClearcoatNormalFlags(
1047     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1048 {
1049     if (material.clearcoat.normalTexture.textureInfo == image) {
1050         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1051         usage |= IMAGE_USAGE_NORMAL_BIT;
1052     }
1053 }
1054 #endif
1055 
1056 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SHEEN)
SheenFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1057 inline void SheenFlags(const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1058 {
1059     if (material.sheen.texture == image) {
1060         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT;
1061         usage |= IMAGE_USAGE_SHEEN_COLOR_BIT;
1062     }
1063 }
1064 
SheenRoughnessFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1065 inline void SheenRoughnessFlags(
1066     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1067 {
1068     if (material.sheen.roughnessTexture == image) {
1069         if (!(usage & IMAGE_USAGE_SHEEN_COLOR_BIT)) {
1070             result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1071         }
1072         usage |= IMAGE_USAGE_SHEEN_ROUGHNESS_BIT;
1073     }
1074 }
1075 #endif
1076 
1077 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SPECULAR)
SpecularColorFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1078 inline void SpecularColorFlags(
1079     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1080 {
1081     if (material.specular.colorTexture == image) {
1082         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT;
1083         usage |= IMAGE_USAGE_SPECULAR_BIT;
1084     }
1085 }
1086 
SpecularStrengthFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1087 inline void SpecularStrengthFlags(
1088     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1089 {
1090     if (material.specular.texture == image) {
1091         if (!(usage & IMAGE_USAGE_SPECULAR_BIT)) {
1092             result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1093         }
1094         usage |= IMAGE_USAGE_SPECULAR_BIT;
1095     }
1096 }
1097 #endif
1098 
1099 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_TRANSMISSION)
TransmissionFlags(const GLTF2::Material & material,const GLTF2::Image & image,uint32_t & result,uint32_t & usage)1100 inline void TransmissionFlags(
1101     const GLTF2::Material& material, const GLTF2::Image& image, uint32_t& result, uint32_t& usage)
1102 {
1103     if (material.transmission.texture == image) {
1104         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1105         usage |= IMAGE_USAGE_TRANSMISSION_BIT;
1106     }
1107 }
1108 #endif
1109 
ResolveImageLoadFlags(GLTF2::Image const & image,GLTF2::Data const & data,const ColorSpaceFlags colorSpaceFlags)1110 uint32_t ResolveImageLoadFlags(
1111     GLTF2::Image const& image, GLTF2::Data const& data, const ColorSpaceFlags colorSpaceFlags)
1112 {
1113     // Resolve whether image should be imported as SRGB or LINEAR.
1114     uint32_t result = 0;
1115     // Resolve in which parts of material this texture has been used.
1116     uint32_t usage = 0;
1117 
1118     // Generating mipmaps for all textures (if not already contained in the image).
1119     result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_GENERATE_MIPS;
1120 
1121     for (const auto& material : data.materials) {
1122         BaseColorFlags(*material, image, result, usage);
1123         MetallicRoughnessFlags(*material, image, result, usage);
1124         NormalFlags(*material, image, result, usage);
1125         EmissiveFlags(*material, image, result, usage);
1126         OcclusionFlags(*material, image, result, usage);
1127 
1128 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_PBRSPECULARGLOSSINESS)
1129         SpecularGlossinessFlags(*material, image, result, usage);
1130 #endif
1131 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_CLEARCOAT)
1132         ClearcoatFlags(*material, image, result, usage);
1133         ClearcoatRoughnessFlags(*material, image, result, usage);
1134         ClearcoatNormalFlags(*material, image, result, usage);
1135 #endif
1136 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SHEEN)
1137         SheenFlags(*material, image, result, usage);
1138         SheenRoughnessFlags(*material, image, result, usage);
1139 #endif
1140 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SPECULAR)
1141         SpecularColorFlags(*material, image, result, usage);
1142         SpecularStrengthFlags(*material, image, result, usage);
1143 #endif
1144 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_TRANSMISSION)
1145         TransmissionFlags(*material, image, result, usage);
1146 #endif
1147         // possible color space conversions
1148         if (colorSpaceFlags & ColorSpaceFlagBits::COLOR_SPACE_SRGB_AS_LINEAR_BIT) {
1149             // remove srgb
1150             result &= (~IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT);
1151             // add forcing of linear
1152             result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1153         }
1154     }
1155 
1156     // In case the texture is only used in occlusion channel, we can convert it to grayscale R8.
1157     if ((usage & (IMAGE_USAGE_SINGLE_CHANNEL)) && !(usage & ~(IMAGE_USAGE_SINGLE_CHANNEL))) {
1158         result |= IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_GRAYSCALE_BIT;
1159     }
1160 
1161     const bool isSRGB = result & IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_SRGB_BIT;
1162     const bool isLinear = result & IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1163     if (isSRGB && isLinear) {
1164         // In case the texture has both SRGB & LINEAR set, default to SRGB and print a warning.
1165         result &= ~IImageLoaderManager::ImageLoaderFlags::IMAGE_LOADER_FORCE_LINEAR_RGB_BIT;
1166 
1167         if (GLTF2::IsDataURI(image.uri)) {
1168             CORE_LOG_W("Unable to resolve color space for Image, defaulting to SRGB.");
1169         } else {
1170             CORE_LOG_W("Unable to resolve color space for Image %s, defaulting to SRGB.", image.uri.c_str());
1171         }
1172     }
1173 
1174     return result;
1175 }
1176 
ResolveSampler(GLTF2::Texture const & texture,GLTF2::Data const & data,GLTFImportResult const & importResult)1177 EntityReference ResolveSampler(
1178     GLTF2::Texture const& texture, GLTF2::Data const& data, GLTFImportResult const& importResult)
1179 {
1180     if (texture.sampler) {
1181         const size_t index = FindIndex(data.samplers, texture.sampler);
1182         if (index != GLTF2::GLTF_INVALID_INDEX) {
1183             return importResult.data.samplers[index];
1184         }
1185     }
1186 
1187     return {};
1188 }
1189 
ResolveSampler(const GLTF2::TextureInfo & textureInfo,GLTF2::Data const & data,GLTFImportResult const & importResult)1190 inline EntityReference ResolveSampler(
1191     const GLTF2::TextureInfo& textureInfo, GLTF2::Data const& data, GLTFImportResult const& importResult)
1192 {
1193     return textureInfo.texture ? ResolveSampler(*textureInfo.texture, data, importResult) : EntityReference {};
1194 }
1195 
1196 // Textures
GatherImageData(GLTF2::Image & image,GLTF2::Data const & data,IFileManager & fileManager,IImageLoaderManager & imageManager,uint32_t loadFlags,ColorSpaceFlags colorSpaceFlags)1197 IImageLoaderManager::LoadResult GatherImageData(GLTF2::Image& image, GLTF2::Data const& data, IFileManager& fileManager,
1198     IImageLoaderManager& imageManager, uint32_t loadFlags, ColorSpaceFlags colorSpaceFlags)
1199 {
1200     vector<uint8_t> raw;
1201 
1202     const GLTF2::BufferView* bufferView = image.bufferView;
1203 
1204     if (bufferView && image.type != GLTF2::MimeType::INVALID) {
1205         if (bufferView->data) {
1206             raw.append(image.bufferView->data, bufferView->data + bufferView->byteLength);
1207         }
1208     } else if (image.uri.size()) {
1209         auto extension = GetImageExtension(image.type);
1210         const auto result = GLTF2::LoadUri(image.uri, "image", data.filepath, fileManager, extension, raw);
1211         switch (result) {
1212             case GLTF2::URI_LOAD_FAILED_TO_DECODE_BASE64:
1213                 return IImageLoaderManager::LoadResult { false, "Base64 decoding failed.", nullptr };
1214 
1215             case GLTF2::URI_LOAD_FAILED_TO_READ_FILE:
1216                 return IImageLoaderManager::LoadResult { false, "Failed to read file.", nullptr };
1217 
1218             case GLTF2::URI_LOAD_FAILED_INVALID_MIME_TYPE:
1219                 return IImageLoaderManager::LoadResult { false, "Image data is not image type.", nullptr };
1220 
1221             default:
1222             case GLTF2::URI_LOAD_SUCCESS:
1223                 break;
1224         }
1225     }
1226 
1227     // Resolve image usage and determine flags.
1228     const uint32_t flags = ResolveImageLoadFlags(image, data, colorSpaceFlags) | loadFlags;
1229 
1230     array_view<const uint8_t> rawdata { raw };
1231     return imageManager.LoadImage(rawdata, flags);
1232 }
1233 
ResolveReferencedImages(GLTF2::Data const & data,vector<bool> & imageLoadingRequred)1234 void ResolveReferencedImages(GLTF2::Data const& data, vector<bool>& imageLoadingRequred)
1235 {
1236     // loader shouldn't add nullptrs to Data::textures or Texture::image, but checking still
1237     for (const auto& texture : data.textures) {
1238         if (!texture) {
1239             continue;
1240         }
1241         const size_t index = FindIndex(data.images, texture->image);
1242         if ((index != GLTF2::GLTF_INVALID_INDEX) && (texture->image)) {
1243             imageLoadingRequred[index] = true;
1244         }
1245     }
1246 
1247 #if defined(GLTF2_EXTENSION_EXT_LIGHTS_IMAGE_BASED)
1248     // Find image references from image based lights.
1249     for (const auto& light : data.imageBasedLights) {
1250         if (light && (light->skymapImage != GLTF2::GLTF_INVALID_INDEX) && (light->skymapImage < data.images.size()) &&
1251             (data.images[light->skymapImage])) {
1252             imageLoadingRequred[light->skymapImage] = true;
1253         }
1254         if (light && (light->specularCubeImage != GLTF2::GLTF_INVALID_INDEX) &&
1255             (light->specularCubeImage < data.images.size()) && (data.images[light->specularCubeImage])) {
1256             imageLoadingRequred[light->specularCubeImage] = true;
1257         }
1258     }
1259 #endif
1260 }
1261 
ConvertAnimationInterpolation(GLTF2::AnimationInterpolation mode)1262 AnimationTrackComponent::Interpolation ConvertAnimationInterpolation(GLTF2::AnimationInterpolation mode)
1263 {
1264     switch (mode) {
1265         case GLTF2::AnimationInterpolation::INVALID:
1266             CORE_ASSERT(false);
1267             break;
1268         case GLTF2::AnimationInterpolation::STEP:
1269             return AnimationTrackComponent::Interpolation::STEP;
1270         case GLTF2::AnimationInterpolation::LINEAR:
1271             return AnimationTrackComponent::Interpolation::LINEAR;
1272         case GLTF2::AnimationInterpolation::SPLINE:
1273             return AnimationTrackComponent::Interpolation::SPLINE;
1274         default:
1275             break;
1276     }
1277 
1278     return AnimationTrackComponent::Interpolation::LINEAR;
1279 }
1280 
1281 template<class T>
CopyFrames(GLTF2::GLTFLoadDataResult const & animationFrameDataResult,vector<T> & destination)1282 void CopyFrames(GLTF2::GLTFLoadDataResult const& animationFrameDataResult, vector<T>& destination)
1283 {
1284     destination.resize(animationFrameDataResult.elementCount);
1285     if (animationFrameDataResult.componentType == GLTF2::ComponentType::FLOAT) {
1286         CORE_ASSERT(animationFrameDataResult.elementSize == sizeof(T));
1287 
1288         const size_t dataSizeInBytes = animationFrameDataResult.elementSize * animationFrameDataResult.elementCount;
1289         if (!CloneData(destination.data(), destination.size() * sizeof(T), animationFrameDataResult.data.data(),
1290             dataSizeInBytes)) {
1291             CORE_LOG_E("Copying of raw framedata failed.");
1292         }
1293     } else {
1294         // Convert data.
1295         if (animationFrameDataResult.normalized) {
1296             ConvertNormalizedDataToFloat(animationFrameDataResult, reinterpret_cast<float*>(destination.data()));
1297         } else {
1298             ConvertDataToFloat(animationFrameDataResult, reinterpret_cast<float*>(destination.data()));
1299         }
1300     }
1301 }
1302 
1303 template<>
CopyFrames(GLTF2::GLTFLoadDataResult const & animationFrameDataResult,vector<bool> & destination)1304 void CopyFrames(GLTF2::GLTFLoadDataResult const& animationFrameDataResult, vector<bool>& destination)
1305 {
1306     destination.resize(animationFrameDataResult.elementCount);
1307     if (animationFrameDataResult.componentType == GLTF2::ComponentType::BYTE ||
1308         animationFrameDataResult.componentType == GLTF2::ComponentType::UNSIGNED_BYTE) {
1309         CORE_ASSERT(animationFrameDataResult.elementSize == sizeof(bool));
1310 
1311         const size_t dataSizeInBytes = animationFrameDataResult.elementSize * animationFrameDataResult.elementCount;
1312         if (!CloneData(destination.data(), destination.size() * sizeof(bool), animationFrameDataResult.data.data(),
1313             dataSizeInBytes)) {
1314             CORE_LOG_E("Copying of raw framedata failed.");
1315         }
1316     } else {
1317         // Convert data.
1318         ConvertDataToBool(animationFrameDataResult, destination.data());
1319     }
1320 }
1321 
BuildAnimationInput(GLTF2::Data const & data,IFileManager & fileManager,GLTF2::Accessor & inputAccessor,AnimationInputComponent & inputComponent)1322 bool BuildAnimationInput(GLTF2::Data const& data, IFileManager& fileManager, GLTF2::Accessor& inputAccessor,
1323     AnimationInputComponent& inputComponent)
1324 {
1325     const GLTF2::GLTFLoadDataResult animationInputDataResult = LoadData(inputAccessor);
1326     if (animationInputDataResult.success) {
1327         // Copy timestamps.
1328         inputComponent.timestamps.reserve(animationInputDataResult.elementCount);
1329         const float* timeStamps =
1330             reinterpret_cast<const float*>(reinterpret_cast<uintptr_t>(animationInputDataResult.data.data()));
1331         inputComponent.timestamps.append(timeStamps, timeStamps + animationInputDataResult.elementCount);
1332     }
1333 
1334     return animationInputDataResult.success;
1335 }
1336 
1337 template<typename ReadType>
AppendAnimationOutputData(uint64_t outputTypeHash,const GLTF2::GLTFLoadDataResult & animationOutputDataResult,AnimationOutputComponent & outputComponent)1338 void AppendAnimationOutputData(uint64_t outputTypeHash, const GLTF2::GLTFLoadDataResult& animationOutputDataResult,
1339     AnimationOutputComponent& outputComponent)
1340 {
1341     outputComponent.type = outputTypeHash;
1342     vector<ReadType> positions;
1343     CopyFrames(animationOutputDataResult, positions);
1344     const auto dataView = array_view(reinterpret_cast<const uint8_t*>(positions.data()), positions.size_in_bytes());
1345     outputComponent.data.append(dataView.cbegin(), dataView.cend());
1346 }
1347 
BuildAnimationOutput(GLTF2::Data const & data,IFileManager & fileManager,GLTF2::Accessor & outputAccessor,GLTF2::AnimationPath path,AnimationOutputComponent & outputComponent)1348 bool BuildAnimationOutput(GLTF2::Data const& data, IFileManager& fileManager, GLTF2::Accessor& outputAccessor,
1349     GLTF2::AnimationPath path, AnimationOutputComponent& outputComponent)
1350 {
1351     const GLTF2::GLTFLoadDataResult animationOutputDataResult = LoadData(outputAccessor);
1352     if (animationOutputDataResult.success) {
1353         switch (path) {
1354             case GLTF2::AnimationPath::TRANSLATION:
1355                 AppendAnimationOutputData<Math::Vec3>(PropertyType::VEC3_T, animationOutputDataResult, outputComponent);
1356                 break;
1357 
1358             case GLTF2::AnimationPath::ROTATION:
1359                 AppendAnimationOutputData<Math::Vec4>(PropertyType::QUAT_T, animationOutputDataResult, outputComponent);
1360                 break;
1361 
1362             case GLTF2::AnimationPath::SCALE:
1363                 AppendAnimationOutputData<Math::Vec3>(PropertyType::VEC3_T, animationOutputDataResult, outputComponent);
1364                 break;
1365 
1366             case GLTF2::AnimationPath::WEIGHTS:
1367                 AppendAnimationOutputData<float>(
1368                     PropertyType::FLOAT_VECTOR_T, animationOutputDataResult, outputComponent);
1369                 break;
1370 
1371             case GLTF2::AnimationPath::VISIBLE:
1372                 AppendAnimationOutputData<bool>(PropertyType::BOOL_T, animationOutputDataResult, outputComponent);
1373                 break;
1374 
1375             case GLTF2::AnimationPath::OPACITY:
1376                 AppendAnimationOutputData<float>(PropertyType::FLOAT_T, animationOutputDataResult, outputComponent);
1377                 break;
1378 
1379             case GLTF2::AnimationPath::INVALID:
1380             default:
1381                 CORE_LOG_W("Animation.channel.path type %d not implemented", static_cast<int>(path));
1382                 break;
1383         }
1384     }
1385 
1386     return animationOutputDataResult.success;
1387 }
1388 
1389 #if defined(GLTF2_EXTENSION_KHR_TEXTURE_TRANSFORM)
FillTextureTransform(const GLTF2::TextureInfo & textureInfo,MaterialComponent::TextureTransform & desc)1390 void FillTextureTransform(const GLTF2::TextureInfo& textureInfo, MaterialComponent::TextureTransform& desc)
1391 {
1392     const auto& transform = textureInfo.transform;
1393     desc.translation = transform.offset;
1394     desc.rotation = transform.rotation;
1395     desc.scale = transform.scale;
1396 }
1397 #endif
1398 
FillTextureParams(const GLTF2::TextureInfo & textureInfo,const GLTFImportResult & importResult,const GLTF2::Data & data,IEntityManager & entityManager,MaterialComponent & desc,MaterialComponent::TextureIndex index)1399 void FillTextureParams(const GLTF2::TextureInfo& textureInfo, const GLTFImportResult& importResult,
1400     const GLTF2::Data& data, IEntityManager& entityManager, MaterialComponent& desc,
1401     MaterialComponent::TextureIndex index)
1402 {
1403     desc.textures[index].image = GetImportedTextureHandle(importResult, textureInfo.index);
1404     if (textureInfo.texture) {
1405         desc.textures[index].sampler = ResolveSampler(*textureInfo.texture, data, importResult);
1406         desc.useTexcoordSetBit |= static_cast<uint32_t>((textureInfo.texCoordIndex == 1)) << index;
1407 #if defined(GLTF2_EXTENSION_KHR_TEXTURE_TRANSFORM)
1408         FillTextureTransform(textureInfo, desc.textures[index].transform);
1409 #endif
1410     }
1411 }
1412 
ImportTexture(const string_view uri,IImageContainer::Ptr image,IRenderDataStoreDefaultStaging & staging,IGpuResourceManager & gpuResourceManager)1413 RenderHandleReference ImportTexture(const string_view uri, IImageContainer::Ptr image,
1414     IRenderDataStoreDefaultStaging& staging, IGpuResourceManager& gpuResourceManager)
1415 {
1416     RenderHandleReference imageHandle;
1417     if (!image) {
1418         return imageHandle;
1419     }
1420     // return if image created already with the uri
1421     imageHandle = gpuResourceManager.GetImageHandle(uri);
1422     if (imageHandle) {
1423         return imageHandle;
1424     }
1425 
1426     const auto& imageDesc = image->GetImageDesc();
1427     const auto& subImageDescs = image->GetBufferImageCopies();
1428     const auto data = image->GetData();
1429 
1430     // Create image according to the image container's description. (expects that conversion handles everything)
1431     const GpuImageDesc gpuImageDesc = gpuResourceManager.CreateGpuImageDesc(imageDesc);
1432     imageHandle = gpuResourceManager.Create(uri, gpuImageDesc);
1433 
1434     if (imageHandle) {
1435         // Create buffer for uploading image data
1436         GpuBufferDesc gpuBufferDesc;
1437         gpuBufferDesc.usageFlags = BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT;
1438         gpuBufferDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1439                                             MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1440         gpuBufferDesc.engineCreationFlags =
1441             EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE |
1442             EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER |
1443             EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DEFERRED_DESTROY;
1444         gpuBufferDesc.byteSize = static_cast<uint32_t>(data.size_bytes());
1445         auto bufferHandle = gpuResourceManager.Create(gpuBufferDesc);
1446         // Ideally ImageLoader would decode directly to the buffer to save one copy.
1447         if (auto buffer = static_cast<uint8_t*>(gpuResourceManager.MapBufferMemory(bufferHandle)); buffer) {
1448             const auto count = Math::min(static_cast<uint32_t>(data.size_bytes()), gpuBufferDesc.byteSize);
1449             std::copy(data.data(), data.data() + count, buffer);
1450         }
1451         gpuResourceManager.UnmapBuffer(bufferHandle);
1452 
1453         // Gather copy operations for all the sub images (mip levels, cube faces)
1454         vector<BufferImageCopy> copies;
1455         copies.reserve(subImageDescs.size());
1456         for (const auto& subImageDesc : subImageDescs) {
1457             const BufferImageCopy bufferImageCopy {
1458                 subImageDesc.bufferOffset,      // bufferOffset
1459                 subImageDesc.bufferRowLength,   // bufferRowLength
1460                 subImageDesc.bufferImageHeight, // bufferImageHeight
1461                 {
1462                     CORE_IMAGE_ASPECT_COLOR_BIT,                                // imageAspectFlags
1463                     subImageDesc.mipLevel,                                      // mipLevel
1464                     0,                                                          // baseArrayLayer
1465                     subImageDesc.layerCount,                                    // layerCount
1466                 },                                                              // imageSubresource
1467                 {},                                                             // imageOffset
1468                 { subImageDesc.width, subImageDesc.height, subImageDesc.depth } // imageExtent
1469             };
1470             copies.push_back(bufferImageCopy);
1471         }
1472         staging.CopyBufferToImage(bufferHandle, imageHandle, copies);
1473     } else {
1474         CORE_LOG_W("Creating an import image failed (format:%u, width:%u, height:%u)",
1475             static_cast<uint32_t>(gpuImageDesc.format), gpuImageDesc.width, gpuImageDesc.height);
1476     }
1477     return imageHandle;
1478 }
1479 
FillMetallicRoughness(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1480 void FillMetallicRoughness(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1481     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1482 {
1483     desc.type = MaterialComponent::Type::METALLIC_ROUGHNESS;
1484     FillTextureParams(gltfMaterial.metallicRoughness.baseColorTexture, importResult, data, em, desc,
1485         MaterialComponent::TextureIndex::BASE_COLOR);
1486     desc.textures[MaterialComponent::TextureIndex::BASE_COLOR].factor = gltfMaterial.metallicRoughness.baseColorFactor;
1487 
1488     // Metallic-roughness.
1489     FillTextureParams(gltfMaterial.metallicRoughness.metallicRoughnessTexture, importResult, data, em, desc,
1490         MaterialComponent::TextureIndex::MATERIAL);
1491     desc.textures[MaterialComponent::TextureIndex::MATERIAL].factor.y = gltfMaterial.metallicRoughness.roughnessFactor;
1492     desc.textures[MaterialComponent::TextureIndex::MATERIAL].factor.z = gltfMaterial.metallicRoughness.metallicFactor;
1493 }
1494 
FillSpecularGlossiness(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1495 void FillSpecularGlossiness(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1496     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1497 {
1498     desc.type = MaterialComponent::Type::SPECULAR_GLOSSINESS;
1499 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_PBRSPECULARGLOSSINESS)
1500     FillTextureParams(gltfMaterial.specularGlossiness.diffuseTexture, importResult, data, em, desc,
1501         MaterialComponent::TextureIndex::BASE_COLOR);
1502     desc.textures[MaterialComponent::TextureIndex::BASE_COLOR].factor = gltfMaterial.specularGlossiness.diffuseFactor;
1503 
1504     // Glossiness.
1505     FillTextureParams(gltfMaterial.specularGlossiness.specularGlossinessTexture, importResult, data, em, desc,
1506         MaterialComponent::TextureIndex::MATERIAL);
1507     desc.textures[MaterialComponent::TextureIndex::MATERIAL].factor = { gltfMaterial.specularGlossiness.specularFactor,
1508         gltfMaterial.specularGlossiness.glossinessFactor };
1509 #endif
1510 }
1511 
FillUnlit(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1512 void FillUnlit(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1513     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1514 {
1515     desc.type = MaterialComponent::Type::UNLIT;
1516 
1517     FillTextureParams(gltfMaterial.metallicRoughness.baseColorTexture, importResult, data, em, desc,
1518         MaterialComponent::TextureIndex::BASE_COLOR);
1519     desc.textures[MaterialComponent::TextureIndex::BASE_COLOR].factor = gltfMaterial.metallicRoughness.baseColorFactor;
1520 }
1521 
FillClearcoat(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1522 void FillClearcoat(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1523     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1524 {
1525 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_CLEARCOAT) || defined(GLTF2_EXTRAS_CLEAR_COAT_MATERIAL)
1526     // Clearcoat.
1527     desc.textures[MaterialComponent::TextureIndex::CLEARCOAT].factor.x = gltfMaterial.clearcoat.factor;
1528     FillTextureParams(
1529         gltfMaterial.clearcoat.texture, importResult, data, em, desc, MaterialComponent::TextureIndex::CLEARCOAT);
1530     desc.textures[MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS].factor.y = gltfMaterial.clearcoat.roughness;
1531     FillTextureParams(gltfMaterial.clearcoat.roughnessTexture, importResult, data, em, desc,
1532         MaterialComponent::TextureIndex::CLEARCOAT_ROUGHNESS);
1533     FillTextureParams(gltfMaterial.clearcoat.normalTexture.textureInfo, importResult, data, em, desc,
1534         MaterialComponent::TextureIndex::CLEARCOAT_NORMAL);
1535     desc.textures[MaterialComponent::TextureIndex::CLEARCOAT_NORMAL].factor.x =
1536         gltfMaterial.clearcoat.normalTexture.scale;
1537 #endif
1538 }
1539 
FillIor(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1540 void FillIor(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1541     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1542 {
1543 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_IOR)
1544     // IOR.
1545     if (gltfMaterial.ior.ior != 1.5f) {
1546         auto reflectance = (gltfMaterial.ior.ior - 1.f) / (gltfMaterial.ior.ior + 1.f);
1547         desc.textures[MaterialComponent::TextureIndex::MATERIAL].factor.w = reflectance * reflectance;
1548     }
1549 #endif
1550 }
1551 
FillSheen(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1552 void FillSheen(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1553     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1554 {
1555 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SHEEN)
1556     // Sheen.
1557     desc.textures[MaterialComponent::TextureIndex::SHEEN].factor = Math::Vec4(gltfMaterial.sheen.factor, 0.f);
1558     FillTextureParams(gltfMaterial.sheen.texture, importResult, data, em, desc, MaterialComponent::TextureIndex::SHEEN);
1559     if (gltfMaterial.sheen.roughnessTexture.texture) {
1560         CORE_LOG_W("Sheen roughness mapping not supported by gltf2 importer");
1561     }
1562     // to sheen alpha
1563     desc.textures[MaterialComponent::TextureIndex::SHEEN].factor.w = gltfMaterial.sheen.roughness;
1564 #endif
1565 }
1566 
FillSpecular(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1567 void FillSpecular(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1568     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1569 {
1570 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_SPECULAR)
1571     // Specular.
1572     desc.textures[MaterialComponent::TextureIndex::SPECULAR].factor =
1573         Math::Vec4(gltfMaterial.specular.color, gltfMaterial.specular.factor);
1574     if (gltfMaterial.specular.texture.index != GLTF2::GLTF_INVALID_INDEX &&
1575         gltfMaterial.specular.colorTexture.index == GLTF2::GLTF_INVALID_INDEX) {
1576         FillTextureParams(
1577             gltfMaterial.specular.texture, importResult, data, em, desc, MaterialComponent::TextureIndex::SPECULAR);
1578     } else if (gltfMaterial.specular.texture.index == GLTF2::GLTF_INVALID_INDEX &&
1579                gltfMaterial.specular.colorTexture.index != GLTF2::GLTF_INVALID_INDEX) {
1580         FillTextureParams(gltfMaterial.specular.colorTexture, importResult, data, em, desc,
1581             MaterialComponent::TextureIndex::SPECULAR);
1582     } else if (gltfMaterial.specular.texture.index != gltfMaterial.specular.colorTexture.index) {
1583         CORE_LOG_W("Separate specular strength and color textures are not supported!");
1584         FillTextureParams(gltfMaterial.specular.colorTexture, importResult, data, em, desc,
1585             MaterialComponent::TextureIndex::SPECULAR);
1586     } else {
1587         FillTextureParams(gltfMaterial.specular.colorTexture, importResult, data, em, desc,
1588             MaterialComponent::TextureIndex::SPECULAR);
1589     }
1590 #endif
1591 }
1592 
FillTransmission(MaterialComponent & desc,const GLTFImportResult & importResult,const GLTF2::Data & data,const GLTF2::Material & gltfMaterial,IEntityManager & em)1593 void FillTransmission(MaterialComponent& desc, const GLTFImportResult& importResult, const GLTF2::Data& data,
1594     const GLTF2::Material& gltfMaterial, IEntityManager& em)
1595 {
1596 #if defined(GLTF2_EXTENSION_KHR_MATERIALS_TRANSMISSION)
1597     // Transmission.
1598     desc.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x = gltfMaterial.transmission.factor;
1599     FillTextureParams(
1600         gltfMaterial.transmission.texture, importResult, data, em, desc, MaterialComponent::TextureIndex::TRANSMISSION);
1601 #endif
1602 }
1603 
SelectShaders(MaterialComponent & desc,const GLTF2::Material & gltfMaterial,const GLTF2::GLTF2Importer::DefaultMaterialShaderData & dmShaderData)1604 void SelectShaders(MaterialComponent& desc, const GLTF2::Material& gltfMaterial,
1605     const GLTF2::GLTF2Importer::DefaultMaterialShaderData& dmShaderData)
1606 {
1607     // Shadow casting is removed from blend modes by default.
1608     // Transmission over writes the gltf material blend mode.
1609     if (desc.textures[MaterialComponent::TextureIndex::TRANSMISSION].factor.x > 0.0f) {
1610         desc.materialShader.shader = dmShaderData.blend.shader;
1611         // no support for double-sideness with default material and transmission
1612         desc.materialShader.graphicsState = dmShaderData.blend.gfxState;
1613         if (gltfMaterial.alphaMode == GLTF2::AlphaMode::BLEND) { // blending -> no shadows
1614             desc.materialLightingFlags &= (~MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT);
1615         }
1616     } else if (gltfMaterial.alphaMode == GLTF2::AlphaMode::BLEND) {
1617         desc.materialShader.shader = dmShaderData.blend.shader;
1618         desc.materialShader.graphicsState =
1619             gltfMaterial.doubleSided ? dmShaderData.blend.gfxStateDoubleSided : dmShaderData.blend.gfxState;
1620         desc.materialLightingFlags &= (~MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT);
1621     } else {
1622         // opaque materials are expected to have alpha value of 1.0f based on the blend state
1623         desc.textures[MaterialComponent::TextureIndex::BASE_COLOR].factor.w = 1.0f;
1624         desc.materialShader.shader = dmShaderData.opaque.shader;
1625         desc.materialShader.graphicsState =
1626             gltfMaterial.doubleSided ? dmShaderData.opaque.gfxStateDoubleSided : dmShaderData.opaque.gfxState;
1627         // default materials support instancing with opaque materials.
1628         desc.extraRenderingFlags |= MaterialComponent::ExtraRenderingFlagBits::ALLOW_GPU_INSTANCING_BIT;
1629     }
1630     // shadow shader data
1631     if (desc.materialLightingFlags & MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT) {
1632         desc.depthShader.shader = dmShaderData.depth.shader;
1633         desc.depthShader.graphicsState =
1634             gltfMaterial.doubleSided ? dmShaderData.depth.gfxStateDoubleSided : dmShaderData.depth.gfxState;
1635     }
1636 }
1637 
ImportMaterial(GLTFImportResult const & importResult,GLTF2::Data const & data,GLTF2::Material const & gltfMaterial,const Entity materialEntity,IMaterialComponentManager & materialManager,IGpuResourceManager const & gpuResourceManager,const GLTF2::GLTF2Importer::DefaultMaterialShaderData & dmShaderData)1638 bool ImportMaterial(GLTFImportResult const& importResult, GLTF2::Data const& data, GLTF2::Material const& gltfMaterial,
1639     const Entity materialEntity, IMaterialComponentManager& materialManager,
1640     IGpuResourceManager const& gpuResourceManager, const GLTF2::GLTF2Importer::DefaultMaterialShaderData& dmShaderData)
1641 {
1642     auto materialHandle = materialManager.Write(materialEntity);
1643     if (!materialHandle) {
1644         return false;
1645     }
1646     auto& desc = *materialHandle;
1647     auto& ecs = materialManager.GetEcs();
1648     auto& em = ecs.GetEntityManager();
1649     if (gltfMaterial.type == GLTF2::Material::Type::MetallicRoughness) {
1650         FillMetallicRoughness(desc, importResult, data, gltfMaterial, em);
1651     } else if (gltfMaterial.type == GLTF2::Material::Type::SpecularGlossiness) {
1652         FillSpecularGlossiness(desc, importResult, data, gltfMaterial, em);
1653     } else if (gltfMaterial.type == GLTF2::Material::Type::Unlit) {
1654         FillUnlit(desc, importResult, data, gltfMaterial, em);
1655     }
1656 
1657     // Normal texture.
1658     FillTextureParams(
1659         gltfMaterial.normalTexture.textureInfo, importResult, data, em, desc, MaterialComponent::TextureIndex::NORMAL);
1660     desc.textures[MaterialComponent::TextureIndex::NORMAL].factor.x = gltfMaterial.normalTexture.scale;
1661 
1662     // Occlusion texture.
1663     FillTextureParams(
1664         gltfMaterial.occlusionTexture.textureInfo, importResult, data, em, desc, MaterialComponent::TextureIndex::AO);
1665     desc.textures[MaterialComponent::TextureIndex::AO].factor.x = gltfMaterial.occlusionTexture.strength;
1666 
1667     // Emissive texture.
1668     FillTextureParams(
1669         gltfMaterial.emissiveTexture, importResult, data, em, desc, MaterialComponent::TextureIndex::EMISSIVE);
1670     desc.textures[MaterialComponent::TextureIndex::EMISSIVE].factor = gltfMaterial.emissiveFactor;
1671 
1672     // Handle material extension
1673     FillClearcoat(desc, importResult, data, gltfMaterial, em);
1674     FillIor(desc, importResult, data, gltfMaterial, em);
1675     FillSheen(desc, importResult, data, gltfMaterial, em);
1676     FillSpecular(desc, importResult, data, gltfMaterial, em);
1677     FillTransmission(desc, importResult, data, gltfMaterial, em);
1678 
1679     // Always receive and cast shadows. (Modified with blend modes below)
1680     desc.materialLightingFlags |= MaterialComponent::LightingFlagBits::SHADOW_RECEIVER_BIT;
1681     desc.materialLightingFlags |= MaterialComponent::LightingFlagBits::SHADOW_CASTER_BIT;
1682 
1683     if (gltfMaterial.alphaMode == GLTF2::AlphaMode::MASK) {
1684         // we "enable" if it's set
1685         desc.alphaCutoff = gltfMaterial.alphaCutoff;
1686     }
1687 
1688     SelectShaders(desc, gltfMaterial, dmShaderData);
1689     return true;
1690 }
1691 
ConvertToCoreFilter(GLTF2::FilterMode mode,Filter & outFilter,Filter & outMipmapMode)1692 void ConvertToCoreFilter(GLTF2::FilterMode mode, Filter& outFilter, Filter& outMipmapMode)
1693 {
1694     switch (mode) {
1695         case GLTF2::FilterMode::NEAREST:
1696             outFilter = CORE_FILTER_NEAREST;
1697             outMipmapMode = CORE_FILTER_NEAREST;
1698             break;
1699 
1700         default:
1701         case GLTF2::FilterMode::LINEAR:
1702             outFilter = CORE_FILTER_LINEAR;
1703             outMipmapMode = CORE_FILTER_LINEAR;
1704             break;
1705 
1706         case GLTF2::FilterMode::NEAREST_MIPMAP_NEAREST:
1707             outFilter = CORE_FILTER_NEAREST;
1708             outMipmapMode = CORE_FILTER_NEAREST;
1709             break;
1710 
1711         case GLTF2::FilterMode::LINEAR_MIPMAP_NEAREST:
1712             outFilter = CORE_FILTER_LINEAR;
1713             outMipmapMode = CORE_FILTER_NEAREST;
1714             break;
1715 
1716         case GLTF2::FilterMode::NEAREST_MIPMAP_LINEAR:
1717             outFilter = CORE_FILTER_NEAREST;
1718             outMipmapMode = CORE_FILTER_LINEAR;
1719             break;
1720 
1721         case GLTF2::FilterMode::LINEAR_MIPMAP_LINEAR:
1722             outFilter = CORE_FILTER_LINEAR;
1723             outMipmapMode = CORE_FILTER_LINEAR;
1724             break;
1725     }
1726 }
1727 
ConvertToCoreFilter(GLTF2::FilterMode mode,Filter & outFilter)1728 void ConvertToCoreFilter(GLTF2::FilterMode mode, Filter& outFilter)
1729 {
1730     Filter unused;
1731     ConvertToCoreFilter(mode, outFilter, unused);
1732 }
1733 
ConvertToCoreWrapMode(GLTF2::WrapMode mode)1734 SamplerAddressMode ConvertToCoreWrapMode(GLTF2::WrapMode mode)
1735 {
1736     switch (mode) {
1737         default:
1738         case GLTF2::WrapMode::CLAMP_TO_EDGE:
1739             return CORE_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
1740 
1741         case GLTF2::WrapMode::MIRRORED_REPEAT:
1742             return CORE_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT;
1743 
1744         case GLTF2::WrapMode::REPEAT:
1745             return CORE_SAMPLER_ADDRESS_MODE_REPEAT;
1746     }
1747 }
1748 
RecursivelyCreateEntities(IEntityManager & entityManager,GLTF2::Data const & data,GLTF2::Node const & node,unordered_map<size_t,Entity> & sceneEntities)1749 void RecursivelyCreateEntities(IEntityManager& entityManager, GLTF2::Data const& data, GLTF2::Node const& node,
1750     unordered_map<size_t, Entity>& sceneEntities)
1751 {
1752     // Look up node index nodes array.
1753     if (size_t const nodeIndex = FindIndex(data.nodes, &node); nodeIndex != GLTF2::GLTF_INVALID_INDEX) {
1754         // Create entity for this node in this scene.
1755         sceneEntities[nodeIndex] = entityManager.Create();
1756     } else {
1757         // NOTE: Failed to find given node.
1758     }
1759 
1760     for (auto child : node.children) {
1761         RecursivelyCreateEntities(entityManager, data, *child, sceneEntities);
1762     }
1763 }
1764 
FindEntity(unordered_map<size_t,Entity> const & sceneEntities,size_t nodeIndex)1765 Entity FindEntity(unordered_map<size_t, Entity> const& sceneEntities, size_t nodeIndex)
1766 {
1767     if (auto const pos = sceneEntities.find(nodeIndex); pos != sceneEntities.end()) {
1768         return pos->second;
1769     } else {
1770         return {};
1771     }
1772 }
1773 
CreateNode(IEcs & ecs,const GLTF2::Node & node,const Entity entity,const GLTF2::Data & data,const unordered_map<size_t,Entity> & sceneEntities,const Entity sceneEntity)1774 void CreateNode(IEcs& ecs, const GLTF2::Node& node, const Entity entity, const GLTF2::Data& data,
1775     const unordered_map<size_t, Entity>& sceneEntities, const Entity sceneEntity)
1776 {
1777     INodeComponentManager& nodeManager = *(GetManager<INodeComponentManager>(ecs));
1778     nodeManager.Create(entity);
1779 
1780     ScopedHandle<NodeComponent> component = nodeManager.Write(entity);
1781     if (const size_t parentIndex = FindIndex(data.nodes, node.parent); parentIndex != GLTF2::GLTF_INVALID_INDEX) {
1782         component->parent = FindEntity(sceneEntities, parentIndex);
1783     } else {
1784         // Set as child of scene.
1785         component->parent = sceneEntity;
1786     }
1787 }
1788 
CreateName(IEcs & ecs,const GLTF2::Node & node,const Entity entity)1789 void CreateName(IEcs& ecs, const GLTF2::Node& node, const Entity entity)
1790 {
1791     INameComponentManager& nameManager = *(GetManager<INameComponentManager>(ecs));
1792     nameManager.Create(entity);
1793     ScopedHandle<NameComponent> nameHandle = nameManager.Write(entity);
1794     nameHandle->name = node.name;
1795 }
1796 
CreateTransform(IEcs & ecs,const GLTF2::Node & node,const Entity entity)1797 void CreateTransform(IEcs& ecs, const GLTF2::Node& node, const Entity entity)
1798 {
1799     ITransformComponentManager& transformManager = *(GetManager<ITransformComponentManager>(ecs));
1800 
1801     transformManager.Create(entity);
1802 
1803     GetManager<ILocalMatrixComponentManager>(ecs)->Create(entity);
1804     GetManager<IWorldMatrixComponentManager>(ecs)->Create(entity);
1805 
1806     ScopedHandle<TransformComponent> component = transformManager.Write(entity);
1807     if (node.usesTRS) {
1808         component->position = node.translation;
1809         component->rotation = node.rotation;
1810         component->scale = node.scale;
1811     } else {
1812         Math::Vec3 skew;
1813         Math::Vec4 perspective;
1814 
1815         if (!Math::Decompose(
1816             node.matrix, component->scale, component->rotation, component->position, skew, perspective)) {
1817             component->position = { 0.f, 0.f, 0.f };
1818             component->rotation = { 0.f, 0.f, 0.f, 1.f };
1819             component->scale = { 1.f, 1.f, 1.f };
1820         }
1821     }
1822 }
1823 
CreateMesh(IEcs & ecs,const GLTF2::Node & node,const Entity entity,const GLTF2::Data & data,const GLTFResourceData & gltfResourceData)1824 void CreateMesh(IEcs& ecs, const GLTF2::Node& node, const Entity entity, const GLTF2::Data& data,
1825     const GLTFResourceData& gltfResourceData)
1826 {
1827     const size_t meshIndex = FindIndex(data.meshes, node.mesh);
1828     if (meshIndex != GLTF2::GLTF_INVALID_INDEX && meshIndex < gltfResourceData.meshes.size()) {
1829         IRenderMeshComponentManager& renderMeshManager = *(GetManager<IRenderMeshComponentManager>(ecs));
1830 
1831         renderMeshManager.Create(entity);
1832         ScopedHandle<RenderMeshComponent> component = renderMeshManager.Write(entity);
1833         component->mesh = gltfResourceData.meshes[meshIndex];
1834     }
1835 }
1836 
CreateCamera(IEcs & ecs,const GLTF2::Node & node,const Entity entity,const Entity environmentEntity)1837 void CreateCamera(IEcs& ecs, const GLTF2::Node& node, const Entity entity, const Entity environmentEntity)
1838 {
1839     if (node.camera && node.camera->type != GLTF2::CameraType::INVALID) {
1840         ICameraComponentManager& cameraManager = *(GetManager<ICameraComponentManager>(ecs));
1841         cameraManager.Create(entity);
1842         ScopedHandle<CameraComponent> component = cameraManager.Write(entity);
1843         if (node.camera->type == GLTF2::CameraType::ORTHOGRAPHIC) {
1844             component->projection = CameraComponent::Projection::ORTHOGRAPHIC;
1845             component->xMag = node.camera->attributes.ortho.xmag;
1846             component->yMag = node.camera->attributes.ortho.ymag;
1847             component->zFar = node.camera->attributes.ortho.zfar;
1848             component->zNear = node.camera->attributes.ortho.znear;
1849         } else {
1850             // GLTF2::CameraType::PERSPECTIVE
1851             component->projection = CameraComponent::Projection::PERSPECTIVE;
1852             component->aspect = node.camera->attributes.perspective.aspect;
1853             component->yFov = node.camera->attributes.perspective.yfov;
1854             component->zFar = node.camera->attributes.perspective.zfar;
1855             component->zNear = node.camera->attributes.perspective.znear;
1856         }
1857         component->environment = environmentEntity;
1858     }
1859 }
1860 
1861 #if defined(GLTF2_EXTENSION_KHR_LIGHTS) || defined(GLTF2_EXTENSION_KHR_LIGHTS_PBR)
CreateLight(IEcs & ecs,const GLTF2::Node & node,const Entity entity)1862 void CreateLight(IEcs& ecs, const GLTF2::Node& node, const Entity entity)
1863 {
1864     if (node.light && node.light->type != GLTF2::LightType::INVALID) {
1865         ILightComponentManager& lightManager = *(GetManager<ILightComponentManager>(ecs));
1866 
1867         LightComponent component = CreateComponent(lightManager, entity);
1868 
1869         component.type = ConvertToCoreLightType(node.light->type);
1870         component.intensity = node.light->intensity;
1871         component.color = { node.light->color.x, node.light->color.y, node.light->color.z };
1872 
1873         if (component.type == LightComponent::Type::POINT || component.type == LightComponent::Type::SPOT) {
1874             // Positional parameters.
1875             component.range = node.light->positional.range;
1876 
1877             if (component.type == LightComponent::Type::SPOT) {
1878                 // Spot parameters.
1879                 component.spotInnerAngle = node.light->positional.spot.innerAngle;
1880                 component.spotOuterAngle = node.light->positional.spot.outerAngle;
1881             }
1882         }
1883 
1884         lightManager.Set(entity, component);
1885     }
1886 }
1887 #endif
1888 
RecursivelyCreateComponents(IEcs & ecs,GLTF2::Data const & data,GLTF2::Node const & node,unordered_map<size_t,Entity> const & sceneEntities,Entity sceneEntity,Entity environmentEntity,const GLTFResourceData & gltfResourceData,Entity & defaultCamera,uint32_t flags)1889 void RecursivelyCreateComponents(IEcs& ecs, GLTF2::Data const& data, GLTF2::Node const& node,
1890     unordered_map<size_t, Entity> const& sceneEntities, Entity sceneEntity, Entity environmentEntity,
1891     const GLTFResourceData& gltfResourceData, Entity& defaultCamera, uint32_t flags)
1892 {
1893     size_t const nodeIndex = FindIndex(data.nodes, &node);
1894     CORE_ASSERT_MSG(nodeIndex != GLTF2::GLTF_INVALID_INDEX, "Cannot find node: %s", node.name.c_str());
1895 
1896     Entity const entity = FindEntity(sceneEntities, nodeIndex);
1897 
1898     // Apply to node hierarchy.
1899     CreateNode(ecs, node, entity, data, sceneEntities, sceneEntity);
1900 
1901     // Add name.
1902     CreateName(ecs, node, entity);
1903 
1904     // Apply transform.
1905     CreateTransform(ecs, node, entity);
1906 
1907     // Apply mesh.
1908     if (node.mesh && (flags & CORE_GLTF_IMPORT_COMPONENT_MESH)) {
1909         CreateMesh(ecs, node, entity, data, gltfResourceData);
1910     }
1911 
1912     // Apply camera.
1913     if (flags & CORE_GLTF_IMPORT_COMPONENT_CAMERA) {
1914         CreateCamera(ecs, node, entity, environmentEntity);
1915 
1916         if (!EntityUtil::IsValid(defaultCamera)) {
1917             defaultCamera = entity;
1918         }
1919     }
1920 
1921 #if defined(GLTF2_EXTENSION_KHR_LIGHTS) || defined(GLTF2_EXTENSION_KHR_LIGHTS_PBR)
1922     // Apply light.
1923     if (flags & CORE_GLTF_IMPORT_COMPONENT_LIGHT) {
1924         CreateLight(ecs, node, entity);
1925     }
1926 #endif
1927 
1928 #if defined(GLTF2_EXTRAS_RSDZ)
1929     if (!node.modelIdRSDZ.empty()) {
1930         IRSDZModelIdComponentManager& rsdzManager = *(GetManager<IRSDZModelIdComponentManager>(ecs));
1931         RSDZModelIdComponent component = CreateComponent(rsdzManager, entity);
1932         StringUtil::CopyStringToArray(
1933             node.modelIdRSDZ, component.modelId, StringUtil::MaxStringLengthFromArray(component.modelId));
1934         rsdzManager.Set(entity, component);
1935     }
1936 #endif
1937 
1938     for (auto child : node.children) {
1939         RecursivelyCreateComponents(
1940             ecs, data, *child, sceneEntities, sceneEntity, environmentEntity, gltfResourceData, defaultCamera, flags);
1941     }
1942 }
1943 
AddSkinJointsComponents(const GLTF2::Data & data,const GLTFResourceData & gltfResourceData,ISkinningSystem & ss,const unordered_map<size_t,Entity> & sceneEntities)1944 void AddSkinJointsComponents(const GLTF2::Data& data, const GLTFResourceData& gltfResourceData, ISkinningSystem& ss,
1945     const unordered_map<size_t, Entity>& sceneEntities)
1946 {
1947     auto skinEntityIt = gltfResourceData.skins.begin();
1948     auto skinJointsManager = GetManager<ISkinJointsComponentManager>(ss.GetECS());
1949     // gltfResourceData.skins and data.skins should be the same size but take min just in case.
1950     auto skins = array_view(data.skins.data(), Math::min(gltfResourceData.skins.size(), data.skins.size()));
1951     for (auto const& skin : skins) {
1952         if (skin && (*skinEntityIt)) {
1953             skinJointsManager->Create(*skinEntityIt);
1954             auto jointsHandle = skinJointsManager->Write(*skinEntityIt);
1955             jointsHandle->count = Math::min(countof(jointsHandle->jointEntities), skin->joints.size());
1956             auto jointEntities = array_view(jointsHandle->jointEntities, jointsHandle->count);
1957             std::transform(skin->joints.begin(), skin->joints.begin() + static_cast<ptrdiff_t>(jointsHandle->count),
1958                 jointEntities.begin(), [&data, &sceneEntities](const auto& jointNode) {
1959                     size_t const jointNodeIndex = FindIndex(data.nodes, jointNode);
1960                     return FindEntity(sceneEntities, jointNodeIndex);
1961                 });
1962         }
1963         ++skinEntityIt;
1964     }
1965 }
1966 
CreateSkinComponents(const GLTF2::Data & data,const GLTFResourceData & gltfResourceData,ISkinningSystem & ss,const unordered_map<size_t,Entity> & sceneEntities)1967 void CreateSkinComponents(const GLTF2::Data& data, const GLTFResourceData& gltfResourceData, ISkinningSystem& ss,
1968     const unordered_map<size_t, Entity>& sceneEntities)
1969 {
1970     auto skinJointsManager = GetManager<ISkinJointsComponentManager>(ss.GetECS());
1971     for (auto const& node : data.nodes) {
1972         if (!node->skin) {
1973             continue;
1974         }
1975 
1976         if (size_t const skinIndex = FindIndex(data.skins, node->skin);
1977             skinIndex != GLTF2::GLTF_INVALID_INDEX && skinIndex < gltfResourceData.skins.size()) {
1978             size_t const nodeIndex = FindIndex(data.nodes, node.get());
1979             Entity const entity = FindEntity(sceneEntities, nodeIndex);
1980             if (!EntityUtil::IsValid(entity)) {
1981                 // node was not part of current scene
1982                 continue;
1983             }
1984 
1985             Entity skeleton {};
1986             if (node->skin->skeleton) {
1987                 size_t const skeletonIndex = FindIndex(data.nodes, node->skin->skeleton);
1988                 skeleton = FindEntity(sceneEntities, skeletonIndex);
1989             }
1990 
1991             vector<Entity> joints;
1992             if (auto jointsHandle = skinJointsManager->Read(gltfResourceData.skins[skinIndex]); jointsHandle) {
1993                 joints.append(jointsHandle->jointEntities, jointsHandle->jointEntities + jointsHandle->count);
1994             } else {
1995                 joints.reserve(node->skin->joints.size());
1996                 std::transform(node->skin->joints.begin(), node->skin->joints.end(), std::back_inserter(joints),
1997                     [&data, &sceneEntities](const auto& jointNode) {
1998                         size_t const jointNodeIndex = FindIndex(data.nodes, jointNode);
1999                         return FindEntity(sceneEntities, jointNodeIndex);
2000                     });
2001             }
2002             ss.CreateInstance(gltfResourceData.skins[skinIndex], joints, entity, skeleton);
2003         }
2004     }
2005 }
2006 
CreateMorphComponents(const GLTF2::Data & data,const GLTFResourceData & gltfResourceData,IMorphComponentManager & mm,const unordered_map<size_t,Entity> & sceneEntities,const Entity sceneEntity)2007 void CreateMorphComponents(const GLTF2::Data& data, const GLTFResourceData& gltfResourceData,
2008     IMorphComponentManager& mm, const unordered_map<size_t, Entity>& sceneEntities, const Entity sceneEntity)
2009 {
2010     for (auto const& node : data.nodes) {
2011         if (!node->mesh || node->mesh->primitives.empty() || node->mesh->primitives[0].targets.empty()) {
2012             continue;
2013         }
2014         const size_t meshIndex = FindIndex(data.meshes, node->mesh);
2015         if ((meshIndex == GLTF2::GLTF_INVALID_INDEX) || (meshIndex >= gltfResourceData.meshes.size())) {
2016             continue;
2017         }
2018         const size_t nodeIndex = FindIndex(data.nodes, node.get());
2019         const Entity entity = FindEntity(sceneEntities, nodeIndex);
2020         if (!EntityUtil::IsValid(entity)) {
2021             // node was not part of current scene
2022             continue;
2023         }
2024         const size_t weightCount = node->mesh->primitives[0].targets.size();
2025         // Assert that all primitives have the same targets. (the spec is a bit confusing here or i just
2026         // can't read.)
2027         for (const auto& primitive : node->mesh->primitives) {
2028             CORE_UNUSED(primitive);
2029             CORE_ASSERT(primitive.targets.size() == weightCount);
2030         }
2031 
2032         // We have targets, so prepare the morph system/component.
2033         vector<string> names;
2034         names.reserve(weightCount);
2035         std::transform(node->mesh->primitives[0].targets.cbegin(), node->mesh->primitives[0].targets.cend(),
2036             std::back_inserter(names), [](const GLTF2::MorphTarget& target) { return target.name; });
2037 
2038         // Apparently the node/mesh weight list is a concatenation of all primitives targets weights....
2039         vector<float> weights;
2040         weights.reserve(weightCount);
2041         if (!node->weights.empty()) {
2042             // Use instance weight (if there is one)
2043             weights.append(node->weights.cbegin(),
2044                 node->weights.cbegin() + static_cast<decltype(node->weights)::difference_type>(weightCount));
2045         } else if (!node->mesh->weights.empty()) {
2046             // Use mesh weight (if there is one)
2047             weights.append(node->mesh->weights.cbegin(),
2048                 node->mesh->weights.cbegin() + static_cast<decltype(node->weights)::difference_type>(weightCount));
2049         } else {
2050             // Default to zero weight.
2051             weights.append(weightCount, 0.f);
2052         }
2053 
2054         mm.Create(entity);
2055         auto handle = mm.Write(entity);
2056         handle->morphNames = BASE_NS::move(names);
2057         handle->morphWeights = BASE_NS::move(weights);
2058     }
2059 }
2060 
GetImageEntity(IEcs & ecs,const GLTFResourceData & gltfResourceData,size_t index)2061 EntityReference GetImageEntity(IEcs& ecs, const GLTFResourceData& gltfResourceData, size_t index)
2062 {
2063     if ((index != CORE_GLTF_INVALID_INDEX) && (index < gltfResourceData.images.size()) &&
2064         GetManager<IRenderHandleComponentManager>(ecs)->HasComponent(gltfResourceData.images[index])) {
2065         return gltfResourceData.images[index];
2066     }
2067     return {};
2068 }
2069 
CreateEnvironmentComponent(IGpuResourceManager & gpuResourceManager,const GLTF2::Data & data,const GLTFResourceData & gltfResourceData,IEcs & ecs,Entity sceneEntity,const size_t lightIndex)2070 Entity CreateEnvironmentComponent(IGpuResourceManager& gpuResourceManager, const GLTF2::Data& data,
2071     const GLTFResourceData& gltfResourceData, IEcs& ecs, Entity sceneEntity, const size_t lightIndex)
2072 {
2073     Entity environmentEntity;
2074 #if defined(GLTF2_EXTENSION_EXT_LIGHTS_IMAGE_BASED)
2075     if (lightIndex == GLTF2::GLTF_INVALID_INDEX || lightIndex >= data.imageBasedLights.size()) {
2076         return environmentEntity;
2077     }
2078     // Create the component to the sceneEntity for convinience.
2079     environmentEntity = sceneEntity;
2080     IEnvironmentComponentManager& envManager = *(GetManager<IEnvironmentComponentManager>(ecs));
2081     envManager.Create(environmentEntity);
2082     auto envHandle = envManager.Write(environmentEntity);
2083 
2084     GLTF2::ImageBasedLight* light = data.imageBasedLights[lightIndex].get();
2085     envHandle->indirectDiffuseFactor.w = light->intensity;
2086     envHandle->indirectSpecularFactor.w = light->intensity;
2087     envHandle->envMapFactor.w = light->intensity;
2088 
2089     envHandle->environmentRotation = light->rotation;
2090 
2091     // Either we have full set of coefficients or there are no coefficients at all.
2092     CORE_ASSERT(light->irradianceCoefficients.size() == 0u || light->irradianceCoefficients.size() == 9u);
2093 
2094     std::transform(light->irradianceCoefficients.begin(), light->irradianceCoefficients.end(),
2095         envHandle->irradianceCoefficients, [](const GLTF2::ImageBasedLight::LightingCoeff& coeff) {
2096             // Each coefficient needs to have three components.
2097             CORE_ASSERT(coeff.size() == 3u);
2098 
2099             // Values are expected to be prescaled with 1.0 / PI for Lambertian diffuse
2100             return Math::Vec3(coeff[0u], coeff[1u], coeff[2u]);
2101         });
2102 
2103     if (lightIndex < gltfResourceData.specularRadianceCubemaps.size() &&
2104         EntityUtil::IsValid(gltfResourceData.specularRadianceCubemaps[lightIndex])) {
2105         envHandle->radianceCubemap = gltfResourceData.specularRadianceCubemaps[lightIndex];
2106         envHandle->radianceCubemapMipCount = (uint32_t)light->specularImages.size();
2107     }
2108 
2109     if (auto imageEntity = GetImageEntity(ecs, gltfResourceData, light->specularCubeImage); imageEntity) {
2110         envHandle->radianceCubemap = imageEntity;
2111     }
2112 
2113     envHandle->envMapLodLevel = light->skymapImageLodLevel;
2114 
2115     if (auto imageEntity = GetImageEntity(ecs, gltfResourceData, light->skymapImage); imageEntity) {
2116         envHandle->envMap = imageEntity;
2117         IRenderHandleComponentManager& gpuHandleManager = *(GetManager<IRenderHandleComponentManager>(ecs));
2118         if (const auto& envMapHandle = gpuHandleManager.Read(imageEntity)->reference; envMapHandle) {
2119             const ImageViewType imageViewType = gpuResourceManager.GetImageDescriptor(envMapHandle).imageViewType;
2120             envHandle->background = (imageViewType == CORE_IMAGE_VIEW_TYPE_CUBE)
2121                                         ? EnvironmentComponent::Background::CUBEMAP
2122                                         : EnvironmentComponent::Background::EQUIRECTANGULAR;
2123         }
2124     }
2125 
2126 #endif
2127     return environmentEntity;
2128 }
2129 
operator +(GLTF2::ImportPhase lhs,int rhs)2130 GLTF2::ImportPhase operator+(GLTF2::ImportPhase lhs, int rhs)
2131 {
2132     return static_cast<GLTF2::ImportPhase>(static_cast<int>(lhs) + rhs);
2133 }
2134 
2135 using ImageLoadResultVector = vector<IImageLoaderManager::LoadResult>;
2136 
2137 struct ImageData {
2138     vector<uint8_t> data;
2139     vector<BufferImageCopy> copyInfo;
2140 };
2141 
PrepareImageData(const ImageLoadResultVector & imageLoadResults,const GpuImageDesc & imageDesc)2142 ImageData PrepareImageData(const ImageLoadResultVector& imageLoadResults, const GpuImageDesc& imageDesc)
2143 {
2144     ImageData data;
2145     const size_t availableMipLayerCount = imageLoadResults.size() / imageDesc.layerCount;
2146     data.copyInfo.resize(availableMipLayerCount);
2147 
2148     // For all mip levels.
2149     size_t byteOffset = 0;
2150     for (size_t mipIndex = 0; mipIndex < availableMipLayerCount; ++mipIndex) {
2151         {
2152             const auto& imageLoadResult = imageLoadResults[(mipIndex * 6u)];
2153             if (!imageLoadResult.image) {
2154                 continue;
2155             }
2156             const auto& loadedImageDesc = imageLoadResult.image->GetImageDesc();
2157             const auto& loadedBufferImageCopy = imageLoadResult.image->GetBufferImageCopies()[0];
2158 
2159             BufferImageCopy& bufferCopy = data.copyInfo[mipIndex];
2160             bufferCopy.bufferOffset = (uint32_t)byteOffset;
2161             bufferCopy.bufferRowLength = loadedBufferImageCopy.bufferRowLength;
2162             bufferCopy.bufferImageHeight = loadedBufferImageCopy.bufferImageHeight;
2163             bufferCopy.imageOffset.width = 0;
2164             bufferCopy.imageOffset.height = 0;
2165             bufferCopy.imageOffset.depth = 0;
2166             bufferCopy.imageExtent.width = loadedImageDesc.width;
2167             bufferCopy.imageExtent.height = loadedImageDesc.height;
2168             bufferCopy.imageExtent.depth = loadedImageDesc.depth;
2169             bufferCopy.imageSubresource.imageAspectFlags = CORE_IMAGE_ASPECT_COLOR_BIT;
2170             bufferCopy.imageSubresource.mipLevel = (uint32_t)mipIndex;
2171             bufferCopy.imageSubresource.baseArrayLayer = 0;
2172             bufferCopy.imageSubresource.layerCount = imageDesc.layerCount;
2173         }
2174 
2175         for (uint32_t face = 0; face < imageDesc.layerCount; ++face) {
2176             const auto& cubeFaceLoadResult = imageLoadResults[(mipIndex * imageDesc.layerCount) + face];
2177             const auto& cubeFaceBufferImageCopy = cubeFaceLoadResult.image->GetBufferImageCopies()[0];
2178 
2179             const auto& loadedImageData = cubeFaceLoadResult.image->GetData();
2180             data.data.append(loadedImageData.begin() + cubeFaceBufferImageCopy.bufferOffset, loadedImageData.end());
2181 
2182             byteOffset += loadedImageData.size() - cubeFaceBufferImageCopy.bufferOffset;
2183         }
2184     }
2185     return data;
2186 }
2187 
CreateCubemapFromImages(uint32_t imageSize,const ImageLoadResultVector & imageLoadResults,IGpuResourceManager & gpuResourceManager)2188 RenderHandleReference CreateCubemapFromImages(
2189     uint32_t imageSize, const ImageLoadResultVector& imageLoadResults, IGpuResourceManager& gpuResourceManager)
2190 {
2191     if (!imageLoadResults[0].image) {
2192         return {};
2193     }
2194 
2195     // Calculate number of mipmaps needed.
2196     uint32_t mipsize = imageSize;
2197     uint32_t totalMipCount = 0;
2198     while (mipsize > 0) {
2199         ++totalMipCount;
2200         mipsize >>= 1;
2201     }
2202 
2203     const ImageUsageFlags usageFlags =
2204         CORE_IMAGE_USAGE_SAMPLED_BIT | CORE_IMAGE_USAGE_TRANSFER_DST_BIT | CORE_IMAGE_USAGE_TRANSFER_SRC_BIT;
2205 
2206     const GpuImageDesc imageDesc = {
2207         ImageType::CORE_IMAGE_TYPE_2D,                                 // imageType
2208         CORE_IMAGE_VIEW_TYPE_CUBE,                                     // imageViewType
2209         imageLoadResults[0].image->GetImageDesc().format,              // format
2210         ImageTiling::CORE_IMAGE_TILING_OPTIMAL,                        // imageTiling
2211         usageFlags,                                                    // usageFlags
2212         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, // memoryPropertyFlags
2213         ImageCreateFlagBits::CORE_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,    // createFlags
2214         CORE_ENGINE_IMAGE_CREATION_GENERATE_MIPS,                      // engineCreationFlags
2215         imageSize,                                                     // width
2216         imageSize,                                                     // height
2217         1,                                                             // depth
2218         totalMipCount,                                                 // mipCount
2219         6,                                                             // layerCount
2220         SampleCountFlagBits::CORE_SAMPLE_COUNT_1_BIT,                  // sampleCountFlags
2221         {},                                                            // componentMapping
2222     };
2223 
2224     const auto data = PrepareImageData(imageLoadResults, imageDesc);
2225 
2226     auto handle = gpuResourceManager.Create("", imageDesc, data.data, data.copyInfo);
2227     if (!handle) {
2228         CORE_LOG_W("Creating an import cubemap image failed (format:%u, width:%u, height:%u)",
2229             static_cast<uint32_t>(imageDesc.format), imageDesc.width, imageDesc.height);
2230     }
2231     return handle;
2232 }
2233 
FillShaderData(IEntityManager & em,IUriComponentManager & uriManager,IRenderHandleComponentManager & renderHandleMgr,const string_view renderSlot,GLTF2::GLTF2Importer::DefaultMaterialShaderData::SingleShaderData & shaderData)2234 auto FillShaderData(IEntityManager& em, IUriComponentManager& uriManager,
2235     IRenderHandleComponentManager& renderHandleMgr, const string_view renderSlot,
2236     GLTF2::GLTF2Importer::DefaultMaterialShaderData::SingleShaderData& shaderData)
2237 {
2238     auto uri = "3dshaders://" + renderSlot;
2239     auto resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
2240     shaderData.shader = em.GetReferenceCounted(resourceEntity);
2241 
2242     uri = "3dshaderstates://";
2243     uri += renderSlot;
2244     resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
2245     shaderData.gfxState = em.GetReferenceCounted(resourceEntity);
2246 
2247     uri += "_DBL";
2248     resourceEntity = LookupResourceByUri(uri, uriManager, renderHandleMgr);
2249     shaderData.gfxStateDoubleSided = em.GetReferenceCounted(resourceEntity);
2250     if (!(EntityUtil::IsValid(shaderData.shader) && EntityUtil::IsValid(shaderData.gfxState) &&
2251             EntityUtil::IsValid(shaderData.gfxStateDoubleSided))) {
2252         CORE_LOG_ONCE_W(renderSlot, "GLTF2 importer cannot find default shader data.");
2253     }
2254 }
2255 } // namespace
2256 
ImportScene(IDevice & device,size_t sceneIndex,const GLTF2::Data & data,const GLTFResourceData & gltfResourceData,IEcs & ecs,Entity rootEntity,GltfSceneImportFlags flags)2257 Entity ImportScene(IDevice& device, size_t sceneIndex, const GLTF2::Data& data,
2258     const GLTFResourceData& gltfResourceData, IEcs& ecs, Entity rootEntity, GltfSceneImportFlags flags)
2259 {
2260     if (sceneIndex >= data.scenes.size()) {
2261         return {};
2262     }
2263     // Create entity for this scene.
2264     const Entity sceneEntity = ecs.GetEntityManager().Create();
2265 
2266     // Create default components for scene.
2267     ITransformComponentManager& transformManager = *(GetManager<ITransformComponentManager>(ecs));
2268     transformManager.Create(sceneEntity);
2269     ILocalMatrixComponentManager& localMatrixManager = *(GetManager<ILocalMatrixComponentManager>(ecs));
2270     localMatrixManager.Create(sceneEntity);
2271     IWorldMatrixComponentManager& worldMatrixManager = *(GetManager<IWorldMatrixComponentManager>(ecs));
2272     worldMatrixManager.Create(sceneEntity);
2273 
2274     auto& scene = data.scenes[sceneIndex];
2275 
2276     INodeComponentManager& nodeManager = *(GetManager<INodeComponentManager>(ecs));
2277     nodeManager.Create(sceneEntity);
2278     if (auto nodeHandle = nodeManager.Write(sceneEntity); nodeHandle) {
2279         nodeHandle->parent = rootEntity;
2280     }
2281 
2282     // Add name.
2283     {
2284         INameComponentManager& nameManager = *(GetManager<INameComponentManager>(ecs));
2285         nameManager.Create(sceneEntity);
2286         ScopedHandle<NameComponent> nameHandle = nameManager.Write(sceneEntity);
2287         nameHandle->name = scene->name;
2288     }
2289 
2290     // Default camera.
2291     Entity defaultCamera;
2292 
2293     IEntityManager& em = ecs.GetEntityManager();
2294 
2295     // Create environment.
2296     Entity environment;
2297     if (flags & CORE_GLTF_IMPORT_COMPONENT_ENVIRONMENT) {
2298 #if defined(GLTF2_EXTENSION_EXT_LIGHTS_IMAGE_BASED)
2299         const size_t lightIndex = scene->imageBasedLightIndex;
2300 #else
2301         const size_t lightIndex = 0; // Not used.
2302 #endif
2303         environment = CreateEnvironmentComponent(
2304             device.GetGpuResourceManager(), data, gltfResourceData, ecs, sceneEntity, lightIndex);
2305     }
2306 
2307     // Create entities for nodes in scene.
2308     unordered_map<size_t, Entity> sceneEntities;
2309     for (auto node : scene->nodes) {
2310         RecursivelyCreateEntities(em, data, *node, sceneEntities);
2311     }
2312 
2313     // Create components for all nodes in this scene.
2314     for (auto node : scene->nodes) {
2315         RecursivelyCreateComponents(
2316             ecs, data, *node, sceneEntities, sceneEntity, environment, gltfResourceData, defaultCamera, flags);
2317     }
2318 
2319     // Apply skins only after the node hiearachy is complete.
2320     if (flags & CORE_GLTF_IMPORT_COMPONENT_SKIN) {
2321         if (ISkinningSystem* ss = GetSystem<ISkinningSystem>(ecs); ss) {
2322             AddSkinJointsComponents(data, gltfResourceData, *ss, sceneEntities);
2323             CreateSkinComponents(data, gltfResourceData, *ss, sceneEntities);
2324         }
2325     }
2326 
2327     // Add the morphing system to entity if needed. (contains the target weights)
2328     if (flags & CORE_GLTF_IMPORT_COMPONENT_MORPH) {
2329         if (IMorphComponentManager* mm = GetManager<IMorphComponentManager>(ecs); mm) {
2330             CreateMorphComponents(data, gltfResourceData, *mm, sceneEntities, sceneEntity);
2331         }
2332     }
2333 
2334     return sceneEntity;
2335 }
2336 
2337 namespace GLTF2 {
2338 struct GLTF2Importer::ImporterTask {
2339     virtual ~ImporterTask() = default;
2340 
2341     enum class State { Queued, Gather, Import, Finished };
2342 
2343     string name;
2344     string errors;
2345     uint64_t id;
2346     bool success { true };
2347 
2348     std::function<bool()> gather;
2349     std::function<bool()> import;
2350     std::function<void()> finished;
2351 
2352     State state { State::Queued };
2353     ImportPhase phase { ImportPhase::FINISHED };
2354 };
2355 
2356 class GLTF2Importer::GatherThreadTask final : public IThreadPool::ITask {
2357 public:
GatherThreadTask(GLTF2Importer & importer,ImporterTask & task)2358     explicit GatherThreadTask(GLTF2Importer& importer, ImporterTask& task) : importer_(importer), task_(task) {};
2359 
operator ()()2360     void operator()() override
2361     {
2362         importer_.Gather(task_);
2363     }
2364 
2365 protected:
Destroy()2366     void Destroy() override
2367     {
2368         delete this;
2369     }
2370 
2371 private:
2372     GLTF2Importer& importer_;
2373     ImporterTask& task_;
2374 };
2375 
2376 class GLTF2Importer::ImportThreadTask final : public IThreadPool::ITask {
2377 public:
ImportThreadTask(GLTF2Importer & importer,ImporterTask & task)2378     explicit ImportThreadTask(GLTF2Importer& importer, ImporterTask& task) : importer_(importer), task_(task) {};
2379 
operator ()()2380     void operator()() override
2381     {
2382         importer_.Import(task_);
2383     }
2384 
2385 protected:
Destroy()2386     void Destroy() override
2387     {
2388         delete this;
2389     }
2390 
2391 private:
2392     GLTF2Importer& importer_;
2393     ImporterTask& task_;
2394 };
2395 
2396 template<class T>
2397 struct GLTF2Importer::GatheredDataTask : GLTF2Importer::ImporterTask {
2398     T data;
2399 };
2400 
2401 template<typename Component>
2402 struct GLTF2Importer::ComponentTaskData {
2403     EntityReference entity;
2404     Component component;
2405 };
2406 
2407 struct GLTF2Importer::AnimationTaskData {
2408     GLTF2Importer* importer;
2409     size_t index;
2410     string uri;
2411     string_view name;
2412     IAnimationComponentManager* animationManager;
2413     IAnimationTrackComponentManager* trackManager;
2414     vector<GatheredDataTask<ComponentTaskData<AnimationInputComponent>>*> inputs;
2415     vector<GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>*> outputs;
2416 
operator ()GLTF2::GLTF2Importer::AnimationTaskData2417     bool operator()()
2418     {
2419         const auto& tracks = importer->data_->animations[index]->tracks;
2420         if (inputs.size() < tracks.size() || outputs.size() < tracks.size()) {
2421             return false;
2422         }
2423         auto& entityManager = importer->ecs_->GetEntityManager();
2424 
2425         auto animationEntity = entityManager.CreateReferenceCounted();
2426         animationManager->Create(animationEntity);
2427         const auto animationHandle = animationManager->Write(animationEntity);
2428 
2429         auto& animationTracks = animationHandle->tracks;
2430         animationTracks.reserve(tracks.size());
2431         auto inputIt = inputs.begin();
2432         auto outputIt = outputs.begin();
2433         float maxLength = 0.f;
2434         for (const auto& track : tracks) {
2435             if (track.sampler) {
2436                 const auto animationTrackEntity = entityManager.CreateReferenceCounted();
2437                 animationTracks.push_back(animationTrackEntity);
2438 
2439                 trackManager->Create(animationTrackEntity);
2440                 if (auto trackHandle = trackManager->Write(animationTrackEntity); trackHandle) {
2441                     if (track.channel.node) {
2442                         // Name the track with the path to the target node. Scene import can then find the
2443                         // target entity.
2444                         importer->nameManager_->Create(animationTrackEntity);
2445                         importer->nameManager_->Write(animationTrackEntity)->name =
2446                             ResolveNodePath(*track.channel.node);
2447                     }
2448 
2449                     SelectComponentProperty(track.channel.path, *trackHandle);
2450 
2451                     trackHandle->interpolationMode = ConvertAnimationInterpolation(track.sampler->interpolation);
2452                     trackHandle->timestamps = (*inputIt)->data.entity;
2453                     trackHandle->data = (*outputIt)->data.entity;
2454                     if (!(*inputIt)->data.component.timestamps.empty()) {
2455                         maxLength = Math::max(maxLength, (*inputIt)->data.component.timestamps.back());
2456                     }
2457                 }
2458                 ++inputIt;
2459                 ++outputIt;
2460             }
2461         }
2462         animationHandle->duration = maxLength;
2463         if (!uri.empty()) {
2464             importer->uriManager_->Create(animationEntity);
2465             importer->uriManager_->Write(animationEntity)->uri = move(uri);
2466         }
2467         if (!name.empty()) {
2468             importer->nameManager_->Create(animationEntity);
2469             importer->nameManager_->Write(animationEntity)->name = name;
2470         }
2471         importer->result_.data.animations[index] = move(animationEntity);
2472         return true;
2473     }
2474 
SelectComponentPropertyGLTF2::GLTF2Importer::AnimationTaskData2475     static void SelectComponentProperty(AnimationPath pathType, AnimationTrackComponent& trackComponent)
2476     {
2477         switch (pathType) {
2478             case GLTF2::AnimationPath::INVALID:
2479                 CORE_ASSERT(false);
2480                 break;
2481             case GLTF2::AnimationPath::TRANSLATION:
2482                 trackComponent.component = ITransformComponentManager::UID;
2483                 trackComponent.property = "position";
2484                 break;
2485             case GLTF2::AnimationPath::ROTATION:
2486                 trackComponent.component = ITransformComponentManager::UID;
2487                 trackComponent.property = "rotation";
2488                 break;
2489             case GLTF2::AnimationPath::SCALE:
2490                 trackComponent.component = ITransformComponentManager::UID;
2491                 trackComponent.property = "scale";
2492                 break;
2493             case GLTF2::AnimationPath::WEIGHTS:
2494                 trackComponent.component = IMorphComponentManager::UID;
2495                 trackComponent.property = "morphWeights";
2496                 break;
2497             case GLTF2::AnimationPath::VISIBLE:
2498                 trackComponent.component = INodeComponentManager::UID;
2499                 trackComponent.property = "enabled";
2500                 break;
2501             case GLTF2::AnimationPath::OPACITY:
2502                 trackComponent.component = IMaterialComponentManager::UID;
2503                 trackComponent.property = "enabled";
2504                 break;
2505         }
2506     }
2507 };
2508 
GLTF2Importer(IEngine & engine,IRenderContext & renderContext,IEcs & ecs,IThreadPool & pool)2509 GLTF2Importer::GLTF2Importer(IEngine& engine, IRenderContext& renderContext, IEcs& ecs, IThreadPool& pool)
2510     : engine_(engine), renderContext_(renderContext), device_(renderContext.GetDevice()),
2511       gpuResourceManager_(device_.GetGpuResourceManager()), ecs_(&ecs),
2512       renderHandleManager_(GetManager<IRenderHandleComponentManager>(*ecs_)),
2513       materialManager_(GetManager<IMaterialComponentManager>(*ecs_)),
2514       meshManager_(GetManager<IMeshComponentManager>(*ecs_)), nameManager_(GetManager<INameComponentManager>(*ecs_)),
2515       uriManager_(GetManager<IUriComponentManager>(*ecs_)), threadPool_(&pool)
2516 {
2517     if (IGraphicsContext* graphicsContext_ =
2518             GetInstance<IGraphicsContext>(*(renderContext_.GetInterface<IClassRegister>()), UID_GRAPHICS_CONTEXT);
2519         graphicsContext_) {
2520         colorSpaceFlags_ = graphicsContext_->GetColorSpaceFlags();
2521     }
2522 
2523     const auto factory = GetInstance<ITaskQueueFactory>(UID_TASK_QUEUE_FACTORY);
2524     mainThreadQueue_ = factory->CreateDispatcherTaskQueue({});
2525     if (renderHandleManager_ && uriManager_) {
2526         // fetch default shaders and graphics states
2527         auto& entityMgr = ecs_->GetEntityManager();
2528         FillShaderData(entityMgr, *uriManager_, *renderHandleManager_,
2529             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_OPAQUE, dmShaderData_.opaque);
2530         FillShaderData(entityMgr, *uriManager_, *renderHandleManager_,
2531             DefaultMaterialShaderConstants::RENDER_SLOT_FORWARD_TRANSLUCENT, dmShaderData_.blend);
2532         FillShaderData(entityMgr, *uriManager_, *renderHandleManager_,
2533             DefaultMaterialShaderConstants::RENDER_SLOT_DEPTH, dmShaderData_.depth);
2534     }
2535 }
2536 
GLTF2Importer(IEngine & engine,IRenderContext & renderContext,IEcs & ecs)2537 GLTF2Importer::GLTF2Importer(IEngine& engine, IRenderContext& renderContext, IEcs& ecs)
2538     : GLTF2Importer(engine, renderContext, ecs,
2539           *GetInstance<ITaskQueueFactory>(UID_TASK_QUEUE_FACTORY)->CreateThreadPool(IMPORTER_THREADS))
2540 {}
2541 
~GLTF2Importer()2542 GLTF2Importer::~GLTF2Importer()
2543 {
2544     Cancel();
2545 }
2546 
ImportGLTF(const IGLTFData & data,GltfResourceImportFlags flags)2547 void GLTF2Importer::ImportGLTF(const IGLTFData& data, GltfResourceImportFlags flags)
2548 {
2549     Cancel();
2550     cancelled_ = false;
2551 
2552     if (!renderHandleManager_ || !materialManager_ || !meshManager_ || !nameManager_ || !uriManager_) {
2553         result_.success = false;
2554         result_.error += "Missing required component managers.";
2555         return;
2556     }
2557     data_ = (const GLTF2::Data*)&data;
2558     if (!data_) {
2559         result_.success = false;
2560         result_.error += "Invalid IGLTFData to ImportGLTF.";
2561         return;
2562     }
2563 
2564     flags_ = flags;
2565     for (auto& pendingGatherTasks : pendingGatherTasks_) {
2566         pendingGatherTasks = 0U;
2567     }
2568     for (auto& finishedGatherTasks : finishedGatherTasks_) {
2569         finishedGatherTasks.clear();
2570     }
2571     result_.data.samplers.clear();
2572     result_.data.images.clear();
2573     result_.data.textures.clear();
2574     result_.data.materials.clear();
2575     result_.data.meshes.clear();
2576     result_.data.skins.clear();
2577     result_.data.animations.clear();
2578     result_.data.specularRadianceCubemaps.clear();
2579 
2580     meshBuilders_.clear();
2581 
2582     // Build tasks.
2583     Prepare();
2584 
2585     // Fill in task queues for first tasks.
2586     StartPhase(ImportPhase::BUFFERS);
2587 
2588     // Run until completed.
2589     while (!Execute(0)) {
2590         if (gatherResults_[static_cast<uint32_t>(phase_)]) {
2591             gatherResults_[static_cast<uint32_t>(phase_)]->Wait();
2592         }
2593     }
2594 }
2595 
ImportGLTFAsync(const IGLTFData & data,GltfResourceImportFlags flags,Listener * listener)2596 void GLTF2Importer::ImportGLTFAsync(const IGLTFData& data, GltfResourceImportFlags flags, Listener* listener)
2597 {
2598     Cancel();
2599     cancelled_ = false;
2600 
2601     if (!renderHandleManager_ || !materialManager_ || !meshManager_ || !nameManager_ || !uriManager_) {
2602         result_.success = false;
2603         result_.error += "Missing required component managers.";
2604         return;
2605     }
2606 
2607     data_ = (const GLTF2::Data*)&data;
2608     if (!data_) {
2609         result_.success = false;
2610         result_.error += "Invalid IGLTFData to ImportGLTFAsync.";
2611         return;
2612     }
2613 
2614     flags_ = flags;
2615 
2616     result_.success = true;
2617     result_.error.clear();
2618     result_.data.samplers.clear();
2619     result_.data.images.clear();
2620     result_.data.textures.clear();
2621     result_.data.materials.clear();
2622     result_.data.meshes.clear();
2623     result_.data.skins.clear();
2624     result_.data.animations.clear();
2625     result_.data.specularRadianceCubemaps.clear();
2626 
2627     meshBuilders_.clear();
2628 
2629     listener_ = listener;
2630 
2631     // Build tasks.
2632     Prepare();
2633 
2634     // Fill in task queues for first tasks.
2635     StartPhase(ImportPhase::BUFFERS);
2636 }
2637 
Cancel()2638 void GLTF2Importer::Cancel()
2639 {
2640     if (!IsCompleted()) {
2641         cancelled_ = true;
2642         // Wait all ongoing threads to complete.
2643         for (auto& result : gatherResults_) {
2644             if (result) {
2645                 result->Wait();
2646             }
2647         }
2648 
2649         StartPhase(ImportPhase::FINISHED);
2650     }
2651 }
2652 
IsCompleted() const2653 bool GLTF2Importer::IsCompleted() const
2654 {
2655     return phase_ == ImportPhase::FINISHED;
2656 }
2657 
GetResult() const2658 const GLTFImportResult& GLTF2Importer::GetResult() const
2659 {
2660     return result_;
2661 }
2662 
GetMeshData() const2663 const GltfMeshData& GLTF2Importer::GetMeshData() const
2664 {
2665     return meshData_;
2666 }
2667 
IsValid() const2668 bool GLTF2Importer::IsValid() const
2669 {
2670     return uriManager_ && renderHandleManager_ && materialManager_ && meshManager_ && nameManager_ && uriManager_;
2671 }
2672 
LaunchGatherTasks(size_t firstTask,ImportPhase phase)2673 void GLTF2Importer::LaunchGatherTasks(size_t firstTask, ImportPhase phase)
2674 {
2675     auto first = tasks_.begin() + static_cast<ptrdiff_t>(firstTask);
2676     const auto end = tasks_.end();
2677     const auto taskCount = static_cast<size_t>(std::distance(first, end));
2678     vector<const IThreadPool::ITask*> tasks;
2679     tasks.reserve(taskCount);
2680     while (first != end) {
2681         auto& task = **first;
2682         if (task.phase == phase) {
2683             task.state = ImporterTask::State::Gather;
2684             auto threadTask = IThreadPool::ITask::Ptr { new GatherThreadTask(*this, task) };
2685             tasks.push_back(threadTask.get());
2686             threadPool_->PushNoWait(BASE_NS::move(threadTask), BASE_NS::array_view(&bufferTask_, 1U));
2687         }
2688         ++first;
2689     }
2690     // Add a task which waits for all the gather tasks for this cateory.
2691     if (!tasks.empty()) {
2692         gatherResults_[static_cast<uint32_t>(phase)] =
2693             threadPool_->Push(IThreadPool::ITask::Ptr { CreateFunctionTask([]() {}) }, tasks);
2694     }
2695 }
2696 
Prepare()2697 void GLTF2Importer::Prepare()
2698 {
2699     // Build tasks.
2700     PrepareBufferTasks();
2701 
2702     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_SAMPLER) {
2703         PrepareSamplerTasks();
2704     }
2705 
2706     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_IMAGE) {
2707         const auto firstTask = tasks_.size();
2708         PrepareImageTasks();
2709         PrepareImageBasedLightTasks();
2710         LaunchGatherTasks(firstTask, ImportPhase::IMAGES);
2711     }
2712 
2713     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_MATERIAL) {
2714         PrepareMaterialTasks();
2715     }
2716 
2717     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_ANIMATION) {
2718         const auto firstTask = tasks_.size();
2719         PrepareAnimationTasks();
2720         LaunchGatherTasks(firstTask, ImportPhase::ANIMATION_SAMPLERS);
2721     }
2722 
2723     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_SKIN) {
2724         const auto firstTask = tasks_.size();
2725         PrepareSkinTasks();
2726         LaunchGatherTasks(firstTask, ImportPhase::SKINS);
2727     }
2728 
2729     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_MESH) {
2730         const auto firstTask = tasks_.size();
2731         PrepareMeshTasks();
2732         LaunchGatherTasks(firstTask, ImportPhase::MESHES);
2733     }
2734 
2735     if (listener_) {
2736         listener_->OnImportStarted();
2737     }
2738 }
2739 
QueueTask(unique_ptr<ImporterTask> && task)2740 void GLTF2Importer::QueueTask(unique_ptr<ImporterTask>&& task)
2741 {
2742     size_t const taskIndex = tasks_.size();
2743     task->id = taskIndex;
2744     tasks_.push_back(move(task));
2745 }
2746 
ProgressTask(ImporterTask & task)2747 bool GLTF2Importer::ProgressTask(ImporterTask& task)
2748 {
2749     if (task.state == ImporterTask::State::Queued) {
2750         // Task not started, proceed to gather phase.
2751         task.state = ImporterTask::State::Gather;
2752         if (task.gather) {
2753             // All gather task should be launched during Prepare() to fully utilize the thread pool.
2754             CORE_ASSERT(false);
2755             return false;
2756         }
2757     }
2758 
2759     if (task.state == ImporterTask::State::Gather) {
2760         // Gather phase started or skipped, proceed to import.
2761         task.state = ImporterTask::State::Import;
2762         if (task.import) {
2763             pendingImportTasks_++;
2764             mainThreadQueue_->Submit(task.id, IThreadPool::ITask::Ptr { new ImportThreadTask(*this, task) });
2765             return false;
2766         }
2767     }
2768 
2769     if (task.state == ImporterTask::State::Import) {
2770         CompleteTask(task);
2771     }
2772 
2773     return task.state == ImporterTask::State::Finished;
2774 }
2775 
Gather(ImporterTask & task)2776 void GLTF2Importer::Gather(ImporterTask& task)
2777 {
2778     {
2779         CORE_CPU_PERF_SCOPE("CORE3D", "Gather", task.name, CORE3D_PROFILER_DEFAULT_COLOR);
2780 
2781         if (cancelled_ || !task.gather()) {
2782             task.success = false;
2783         }
2784     }
2785 
2786     {
2787         // Mark task completed.
2788         std::lock_guard lock(gatherTasksLock_);
2789         finishedGatherTasks_[static_cast<uint32_t>(task.phase)].push_back(task.id);
2790     }
2791 }
2792 
Import(ImporterTask & task)2793 void GLTF2Importer::Import(ImporterTask& task)
2794 {
2795     CORE_CPU_PERF_SCOPE("CORE3D", "Import", task.name, CORE3D_PROFILER_DEFAULT_COLOR);
2796 
2797     if (cancelled_ || !task.import()) {
2798         task.success = false;
2799     }
2800 }
2801 
CompleteTask(ImporterTask & task)2802 void GLTF2Importer::CompleteTask(ImporterTask& task)
2803 {
2804     if (task.finished) {
2805         task.finished();
2806     }
2807 
2808     task.state = ImporterTask::State::Finished;
2809 
2810     completedTasks_++;
2811 
2812     if (listener_) {
2813         listener_->OnImportProgressed(completedTasks_, tasks_.size());
2814     }
2815 }
2816 
StartPhase(ImportPhase phase)2817 void GLTF2Importer::StartPhase(ImportPhase phase)
2818 {
2819     phase_ = phase;
2820     pendingImportTasks_ = 0;
2821     completedTasks_ = 0;
2822 
2823     if (phase == ImportPhase::FINISHED) {
2824         if ((flags_ & CORE_GLTF_IMPORT_RESOURCE_MESH_CPU_ACCESS) && !meshBuilders_.empty()) {
2825             {
2826                 auto& shaderManager = renderContext_.GetDevice().GetShaderManager();
2827                 const VertexInputDeclarationView vertexInputDeclaration =
2828                     shaderManager.GetVertexInputDeclarationView(shaderManager.GetVertexInputDeclarationHandle(
2829                         DefaultMaterialShaderConstants::VERTEX_INPUT_DECLARATION_FORWARD));
2830                 meshData_.vertexInputDeclaration.bindingDescriptionCount =
2831                     static_cast<uint32_t>(vertexInputDeclaration.bindingDescriptions.size());
2832                 meshData_.vertexInputDeclaration.attributeDescriptionCount =
2833                     static_cast<uint32_t>(vertexInputDeclaration.attributeDescriptions.size());
2834                 std::copy(vertexInputDeclaration.bindingDescriptions.cbegin(),
2835                     vertexInputDeclaration.bindingDescriptions.cend(),
2836                     meshData_.vertexInputDeclaration.bindingDescriptions);
2837                 std::copy(vertexInputDeclaration.attributeDescriptions.cbegin(),
2838                     vertexInputDeclaration.attributeDescriptions.cend(),
2839                     meshData_.vertexInputDeclaration.attributeDescriptions);
2840             }
2841             meshData_.meshes.resize(meshBuilders_.size());
2842             for (uint32_t mesh = 0U; mesh < meshBuilders_.size(); ++mesh) {
2843                 if (!meshBuilders_[mesh]) {
2844                     continue;
2845                 }
2846                 auto& currentMesh = meshData_.meshes[mesh];
2847                 auto vertexData = meshBuilders_[mesh]->GetVertexData();
2848                 auto indexData = meshBuilders_[mesh]->GetIndexData();
2849                 auto jointData = meshBuilders_[mesh]->GetJointData();
2850                 auto submeshes = meshBuilders_[mesh]->GetSubmeshes();
2851                 currentMesh.subMeshes.resize(submeshes.size());
2852                 for (uint32_t subMesh = 0U; subMesh < submeshes.size(); ++subMesh) {
2853                     auto& currentSubMesh = currentMesh.subMeshes[subMesh];
2854                     currentSubMesh.indices = submeshes[subMesh].indexCount;
2855                     currentSubMesh.vertices = submeshes[subMesh].vertexCount;
2856 
2857                     currentSubMesh.indexBuffer = array_view(indexData.data() + submeshes[subMesh].indexBuffer.offset,
2858                         submeshes[subMesh].indexBuffer.byteSize);
2859 
2860                     auto& bufferAccess = submeshes[subMesh].bufferAccess;
2861                     auto fill = [](array_view<const uint8_t> data, const MeshComponent::Submesh::BufferAccess& buffer) {
2862                         if (buffer.offset > data.size() || buffer.offset + buffer.byteSize > data.size()) {
2863                             return array_view<const uint8_t> {};
2864                         }
2865                         return array_view(data.data() + buffer.offset, buffer.byteSize);
2866                     };
2867                     currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_POS] =
2868                         fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_POS]);
2869                     currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_NOR] =
2870                         fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_NOR]);
2871                     currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_UV0] =
2872                         fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_UV0]);
2873                     if (submeshes[subMesh].flags & MeshComponent::Submesh::SECOND_TEXCOORD_BIT) {
2874                         currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_UV1] =
2875                             fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_UV1]);
2876                     }
2877                     if (submeshes[subMesh].flags & MeshComponent::Submesh::TANGENTS_BIT) {
2878                         currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_TAN] =
2879                             fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_TAN]);
2880                     }
2881                     if (submeshes[subMesh].flags & MeshComponent::Submesh::VERTEX_COLORS_BIT) {
2882                         currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_COL] =
2883                             fill(vertexData, bufferAccess[MeshComponent::Submesh::DM_VB_COL]);
2884                     }
2885                     if (submeshes[subMesh].flags & MeshComponent::Submesh::SKIN_BIT) {
2886                         currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_JOI] =
2887                             fill(jointData, bufferAccess[MeshComponent::Submesh::DM_VB_JOI]);
2888                         currentSubMesh.attributeBuffers[MeshComponent::Submesh::DM_VB_JOW] =
2889                             fill(jointData, bufferAccess[MeshComponent::Submesh::DM_VB_JOW]);
2890                     }
2891                 }
2892             }
2893         }
2894         // All tasks are done.
2895         if (listener_) {
2896             listener_->OnImportFinished();
2897         }
2898         tasks_.clear();
2899         return;
2900     }
2901 
2902     for (auto& task : tasks_) {
2903         if (task->state == ImporterTask::State::Finished) {
2904             continue;
2905         }
2906 
2907         if (task->phase != phase) {
2908             continue;
2909         }
2910 
2911         // This will turn queued tasks to running ones.
2912         if (task->state == ImporterTask::State::Queued) {
2913             ProgressTask(*task);
2914         }
2915     }
2916 }
2917 
FindTaskById(uint64_t id)2918 GLTF2Importer::ImporterTask* GLTF2Importer::FindTaskById(uint64_t id)
2919 {
2920     for (size_t i = 0; i < tasks_.size(); ++i) {
2921         if (tasks_[i]->id == id) {
2922             return tasks_[i].get();
2923         }
2924     }
2925 
2926     return nullptr;
2927 }
2928 
Execute(uint32_t timeBudget)2929 bool GLTF2Importer::Execute(uint32_t timeBudget)
2930 {
2931     if (IsCompleted()) {
2932         return true;
2933     }
2934 
2935     // Handle data gathering.
2936     HandleGatherTasks();
2937 
2938     // 'timeBudget' is given in microseconds
2939     const auto budget = std::chrono::microseconds(timeBudget);
2940 
2941     // Use steady_clock for measuring
2942     using Clock = std::chrono::steady_clock;
2943 
2944     // Start time.
2945     const auto s0 = Clock::now();
2946 
2947     // Handle resource / scene importing.
2948     while (pendingImportTasks_ > 0) {
2949         // Execute and handle one task.
2950         mainThreadQueue_->Execute();
2951         HandleImportTasks();
2952 
2953         // Check how much time has elapsed.
2954         if (timeBudget > 0) {
2955             const auto s1 = Clock::now();
2956             if (((s1 - s0) >= budget)) {
2957                 // Break if whole time budget consumed.
2958                 break;
2959             }
2960         }
2961     }
2962 
2963     // All tasks done for this phase?
2964     if ((!gatherResults_[static_cast<uint32_t>(phase_)] || gatherResults_[static_cast<uint32_t>(phase_)]->IsDone()) &&
2965         pendingImportTasks_ == 0) {
2966         // Proceed to next phase.
2967         StartPhase((ImportPhase)(phase_ + 1));
2968     }
2969 
2970     return IsCompleted();
2971 }
2972 
HandleImportTasks()2973 void GLTF2Importer::HandleImportTasks()
2974 {
2975     const vector<uint64_t> finishedImportTasks = mainThreadQueue_->CollectFinishedTasks();
2976     if (!finishedImportTasks.empty()) {
2977         pendingImportTasks_ -= finishedImportTasks.size();
2978 
2979         for (auto& finishedId : finishedImportTasks) {
2980             ImporterTask* task = FindTaskById(finishedId);
2981             if (task) {
2982                 if (task->success) {
2983                     ProgressTask(*task);
2984                 } else {
2985                     // Import phase failed.
2986                     const string error = "Import data failed: " + task->name;
2987                     CORE_LOG_W("%s", error.c_str());
2988                     result_.success = false;
2989                     result_.error += error + '\n';
2990                 }
2991             }
2992         }
2993     }
2994 }
2995 
HandleGatherTasks()2996 void GLTF2Importer::HandleGatherTasks()
2997 {
2998     auto& result = gatherResults_[static_cast<uint32_t>(phase_)];
2999     if (!result || !result->IsDone()) {
3000         return;
3001     }
3002 
3003     vector<uint64_t> finishedGatherTasks;
3004     {
3005         std::lock_guard lock(gatherTasksLock_);
3006         std::swap(finishedGatherTasks, finishedGatherTasks_[static_cast<uint32_t>(phase_)]);
3007     }
3008 
3009     if (finishedGatherTasks.size() > 0) {
3010         for (auto& finishedId : finishedGatherTasks) {
3011             ImporterTask* task = FindTaskById(finishedId);
3012             if (task) {
3013                 if (task->success) {
3014                     ProgressTask(*task);
3015                 } else {
3016                     // Gather phase failed.
3017                     const string error = "Gather data failed: " + task->name;
3018                     CORE_LOG_W("%s", error.c_str());
3019                     result_.success = false;
3020                     result_.error += error + '\n';
3021                 }
3022                 result_.error += task->errors;
3023             }
3024         }
3025     }
3026 }
3027 
PrepareBufferTasks()3028 void GLTF2Importer::PrepareBufferTasks()
3029 {
3030     // Buffers task.
3031     const auto firstTask = static_cast<ptrdiff_t>(tasks_.size());
3032     auto task = make_unique<ImporterTask>();
3033     task->name = "Load buffers";
3034     task->phase = ImportPhase::BUFFERS;
3035     task->gather = [this, t = task.get()]() -> bool {
3036         BufferLoadResult result = LoadBuffers(data_, engine_.GetFileManager());
3037         t->errors += result.error;
3038         return result.success;
3039     };
3040     QueueTask(BASE_NS::move(task));
3041 
3042     // We're loading all the buffers in one gather. This is probably fine as typical glTF files have just one binary
3043     // blob.
3044     (*(tasks_.begin() + firstTask))->state = ImporterTask::State::Gather;
3045     auto threadTask = IThreadPool::ITask::Ptr { new GatherThreadTask(*this, *(*(tasks_.begin() + firstTask))) };
3046     bufferTask_ = threadTask.get();
3047     ++pendingGatherTasks_[static_cast<uint32_t>(ImportPhase::BUFFERS)];
3048     gatherResults_[static_cast<uint32_t>(ImportPhase::BUFFERS)] = threadPool_->Push(BASE_NS::move(threadTask));
3049 }
3050 
PrepareSamplerTasks()3051 void GLTF2Importer::PrepareSamplerTasks()
3052 {
3053     for (size_t i = 0; i < data_->samplers.size(); ++i) {
3054         auto task = make_unique<ImporterTask>();
3055         task->name = "Import sampler";
3056         task->phase = ImportPhase::SAMPLERS;
3057         task->import = [this, i]() -> bool {
3058             EntityReference entity;
3059             auto const& sampler = data_->samplers[i];
3060             if ((sampler->magFilter != FilterMode::LINEAR) || (sampler->minFilter != FilterMode::LINEAR) ||
3061                 (sampler->wrapS != WrapMode::REPEAT) || (sampler->wrapT != WrapMode::REPEAT)) {
3062                 GpuSamplerDesc desc;
3063                 ConvertToCoreFilter(sampler->magFilter, desc.magFilter);
3064                 ConvertToCoreFilter(sampler->minFilter, desc.minFilter, desc.mipMapMode);
3065 
3066                 desc.minLod = 0.0f;
3067                 desc.maxLod = 32.0f;
3068 
3069                 desc.addressModeU = ConvertToCoreWrapMode(sampler->wrapS);
3070                 desc.addressModeV = ConvertToCoreWrapMode(sampler->wrapT);
3071                 desc.addressModeW = desc.addressModeU;
3072 
3073                 entity = ecs_->GetEntityManager().CreateReferenceCounted();
3074                 renderHandleManager_->Create(entity);
3075                 string const name = data_->defaultResources + "_sampler_" + to_string(i);
3076                 renderHandleManager_->Write(entity)->reference = gpuResourceManager_.GetOrCreate(name, desc);
3077             }
3078             result_.data.samplers.push_back(move(entity));
3079 
3080             return true;
3081         };
3082 
3083         QueueTask(move(task));
3084     }
3085 }
3086 
QueueImage(size_t i,string && uri,string && name)3087 void GLTF2Importer::QueueImage(size_t i, string&& uri, string&& name)
3088 {
3089     struct ImageTaskData {
3090         GLTF2Importer* importer;
3091         size_t index;
3092         string uri;
3093         string name;
3094         refcnt_ptr<IRenderDataStoreDefaultStaging> staging;
3095         RenderHandleReference imageHandle;
3096     };
3097 
3098     constexpr const string_view RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging";
3099 
3100     auto staging = refcnt_ptr<IRenderDataStoreDefaultStaging>(
3101         renderContext_.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING.data()));
3102     // Does not exist, which means it needs to be imported.
3103     auto task = make_unique<GatheredDataTask<ImageTaskData>>();
3104     task->data = ImageTaskData { this, i, move(uri), move(name), staging, {} };
3105     task->name = "Import image";
3106     task->phase = ImportPhase::IMAGES;
3107     task->gather = [t = task.get(), colorSpaceFlags = colorSpaceFlags_]() -> bool {
3108         GLTF2Importer* importer = t->data.importer;
3109         auto const& image = importer->data_->images[t->data.index];
3110         IImageLoaderManager::LoadResult result = GatherImageData(*image, *importer->data_,
3111             importer->engine_.GetFileManager(), importer->engine_.GetImageLoaderManager(), 0U, colorSpaceFlags);
3112         if (result.success) {
3113             t->data.imageHandle =
3114                 ImportTexture(t->data.uri, move(result.image), *t->data.staging, importer->gpuResourceManager_);
3115         } else {
3116             CORE_LOG_W("Loading image '%s' failed: %s", image->uri.c_str(), result.error);
3117             t->errors += result.error;
3118             t->errors += '\n';
3119         }
3120 
3121         return true;
3122     };
3123 
3124     task->import = [t = task.get()]() mutable -> bool {
3125         if (t->data.imageHandle) {
3126             GLTF2Importer* importer = t->data.importer;
3127             auto imageEntity = importer->ecs_->GetEntityManager().CreateReferenceCounted();
3128             importer->renderHandleManager_->Create(imageEntity);
3129             importer->renderHandleManager_->Write(imageEntity)->reference = move(t->data.imageHandle);
3130             if (!t->data.uri.empty()) {
3131                 importer->uriManager_->Create(imageEntity);
3132                 importer->uriManager_->Write(imageEntity)->uri = move(t->data.uri);
3133             }
3134             if (!t->data.name.empty()) {
3135                 importer->nameManager_->Create(imageEntity);
3136                 importer->nameManager_->Write(imageEntity)->name = move(t->data.name);
3137             }
3138 
3139             importer->result_.data.images[t->data.index] = move(imageEntity);
3140         }
3141 
3142         return true;
3143     };
3144 
3145     task->finished = [t = task.get()]() {};
3146 
3147     QueueTask(move(task));
3148 }
3149 
PrepareImageTasks()3150 void GLTF2Importer::PrepareImageTasks()
3151 {
3152     result_.data.images.resize(data_->images.size(), {});
3153     result_.data.textures.resize(data_->textures.size(), {});
3154 
3155     const bool skipUnusedResources = (flags_ & CORE_GLTF_IMPORT_RESOURCE_SKIP_UNUSED) != 0;
3156 
3157     vector<bool> imageLoadingRequred;
3158     imageLoadingRequred.resize(data_->images.size(), skipUnusedResources ? false : true);
3159 
3160     if (skipUnusedResources) {
3161         // Find image references from textures.
3162         ResolveReferencedImages(*data_, imageLoadingRequred);
3163     }
3164 
3165     // Tasks for image loading.
3166     for (size_t i = 0; i < data_->images.size(); ++i) {
3167         // Skip loading of this image if it is not referenced by textures.
3168         if (!imageLoadingRequred[i]) {
3169             continue;
3170         }
3171 
3172         string uri;
3173         string name = data_->defaultResources + "/images/" + to_string(i);
3174 
3175         auto const& image = data_->images[i];
3176         if (image->uri.empty() || GLTF2::IsDataURI(image->uri)) {
3177             // NOTE: Might need to figure out better way to reference embedded resources.
3178             uri = data_->filepath + "/" + name;
3179         } else {
3180             uri = data_->filepath + "/" + image->uri;
3181         }
3182 
3183         // See if this resource already exists.
3184         Entity imageEntity = LookupResourceByUri(uri, *uriManager_, *renderHandleManager_);
3185         if (EntityUtil::IsValid(imageEntity)) {
3186             // Already exists.
3187             result_.data.images[i] = ecs_->GetEntityManager().GetReferenceCounted(imageEntity);
3188             CORE_LOG_D("Resource already exists, skipping ('%s')", uri.c_str());
3189             continue;
3190         }
3191 
3192         QueueImage(i, move(uri), move(name));
3193     }
3194 
3195     // Tasks assigning textures to images.
3196     for (size_t i = 0; i < data_->textures.size(); ++i) {
3197         auto task = make_unique<ImporterTask>();
3198         task->name = "Import texture";
3199         task->phase = ImportPhase::TEXTURES;
3200         task->import = [this, i]() -> bool {
3201             const GLTF2::Texture& texture = *(data_->textures[i]);
3202 
3203             const size_t index = FindIndex(data_->images, texture.image);
3204             if (index != GLTF_INVALID_INDEX) {
3205                 result_.data.textures[i] = result_.data.images[index];
3206             }
3207 
3208             return true;
3209         };
3210         QueueTask(move(task));
3211     }
3212 }
3213 
PrepareImageBasedLightTasks()3214 void GLTF2Importer::PrepareImageBasedLightTasks()
3215 {
3216 #if defined(GLTF2_EXTENSION_EXT_LIGHTS_IMAGE_BASED)
3217     result_.data.specularRadianceCubemaps.resize(data_->imageBasedLights.size(), {});
3218 
3219     // Do nothing in case there are no image based lights.
3220     if (data_->imageBasedLights.empty()) {
3221         return;
3222     }
3223 
3224     for (size_t lightIndex = 0; lightIndex < data_->imageBasedLights.size(); ++lightIndex) {
3225         const auto& light = data_->imageBasedLights[lightIndex];
3226 
3227         // Create gather task that loads all cubemap faces for this light.
3228         auto task = make_unique<GatheredDataTask<RenderHandleReference>>();
3229         task->name = "Import specular radiance cubemaps";
3230         task->phase = ImportPhase::IMAGES;
3231 
3232         task->gather = [this, &light, t = task.get()]() -> bool {
3233             bool success = true;
3234             vector<IImageLoaderManager::LoadResult> mipLevels;
3235             // For all mip levels.
3236             for (const auto& mipLevel : light->specularImages) {
3237                 // For all cube faces.
3238                 for (const auto& cubeFace : mipLevel) {
3239                     if (cubeFace >= data_->images.size()) {
3240                         success = false;
3241                         break;
3242                     }
3243                     // Get image for this cube face.
3244                     auto& image = data_->images[cubeFace];
3245                     if (!image) {
3246                         success = false;
3247                         break;
3248                     }
3249                     // Load image.
3250                     auto loadResult =
3251                         GatherImageData(*image, *data_, engine_.GetFileManager(), engine_.GetImageLoaderManager(),
3252                             IImageLoaderManager::IMAGE_LOADER_FLIP_VERTICALLY_BIT, colorSpaceFlags_);
3253                     if (!loadResult.success) {
3254                         success = false;
3255                         CORE_LOG_W("Loading image '%s' failed: %s", image->uri.c_str(), loadResult.error);
3256                         break;
3257                     }
3258 
3259                     mipLevels.push_back(move(loadResult));
3260                 }
3261             }
3262             if (!mipLevels.empty()) {
3263                 t->data = CreateCubemapFromImages(light->specularImageSize, mipLevels, gpuResourceManager_);
3264             }
3265             return success;
3266         };
3267 
3268         task->import = [this, lightIndex, t = task.get()]() -> bool {
3269             // Import specular cubemap image if needed.
3270             if (t->data) {
3271                 EntityReference imageEntity = ecs_->GetEntityManager().CreateReferenceCounted();
3272                 renderHandleManager_->Create(imageEntity);
3273                 renderHandleManager_->Write(imageEntity)->reference = move(t->data);
3274                 result_.data.specularRadianceCubemaps[lightIndex] = move(imageEntity);
3275             }
3276 
3277             return true;
3278         };
3279 
3280         QueueTask(move(task));
3281     }
3282 #endif
3283 }
3284 
PrepareMaterialTasks()3285 void GLTF2Importer::PrepareMaterialTasks()
3286 {
3287     // Create EntityReferences for materials already at this stage. This allows assigning materials to meshes before
3288     // they are ready.
3289     const auto materialCount = data_->materials.size();
3290     result_.data.materials.reserve(materialCount);
3291 
3292     for (size_t i = 0; i < materialCount; ++i) {
3293         string uri;
3294         static constexpr string_view materialsPath = "/materials/";
3295         uri.reserve(data_->filepath.size() + data_->defaultResources.size() + materialsPath.size() + 2U);
3296         uri += data_->filepath;
3297         uri += '/';
3298         uri += data_->defaultResources;
3299         uri += materialsPath;
3300         uri += to_string(i);
3301         auto materialEntity = LookupResourceByUri(uri, *uriManager_, *materialManager_);
3302         if (EntityUtil::IsValid(materialEntity)) {
3303             CORE_LOG_D("Resource already exists, skipping ('%s')", uri.c_str());
3304         } else {
3305             materialEntity = ecs_->GetEntityManager().Create();
3306             if (!uri.empty()) {
3307                 uriManager_->Create(materialEntity);
3308                 uriManager_->Write(materialEntity)->uri = BASE_NS::move(uri);
3309             }
3310         }
3311 
3312         result_.data.materials.push_back(ecs_->GetEntityManager().GetReferenceCounted(materialEntity));
3313     }
3314 
3315     auto task = make_unique<ImporterTask>();
3316     task->name = "Import material";
3317     task->phase = ImportPhase::MATERIALS;
3318     task->import = [this]() -> bool {
3319         bool success = true;
3320         for (size_t i = 0; i < data_->materials.size(); ++i) {
3321             const Entity materialEntity = result_.data.materials[i];
3322             if (const auto materialComponentId = materialManager_->GetComponentId(materialEntity);
3323                 materialComponentId != IComponentManager::INVALID_COMPONENT_ID) {
3324                 // Material was already created
3325                 continue;
3326             }
3327             // Does not exist, so needs to be imported.
3328             const auto& gltfMaterial = *data_->materials[i];
3329             if (!gltfMaterial.name.empty()) {
3330                 nameManager_->Create(materialEntity);
3331                 nameManager_->Write(materialEntity)->name = gltfMaterial.name;
3332             }
3333             materialManager_->Create(materialEntity);
3334             success = ImportMaterial(result_, *data_, gltfMaterial, materialEntity, *materialManager_,
3335                                      gpuResourceManager_, dmShaderData_) &&
3336                       success;
3337         }
3338 
3339         return success;
3340     };
3341 
3342     QueueTask(move(task));
3343 }
3344 
PrepareMeshTasks()3345 void GLTF2Importer::PrepareMeshTasks()
3346 {
3347     result_.data.meshes.resize(data_->meshes.size(), {});
3348     if (flags_ & CORE_GLTF_IMPORT_RESOURCE_MESH_CPU_ACCESS) {
3349         meshBuilders_.resize(data_->meshes.size());
3350     }
3351 
3352     for (size_t i = 0; i < data_->meshes.size(); ++i) {
3353         string uri = data_->filepath + '/' + data_->defaultResources + "/meshes/" + to_string(i);
3354         const string_view name = data_->meshes[i]->name;
3355 
3356         // See if this resource already exists.
3357         const auto meshEntity = LookupResourceByUri(uri, *uriManager_, *meshManager_);
3358         if (EntityUtil::IsValid(meshEntity)) {
3359             // Already exists.
3360             result_.data.meshes[i] = ecs_->GetEntityManager().GetReferenceCounted(meshEntity);
3361             CORE_LOG_D("Resource already exists, skipping ('%s')", uri.c_str());
3362             continue;
3363         }
3364 
3365         auto task = make_unique<GatheredDataTask<GatherMeshDataResult>>();
3366         task->name = "Import mesh";
3367         task->phase = ImportPhase::MESHES;
3368         task->gather = [this, i, t = task.get()]() -> bool {
3369             const GLTF2::Mesh& mesh = *(data_->meshes[i]);
3370 
3371             // Gather mesh data.
3372             t->data = GatherMeshData(mesh, result_, flags_, *materialManager_, device_, engine_);
3373             return t->data.success;
3374         };
3375 
3376         task->import = [this, i, uri = move(uri), name, t = task.get()]() mutable -> bool {
3377             if (!t->data.success) {
3378                 return false;
3379             }
3380             // Import mesh.
3381             auto meshEntity = ImportMesh(*ecs_, t->data);
3382             if (!EntityUtil::IsValid(meshEntity)) {
3383                 return false;
3384             }
3385             if (!uri.empty()) {
3386                 uriManager_->Create(meshEntity);
3387                 uriManager_->Write(meshEntity)->uri = move(uri);
3388             }
3389             if (!name.empty()) {
3390                 nameManager_->Create(meshEntity);
3391                 nameManager_->Write(meshEntity)->name = name;
3392             }
3393 
3394             result_.data.meshes[i] = ecs_->GetEntityManager().GetReferenceCounted(meshEntity);
3395             return true;
3396         };
3397 
3398         task->finished = [this, i, t = task.get()]() {
3399             if (flags_ & CORE_GLTF_IMPORT_RESOURCE_MESH_CPU_ACCESS) {
3400                 meshBuilders_[i] = BASE_NS::move(t->data.meshBuilder);
3401             } else {
3402                 t->data.meshBuilder.reset();
3403             }
3404         };
3405 
3406         QueueTask(move(task));
3407     }
3408 }
3409 
3410 template<>
3411 GLTF2Importer::GatheredDataTask<GLTF2Importer::ComponentTaskData<AnimationInputComponent>>*
PrepareAnimationInputTask(unordered_map<Accessor *,GatheredDataTask<ComponentTaskData<AnimationInputComponent>> * > & inputs,const AnimationTrack & track,IAnimationInputComponentManager * animationInputManager)3412 GLTF2Importer::PrepareAnimationInputTask(
3413     unordered_map<Accessor*, GatheredDataTask<ComponentTaskData<AnimationInputComponent>>*>& inputs,
3414     const AnimationTrack& track, IAnimationInputComponentManager* animationInputManager)
3415 {
3416     GLTF2Importer::GatheredDataTask<GLTF2Importer::ComponentTaskData<AnimationInputComponent>>* result = nullptr;
3417     if (auto pos = inputs.find(track.sampler->input); pos == inputs.end()) {
3418         auto task = make_unique<GatheredDataTask<ComponentTaskData<AnimationInputComponent>>>();
3419         task->name = "Import animation input";
3420         task->phase = ImportPhase::ANIMATION_SAMPLERS;
3421         task->gather = [this, accessor = track.sampler->input, t = task.get()]() -> bool {
3422             return BuildAnimationInput(*data_, engine_.GetFileManager(), *accessor, t->data.component);
3423         };
3424         task->import = [em = &ecs_->GetEntityManager(), animationInputManager, t = task.get()]() -> bool {
3425             t->data.entity = em->CreateReferenceCounted();
3426             animationInputManager->Set(t->data.entity, t->data.component);
3427             return true;
3428         };
3429         inputs.insert({ track.sampler->input, task.get() });
3430         result = task.get();
3431         QueueTask(move(task));
3432     } else {
3433         result = pos->second;
3434     }
3435     return result;
3436 }
3437 
3438 template<>
3439 GLTF2Importer::GatheredDataTask<GLTF2Importer::ComponentTaskData<AnimationOutputComponent>>*
PrepareAnimationOutputTask(unordered_map<Accessor *,GatheredDataTask<ComponentTaskData<AnimationOutputComponent>> * > & outputs,const AnimationTrack & track,IAnimationOutputComponentManager * animationOutputManager)3440 GLTF2Importer::PrepareAnimationOutputTask(
3441     unordered_map<Accessor*, GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>*>& outputs,
3442     const AnimationTrack& track, IAnimationOutputComponentManager* animationOutputManager)
3443 {
3444     GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>* result = nullptr;
3445     if (auto pos = outputs.find(track.sampler->output); pos == outputs.end()) {
3446         auto task = make_unique<GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>>();
3447         task->name = "Import animation output";
3448         task->phase = ImportPhase::ANIMATION_SAMPLERS;
3449         task->gather = [this, accessor = track.sampler->output, path = track.channel.path, t = task.get()]() -> bool {
3450             return BuildAnimationOutput(*data_, engine_.GetFileManager(), *accessor, path, t->data.component);
3451         };
3452         task->import = [em = &ecs_->GetEntityManager(), animationOutputManager, t = task.get()]() -> bool {
3453             t->data.entity = em->CreateReferenceCounted();
3454             animationOutputManager->Set(t->data.entity, t->data.component);
3455             return true;
3456         };
3457         outputs.insert({ track.sampler->output, task.get() });
3458         result = task.get();
3459         QueueTask(move(task));
3460     } else {
3461         result = pos->second;
3462     }
3463     return result;
3464 }
3465 
PrepareAnimationTasks()3466 void GLTF2Importer::PrepareAnimationTasks()
3467 {
3468     auto animationManager = GetManager<IAnimationComponentManager>(*ecs_);
3469     auto animationInputManager = GetManager<IAnimationInputComponentManager>(*ecs_);
3470     auto animationOutputManager = GetManager<IAnimationOutputComponentManager>(*ecs_);
3471     auto animationTrackManager = GetManager<IAnimationTrackComponentManager>(*ecs_);
3472     if (!animationManager || !animationInputManager || !animationOutputManager || !animationTrackManager) {
3473         return;
3474     }
3475     result_.data.animations.resize(data_->animations.size(), {});
3476 
3477     unordered_map<Accessor*, GatheredDataTask<ComponentTaskData<AnimationInputComponent>>*> inputs;
3478     unordered_map<Accessor*, GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>*> outputs;
3479     for (size_t i = 0; i < data_->animations.size(); i++) {
3480         const string uri = data_->filepath + '/' + data_->defaultResources + "/animations/" + to_string(i);
3481         const string_view name = data_->animations[i]->name;
3482 
3483         // See if this resource already exists.
3484         const auto animationEntity = LookupResourceByUri(uri, *uriManager_, *animationManager);
3485         if (EntityUtil::IsValid(animationEntity)) {
3486             result_.data.animations[i] = ecs_->GetEntityManager().GetReferenceCounted(animationEntity);
3487             CORE_LOG_D("Resource already exists, skipping ('%s')", uri.c_str());
3488             continue;
3489         }
3490         vector<GatheredDataTask<ComponentTaskData<AnimationInputComponent>>*> inputResults;
3491         vector<GatheredDataTask<ComponentTaskData<AnimationOutputComponent>>*> outputResults;
3492         for (const auto& track : data_->animations[i]->tracks) {
3493             if (track.sampler && track.sampler->input && track.sampler->output) {
3494                 inputResults.push_back(PrepareAnimationInputTask(inputs, track, animationInputManager));
3495                 outputResults.push_back(PrepareAnimationOutputTask(outputs, track, animationOutputManager));
3496             }
3497         }
3498 
3499         auto task = make_unique<ImporterTask>();
3500         task->name = "Import animation";
3501         task->phase = ImportPhase::ANIMATIONS;
3502         task->import = AnimationTaskData { this, i, uri, name, animationManager, animationTrackManager,
3503             move(inputResults), move(outputResults) };
3504         task->finished = [t = task.get()]() { t->import = {}; };
3505 
3506         QueueTask(move(task));
3507     }
3508 }
3509 
PrepareSkinTasks()3510 void GLTF2Importer::PrepareSkinTasks()
3511 {
3512     auto* skinIbmManager = GetManager<ISkinIbmComponentManager>(*ecs_);
3513     if (!skinIbmManager) {
3514         return;
3515     }
3516     result_.data.skins.resize(data_->skins.size(), {});
3517 
3518     for (size_t i = 0; i < data_->skins.size(); i++) {
3519         string name = data_->defaultResources + "/skins/" + to_string(i);
3520         string uri = data_->filepath + '/' + name;
3521 
3522         // See if this resource already exists.
3523         const Entity skinIbmEntity = LookupResourceByUri(uri, *uriManager_, *skinIbmManager);
3524         if (EntityUtil::IsValid(skinIbmEntity)) {
3525             // Already exists.
3526             result_.data.skins[i] = ecs_->GetEntityManager().GetReferenceCounted(skinIbmEntity);
3527             CORE_LOG_D("Resource already exists, skipping ('%s')", uri.c_str());
3528             continue;
3529         }
3530 
3531         auto task = make_unique<GatheredDataTask<SkinIbmComponent>>();
3532         task->name = "Import skin";
3533         task->phase = ImportPhase::SKINS;
3534         task->gather = [this, i, t = task.get()]() -> bool {
3535             return BuildSkinIbmComponent(*(data_->skins[i]), t->data);
3536         };
3537 
3538         task->import = [this, i, uri = move(uri), name = move(name), t = task.get(), skinIbmManager]() mutable -> bool {
3539             if (!t->data.matrices.empty()) {
3540                 auto skinIbmEntity = ecs_->GetEntityManager().CreateReferenceCounted();
3541 
3542                 skinIbmManager->Create(skinIbmEntity);
3543                 {
3544                     auto skinIbmHandle = skinIbmManager->Write(skinIbmEntity);
3545                     *skinIbmHandle = move(t->data);
3546                 }
3547 
3548                 uriManager_->Create(skinIbmEntity);
3549                 uriManager_->Write(skinIbmEntity)->uri = move(uri);
3550                 nameManager_->Create(skinIbmEntity);
3551                 nameManager_->Write(skinIbmEntity)->name = move(name);
3552                 result_.data.skins[i] = move(skinIbmEntity);
3553                 return true;
3554             }
3555 
3556             return false;
3557         };
3558 
3559         task->finished = [t = task.get()]() { t->data = {}; };
3560 
3561         QueueTask(move(task));
3562     }
3563 }
3564 
Destroy()3565 void GLTF2Importer::Destroy()
3566 {
3567     delete this;
3568 }
3569 
Gltf2SceneImporter(IEngine & engine,IRenderContext & renderContext,IEcs & ecs)3570 Gltf2SceneImporter::Gltf2SceneImporter(IEngine& engine, IRenderContext& renderContext, IEcs& ecs)
3571     : ecs_(ecs), graphicsContext_(GetInstance<IGraphicsContext>(
3572                      *renderContext.GetInterface<IClassRegister>(), UID_GRAPHICS_CONTEXT)),
3573       importer_(new GLTF2::GLTF2Importer(engine, renderContext, ecs))
3574 {}
3575 
Gltf2SceneImporter(IEngine & engine,IRenderContext & renderContext,IEcs & ecs,IThreadPool & pool)3576 Gltf2SceneImporter::Gltf2SceneImporter(IEngine& engine, IRenderContext& renderContext, IEcs& ecs, IThreadPool& pool)
3577     : ecs_(ecs), graphicsContext_(GetInstance<IGraphicsContext>(
3578                      *renderContext.GetInterface<IClassRegister>(), UID_GRAPHICS_CONTEXT)),
3579       importer_(new GLTF2::GLTF2Importer(engine, renderContext, ecs, pool))
3580 {}
3581 
ImportResources(const ISceneData::Ptr & data,ResourceImportFlags flags)3582 void Gltf2SceneImporter::ImportResources(const ISceneData::Ptr& data, ResourceImportFlags flags)
3583 {
3584     data_ = {};
3585     listener_ = nullptr;
3586     result_.error = 1;
3587     if (auto sceneData = data->GetInterface<SceneData>()) {
3588         if (auto* gltfData = sceneData->GetData()) {
3589             importer_->ImportGLTF(*gltfData, flags);
3590             const auto& result = importer_->GetResult();
3591             result_.error = result.success ? 0 : 1;
3592             result_.message = result.error;
3593             result_.data.samplers = result.data.samplers;
3594             result_.data.images = result.data.images;
3595             result_.data.textures = result.data.textures;
3596             result_.data.materials = result.data.materials;
3597             result_.data.meshes = result.data.meshes;
3598             result_.data.skins = result.data.skins;
3599             result_.data.animations = result.data.animations;
3600             result_.data.specularRadianceCubemaps = result.data.specularRadianceCubemaps;
3601             if (!result_.error) {
3602                 data_ = data;
3603             }
3604         }
3605     }
3606 }
3607 
ImportResources(const ISceneData::Ptr & data,ResourceImportFlags flags,ISceneImporter::Listener * listener)3608 void Gltf2SceneImporter::ImportResources(
3609     const ISceneData::Ptr& data, ResourceImportFlags flags, ISceneImporter::Listener* listener)
3610 {
3611     data_ = {};
3612     listener_ = nullptr;
3613 
3614     if (auto sceneData = data->GetInterface<SceneData>()) {
3615         if (auto* gltfData = sceneData->GetData()) {
3616             listener_ = listener;
3617             data_ = data;
3618             importer_->ImportGLTFAsync(*gltfData, flags, this);
3619         }
3620     }
3621 }
3622 
Execute(uint32_t timeBudget)3623 bool Gltf2SceneImporter::Execute(uint32_t timeBudget)
3624 {
3625     if (importer_->Execute(timeBudget)) {
3626         const auto& result = importer_->GetResult();
3627         result_.error = result.success ? 0 : 1;
3628         result_.message = result.error;
3629         result_.data.samplers = result.data.samplers;
3630         result_.data.images = result.data.images;
3631         result_.data.textures = result.data.textures;
3632         result_.data.materials = result.data.materials;
3633         result_.data.meshes = result.data.meshes;
3634         result_.data.skins = result.data.skins;
3635         result_.data.animations = result.data.animations;
3636         result_.data.specularRadianceCubemaps = result.data.specularRadianceCubemaps;
3637         const auto& meshData = importer_->GetMeshData();
3638         meshData_.meshes.resize(meshData.meshes.size());
3639         for (size_t i = 0U; i < meshData.meshes.size(); ++i) {
3640             auto& dstMesh = meshData_.meshes[i];
3641             const auto& srcMesh = meshData.meshes[i];
3642             dstMesh.subMeshes.resize(srcMesh.subMeshes.size());
3643             std::transform(srcMesh.subMeshes.cbegin(), srcMesh.subMeshes.cend(), dstMesh.subMeshes.begin(),
3644                 [](const GltfMeshData::SubMesh& gltfSubmesh) {
3645                     MeshData::SubMesh submesh;
3646                     submesh.indices = gltfSubmesh.indices;
3647                     submesh.vertices = gltfSubmesh.vertices;
3648                     submesh.indexBuffer = gltfSubmesh.indexBuffer;
3649                     std::copy(std::begin(gltfSubmesh.attributeBuffers), std::end(gltfSubmesh.attributeBuffers),
3650                         std::begin(submesh.attributeBuffers));
3651                     return submesh;
3652                 });
3653         }
3654         meshData_.vertexInputDeclaration = meshData.vertexInputDeclaration;
3655         return true;
3656     }
3657     return false;
3658 }
3659 
Cancel()3660 void Gltf2SceneImporter::Cancel()
3661 {
3662     importer_->Cancel();
3663 }
3664 
IsCompleted() const3665 bool Gltf2SceneImporter::IsCompleted() const
3666 {
3667     return importer_->IsCompleted();
3668 }
3669 
GetResult() const3670 const ISceneImporter::Result& Gltf2SceneImporter::GetResult() const
3671 {
3672     return result_;
3673 }
3674 
GetMeshData() const3675 const MeshData& Gltf2SceneImporter::GetMeshData() const
3676 {
3677     return meshData_;
3678 }
3679 
ImportScene(size_t sceneIndex)3680 Entity Gltf2SceneImporter::ImportScene(size_t sceneIndex)
3681 {
3682     return ImportScene(sceneIndex, {}, SceneImportFlagBits::CORE_IMPORT_COMPONENT_FLAG_BITS_ALL);
3683 }
3684 
ImportScene(size_t sceneIndex,SceneImportFlags flags)3685 Entity Gltf2SceneImporter::ImportScene(size_t sceneIndex, SceneImportFlags flags)
3686 {
3687     return ImportScene(sceneIndex, {}, flags);
3688 }
3689 
ImportScene(size_t sceneIndex,Entity parentEntity)3690 Entity Gltf2SceneImporter::ImportScene(size_t sceneIndex, Entity parentEntity)
3691 {
3692     return ImportScene(sceneIndex, parentEntity, SceneImportFlagBits::CORE_IMPORT_COMPONENT_FLAG_BITS_ALL);
3693 }
3694 
ImportScene(size_t sceneIndex,Entity parentEntity,SceneImportFlags flags)3695 Entity Gltf2SceneImporter::ImportScene(size_t sceneIndex, Entity parentEntity, SceneImportFlags flags)
3696 {
3697     if (importer_ && data_) {
3698         if (auto sceneData = data_->GetInterface<SceneData>()) {
3699             if (auto* gltfData = sceneData->GetData()) {
3700                 auto& gltf = graphicsContext_->GetGltf();
3701                 return gltf.ImportGltfScene(
3702                     sceneIndex, *gltfData, importer_->GetResult().data, ecs_, parentEntity, flags);
3703             }
3704         }
3705     }
3706     return {};
3707 }
3708 
3709 // IInterface
GetInterface(const BASE_NS::Uid & uid) const3710 const IInterface* Gltf2SceneImporter::GetInterface(const BASE_NS::Uid& uid) const
3711 {
3712     if (uid == ISceneImporter::UID) {
3713         return static_cast<const ISceneImporter*>(this);
3714     }
3715     if (uid == IInterface::UID) {
3716         return static_cast<const IInterface*>(this);
3717     }
3718     return nullptr;
3719 }
3720 
GetInterface(const BASE_NS::Uid & uid)3721 IInterface* Gltf2SceneImporter::GetInterface(const BASE_NS::Uid& uid)
3722 {
3723     if (uid == ISceneImporter::UID) {
3724         return static_cast<ISceneImporter*>(this);
3725     }
3726     if (uid == IInterface::UID) {
3727         return static_cast<IInterface*>(this);
3728     }
3729     return nullptr;
3730 }
3731 
Ref()3732 void Gltf2SceneImporter::Ref()
3733 {
3734     ++refcnt_;
3735 }
3736 
Unref()3737 void Gltf2SceneImporter::Unref()
3738 {
3739     if (--refcnt_ == 0) {
3740         delete this;
3741     }
3742 }
3743 
OnImportStarted()3744 void Gltf2SceneImporter::OnImportStarted()
3745 {
3746     if (listener_) {
3747         listener_->OnImportStarted();
3748     }
3749 }
3750 
OnImportFinished()3751 void Gltf2SceneImporter::OnImportFinished()
3752 {
3753     if (listener_) {
3754         listener_->OnImportFinished();
3755     }
3756 }
3757 
OnImportProgressed(size_t taskIndex,size_t taskCount)3758 void Gltf2SceneImporter::OnImportProgressed(size_t taskIndex, size_t taskCount)
3759 {
3760     if (listener_) {
3761         listener_->OnImportProgressed(taskIndex, taskCount);
3762     }
3763 }
3764 } // namespace GLTF2
3765 
3766 CORE3D_END_NAMESPACE()
3767