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