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 == ℑ
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