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 "mesh_builder.h"
17 
18 #include <algorithm>
19 #include <securec.h>
20 
21 #include <3d/ecs/components/mesh_component.h>
22 #include <3d/ecs/components/render_handle_component.h>
23 #include <3d/util/intf_picking.h>
24 #include <base/containers/type_traits.h>
25 #include <base/math/float_packer.h>
26 #include <base/math/mathf.h>
27 #include <base/math/vector_util.h>
28 #include <core/ecs/entity_reference.h>
29 #include <core/ecs/intf_ecs.h>
30 #include <core/ecs/intf_entity_manager.h>
31 #include <core/intf_engine.h>
32 #include <core/log.h>
33 #include <core/namespace.h>
34 #include <core/plugin/intf_class_factory.h>
35 #include <core/plugin/intf_class_register.h>
36 #include <core/property/intf_property_handle.h>
37 #include <render/datastore/intf_render_data_store_default_staging.h>
38 #include <render/datastore/intf_render_data_store_manager.h>
39 #include <render/device/intf_device.h>
40 #include <render/device/intf_gpu_resource_manager.h>
41 #include <render/implementation_uids.h>
42 #include <render/intf_render_context.h>
43 
44 #include "util/mesh_util.h"
45 
46 namespace {
47 #include "3d/shaders/common/morph_target_structs.h"
48 } // namespace
49 
50 CORE3D_BEGIN_NAMESPACE()
51 using namespace BASE_NS;
52 using namespace CORE_NS;
53 using namespace RENDER_NS;
54 
55 namespace {
56 constexpr uint32_t BUFFER_ALIGN = 0x100; // on Nvidia = 0x20, on Mali and Intel = 0x10, SBO on Mali = 0x100
57 constexpr auto POSITION_FORMAT = BASE_FORMAT_R32G32B32_SFLOAT;
58 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
59 constexpr auto NORMAL_FORMAT = BASE_FORMAT_R16G16B16_SFLOAT;
60 constexpr auto TANGENT_FORMAT = BASE_FORMAT_R16G16B16A16_SFLOAT;
61 #else
62 constexpr auto NORMAL_FORMAT = BASE_FORMAT_R32G32B32_SFLOAT;
63 constexpr auto TANGENT_FORMAT = BASE_FORMAT_R32G32B32_SFLOAT;
64 #endif
65 
66 constexpr auto R = 0;
67 constexpr auto G = 1;
68 constexpr auto B = 2;
69 
70 constexpr auto RG = 2;
71 constexpr auto RGB = 3;
72 constexpr auto RGBA = 4;
73 
74 template<typename Container>
75 using ContainerValueType = typename remove_reference_t<Container>::value_type;
76 
77 template<typename Container>
78 constexpr const auto SIZE_OF_VALUE_TYPE_V = sizeof(ContainerValueType<Container>);
79 
80 constexpr inline size_t Align(size_t value, size_t align) noexcept
81 {
82     if (align == 0U) {
83         return value;
84     }
85 
86     return ((value + align - 1U) / align) * align;
87 }
88 
89 const VertexInputDeclaration::VertexInputAttributeDescription* GetVertexAttributeDescription(uint32_t location,
90     const array_view<const VertexInputDeclaration::VertexInputAttributeDescription>& attributeDescriptions) noexcept
91 {
92     const auto cmpLocationIndex = [location](auto const& attribute) { return attribute.location == location; };
93     if (const auto pos = std::find_if(attributeDescriptions.begin(), attributeDescriptions.end(), cmpLocationIndex);
94         pos != attributeDescriptions.end()) {
95         return pos.ptr();
96     }
97 
98     return nullptr;
99 }
100 
101 const VertexInputDeclaration::VertexInputBindingDescription* GetVertexBindingeDescription(uint32_t bindingIndex,
102     const array_view<const VertexInputDeclaration::VertexInputBindingDescription>& bindingDescriptions) noexcept
103 {
104     const auto cmpBindingIndex = [bindingIndex](auto const& binding) { return binding.binding == bindingIndex; };
105     if (const auto pos = std::find_if(bindingDescriptions.begin(), bindingDescriptions.end(), cmpBindingIndex);
106         pos != bindingDescriptions.end()) {
107         return pos.ptr();
108     }
109 
110     return nullptr;
111 }
112 
113 struct Intermediate {
114     float data[RGBA];
115 };
116 
117 using ToIntermediate = float (*)(const uint8_t* src) noexcept;
118 using FromIntermediate = void (*)(uint8_t* dst, float) noexcept;
119 
120 struct FormatProperties {
121     size_t componentCount;
122     size_t componentByteSize;
123     Format format;
124     bool isNormalized;
125     bool isSigned;
126     ToIntermediate toIntermediate;
127     FromIntermediate fromIntermediate;
128 };
129 
130 struct OutputBuffer {
131     BASE_NS::Format format;
132     uint32_t stride;
133     BASE_NS::array_view<uint8_t> buffer;
134 };
135 
136 template<typename T, size_t N, size_t M>
137 inline void GatherMin(T (&minimum)[N], const T (&value)[M])
138 {
139     for (size_t i = 0; i < Math::min(N, M); ++i) {
140         minimum[i] = Math::min(minimum[i], value[i]);
141     }
142 }
143 
144 template<typename T, size_t N, size_t M>
145 inline void GatherMax(T (&minimum)[N], const T (&value)[M])
146 {
147     for (size_t i = 0; i < Math::min(N, M); ++i) {
148         minimum[i] = Math::max(minimum[i], value[i]);
149     }
150 }
151 
152 // floating point to signed normalized integer
153 template<typename T, typename = enable_if_t<is_signed_v<T>>>
154 constexpr inline T Snorm(float v) noexcept
155 {
156     const float round = v >= 0.f ? +.5f : -.5f;
157     v = v < -1.f ? -1.f : (v > 1.f ? 1.f : v);
158     return static_cast<T>(v * static_cast<float>(std::numeric_limits<T>::max()) + round);
159 }
160 
161 // signed normalized integer to floating point
162 template<typename T, typename = enable_if_t<is_signed_v<T> && is_integral_v<T>>>
163 constexpr inline float Snorm(T v) noexcept
164 {
165     return static_cast<float>(v) / static_cast<float>(std::numeric_limits<T>::max());
166 }
167 
168 // floating point to unsigned normalized integer
169 template<typename T, typename = enable_if_t<is_unsigned_v<T>>>
170 constexpr inline T Unorm(float v) noexcept
171 {
172     v = v < 0.f ? 0.f : (v > 1.f ? 1.f : v);
173     return static_cast<T>(v * static_cast<float>(std::numeric_limits<T>::max()) + 0.5f);
174 }
175 
176 // unsigned normalized integer to floating point
177 template<typename T, typename = enable_if_t<is_unsigned_v<T> && is_integral_v<T>>>
178 constexpr inline float Unorm(T v) noexcept
179 {
180     return static_cast<float>(v) / static_cast<float>(std::numeric_limits<T>::max());
181 }
182 
183 // floating point to signed integer
184 template<typename T, typename = enable_if_t<is_signed_v<T>>>
185 constexpr inline T Sint(float v) noexcept
186 {
187     const float round = v >= 0.f ? +.5f : -.5f;
188     constexpr auto l = static_cast<float>(std::numeric_limits<T>::lowest());
189     constexpr auto h = static_cast<float>(std::numeric_limits<T>::max());
190     v = v < l ? l : (v > h ? h : v);
191     return static_cast<T>(v + round);
192 }
193 
194 // signed integer to floating point
195 template<typename T, typename = enable_if_t<is_signed_v<T> && is_integral_v<T>>>
196 constexpr inline float Sint(T v) noexcept
197 {
198     return static_cast<float>(v);
199 }
200 
201 // floating point to unsigned integer
202 template<typename T, typename = enable_if_t<is_unsigned_v<T>>>
203 constexpr inline T Uint(float v) noexcept
204 {
205     constexpr auto h = static_cast<float>(std::numeric_limits<T>::max());
206     v = v < 0.f ? 0.f : (v > h ? h : v);
207     return static_cast<T>(v + 0.5f);
208 }
209 
210 // unsigned integer to floating point
211 template<typename T, typename = enable_if_t<is_unsigned_v<T> && is_integral_v<T>>>
212 constexpr inline float Uint(T v) noexcept
213 {
214     return static_cast<float>(v);
215 }
216 
217 // helpers for ingeter - integer conversions
218 template<typename T, typename U>
219 struct IntegerNorm {
220     using InType = T;
221     using OutType = U;
222 
223     static U convert(T v) noexcept
224     {
225         constexpr auto dstH = std::numeric_limits<U>::max();
226         constexpr auto srcH = std::numeric_limits<T>::max();
onstexpr(is_signed_v<T>)227         if constexpr (is_signed_v<T>) {
228             auto round = v >= 0 ? (srcH - 1) : (-srcH + 1);
229             return static_cast<U>(((static_cast<int32_t>(v) * dstH) + round) / srcH);
230         } else {
231             return static_cast<U>(((static_cast<uint32_t>(v) * dstH) + (srcH - 1)) / srcH);
232         }
233     }
234 };
235 
236 template<typename T, typename U>
237 struct IntegerToInt {
238     using InType = T;
239     using OutType = U;
240 
241     static U convert(T v) noexcept
242     {
243         return static_cast<U>(v);
244     }
245 };
246 
247 template<typename Converter, size_t components>
Convert(uint8_t* dstPtr, size_t dstStride, const uint8_t* srcPtr, size_t srcStride, size_t elements)248 void Convert(uint8_t* dstPtr, size_t dstStride, const uint8_t* srcPtr, size_t srcStride, size_t elements)
249 {
250     while (elements--) {
251         for (auto i = 0U; i < components; ++i) {
252             reinterpret_cast<typename Converter::OutType*>(dstPtr)[i] = static_cast<typename Converter::OutType>(
253                 Converter::convert(reinterpret_cast<const typename Converter::InType*>(srcPtr)[i]));
254         }
255         srcPtr += srcStride;
256         dstPtr += dstStride;
257     }
258 }
259 
260 // helpers for type T - float - type U conversions
261 template<typename T>
262 struct Norm {
263     using Type = T;
264 
265     static T To(float f) noexcept
266     {
onstexpr(is_signed_v<T>)267         if constexpr (is_signed_v<T>) {
268             return Snorm<T>(f);
269         } else {
270             return Unorm<T>(f);
271         }
272     }
273 
274     static float From(T v) noexcept
275     {
onstexpr(is_signed_v<T>)276         if constexpr (is_signed_v<T>) {
277             return Snorm<T>(v);
278         } else {
279             return Unorm<T>(v);
280         }
281     }
282 };
283 
284 template<typename T>
285 struct Int {
286     using Type = T;
287 
To__anon9788::Int288     static T To(float f)
289     {
290         if constexpr (is_signed_v<T>) {
291             return Sint<T>(f);
292         } else {
293             return Uint<T>(f);
294         }
295     }
296 
From__anon9788::Int297     static float From(T v)
298     {
299         if constexpr (is_signed_v<T>) {
300             return Sint<T>(v);
301         } else {
302             return Uint<T>(v);
303         }
304     }
305 };
306 
307 template<typename T>
308 struct Float {
309     using Type = T;
310 
To__anon9788::Float311     static T To(float f)
312     {
313         if constexpr (is_same_v<T, float>) {
314             return f;
315         }
316         if constexpr (sizeof(T) == sizeof(uint16_t)) {
317             return Math::F32ToF16(f);
318         }
319     }
320 
From__anon9788::Float321     static float From(T v)
322     {
323         if constexpr (is_same_v<T, float>) {
324             return v;
325         }
326         if constexpr (sizeof(T) == sizeof(uint16_t)) {
327             return Math::F16ToF32(v);
328         }
329     }
330 };
331 
332 template<typename SourceFn, typename DestFn, size_t components>
Convert(uint8_t* dstPtr, size_t dstStride, const uint8_t* srcPtr, size_t srcStride, size_t elements)333 void Convert(uint8_t* dstPtr, size_t dstStride, const uint8_t* srcPtr, size_t srcStride, size_t elements)
334 {
335     while (elements--) {
336         for (auto i = 0U; i < components; ++i) {
337             reinterpret_cast<typename DestFn::Type*>(dstPtr)[i] =
338                 DestFn::To(SourceFn::From(reinterpret_cast<const typename SourceFn::Type*>(srcPtr)[i]));
339         }
340         srcPtr += srcStride;
341         dstPtr += dstStride;
342     }
343 }
344 
345 template<typename SourceFn>
346 float From(const uint8_t* src) noexcept
347 {
348     return SourceFn::From(reinterpret_cast<const typename SourceFn::Type*>(src)[R]);
349 }
350 
351 template<typename DestFn>
352 void To(uint8_t* dst, float f) noexcept
353 {
354     reinterpret_cast<typename DestFn::Type*>(dst)[R] = DestFn::To(f);
355 }
356 
357 static constexpr const FormatProperties DATA_FORMATS[] = {
358     { 0, 0, BASE_FORMAT_UNDEFINED, false, false, nullptr, nullptr },
359 
360     { 1, 1, BASE_FORMAT_R8_UNORM, true, false, From<Norm<uint8_t>>, To<Norm<uint8_t>> },
361     { 1, 1, BASE_FORMAT_R8_SNORM, true, true, From<Norm<int8_t>>, To<Norm<int8_t>> },
362     { 1, 1, BASE_FORMAT_R8_UINT, false, false, From<Int<uint8_t>>, To<Int<uint8_t>> },
363 
364     { 3, 1, BASE_FORMAT_R8G8B8_SNORM, true, false, From<Norm<int8_t>>, To<Norm<int8_t>> },
365 
366     { 4, 1, BASE_FORMAT_R8G8B8A8_UNORM, true, false, From<Norm<uint8_t>>, To<Norm<uint8_t>> },
367     { 4, 1, BASE_FORMAT_R8G8B8A8_SNORM, true, false, From<Norm<int8_t>>, To<Norm<int8_t>> },
368     { 4, 1, BASE_FORMAT_R8G8B8A8_UINT, false, false, From<Int<uint8_t>>, To<Int<uint8_t>> },
369 
370     { 1, 2, BASE_FORMAT_R16_UINT, false, false, From<Int<uint16_t>>, To<Int<uint16_t>> },
371 
372     { 2, 2, BASE_FORMAT_R16G16_UNORM, true, false, From<Norm<uint16_t>>, To<Norm<uint16_t>> },
373     { 2, 2, BASE_FORMAT_R16G16_UINT, false, true, From<Int<uint16_t>>, To<Int<uint16_t>> },
374     { 2, 2, BASE_FORMAT_R16G16_SFLOAT, false, true, From<Float<uint16_t>>, To<Float<uint16_t>> },
375 
376     { 3, 2, BASE_FORMAT_R16G16B16_UINT, true, true, From<Int<uint16_t>>, To<Int<uint16_t>> },
377     { 3, 2, BASE_FORMAT_R16G16B16_SINT, true, true, From<Int<int16_t>>, To<Int<int16_t>> },
378     { 3, 2, BASE_FORMAT_R16G16B16_SFLOAT, false, true, From<Float<uint16_t>>, To<Float<uint16_t>> },
379 
380     { 4, 2, BASE_FORMAT_R16G16B16A16_UNORM, true, true, From<Norm<uint16_t>>, To<Norm<uint16_t>> },
381     { 4, 2, BASE_FORMAT_R16G16B16A16_SNORM, true, true, From<Norm<int16_t>>, To<Norm<int16_t>> },
382     { 4, 2, BASE_FORMAT_R16G16B16A16_UINT, false, false, From<Int<uint16_t>>, To<Int<uint16_t>> },
383     { 4, 2, BASE_FORMAT_R16G16B16A16_SFLOAT, false, true, From<Float<uint16_t>>, To<Float<uint16_t>> },
384 
385     { 1, 4, BASE_FORMAT_R32_UINT, false, false, From<Int<uint32_t>>, To<Int<uint32_t>> },
386 
387     { 2, 4, BASE_FORMAT_R32G32_SFLOAT, false, true, From<Float<float>>, To<Float<float>> },
388 
389     { 3, 4, BASE_FORMAT_R32G32B32_SFLOAT, false, true, From<Float<float>>, To<Float<float>> },
390 
391     { 4, 4, BASE_FORMAT_R32G32B32A32_SFLOAT, false, true, From<Float<float>>, To<Float<float>> },
392 };
393 
394 template<class It, class T, class Pred>
LowerBound(It first, const It last, const T& val, Pred pred)395 constexpr It LowerBound(It first, const It last, const T& val, Pred pred)
396 {
397     auto count = std::distance(first, last);
398 
399     while (count > 0) {
400         const auto half = count / 2;
401         const auto mid = std::next(first, half);
402         if (pred(*mid, val)) {
403             first = mid + 1;
404             count -= half + 1;
405         } else {
406             count = half;
407         }
408     }
409     return first;
410 }
411 
GetFormatSpec(Format format)412 constexpr const FormatProperties& GetFormatSpec(Format format)
413 {
414 #if defined(__cpp_lib_constexpr_algorithms) && (__cpp_lib_constexpr_algorithms >= 201806L)
415     static_assert(std::is_sorted(std::begin(DATA_FORMATS), std::end(DATA_FORMATS),
416         [](const FormatProperties& lhs, const FormatProperties& rhs) { return lhs.format < rhs.format; }));
417 #endif
418     if (auto pos = LowerBound(std::begin(DATA_FORMATS), std::end(DATA_FORMATS), format,
419             [](const FormatProperties& element, Format value) { return element.format < value; });
420         (pos != std::end(DATA_FORMATS)) && (pos->format == format)) {
421         return *pos;
422     }
423     return DATA_FORMATS[0];
424 }
425 
GetVertexAttributeByteSize( const uint32_t vertexAttributeLocation, const VertexInputDeclarationView& vertexInputDeclaration)426 size_t GetVertexAttributeByteSize(
427     const uint32_t vertexAttributeLocation, const VertexInputDeclarationView& vertexInputDeclaration)
428 {
429     if (const auto* vertexAttributeDesc =
430             GetVertexAttributeDescription(vertexAttributeLocation, vertexInputDeclaration.attributeDescriptions);
431         vertexAttributeDesc) {
432         const FormatProperties& properties = GetFormatSpec(vertexAttributeDesc->format);
433 
434         CORE_ASSERT_MSG(
435             properties.format != BASE_FORMAT_UNDEFINED, "Format not supported (%u).", vertexAttributeDesc->format);
436         return properties.componentCount * properties.componentByteSize;
437     }
438     return 0;
439 }
440 
441 // For each joint 6 values defining the min and max bounds (world space AABB) of the vertices affected by the joint.
442 constexpr const size_t JOINT_BOUNDS_COMPONENTS = 6u;
443 
GetVertexBufferDesc(size_t byteSize, BufferUsageFlags additionalFlags, bool morphTarget)444 GpuBufferDesc GetVertexBufferDesc(size_t byteSize, BufferUsageFlags additionalFlags, bool morphTarget)
445 {
446     // NOTE: storage buffer usage is currently enabled for all
447     // there's no API to define flags for auto loaded and build meshes
448     // one might always want more (and e.g. with particle cases we should use texel storage for auto formats)
449     GpuBufferDesc desc;
450     desc.usageFlags = BufferUsageFlagBits::CORE_BUFFER_USAGE_VERTEX_BUFFER_BIT |
451                       BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_DST_BIT |
452                       BufferUsageFlagBits::CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT;
453     desc.usageFlags |= additionalFlags;
454     desc.engineCreationFlags = 0U;
455     // EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_ENABLE_MEMORY_OPTIMIZATIONS;
456     if (morphTarget) {
457         desc.engineCreationFlags |= CORE_ENGINE_BUFFER_CREATION_DYNAMIC_BARRIERS;
458     }
459     desc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
460     desc.byteSize = (uint32_t)byteSize;
461 
462     return desc;
463 }
464 
465 template<typename T>
GetIndexBufferDesc(size_t indexCount, BufferUsageFlags additionalFlags)466 constexpr GpuBufferDesc GetIndexBufferDesc(size_t indexCount, BufferUsageFlags additionalFlags)
467 {
468     // NOTE: storage buffer usage is currently enabled for all
469     // there's no API to define flags for auto loaded and build meshes
470     // one might always want more (and e.g. with particle cases we should use texel storage for auto formats)
471     GpuBufferDesc indexBufferDesc;
472     indexBufferDesc.usageFlags = BufferUsageFlagBits::CORE_BUFFER_USAGE_INDEX_BUFFER_BIT |
473                                  BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_DST_BIT |
474                                  BufferUsageFlagBits::CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT;
475     indexBufferDesc.usageFlags |= additionalFlags;
476     indexBufferDesc.engineCreationFlags = 0;
477     indexBufferDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
478     indexBufferDesc.byteSize = sizeof(T) * (uint32_t)indexCount;
479 
480     return indexBufferDesc;
481 }
482 
GetMorphTargetBufferDesc(size_t byteSize, BufferUsageFlags additionalFlags)483 constexpr GpuBufferDesc GetMorphTargetBufferDesc(size_t byteSize, BufferUsageFlags additionalFlags)
484 {
485     // NOTE: These are only morph targets which are read only
486     GpuBufferDesc desc;
487     desc.usageFlags = BufferUsageFlagBits::CORE_BUFFER_USAGE_STORAGE_BUFFER_BIT |
488                       BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_DST_BIT;
489     desc.usageFlags |= additionalFlags;
490     desc.engineCreationFlags = 0; // read-only
491     desc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
492     desc.byteSize = (uint32_t)byteSize;
493 
494     return desc;
495 }
496 
CreateBuffer(IEntityManager& entityManager, IRenderHandleComponentManager& handleManager, const RenderHandleReference& bufferHandle)497 EntityReference CreateBuffer(IEntityManager& entityManager, IRenderHandleComponentManager& handleManager,
498     const RenderHandleReference& bufferHandle)
499 {
500     auto sharedEntity = entityManager.CreateReferenceCounted();
501     handleManager.Create(sharedEntity);
502     handleManager.Write(sharedEntity)->reference = bufferHandle;
503     return sharedEntity;
504 }
505 
CreateGpuBuffers(IRenderContext& renderContext, size_t vertexDataSize, size_t indexDataSize, uint32_t indexCount, size_t jointDataSize, size_t targetDataSize, const MeshBuilder::GpuBufferCreateInfo& createInfo)506 MeshBuilder::BufferHandles CreateGpuBuffers(IRenderContext& renderContext, size_t vertexDataSize, size_t indexDataSize,
507     uint32_t indexCount, size_t jointDataSize, size_t targetDataSize,
508     const MeshBuilder::GpuBufferCreateInfo& createInfo)
509 {
510     MeshBuilder::BufferHandles handles;
511 
512     auto& gpuResourceManager = renderContext.GetDevice().GetGpuResourceManager();
513 
514     {
515         // targetDataSize is zero when there's no morph targets
516         const GpuBufferDesc vertexBufferDesc =
517             GetVertexBufferDesc(vertexDataSize, createInfo.vertexBufferFlags, targetDataSize != 0U);
518         handles.vertexBuffer = gpuResourceManager.Create(vertexBufferDesc);
519     }
520 
521     if (indexDataSize) {
522         const GpuBufferDesc indexBufferDesc = GetIndexBufferDesc<uint32_t>(indexCount, createInfo.indexBufferFlags);
523         handles.indexBuffer = gpuResourceManager.Create(indexBufferDesc);
524     }
525 
526     if (jointDataSize) {
527         const GpuBufferDesc jointAttributeDesc =
528             GetVertexBufferDesc(jointDataSize, createInfo.vertexBufferFlags, false);
529         handles.jointBuffer = gpuResourceManager.Create(jointAttributeDesc);
530     }
531 
532     if (targetDataSize) {
533         const GpuBufferDesc targetDesc = GetMorphTargetBufferDesc(targetDataSize, createInfo.morphBufferFlags);
534         handles.morphBuffer = gpuResourceManager.Create(targetDesc);
535     }
536 
537     return handles;
538 }
539 
StageToBuffers(IRenderContext& renderContext, size_t vertexDataSize, size_t indexDataSize, size_t jointDataSize, size_t targetDataSize, const MeshBuilder::BufferHandles& handles, const RenderHandleReference& stagingBuffer)540 void StageToBuffers(IRenderContext& renderContext, size_t vertexDataSize, size_t indexDataSize, size_t jointDataSize,
541     size_t targetDataSize, const MeshBuilder::BufferHandles& handles, const RenderHandleReference& stagingBuffer)
542 {
543     constexpr const string_view RENDER_DATA_STORE_DEFAULT_STAGING = "RenderDataStoreDefaultStaging";
544     auto staging = static_cast<IRenderDataStoreDefaultStaging*>(
545         renderContext.GetRenderDataStoreManager().GetRenderDataStore(RENDER_DATA_STORE_DEFAULT_STAGING.data()));
546     BufferCopy copyData {};
547     if (vertexDataSize) {
548         copyData.size = static_cast<uint32_t>(vertexDataSize);
549         staging->CopyBufferToBuffer(stagingBuffer, handles.vertexBuffer, copyData);
550         copyData.srcOffset += copyData.size;
551     }
552     if (indexDataSize) {
553         copyData.size = static_cast<uint32_t>(indexDataSize);
554         staging->CopyBufferToBuffer(stagingBuffer, handles.indexBuffer, copyData);
555         copyData.srcOffset += copyData.size;
556     }
557 
558     if (jointDataSize) {
559         copyData.size = static_cast<uint32_t>(jointDataSize);
560         staging->CopyBufferToBuffer(stagingBuffer, handles.jointBuffer, copyData);
561         copyData.srcOffset += copyData.size;
562     }
563     if (targetDataSize) {
564         copyData.size = static_cast<uint32_t>(targetDataSize);
565         staging->CopyBufferToBuffer(stagingBuffer, handles.morphBuffer, copyData);
566     }
567 }
568 
FillSubmeshBuffers(array_view<MeshComponent::Submesh> submeshes, const MeshBuilder::BufferEntities& bufferEntities)569 void FillSubmeshBuffers(array_view<MeshComponent::Submesh> submeshes, const MeshBuilder::BufferEntities& bufferEntities)
570 {
571     for (MeshComponent::Submesh& submesh : submeshes) {
572         submesh.indexBuffer.buffer = bufferEntities.indexBuffer;
573         submesh.morphTargetBuffer.buffer = bufferEntities.morphBuffer;
574 
575         submesh.bufferAccess[MeshComponent::Submesh::DM_VB_POS].buffer = bufferEntities.vertexBuffer;
576         submesh.bufferAccess[MeshComponent::Submesh::DM_VB_NOR].buffer = bufferEntities.vertexBuffer;
577         submesh.bufferAccess[MeshComponent::Submesh::DM_VB_UV0].buffer = bufferEntities.vertexBuffer;
578 
579         if (submesh.flags & MeshComponent::Submesh::FlagBits::SECOND_TEXCOORD_BIT) {
580             submesh.bufferAccess[MeshComponent::Submesh::DM_VB_UV1].buffer = bufferEntities.vertexBuffer;
581         }
582 
583         if (submesh.flags & MeshComponent::Submesh::FlagBits::TANGENTS_BIT) {
584             submesh.bufferAccess[MeshComponent::Submesh::DM_VB_TAN].buffer = bufferEntities.vertexBuffer;
585         }
586         if (submesh.flags & MeshComponent::Submesh::FlagBits::VERTEX_COLORS_BIT) {
587             submesh.bufferAccess[MeshComponent::Submesh::DM_VB_COL].buffer = bufferEntities.vertexBuffer;
588         }
589 
590         if (submesh.flags & MeshComponent::Submesh::FlagBits::SKIN_BIT) {
591             submesh.bufferAccess[MeshComponent::Submesh::DM_VB_JOI].buffer = bufferEntities.jointBuffer;
592             submesh.bufferAccess[MeshComponent::Submesh::DM_VB_JOW].buffer = bufferEntities.jointBuffer;
593         }
594     }
595 }
596 
CalculateAabb(array_view<const MeshComponent::Submesh> submeshes)597 MinAndMax CalculateAabb(array_view<const MeshComponent::Submesh> submeshes)
598 {
599     MinAndMax minMax;
600     for (const auto& submesh : submeshes) {
601         minMax.minAABB = min(minMax.minAABB, submesh.aabbMin);
602         minMax.maxAABB = max(minMax.maxAABB, submesh.aabbMax);
603     }
604     return minMax;
605 }
606 
Fill(OutputBuffer& dstData, const MeshBuilder::DataBuffer& srcData, size_t count)607 void Fill(OutputBuffer& dstData, const MeshBuilder::DataBuffer& srcData, size_t count)
608 {
609     if (!count) {
610         return;
611     }
612     const auto dstFormat = GetFormatSpec(dstData.format);
613     if (dstFormat.format == BASE_FORMAT_UNDEFINED) {
614         CORE_LOG_E("destination format (%u) not supported", dstData.format);
615         return;
616     }
617     const auto dstElementSize = dstFormat.componentCount * dstFormat.componentByteSize;
618     if (count == 0) {
619         return;
620     }
621     if ((dstElementSize > dstData.stride) || (dstData.stride > (dstData.buffer.size() / count))) {
622         return;
623     }
624     const auto srcFormat = GetFormatSpec(srcData.format);
625     if (srcFormat.format == BASE_FORMAT_UNDEFINED) {
626         CORE_LOG_E("source format (%u) not supported", srcData.format);
627         return;
628     }
629     const auto srcElementSize = srcFormat.componentCount * srcFormat.componentByteSize;
630     if ((srcElementSize > srcData.stride) || (srcData.stride > (srcData.buffer.size() / count))) {
631         return;
632     }
633     if (dstData.format == srcData.format) {
634         // no conversion required
635         if (dstData.stride == srcData.stride && dstData.stride == dstElementSize) {
636             // strides match and no padding
637             CloneData(dstData.buffer.data(), dstData.buffer.size(), srcData.buffer.data(), srcElementSize * count);
638         } else {
639             // stride mismatch or padding
640             auto dstPtr = dstData.buffer.data();
641             auto dstSize = dstData.buffer.size();
642             auto srcPtr = srcData.buffer.data();
643             while (count--) {
644                 CloneData(dstPtr, dstSize, srcPtr, srcElementSize);
645                 dstPtr += dstData.stride;
646                 srcPtr += srcData.stride;
647                 dstSize -= dstData.stride;
648             }
649         }
650     } else if (!srcFormat.toIntermediate || !dstFormat.fromIntermediate) {
651         CORE_LOG_E("missing conversion from %u to %u", srcFormat.format, dstFormat.format);
652     } else {
653         // must convert between formats
654         auto dstPtr = dstData.buffer.data();
655         auto srcPtr = srcData.buffer.data();
656         // attempt to inline commonly used conversions
657         switch (srcData.format) {
658             case BASE_FORMAT_R8_UINT: {
659                 switch (dstData.format) {
660                     case BASE_FORMAT_R16_UINT:
661                         Convert<IntegerToInt<uint8_t, uint16_t>, 1U>(
662                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
663                         return;
664                     default:
665                         break;
666                 }
667             } break;
668 
669             case BASE_FORMAT_R8G8B8_SNORM: {
670                 switch (dstData.format) {
671                     case BASE_FORMAT_R16G16B16A16_SNORM:
672                         Convert<IntegerNorm<int8_t, int16_t>, RGB>(
673                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
674                         return;
675                     case BASE_FORMAT_R16G16B16_SFLOAT:
676                         Convert<Norm<int8_t>, Float<uint16_t>, RGB>(
677                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
678                         return;
679                     case BASE_FORMAT_R32G32B32_SFLOAT:
680                         Convert<Norm<int8_t>, Float<float>, RGB>(dstPtr, dstData.stride, srcPtr, srcData.stride, count);
681                         return;
682                     default:
683                         break;
684                 }
685             } break;
686 
687             case BASE_FORMAT_R8G8B8A8_SNORM: {
688                 switch (dstData.format) {
689                     case BASE_FORMAT_R16G16B16A16_SNORM:
690                         Convert<IntegerNorm<int8_t, int16_t>, RGBA>(
691                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
692                         return;
693                     default:
694                         break;
695                 }
696             } break;
697 
698             case BASE_FORMAT_R16G16_UNORM: {
699                 switch (dstData.format) {
700                     case BASE_FORMAT_R16G16_SFLOAT:
701                         Convert<Norm<uint16_t>, Float<uint16_t>, RG>(
702                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
703                         return;
704                     default:
705                         break;
706                 }
707             } break;
708 
709             case BASE_FORMAT_R16G16_UINT: {
710                 switch (dstData.format) {
711                     case BASE_FORMAT_R16G16_SFLOAT:
712                         Convert<Int<uint16_t>, Float<uint16_t>, RG>(
713                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
714                         return;
715                     default:
716                         break;
717                 }
718             } break;
719 
720             case BASE_FORMAT_R16G16_SFLOAT: {
721                 switch (dstData.format) {
722                     case BASE_FORMAT_R32G32_SFLOAT:
723                         Convert<Float<uint16_t>, Float<float>, RG>(
724                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
725                         return;
726                     default:
727                         break;
728                 }
729             } break;
730 
731             case BASE_FORMAT_R16G16B16_UINT: {
732                 switch (dstData.format) {
733                     case BASE_FORMAT_R32G32B32_SFLOAT:
734                         Convert<Int<uint16_t>, Float<float>, RGB>(
735                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
736                         return;
737                     default:
738                         break;
739                 }
740             } break;
741 
742             case BASE_FORMAT_R16G16B16A16_UNORM: {
743                 switch (dstData.format) {
744                     case BASE_FORMAT_R8G8B8A8_UNORM:
745                         Convert<IntegerNorm<uint16_t, uint8_t>, RGBA>(
746                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
747                         return;
748                     default:
749                         break;
750                 }
751 
752             } break;
753 
754             case BASE_FORMAT_R16G16B16A16_SNORM: {
755                 switch (dstData.format) {
756                     case BASE_FORMAT_R32G32B32_SFLOAT:
757                         Convert<Norm<int16_t>, Float<float>, RGB>(
758                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
759                         return;
760                     default:
761                         break;
762                 }
763 
764             } break;
765 
766             case BASE_FORMAT_R16G16B16A16_UINT: {
767                 switch (dstData.format) {
768                     case BASE_FORMAT_R8G8B8A8_UINT:
769                         Convert<IntegerToInt<uint16_t, uint8_t>, RGBA>(
770                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
771                         return;
772                     default:
773                         break;
774                 }
775             } break;
776 
777             case BASE_FORMAT_R16G16B16A16_SFLOAT: {
778                 switch (dstData.format) {
779                     case BASE_FORMAT_R16G16B16A16_SNORM:
780                         Convert<Float<uint16_t>, Norm<int16_t>, RGBA>(
781                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
782                         return;
783                     default:
784                         break;
785                 }
786             } break;
787 
788             case BASE_FORMAT_R32_UINT: {
789                 switch (dstData.format) {
790                     case BASE_FORMAT_R16_UINT:
791                         Convert<IntegerToInt<uint32_t, uint16_t>, 1U>(
792                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
793                         return;
794                     default:
795                         break;
796                 }
797 
798             } break;
799 
800             case BASE_FORMAT_R32G32_SFLOAT: {
801                 switch (dstData.format) {
802                     case BASE_FORMAT_R16G16_SFLOAT:
803                         Convert<Float<float>, Float<uint16_t>, RG>(
804                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
805                         return;
806                     default:
807                         break;
808                 }
809             } break;
810 
811             case BASE_FORMAT_R32G32B32_SFLOAT: {
812                 switch (dstData.format) {
813                     case BASE_FORMAT_R16G16B16_SFLOAT:
814                         Convert<Float<float>, Float<uint16_t>, RGB>(
815                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
816                         return;
817                     case BASE_FORMAT_R16G16B16A16_SNORM:
818                         Convert<Float<float>, Norm<int16_t>, RGB>(
819                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
820                         return;
821                     default:
822                         break;
823                 }
824             } break;
825 
826             case BASE_FORMAT_R32G32B32A32_SFLOAT: {
827                 switch (dstData.format) {
828                     case BASE_FORMAT_R8G8B8A8_UNORM:
829                         Convert<Float<float>, Norm<uint8_t>, RGBA>(
830                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
831                         return;
832                     case BASE_FORMAT_R16G16B16A16_SNORM:
833                         Convert<Float<float>, Norm<int16_t>, RGBA>(
834                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
835                         return;
836                     case BASE_FORMAT_R16G16B16A16_SFLOAT:
837                         Convert<Float<float>, Float<uint16_t>, RGBA>(
838                             dstPtr, dstData.stride, srcPtr, srcData.stride, count);
839                         return;
840                     default:
841                         break;
842                 }
843             } break;
844 
845             default:
846                 break;
847         }
848 
849         CORE_LOG_V("%u %u", srcData.format, dstData.format);
850         const auto components = Math::min(srcFormat.componentCount, dstFormat.componentCount);
851         while (count--) {
852             for (auto i = 0U; i < components; ++i) {
853                 dstFormat.fromIntermediate(dstPtr + i * dstFormat.componentByteSize,
854                     srcFormat.toIntermediate(srcPtr + i * srcFormat.componentByteSize));
855             }
856             auto intermediate = srcFormat.toIntermediate(srcPtr);
857             dstFormat.fromIntermediate(dstPtr, intermediate);
858             srcPtr += srcData.stride;
859             dstPtr += dstData.stride;
860         }
861     }
862 }
863 
864 template<typename T>
SmoothNormal(array_view<const T> indices, const Math::Vec3* posPtr, Math::Vec3* norPtr)865 void SmoothNormal(array_view<const T> indices, const Math::Vec3* posPtr, Math::Vec3* norPtr)
866 {
867     for (auto i = 0U; i < indices.size(); i += 3) { // 3: step
868         const auto aa = indices[i];
869         const auto bb = indices[i + 1];
870         const auto cc = indices[i + 2]; // 2: index
871         const auto& pos1 = posPtr[aa];
872         const auto& pos2 = posPtr[bb];
873         const auto& pos3 = posPtr[cc];
874         auto faceNorm = Math::Cross(pos2 - pos1, pos3 - pos1);
875         norPtr[aa] += faceNorm;
876         norPtr[bb] += faceNorm;
877         norPtr[cc] += faceNorm;
878     }
879 }
880 
GenerateDefaultNormals(vector<uint8_t>& generatedNormals, const IMeshBuilder::DataBuffer& indices, const IMeshBuilder::DataBuffer& positions, uint32_t vertexCount)881 void GenerateDefaultNormals(vector<uint8_t>& generatedNormals, const IMeshBuilder::DataBuffer& indices,
882     const IMeshBuilder::DataBuffer& positions, uint32_t vertexCount)
883 {
884     auto offset = generatedNormals.size();
885     generatedNormals.resize(generatedNormals.size() + sizeof(Math::Vec3) * vertexCount);
886     auto* norPtr = reinterpret_cast<Math::Vec3*>(generatedNormals.data() + offset);
887     auto* posPtr = reinterpret_cast<const Math::Vec3*>(positions.buffer.data());
888     if (indices.buffer.empty()) {
889         // Mesh without indices will have flat normals
890         for (auto i = 0U; i < vertexCount; i += 3) { // 3: step
891             const auto& pos1 = posPtr[i];
892             const auto& pos2 = posPtr[i + 1];
893             const auto& pos3 = posPtr[i + 2]; // 2: index
894             auto faceNorm = Math::Normalize(Math::Cross(pos2 - pos1, pos3 - pos1));
895             norPtr[i] = faceNorm;
896             norPtr[i + 1] = faceNorm;
897             norPtr[i + 2] = faceNorm; // 2: index
898         }
899     } else {
900         // With indexed data flat normals would require duplicating shared vertices. Instead calculate smooth normals.
901         if (indices.stride == sizeof(uint16_t)) {
902             auto view = array_view(
903                 reinterpret_cast<const uint16_t*>(indices.buffer.data()), indices.buffer.size() / indices.stride);
904             SmoothNormal(view, posPtr, norPtr);
905         } else if (indices.stride == sizeof(uint32_t)) {
906             auto view = array_view(
907                 reinterpret_cast<const uint32_t*>(indices.buffer.data()), indices.buffer.size() / indices.stride);
908             SmoothNormal(view, posPtr, norPtr);
909         }
910         for (auto& nor : array_view(norPtr, vertexCount)) {
911             nor = Math::Normalize(nor);
912         }
913     }
914 }
915 
GenerateDefaultUvs(vector<uint8_t>& generatedUvs, uint32_t vertexCount)916 void GenerateDefaultUvs(vector<uint8_t>& generatedUvs, uint32_t vertexCount)
917 {
918     auto offset = generatedUvs.size();
919     generatedUvs.resize(generatedUvs.size() + sizeof(Math::Vec2) * vertexCount);
920     auto* ptr = reinterpret_cast<Math::Vec2*>(generatedUvs.data() + offset);
921     std::fill(ptr, ptr + vertexCount, Math::Vec2(0.0f, 0.0f));
922 }
923 
GenerateDefaultTangents(IMeshBuilder::DataBuffer& tangents, vector<uint8_t>& generatedTangents, const IMeshBuilder::DataBuffer& indices, const IMeshBuilder::DataBuffer& positions, const IMeshBuilder::DataBuffer& normals, const IMeshBuilder::DataBuffer& uvs, uint32_t vertexCount)924 void GenerateDefaultTangents(IMeshBuilder::DataBuffer& tangents, vector<uint8_t>& generatedTangents,
925     const IMeshBuilder::DataBuffer& indices, const IMeshBuilder::DataBuffer& positions,
926     const IMeshBuilder::DataBuffer& normals, const IMeshBuilder::DataBuffer& uvs, uint32_t vertexCount)
927 {
928     auto offset = generatedTangents.size();
929     generatedTangents.resize(generatedTangents.size() + sizeof(Math::Vec4) * vertexCount);
930     tangents.format = BASE_FORMAT_R32G32B32A32_SFLOAT;
931     tangents.stride = sizeof(Math::Vec4);
932     tangents.buffer = generatedTangents;
933 
934     auto posView = array_view(reinterpret_cast<const Math::Vec3*>(positions.buffer.data()), vertexCount);
935     auto norView = array_view(reinterpret_cast<const Math::Vec3*>(normals.buffer.data()), vertexCount);
936     auto uvsView = array_view(reinterpret_cast<const Math::Vec2*>(uvs.buffer.data()), vertexCount);
937 
938     auto outTangents = array_view(reinterpret_cast<Math::Vec4*>(generatedTangents.data() + offset), vertexCount);
939 
940     vector<uint8_t> indexData(indices.buffer.size());
941 
942     const auto indexCountCount = indices.buffer.size() / indices.stride;
943     switch (indices.stride) {
944         case sizeof(uint8_t): {
945             auto indicesView = array_view(reinterpret_cast<const uint8_t*>(indices.buffer.data()), indexCountCount);
946             MeshUtil::CalculateTangents(indicesView, posView, norView, uvsView, outTangents);
947             break;
948         }
949         case sizeof(uint16_t): {
950             auto indicesView = array_view(reinterpret_cast<const uint16_t*>(indices.buffer.data()), indexCountCount);
951             MeshUtil::CalculateTangents(indicesView, posView, norView, uvsView, outTangents);
952             break;
953         }
954         case sizeof(uint32_t): {
955             auto indicesView = array_view(reinterpret_cast<const uint32_t*>(indices.buffer.data()), indexCountCount);
956             MeshUtil::CalculateTangents(indicesView, posView, norView, uvsView, outTangents);
957             break;
958         }
959         default:
960             CORE_ASSERT_MSG(false, "Invalid elementSize %u", indices.stride);
961     }
962 }
963 } // namespace
964 
MeshBuilder(IRenderContext& renderContext)965 MeshBuilder::MeshBuilder(IRenderContext& renderContext) : renderContext_(renderContext) {}
966 
967 // Public interface from IMeshBuilder
Initialize(const VertexInputDeclarationView& vertexInputDeclaration, size_t submeshCount)968 void MeshBuilder::Initialize(const VertexInputDeclarationView& vertexInputDeclaration, size_t submeshCount)
969 {
970     submeshInfos_.clear();
971     submeshInfos_.reserve(submeshCount);
972     submeshes_.clear();
973     submeshes_.resize(submeshCount);
974 
975     vertexCount_ = 0;
976     indexCount_ = 0;
977 
978     vertexDataSize_ = 0;
979     indexDataSize_ = 0;
980     jointDataSize_ = 0;
981     targetDataSize_ = 0;
982 
983     jointBoundsData_.clear();
984 
985     bufferHandles_ = {};
986     if (stagingPtr_) {
987         stagingPtr_ = nullptr;
988         auto& gpuResourceManager = renderContext_.GetDevice().GetGpuResourceManager();
989         gpuResourceManager.UnmapBuffer(stagingBuffer_);
990     }
991     stagingBuffer_ = {};
992     vertexInputDeclaration_ = vertexInputDeclaration;
993 }
994 
AddSubmesh(const Submesh& info)995 void MeshBuilder::AddSubmesh(const Submesh& info)
996 {
997     submeshInfos_.push_back(SubmeshExt { info, {}, {}, {} });
998 }
999 
GetSubmesh(size_t index) const1000 const MeshBuilder::Submesh& MeshBuilder::GetSubmesh(size_t index) const
1001 {
1002     return submeshInfos_[index].info;
1003 }
1004 
Allocate()1005 void MeshBuilder::Allocate()
1006 {
1007     BufferSizesInBytes bufferSizes = CalculateSizes();
1008     bufferSizes.indexBuffer = Align(bufferSizes.indexBuffer, BUFFER_ALIGN);
1009     bufferSizes.jointBuffer = Align(bufferSizes.jointBuffer, BUFFER_ALIGN);
1010     bufferSizes.morphVertexData = Align(bufferSizes.morphVertexData, BUFFER_ALIGN);
1011 
1012     indexCount_ = (uint32_t)bufferSizes.indexBuffer / sizeof(uint32_t);
1013 
1014     uint32_t vertexBufferSizeInBytes = 0;
1015 
1016     // Set binding offsets.
1017     for (auto const& bindingDesc : vertexInputDeclaration_.bindingDescriptions) {
1018         for (auto& submesh : submeshInfos_) {
1019             submesh.vertexBindingOffset[bindingDesc.binding] = vertexBufferSizeInBytes;
1020             vertexBufferSizeInBytes += submesh.vertexBindingByteSize[bindingDesc.binding];
1021         }
1022     }
1023 
1024     vertexDataSize_ = vertexBufferSizeInBytes;
1025     indexDataSize_ = bufferSizes.indexBuffer;
1026     jointDataSize_ = bufferSizes.jointBuffer;
1027     targetDataSize_ = bufferSizes.morphVertexData;
1028 
1029     auto& gpuResourceManager = renderContext_.GetDevice().GetGpuResourceManager();
1030 
1031     GpuBufferDesc gpuBufferDesc;
1032     gpuBufferDesc.usageFlags = BufferUsageFlagBits::CORE_BUFFER_USAGE_TRANSFER_SRC_BIT;
1033     gpuBufferDesc.memoryPropertyFlags = MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
1034                                         MemoryPropertyFlagBits::CORE_MEMORY_PROPERTY_HOST_COHERENT_BIT;
1035     gpuBufferDesc.engineCreationFlags = EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_CREATE_IMMEDIATE |
1036                                         EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_MAP_OUTSIDE_RENDERER |
1037                                         EngineBufferCreationFlagBits::CORE_ENGINE_BUFFER_CREATION_DEFERRED_DESTROY;
1038     gpuBufferDesc.byteSize = static_cast<uint32_t>(vertexDataSize_ + indexDataSize_ + jointDataSize_ + targetDataSize_);
1039     if (gpuBufferDesc.byteSize) {
1040         stagingBuffer_ = gpuResourceManager.Create(gpuBufferDesc);
1041         stagingPtr_ = static_cast<uint8_t*>(gpuResourceManager.MapBufferMemory(stagingBuffer_));
1042     }
1043 }
1044 
CalculateSizes()1045 MeshBuilder::BufferSizesInBytes MeshBuilder::CalculateSizes()
1046 {
1047     BufferSizesInBytes bufferSizes {};
1048 
1049     const size_t jointIndexSizeInBytes =
1050         GetVertexAttributeByteSize(MeshComponent::Submesh::DM_VB_JOI, vertexInputDeclaration_);
1051     const size_t jointWeightSizeInBytes =
1052         GetVertexAttributeByteSize(MeshComponent::Submesh::DM_VB_JOW, vertexInputDeclaration_);
1053 
1054     for (auto& submesh : submeshInfos_) {
1055         // Calculate vertex binding sizes.
1056         submesh.vertexBindingByteSize.resize(vertexInputDeclaration_.bindingDescriptions.size());
1057         submesh.vertexBindingOffset.resize(vertexInputDeclaration_.bindingDescriptions.size());
1058         for (auto const& bindingDesc : vertexInputDeclaration_.bindingDescriptions) {
1059             submesh.vertexBindingByteSize[bindingDesc.binding] =
1060                 static_cast<uint32_t>(Align(bindingDesc.stride * submesh.info.vertexCount, BUFFER_ALIGN));
1061         }
1062 
1063         submesh.indexBufferOffset = (uint32_t)Align(bufferSizes.indexBuffer, BUFFER_ALIGN);
1064         submesh.jointBufferOffset = (uint32_t)Align(bufferSizes.jointBuffer, BUFFER_ALIGN);
1065         submesh.morphTargetBufferOffset = (uint32_t)Align(bufferSizes.morphVertexData, BUFFER_ALIGN);
1066 
1067         if (submesh.info.indexType == CORE_INDEX_TYPE_UINT16) {
1068             bufferSizes.indexBuffer = submesh.indexBufferOffset + (submesh.info.indexCount * sizeof(uint16_t));
1069         } else {
1070             bufferSizes.indexBuffer = submesh.indexBufferOffset + (submesh.info.indexCount * sizeof(uint32_t));
1071         }
1072 
1073         if (submesh.info.joints) {
1074             const size_t currJointIndexByteSize = Align(jointIndexSizeInBytes * submesh.info.vertexCount, BUFFER_ALIGN);
1075             const size_t currJointWeightByteSize =
1076                 Align(jointWeightSizeInBytes * submesh.info.vertexCount, BUFFER_ALIGN);
1077             // joint index and joint weight bytesizes both need to be aligned
1078             bufferSizes.jointBuffer = submesh.jointBufferOffset + currJointIndexByteSize + currJointWeightByteSize;
1079         }
1080 
1081         if (submesh.info.morphTargetCount > 0) {
1082             submesh.morphTargets.resize(submesh.info.morphTargetCount);
1083             // vertexCount * uint32_t * morphTargetCount, index/indexOffset to sparse target data
1084             // vertexCount * MorphInputData, base data
1085             // vertexCount * MorphInputData * morphTargetCount, target data
1086             const uint32_t indexSize = (uint32_t)Align(
1087                 submesh.info.vertexCount * submesh.info.morphTargetCount * sizeof(uint32_t), BUFFER_ALIGN);
1088             const uint32_t targetSize = (uint32_t)Align(
1089                 submesh.info.vertexCount * sizeof(MorphInputData) * (submesh.info.morphTargetCount + 1u), BUFFER_ALIGN);
1090             bufferSizes.morphVertexData = submesh.morphTargetBufferOffset + indexSize + targetSize;
1091         }
1092 
1093         vertexCount_ += submesh.info.vertexCount;
1094     }
1095     return bufferSizes;
1096 }
1097 
SetVertexData(size_t submeshIndex, const DataBuffer& positions, const DataBuffer& normals, const DataBuffer& texcoords0, const DataBuffer& texcoords1, const DataBuffer& tangents, const DataBuffer& colors)1098 void MeshBuilder::SetVertexData(size_t submeshIndex, const DataBuffer& positions, const DataBuffer& normals,
1099     const DataBuffer& texcoords0, const DataBuffer& texcoords1, const DataBuffer& tangents, const DataBuffer& colors)
1100 {
1101     if (auto buffer = stagingPtr_; buffer) {
1102         // *Vertex data* | index data | joint data | morph data
1103         SubmeshExt& submesh = submeshInfos_[submeshIndex];
1104 
1105         // Submesh info for this submesh.
1106         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1107 
1108         submeshDesc.material = submesh.info.material;
1109         submeshDesc.vertexCount = submesh.info.vertexCount;
1110         submeshDesc.instanceCount = submesh.info.instanceCount;
1111 
1112         // If we need to generate tangents we need float copies of position, normal and uv0
1113         const bool generateTangents = submesh.info.tangents && tangents.buffer.empty();
1114 
1115         // Process position.
1116         {
1117             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_POS];
1118             WriteData(positions, submesh, MeshComponent::Submesh::DM_VB_POS, acc.offset, acc.byteSize, buffer);
1119             if (normals.buffer.empty() || generateTangents) {
1120                 auto offset = vertexData_.size();
1121                 vertexData_.resize(offset + sizeof(Math::Vec3) * submeshDesc.vertexCount);
1122                 OutputBuffer dst { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1123                     { vertexData_.data() + offset, sizeof(Math::Vec3) * submeshDesc.vertexCount } };
1124                 Fill(dst, positions, submeshDesc.vertexCount);
1125                 submesh.positionOffset = static_cast<int32_t>(offset);
1126                 submesh.positionSize = sizeof(Math::Vec3) * submeshDesc.vertexCount;
1127             }
1128         }
1129 
1130         // Process normal.
1131         if (!normals.buffer.empty()) {
1132             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_NOR];
1133             WriteData(normals, submesh, MeshComponent::Submesh::DM_VB_NOR, acc.offset, acc.byteSize, buffer);
1134             submesh.hasNormals = true;
1135             if (generateTangents) {
1136                 auto offset = vertexData_.size();
1137                 vertexData_.resize(offset + sizeof(Math::Vec3) * submeshDesc.vertexCount);
1138                 OutputBuffer dst { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1139                     { vertexData_.data() + offset, sizeof(Math::Vec3) * submeshDesc.vertexCount } };
1140                 Fill(dst, normals, submeshDesc.vertexCount);
1141                 submesh.normalOffset = static_cast<int32_t>(offset);
1142                 submesh.normalSize = sizeof(Math::Vec3) * submeshDesc.vertexCount;
1143             }
1144         }
1145 
1146         // Process uv.
1147         if (!texcoords0.buffer.empty()) {
1148             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1149             WriteData(texcoords0, submesh, MeshComponent::Submesh::DM_VB_UV0, acc.offset, acc.byteSize, buffer);
1150             submesh.hasUv0 = true;
1151             if (generateTangents) {
1152                 auto offset = vertexData_.size();
1153                 vertexData_.resize(offset + sizeof(Math::Vec2) * submeshDesc.vertexCount);
1154                 OutputBuffer dst { BASE_FORMAT_R32G32_SFLOAT, sizeof(Math::Vec2),
1155                     { vertexData_.data() + offset, sizeof(Math::Vec2) * submeshDesc.vertexCount } };
1156                 Fill(dst, texcoords0, submeshDesc.vertexCount);
1157                 submesh.uvOffset = static_cast<int32_t>(offset);
1158                 submesh.uvSize = sizeof(Math::Vec2) * submeshDesc.vertexCount;
1159             }
1160         }
1161 
1162         if (!texcoords1.buffer.empty()) {
1163             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV1];
1164             if (WriteData(texcoords1, submesh, MeshComponent::Submesh::DM_VB_UV1, acc.offset, acc.byteSize, buffer)) {
1165                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::SECOND_TEXCOORD_BIT;
1166             }
1167         } else {
1168             const auto& uv0 = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1169             auto& uv1 = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV1];
1170             uv1 = uv0;
1171         }
1172 
1173         // Process tangent.
1174         if (!tangents.buffer.empty() && submesh.info.tangents) {
1175             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_TAN];
1176             if (WriteData(tangents, submesh, MeshComponent::Submesh::DM_VB_TAN, acc.offset, acc.byteSize, buffer)) {
1177                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::TANGENTS_BIT;
1178                 submesh.hasTangents = true;
1179             }
1180         }
1181 
1182         // Process vertex colors.
1183         if (!colors.buffer.empty() && submesh.info.colors) {
1184             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_COL];
1185             if (WriteData(colors, submesh, MeshComponent::Submesh::DM_VB_COL, acc.offset, acc.byteSize, buffer)) {
1186                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::VERTEX_COLORS_BIT;
1187             }
1188         }
1189     }
1190 }
1191 
SetIndexData(size_t submeshIndex, const DataBuffer& indices)1192 void MeshBuilder::SetIndexData(size_t submeshIndex, const DataBuffer& indices)
1193 {
1194     if (auto buffer = stagingPtr_; buffer) {
1195         // Vertex data | *index data* | joint data | morph data
1196         buffer += vertexDataSize_;
1197         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1198         SubmeshExt& submesh = submeshInfos_[submeshIndex];
1199 
1200         OutputBuffer output { (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16) ? BASE_FORMAT_R16_UINT
1201                                                                                             : BASE_FORMAT_R32_UINT,
1202             static_cast<uint32_t>(
1203                 (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16) ? sizeof(uint16_t) : sizeof(uint32_t)),
1204             {} };
1205         // If we need to generate normals or tangents we need CPU copies of the indices
1206         if (!submesh.hasNormals || (submesh.info.tangents && !submesh.hasTangents)) {
1207             // First convert and write to a plain vector
1208             auto offset = indexData_.size();
1209             indexData_.resize(offset + output.stride * submesh.info.indexCount);
1210             output.buffer = { indexData_.data() + offset, output.stride * submesh.info.indexCount };
1211             Fill(output, indices, submesh.info.indexCount);
1212             submesh.indexOffset = static_cast<int32_t>(offset);
1213             submesh.indexSize = output.stride * submesh.info.indexCount;
1214             // Then copy the data to staging buffer.
1215             std::copy(indexData_.data() + offset, indexData_.data() + offset + output.stride * submesh.info.indexCount,
1216                 buffer + submesh.indexBufferOffset);
1217         } else {
1218             // Convert directly to the staging buffer.
1219             output.buffer = { buffer + submesh.indexBufferOffset, output.stride * submesh.info.indexCount };
1220             Fill(output, indices, submesh.info.indexCount);
1221         }
1222 
1223         submeshDesc.indexCount = submesh.info.indexCount;
1224         submeshDesc.indexBuffer.indexType = submesh.info.indexType;
1225         submeshDesc.indexBuffer.offset = submesh.indexBufferOffset;
1226         submeshDesc.indexBuffer.byteSize = static_cast<uint32_t>(output.buffer.size());
1227     }
1228 }
1229 
SetJointData( size_t submeshIndex, const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& vertexPositions)1230 void MeshBuilder::SetJointData(
1231     size_t submeshIndex, const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& vertexPositions)
1232 {
1233     if (auto buffer = stagingPtr_; buffer) {
1234         // Vertex data | index data | *joint data* | morph data
1235         buffer += vertexDataSize_ + indexDataSize_;
1236         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1237         const SubmeshExt& submesh = submeshInfos_[submeshIndex];
1238         if (const auto* indexAttributeDesc = GetVertexAttributeDescription(
1239                 MeshComponent::Submesh::DM_VB_JOI, vertexInputDeclaration_.attributeDescriptions);
1240             indexAttributeDesc) {
1241             if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc = GetVertexBindingeDescription(
1242                     indexAttributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
1243                 bindingDesc) {
1244                 auto& jointIndexAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOI];
1245                 jointIndexAcc.offset = (uint32_t)Align(submesh.jointBufferOffset, BUFFER_ALIGN);
1246                 jointIndexAcc.byteSize = (uint32_t)bindingDesc->stride * submesh.info.vertexCount;
1247 
1248                 OutputBuffer dstData { indexAttributeDesc->format, bindingDesc->stride,
1249                     { buffer + jointIndexAcc.offset, jointIndexAcc.byteSize } };
1250                 Fill(dstData, jointData, submesh.info.vertexCount);
1251             }
1252         }
1253         if (const auto* weightAttributeDesc = GetVertexAttributeDescription(
1254                 MeshComponent::Submesh::DM_VB_JOW, vertexInputDeclaration_.attributeDescriptions);
1255             weightAttributeDesc) {
1256             if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc = GetVertexBindingeDescription(
1257                     weightAttributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
1258                 bindingDesc) {
1259                 auto& jointIndexAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOI];
1260                 // Process joint weights.
1261                 auto& jointWeightAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOW];
1262                 // index aligned offset + index bytesize -> aligned to offset
1263                 jointWeightAcc.offset = (uint32_t)Align(jointIndexAcc.offset + jointIndexAcc.byteSize, BUFFER_ALIGN);
1264                 jointWeightAcc.byteSize = (uint32_t)bindingDesc->stride * submesh.info.vertexCount;
1265 
1266                 OutputBuffer dstData { weightAttributeDesc->format, bindingDesc->stride,
1267                     { buffer + jointWeightAcc.offset, jointWeightAcc.byteSize } };
1268                 Fill(dstData, weightData, submesh.info.vertexCount);
1269             }
1270         }
1271         submeshDesc.flags |= MeshComponent::Submesh::FlagBits::SKIN_BIT;
1272         CalculateJointBounds(jointData, weightData, vertexPositions);
1273     }
1274 }
1275 
SetMorphTargetData(size_t submeshIndex, const DataBuffer& basePositions, const DataBuffer& baseNormals, const DataBuffer& baseTangents, const DataBuffer& targetPositions, const DataBuffer& targetNormals, const DataBuffer& targetTangents)1276 void MeshBuilder::SetMorphTargetData(size_t submeshIndex, const DataBuffer& basePositions,
1277     const DataBuffer& baseNormals, const DataBuffer& baseTangents, const DataBuffer& targetPositions,
1278     const DataBuffer& targetNormals, const DataBuffer& targetTangents)
1279 {
1280     // Submesh info for this submesh.
1281     SubmeshExt& submesh = submeshInfos_[submeshIndex];
1282     if (submesh.info.morphTargetCount > 0) {
1283         if (auto buffer = stagingPtr_; buffer) {
1284             // Vertex data | index data | joint data | *morph data*
1285             buffer += vertexDataSize_ + indexDataSize_ + jointDataSize_;
1286 
1287             // Offset to morph index data is previous offset + size (or zero for the first submesh)
1288             uint32_t indexOffset = 0u;
1289             if (submeshIndex) {
1290                 indexOffset = static_cast<uint32_t>(Align(submeshInfos_[submeshIndex - 1u].morphTargetBufferOffset +
1291                                                               submeshInfos_[submeshIndex - 1u].morphTargetBufferSize,
1292                     BUFFER_ALIGN));
1293             }
1294             submesh.morphTargetBufferOffset = indexOffset;
1295 
1296             // 32bit index/offset for each vertex in each morph target
1297             const uint32_t indexSize = sizeof(uint32_t) * submesh.info.vertexCount;
1298             const uint32_t totalIndexSize =
1299                 static_cast<uint32_t>(Align(indexSize * submesh.info.morphTargetCount, BUFFER_ALIGN));
1300 
1301             // Data struct (pos, nor, tan) for each vertex. total amount is target size for each target data and one
1302             // base data
1303             const uint32_t targetSize = submesh.info.vertexCount * sizeof(MorphInputData);
1304 
1305             // Base data starts after index data
1306             const uint32_t baseOffset = indexOffset + totalIndexSize;
1307             {
1308                 OutputBuffer dstData { POSITION_FORMAT, sizeof(MorphInputData), { buffer + baseOffset, targetSize } };
1309                 Fill(dstData, basePositions, submesh.info.vertexCount);
1310             }
1311 
1312             if (!baseNormals.buffer.empty()) {
1313 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1314                 OutputBuffer dstData { NORMAL_FORMAT, sizeof(MorphInputData),
1315                     { buffer + baseOffset + offsetof(MorphInputData, nortan), targetSize } };
1316 #else
1317                 OutputBuffer dstData { NORMAL_FORMAT, sizeof(MorphInputData),
1318                     { buffer + baseOffset + offsetof(MorphInputData, nor), targetSize } };
1319 #endif
1320                 Fill(dstData, baseNormals, submesh.info.vertexCount);
1321             }
1322             if (!baseTangents.buffer.empty()) {
1323 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1324                 OutputBuffer dstData { TANGENT_FORMAT, sizeof(MorphInputData),
1325                     { buffer + baseOffset + offsetof(MorphInputData, nortan) + 8U, targetSize } };
1326 #else
1327                 OutputBuffer dstData { TANGENT_FORMAT, sizeof(MorphInputData),
1328                     { buffer + baseOffset + offsetof(MorphInputData, tan), targetSize } };
1329 #endif
1330                 Fill(dstData, baseTangents, submesh.info.vertexCount);
1331             }
1332             // Gather non-zero deltas.
1333             if (targetNormals.buffer.empty() && targetTangents.buffer.empty()) {
1334                 GatherDeltasP(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions);
1335             } else if (!targetNormals.buffer.empty() && targetTangents.buffer.empty()) {
1336                 GatherDeltasPN(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetNormals);
1337             } else if (targetNormals.buffer.empty() && !targetTangents.buffer.empty()) {
1338                 GatherDeltasPT(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetTangents);
1339             } else {
1340                 GatherDeltasPNT(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetNormals,
1341                     targetTangents);
1342             }
1343 
1344             // Actual buffer size based on the offset and size of the last morph target.
1345             submesh.morphTargetBufferSize = submesh.morphTargets[submesh.info.morphTargetCount - 1].offset -
1346                                             indexOffset +
1347                                             submesh.morphTargets[submesh.info.morphTargetCount - 1].byteSize;
1348 
1349             // Clamp to actual size which might be less than what was asked for before gathering the non-zero deltas.
1350             targetDataSize_ = static_cast<size_t>(submesh.morphTargetBufferOffset + submesh.morphTargetBufferSize);
1351 
1352             MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1353             submeshDesc.morphTargetBuffer.offset = submesh.morphTargetBufferOffset;
1354             submeshDesc.morphTargetBuffer.byteSize = submesh.morphTargetBufferSize;
1355             submeshDesc.morphTargetCount = static_cast<uint32_t>(submesh.morphTargets.size());
1356         }
1357     }
1358 }
1359 
SetAABB(size_t submeshIndex, const Math::Vec3& min, const Math::Vec3& max)1360 void MeshBuilder::SetAABB(size_t submeshIndex, const Math::Vec3& min, const Math::Vec3& max)
1361 {
1362     MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1363     submeshDesc.aabbMin = min;
1364     submeshDesc.aabbMax = max;
1365 }
1366 
CalculateAABB(size_t submeshIndex, const DataBuffer& positions)1367 void MeshBuilder::CalculateAABB(size_t submeshIndex, const DataBuffer& positions)
1368 {
1369     const auto posFormat = GetFormatSpec(positions.format);
1370     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1371         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1372         return;
1373     }
1374     const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1375     if (posElementSize > positions.stride) {
1376         return;
1377     }
1378     auto count = positions.buffer.size() / positions.stride;
1379 
1380     constexpr float maxLimits = std::numeric_limits<float>::max();
1381     constexpr float minLimits = -std::numeric_limits<float>::max();
1382 
1383     Math::Vec3 finalMinimum = { maxLimits, maxLimits, maxLimits };
1384     Math::Vec3 finalMaximum = { minLimits, minLimits, minLimits };
1385 
1386     auto srcPtr = positions.buffer.data();
1387     switch (posFormat.format) {
1388         case BASE_FORMAT_R16G16_UNORM: {
1389             uint16_t minimum[RG] { std::numeric_limits<uint16_t>::max() };
1390             uint16_t maximum[RG] { std::numeric_limits<uint16_t>::lowest() };
1391             while (count--) {
1392                 uint16_t value[RG] = { reinterpret_cast<const uint16_t*>(srcPtr)[R],
1393                     reinterpret_cast<const uint16_t*>(srcPtr)[G] };
1394                 srcPtr += positions.stride;
1395                 GatherMin(minimum, value);
1396                 GatherMax(maximum, value);
1397             }
1398             for (auto i = 0U; i < RG; ++i) {
1399                 finalMinimum[i] = Norm<uint16_t>::From(minimum[i]);
1400             }
1401             finalMinimum[B] = 0.f;
1402             for (auto i = 0U; i < RG; ++i) {
1403                 finalMaximum[i] = Norm<uint16_t>::From(maximum[i]);
1404             }
1405             finalMaximum[B] = 0.f;
1406         } break;
1407 
1408         case BASE_FORMAT_R8G8B8_SNORM: {
1409             int8_t minimum[RGB] { std::numeric_limits<int8_t>::max() };
1410             int8_t maximum[RGB] { std::numeric_limits<int8_t>::lowest() };
1411             while (count--) {
1412                 int8_t value[RGB] = { reinterpret_cast<const int8_t*>(srcPtr)[R],
1413                     reinterpret_cast<const int8_t*>(srcPtr)[G], reinterpret_cast<const int8_t*>(srcPtr)[B] };
1414                 srcPtr += positions.stride;
1415                 GatherMin(minimum, value);
1416                 GatherMax(maximum, value);
1417             }
1418             for (auto i = 0U; i < RGB; ++i) {
1419                 finalMinimum[i] = Norm<int8_t>::From(minimum[i]);
1420             }
1421             for (auto i = 0U; i < RGB; ++i) {
1422                 finalMaximum[i] = Norm<int8_t>::From(maximum[i]);
1423             }
1424         } break;
1425 
1426         case BASE_FORMAT_R16G16B16_UINT:
1427         case BASE_FORMAT_R16G16B16A16_UINT: {
1428             uint16_t minimum[RGB] { std::numeric_limits<uint16_t>::max() };
1429             uint16_t maximum[RGB] { std::numeric_limits<uint16_t>::lowest() };
1430             while (count--) {
1431                 uint16_t value[RGB] = { reinterpret_cast<const uint16_t*>(srcPtr)[R],
1432                     reinterpret_cast<const uint16_t*>(srcPtr)[G], reinterpret_cast<const uint16_t*>(srcPtr)[B] };
1433                 srcPtr += positions.stride;
1434                 GatherMin(minimum, value);
1435                 GatherMax(maximum, value);
1436             }
1437             for (auto i = 0U; i < RGB; ++i) {
1438                 finalMinimum[i] = Int<uint16_t>::From(minimum[i]);
1439             }
1440             for (auto i = 0U; i < RGB; ++i) {
1441                 finalMaximum[i] = Int<uint16_t>::From(maximum[i]);
1442             }
1443         } break;
1444 
1445         case BASE_FORMAT_R32G32_SFLOAT: {
1446             while (count--) {
1447                 float value[RG] = { reinterpret_cast<const float*>(srcPtr)[R],
1448                     reinterpret_cast<const float*>(srcPtr)[G] };
1449                 srcPtr += positions.stride;
1450                 GatherMin(finalMinimum.data, value);
1451                 GatherMax(finalMaximum.data, value);
1452             }
1453         } break;
1454 
1455         case BASE_FORMAT_R32G32B32_SFLOAT:
1456         case BASE_FORMAT_R32G32B32A32_SFLOAT: {
1457             while (count--) {
1458                 float value[RGB] = { reinterpret_cast<const float*>(srcPtr)[R],
1459                     reinterpret_cast<const float*>(srcPtr)[G], reinterpret_cast<const float*>(srcPtr)[B] };
1460                 srcPtr += positions.stride;
1461                 GatherMin(finalMinimum.data, value);
1462                 GatherMax(finalMaximum.data, value);
1463             }
1464         } break;
1465 
1466         default:
1467             CORE_LOG_W("CalculateAABB: position format %u not handled.", posFormat.format);
1468             break;
1469     }
1470     SetAABB(submeshIndex, finalMinimum, finalMaximum);
1471 }
1472 
GetVertexData() const1473 array_view<const uint8_t> MeshBuilder::GetVertexData() const
1474 {
1475     return array_view<const uint8_t>(stagingPtr_, vertexDataSize_);
1476 }
1477 
GetIndexData() const1478 array_view<const uint8_t> MeshBuilder::GetIndexData() const
1479 {
1480     return array_view<const uint8_t>(stagingPtr_ ? (stagingPtr_ + vertexDataSize_) : nullptr, indexDataSize_);
1481 }
1482 
GetJointData() const1483 array_view<const uint8_t> MeshBuilder::GetJointData() const
1484 {
1485     return array_view<const uint8_t>(
1486         stagingPtr_ ? (stagingPtr_ + vertexDataSize_ + indexDataSize_) : nullptr, jointDataSize_);
1487 }
1488 
GetMorphTargetData() const1489 array_view<const uint8_t> MeshBuilder::GetMorphTargetData() const
1490 {
1491     return array_view<const uint8_t>(
1492         stagingPtr_ ? (stagingPtr_ + vertexDataSize_ + indexDataSize_ + jointDataSize_) : nullptr, targetDataSize_);
1493 }
1494 
GetJointBoundsData() const1495 array_view<const float> MeshBuilder::GetJointBoundsData() const
1496 {
1497     return array_view(reinterpret_cast<const float*>(jointBoundsData_.data()),
1498         jointBoundsData_.size() * SIZE_OF_VALUE_TYPE_V<decltype(jointBoundsData_)> / sizeof(float));
1499 }
1500 
GetSubmeshes() const1501 array_view<const MeshComponent::Submesh> MeshBuilder::GetSubmeshes() const
1502 {
1503     return array_view<const MeshComponent::Submesh>(submeshes_);
1504 }
1505 
GetVertexCount() const1506 uint32_t MeshBuilder::GetVertexCount() const
1507 {
1508     return vertexCount_;
1509 }
1510 
GetIndexCount() const1511 uint32_t MeshBuilder::GetIndexCount() const
1512 {
1513     return indexCount_;
1514 }
1515 
CreateGpuResources(const GpuBufferCreateInfo& createInfo)1516 void MeshBuilder::CreateGpuResources(const GpuBufferCreateInfo& createInfo)
1517 {
1518     GenerateMissingAttributes();
1519 
1520     bufferHandles_ = CreateGpuBuffers(
1521         renderContext_, vertexDataSize_, indexDataSize_, indexCount_, jointDataSize_, targetDataSize_, createInfo);
1522 
1523     StageToBuffers(renderContext_, vertexDataSize_, indexDataSize_, jointDataSize_, targetDataSize_, bufferHandles_,
1524         stagingBuffer_);
1525 }
1526 
CreateGpuResources()1527 void MeshBuilder::CreateGpuResources()
1528 {
1529     CreateGpuResources({});
1530 }
1531 
CreateMesh(IEcs& ecs) const1532 Entity MeshBuilder::CreateMesh(IEcs& ecs) const
1533 {
1534     if (!vertexDataSize_) {
1535         return {};
1536     }
1537 
1538     auto meshManager = GetManager<IMeshComponentManager>(ecs);
1539     if (!meshManager) {
1540         return {};
1541     }
1542 
1543     auto& em = ecs.GetEntityManager();
1544     auto meshEntity = em.Create();
1545     meshManager->Create(meshEntity);
1546     if (auto meshHandle = meshManager->Write(meshEntity); meshHandle) {
1547         MeshComponent& mesh = *meshHandle;
1548 
1549         // Copy skin joint bounding boxes.
1550         const size_t jointBoundsDataSize = jointBoundsData_.size();
1551         if (jointBoundsDataSize != 0) {
1552             mesh.jointBounds.reserve(jointBoundsDataSize * JOINT_BOUNDS_COMPONENTS);
1553             for (const auto& bounds : jointBoundsData_) {
1554                 for (const auto& f : bounds.min.data) {
1555                     mesh.jointBounds.push_back(f);
1556                 }
1557                 for (const auto& f : bounds.max.data) {
1558                     mesh.jointBounds.push_back(f);
1559                 }
1560             }
1561         }
1562 
1563         // Copy submeshes for this mesh.
1564         mesh.submeshes.insert(mesh.submeshes.end(), submeshes_.begin(), submeshes_.end());
1565 
1566         // Create buffers for whole mesh and assign them to submeshes.
1567         const auto bufferEntities = CreateBuffers(ecs);
1568         FillSubmeshBuffers(mesh.submeshes, bufferEntities);
1569 
1570         // AABB for mesh
1571         const auto minMax = CalculateAabb(submeshes_);
1572         mesh.aabbMin = minMax.minAABB;
1573         mesh.aabbMax = minMax.maxAABB;
1574     }
1575     return meshEntity;
1576 }
1577 
GetInterface(const Uid& uid) const1578 const IInterface* MeshBuilder::GetInterface(const Uid& uid) const
1579 {
1580     if ((uid == IMeshBuilder::UID) || (uid == IInterface::UID)) {
1581         return this;
1582     }
1583     return nullptr;
1584 }
1585 
GetInterface(const Uid& uid)1586 IInterface* MeshBuilder::GetInterface(const Uid& uid)
1587 {
1588     if ((uid == IMeshBuilder::UID) || (uid == IInterface::UID)) {
1589         return this;
1590     }
1591     return nullptr;
1592 }
1593 
Ref()1594 void MeshBuilder::Ref()
1595 {
1596     refCount_++;
1597 }
1598 
Unref()1599 void MeshBuilder::Unref()
1600 {
1601     if (--refCount_ == 0) {
1602         delete this;
1603     }
1604 }
1605 
1606 // Private methods
CreateBuffers(IEcs& ecs) const1607 MeshBuilder::BufferEntities MeshBuilder::CreateBuffers(IEcs& ecs) const
1608 {
1609     BufferEntities entities;
1610 
1611     BufferHandles handles;
1612     if (bufferHandles_.vertexBuffer) {
1613         handles = bufferHandles_;
1614     } else {
1615         GenerateMissingAttributes();
1616         handles = CreateGpuBuffers(
1617             renderContext_, vertexDataSize_, indexDataSize_, indexCount_, jointDataSize_, targetDataSize_, {});
1618         StageToBuffers(
1619             renderContext_, vertexDataSize_, indexDataSize_, jointDataSize_, targetDataSize_, handles, stagingBuffer_);
1620     }
1621 
1622     auto renderHandleManager = GetManager<IRenderHandleComponentManager>(ecs);
1623     if (!renderHandleManager) {
1624         return entities;
1625     }
1626 
1627     auto& em = ecs.GetEntityManager();
1628 
1629     // Create vertex buffer for this mesh.
1630     entities.vertexBuffer = CreateBuffer(em, *renderHandleManager, handles.vertexBuffer);
1631 
1632     // Create index buffer for this mesh.
1633     if (handles.indexBuffer) {
1634         entities.indexBuffer = CreateBuffer(em, *renderHandleManager, handles.indexBuffer);
1635     }
1636 
1637     if (handles.jointBuffer) {
1638         entities.jointBuffer = CreateBuffer(em, *renderHandleManager, handles.jointBuffer);
1639     }
1640 
1641     if (handles.morphBuffer) {
1642         entities.morphBuffer = CreateBuffer(em, *renderHandleManager, handles.morphBuffer);
1643     }
1644     return entities;
1645 }
1646 
GenerateMissingAttributes() const1647 void MeshBuilder::GenerateMissingAttributes() const
1648 {
1649     if (auto buffer = stagingPtr_; buffer) {
1650         auto submeshIt = submeshes_.begin();
1651         for (auto& submesh : submeshInfos_) {
1652             if (!vertexData_.empty() &&
1653                 (!submesh.hasNormals || !submesh.hasUv0 || (submesh.info.tangents && !submesh.hasTangents))) {
1654                 MeshComponent::Submesh& submeshDesc = *submeshIt;
1655                 const DataBuffer indexData { (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16)
1656                                                  ? BASE_FORMAT_R16_UINT
1657                                                  : BASE_FORMAT_R32_UINT,
1658                     static_cast<uint32_t>((submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16)
1659                                               ? sizeof(uint16_t)
1660                                               : sizeof(uint32_t)),
1661                     { indexData_.data() + submesh.indexOffset, submesh.indexSize } };
1662 
1663                 // Reserve space for the to be generated normals and uvs
1664                 vertexData_.reserve(vertexData_.size() +
1665                                     (submesh.hasNormals ? 0 : submesh.info.vertexCount * sizeof(Math::Vec3)) +
1666                                     (submesh.hasUv0 ? 0 : submesh.info.vertexCount * sizeof(Math::Vec2)));
1667 
1668                 DataBuffer positionData { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1669                     { vertexData_.data() + submesh.positionOffset, submesh.positionSize } };
1670 
1671                 DataBuffer normalData { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1672                     { vertexData_.data() + submesh.normalOffset, submesh.normalSize } };
1673 
1674                 if (!submesh.hasNormals) {
1675                     const auto offset = vertexData_.size();
1676                     GenerateDefaultNormals(vertexData_, indexData, positionData, submesh.info.vertexCount);
1677                     submesh.normalOffset = static_cast<int32_t>(offset);
1678                     submesh.normalSize = static_cast<uint32_t>(vertexData_.size() - offset);
1679                     normalData.buffer = { vertexData_.data() + submesh.normalOffset, submesh.normalSize };
1680 
1681                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_NOR];
1682                     WriteData(normalData, submesh, MeshComponent::Submesh::DM_VB_NOR, acc.offset, acc.byteSize, buffer);
1683                     submesh.hasNormals = true;
1684                 }
1685 
1686                 DataBuffer uvData { BASE_FORMAT_R32G32_SFLOAT, sizeof(Math::Vec2),
1687                     { vertexData_.data() + submesh.uvOffset, submesh.uvSize } };
1688                 if (!submesh.hasUv0) {
1689                     const auto offset = vertexData_.size();
1690                     GenerateDefaultUvs(vertexData_, submesh.info.vertexCount);
1691                     submesh.uvOffset = static_cast<int32_t>(offset);
1692                     submesh.uvSize = static_cast<uint32_t>(vertexData_.size() - offset);
1693                     uvData.buffer = { vertexData_.data() + submesh.uvOffset, submesh.uvSize };
1694 
1695                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1696                     WriteData(uvData, submesh, MeshComponent::Submesh::DM_VB_UV0, acc.offset, acc.byteSize, buffer);
1697                     submesh.hasUv0 = true;
1698                 }
1699 
1700                 if (submesh.info.tangents && !submesh.hasTangents) {
1701                     DataBuffer tangentData;
1702                     vector<uint8_t> generatedTangents;
1703                     GenerateDefaultTangents(tangentData, generatedTangents, indexData, positionData, normalData, uvData,
1704                         submesh.info.vertexCount);
1705 
1706                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_TAN];
1707                     if (WriteData(tangentData, submesh, MeshComponent::Submesh::DM_VB_TAN, acc.offset, acc.byteSize,
1708                             buffer)) {
1709                         submeshDesc.flags |= MeshComponent::Submesh::FlagBits::TANGENTS_BIT;
1710                         submesh.hasTangents = true;
1711                     }
1712                 }
1713             }
1714             ++submeshIt;
1715         }
1716     }
1717 }
1718 
GatherDeltasP(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset, uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions)1719 void MeshBuilder::GatherDeltasP(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1720     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions)
1721 {
1722     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1723         return;
1724     }
1725     const auto posFormat = GetFormatSpec(targetPositions.format);
1726     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1727         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1728         return;
1729     }
1730     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1731         posElementSize > targetPositions.stride) {
1732         return;
1733     }
1734 
1735     // Target data starts after base
1736     uint32_t targetOffset = baseOffset + targetSize;
1737 
1738     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1739     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1740         // special case which matches glTF 2.0. morph targets are three float components.
1741         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1742             submesh.morphTargets[trg].offset = targetOffset;
1743             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1744             auto target = startTarget;
1745             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1746                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1747                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1748                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1749                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1750                 const auto zeroDelta = (pos == Math::Vec3 {});
1751                 // store offset for each non-zero
1752                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1753                 if (zeroDelta) {
1754                     continue;
1755                 }
1756                 targetOffset += sizeof(MorphInputData);
1757 
1758                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1759                 ++target;
1760             }
1761             // Store the size and indexOffset of the gathered deltas.
1762             const auto byteSize =
1763                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1764             submesh.morphTargets[trg].byteSize = byteSize;
1765         }
1766     } else {
1767         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1768             submesh.morphTargets[trg].offset = targetOffset;
1769             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1770             auto target = startTarget;
1771             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1772                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1773                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1774                 Math::Vec3 pos;
1775                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
1776                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
1777                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
1778                 }
1779                 const auto zeroDelta = (pos == Math::Vec3 {});
1780                 // store offset for each non-zero
1781                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1782                 if (zeroDelta) {
1783                     continue;
1784                 }
1785                 targetOffset += sizeof(MorphInputData);
1786 
1787                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1788                 ++target;
1789             }
1790             // Store the size and indexOffset of the gathered deltas.
1791             const auto byteSize =
1792                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1793             submesh.morphTargets[trg].byteSize = byteSize;
1794         }
1795     }
1796 }
1797 
GatherDeltasPN(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset, uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals)1798 void MeshBuilder::GatherDeltasPN(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1799     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals)
1800 {
1801     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1802         return;
1803     }
1804     const auto posFormat = GetFormatSpec(targetPositions.format);
1805     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1806         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1807         return;
1808     }
1809     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1810         posElementSize > targetPositions.stride) {
1811         return;
1812     }
1813 
1814     if (targetNormals.stride > (targetNormals.buffer.size() / submesh.info.vertexCount)) {
1815         return;
1816     }
1817     const auto norFormat = GetFormatSpec(targetNormals.format);
1818     if (norFormat.format == BASE_FORMAT_UNDEFINED) {
1819         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1820         return;
1821     }
1822     if (const auto norElementSize = norFormat.componentCount * norFormat.componentByteSize;
1823         norElementSize > targetNormals.stride) {
1824         return;
1825     }
1826 
1827     // Target data starts after base
1828     uint32_t targetOffset = baseOffset + targetSize;
1829 
1830     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1831     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT && norFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1832         // special case which matches glTF 2.0. morph targets are three float components.
1833         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1834             submesh.morphTargets[trg].offset = targetOffset;
1835             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1836             auto target = startTarget;
1837             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1838                 // for each vertex in target check that position and normal deltas are non-zero.
1839                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1840                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1841                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1842                 auto nor = *reinterpret_cast<const Math::Vec3*>(
1843                     targetNormals.buffer.data() + targetNormals.stride * vertexIndex);
1844                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {});
1845                 // store offset for each non-zero
1846                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1847                 if (zeroDelta) {
1848                     continue;
1849                 }
1850                 targetOffset += sizeof(MorphInputData);
1851 
1852                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1853 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1854                 target->nortan.x = Math::PackHalf2X16({ nor.x, nor.y });
1855                 target->nortan.y = Math::PackHalf2X16({ nor.z, 0.f });
1856 #else
1857                 target->nor = Math::Vec4(nor, 0.f);
1858 #endif
1859                 ++target;
1860             }
1861             // Store the size of the gathered deltas.
1862             const auto byteSize =
1863                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1864             submesh.morphTargets[trg].byteSize = byteSize;
1865         }
1866     } else {
1867         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1868             submesh.morphTargets[trg].offset = targetOffset;
1869             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1870             auto target = startTarget;
1871             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1872                 // for each vertex in target check that position and normal deltas are non-zero.
1873                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1874                 Math::Vec3 pos;
1875                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
1876                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
1877                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
1878                 }
1879                 Math::Vec3 nor;
1880                 ptr = targetNormals.buffer.data() + targetNormals.stride * vertexIndex;
1881                 for (auto i = 0U; i < Math::min(countof(nor.data), norFormat.componentCount); ++i) {
1882                     nor[i] = norFormat.toIntermediate(ptr + i * norFormat.componentByteSize);
1883                 }
1884                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {});
1885                 // store offset for each non-zero
1886                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1887                 if (zeroDelta) {
1888                     continue;
1889                 }
1890                 targetOffset += sizeof(MorphInputData);
1891 
1892                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1893 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1894                 target->nortan.x = Math::PackHalf2X16({ nor.data[R], nor.data[G] });
1895                 target->nortan.y = Math::PackHalf2X16({ nor.data[B], 0.f });
1896 #else
1897                 target->nor = Math::Vec4(nor.data[R], nor.data[G], nor.data[B], 0.f);
1898 #endif
1899                 ++target;
1900             }
1901             // Store the size of the gathered deltas.
1902             const auto byteSize =
1903                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1904             submesh.morphTargets[trg].byteSize = byteSize;
1905         }
1906     }
1907 }
1908 
GatherDeltasPT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset, uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetTangents)1909 void MeshBuilder::GatherDeltasPT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1910     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetTangents)
1911 {}
1912 
GatherDeltasPNT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset, uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals, const MeshBuilder::DataBuffer& targetTangents)1913 void MeshBuilder::GatherDeltasPNT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1914     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals,
1915     const MeshBuilder::DataBuffer& targetTangents)
1916 {
1917     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1918         return;
1919     }
1920     const auto posFormat = GetFormatSpec(targetPositions.format);
1921     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1922         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1923         return;
1924     }
1925     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1926         posElementSize > targetPositions.stride) {
1927         return;
1928     }
1929 
1930     if (targetNormals.stride > (targetNormals.buffer.size() / submesh.info.vertexCount)) {
1931         return;
1932     }
1933     const auto norFormat = GetFormatSpec(targetNormals.format);
1934     if (norFormat.format == BASE_FORMAT_UNDEFINED) {
1935         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1936         return;
1937     }
1938     if (const auto norElementSize = norFormat.componentCount * norFormat.componentByteSize;
1939         norElementSize > targetNormals.stride) {
1940         return;
1941     }
1942 
1943     if (targetTangents.stride > (targetTangents.buffer.size() / submesh.info.vertexCount)) {
1944         return;
1945     }
1946     const auto tanFormat = GetFormatSpec(targetTangents.format);
1947     if (tanFormat.format == BASE_FORMAT_UNDEFINED) {
1948         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1949         return;
1950     }
1951     if (const auto tanElementSize = tanFormat.componentCount * tanFormat.componentByteSize;
1952         tanElementSize > targetTangents.stride) {
1953         return;
1954     }
1955 
1956     // Target data starts after base
1957     uint32_t targetOffset = baseOffset + targetSize;
1958 
1959     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1960     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT && norFormat.format == BASE_FORMAT_R32G32B32_SFLOAT &&
1961         tanFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1962         // special case which matches glTF 2.0. morph targets are three float components.
1963         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1964             submesh.morphTargets[trg].offset = targetOffset;
1965             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1966             auto target = startTarget;
1967             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1968                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1969                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1970                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1971                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1972                 auto nor = *reinterpret_cast<const Math::Vec3*>(
1973                     targetNormals.buffer.data() + targetNormals.stride * vertexIndex);
1974                 auto tan = *reinterpret_cast<const Math::Vec3*>(
1975                     targetTangents.buffer.data() + targetTangents.stride * vertexIndex);
1976                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {} && tan == Math::Vec3 {});
1977                 // store offset for each non-zero
1978                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1979                 if (zeroDelta) {
1980                     continue;
1981                 }
1982                 targetOffset += sizeof(MorphInputData);
1983                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1984 
1985 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1986                 target->nortan.x = Math::PackHalf2X16({ nor.x, nor.y });
1987                 target->nortan.y = Math::PackHalf2X16({ nor.z, 0.f });
1988                 target->nortan.z = Math::PackHalf2X16({ tan.x, tan.y });
1989                 target->nortan.w = Math::PackHalf2X16({ tan.z, 0.f });
1990 #else
1991                 target->nor = Math::Vec4(nor, 0.f);
1992                 target->tan = Math::Vec4(tan, 0.f);
1993 #endif
1994                 ++target;
1995             }
1996             // Store the size of the gathered deltas.
1997             const auto byteSize =
1998                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1999             submesh.morphTargets[trg].byteSize = byteSize;
2000         }
2001     } else {
2002         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
2003             submesh.morphTargets[trg].offset = targetOffset;
2004             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
2005             auto target = startTarget;
2006             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
2007                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
2008                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
2009                 Math::Vec3 pos;
2010                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
2011                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
2012                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
2013                 }
2014                 Math::Vec3 nor;
2015                 ptr = targetNormals.buffer.data() + targetNormals.stride * vertexIndex;
2016                 for (auto i = 0U; i < Math::min(countof(nor.data), norFormat.componentCount); ++i) {
2017                     nor[i] = norFormat.toIntermediate(ptr + i * norFormat.componentByteSize);
2018                 }
2019                 Math::Vec3 tan;
2020                 ptr = targetTangents.buffer.data() + targetTangents.stride * vertexIndex;
2021                 for (auto i = 0U; i < Math::min(countof(tan.data), tanFormat.componentCount); ++i) {
2022                     tan[i] = tanFormat.toIntermediate(ptr + i * tanFormat.componentByteSize);
2023                 }
2024                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {} && tan == Math::Vec3 {});
2025                 // store offset for each non-zero
2026                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
2027                 if (zeroDelta) {
2028                     continue;
2029                 }
2030                 targetOffset += sizeof(MorphInputData);
2031 
2032                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
2033 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
2034                 target->nortan.x = Math::PackHalf2X16({ nor.data[R], nor.data[G] });
2035                 target->nortan.y = Math::PackHalf2X16({ nor.data[B], 0.f });
2036                 target->nortan.z = Math::PackHalf2X16({ tan.data[R], tan.data[G] });
2037                 target->nortan.w = Math::PackHalf2X16({ tan.data[B], 0.f });
2038 #else
2039                 target->nor = Math::Vec4(nor.data[R], nor.data[G], nor.data[B], 0.f);
2040                 target->tan = Math::Vec4(tan.data[R], tan.data[G], tan.data[B], 0.f);
2041 #endif
2042                 ++target;
2043             }
2044             // Store the size of the gathered deltas.
2045             const auto byteSize =
2046                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
2047             submesh.morphTargets[trg].byteSize = byteSize;
2048         }
2049     }
2050 }
2051 
CalculateJointBounds( const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& positionData)2052 void MeshBuilder::CalculateJointBounds(
2053     const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& positionData)
2054 {
2055     // Calculate joint bounds as the bounds of the vertices that the joint references.
2056 
2057     const auto jointFormat = GetFormatSpec(jointData.format);
2058     if (jointFormat.format == BASE_FORMAT_UNDEFINED) {
2059         return;
2060     }
2061     if (const auto jointElementSize = jointFormat.componentCount * jointFormat.componentByteSize;
2062         jointElementSize > jointData.stride) {
2063         return;
2064     }
2065 
2066     const auto weightFormat = GetFormatSpec(weightData.format);
2067     if (weightFormat.format == BASE_FORMAT_UNDEFINED) {
2068         return;
2069     }
2070     if (const auto weightElementSize = weightFormat.componentCount * weightFormat.componentByteSize;
2071         weightElementSize > weightData.stride) {
2072         return;
2073     }
2074 
2075     const auto positionFormat = GetFormatSpec(positionData.format);
2076     if (positionFormat.format == BASE_FORMAT_UNDEFINED) {
2077         return;
2078     }
2079     if (const auto positionElementSize = positionFormat.componentCount * positionFormat.componentByteSize;
2080         positionElementSize > positionData.stride) {
2081         return;
2082     }
2083 
2084     const auto* weights = weightData.buffer.data();
2085     const auto* joints = jointData.buffer.data();
2086 
2087     const size_t jointIndexCount = jointData.buffer.size() / jointData.stride;
2088 
2089     // Find the amount of referenced joints
2090     size_t maxJointIndex = 0;
2091     for (size_t i = 0; i < jointIndexCount; ++i) {
2092         float fWeights[4U];
2093         for (auto j = 0U; j < weightFormat.componentCount; ++j) {
2094             fWeights[j] = weightFormat.toIntermediate(weights + j * weightFormat.componentByteSize);
2095         }
2096         weights += weightData.stride;
2097         for (size_t w = 0; w < countof(fWeights); ++w) {
2098             // Ignore joints with weight that is effectively 0.0
2099             if (fWeights[w] >= Math::EPSILON) {
2100                 const uint8_t jointIndex = joints[jointFormat.componentByteSize * w];
2101 
2102                 if (jointIndex > maxJointIndex) {
2103                     maxJointIndex = jointIndex;
2104                 }
2105             }
2106         }
2107         joints += jointData.stride;
2108     }
2109 
2110     // Make sure bounds data is big enough. Initialize new bounds to min and max values.
2111     const size_t oldSize = jointBoundsData_.size();
2112     const size_t newSize = (maxJointIndex + 1);
2113     if (newSize > 0 && newSize > oldSize) {
2114         constexpr float floatMin = std::numeric_limits<float>::lowest();
2115         constexpr float floatMax = std::numeric_limits<float>::max();
2116 
2117         constexpr const Bounds minMax = { { floatMax, floatMax, floatMax }, { floatMin, floatMin, floatMin } };
2118         jointBoundsData_.resize(newSize, minMax);
2119     }
2120 
2121     weights = weightData.buffer.data();
2122     joints = jointData.buffer.data();
2123     const auto* positions = positionData.buffer.data();
2124     for (auto i = 0U; i < jointIndexCount; ++i) {
2125         // Each vertex can reference 4 joint indices.
2126         Math::Vec3 pos;
2127         auto ptr = positions + i * positionData.stride;
2128         for (auto j = 0U; j < positionFormat.componentCount; ++j) {
2129             pos[j] = positionFormat.toIntermediate(ptr + j * positionFormat.componentByteSize);
2130         }
2131 
2132         float fWeights[4U];
2133         for (auto j = 0U; j < weightFormat.componentCount; ++j) {
2134             fWeights[j] = weightFormat.toIntermediate(weights + j * weightFormat.componentByteSize);
2135         }
2136         weights += weightData.stride;
2137         for (size_t w = 0; w < countof(fWeights); ++w) {
2138             if (fWeights[w] < Math::EPSILON) {
2139                 // Ignore joints with weight that is effectively 0.0
2140                 continue;
2141             }
2142 
2143             auto& boundsData = jointBoundsData_[joints[w]];
2144             boundsData.min = Math::min(boundsData.min, pos);
2145             boundsData.max = Math::max(boundsData.max, pos);
2146         }
2147         joints += jointData.stride;
2148     }
2149 }
2150 
WriteData(const DataBuffer& srcData, const SubmeshExt& submesh, uint32_t attributeLocation, uint32_t& byteOffset, uint32_t& byteSize, uint8_t* dst) const2151 bool MeshBuilder::WriteData(const DataBuffer& srcData, const SubmeshExt& submesh, uint32_t attributeLocation,
2152     uint32_t& byteOffset, uint32_t& byteSize, uint8_t* dst) const
2153 {
2154     if (const VertexInputDeclaration::VertexInputAttributeDescription* attributeDesc =
2155             GetVertexAttributeDescription(attributeLocation, vertexInputDeclaration_.attributeDescriptions);
2156         attributeDesc) {
2157         if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc =
2158                 GetVertexBindingeDescription(attributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
2159             bindingDesc) {
2160             // this offset and size should be aligned
2161             byteOffset = submesh.vertexBindingOffset[bindingDesc->binding] + attributeDesc->offset;
2162             byteSize = submesh.info.vertexCount * bindingDesc->stride;
2163             OutputBuffer dstData { attributeDesc->format, bindingDesc->stride, { dst + byteOffset, byteSize } };
2164             Fill(dstData, srcData, submesh.info.vertexCount);
2165             return true;
2166         }
2167     }
2168     return false;
2169 }
2170 CORE3D_END_NAMESPACE()
2171