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 
Align(size_t value,size_t align)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 
GetVertexAttributeDescription(uint32_t location,const array_view<const VertexInputDeclaration::VertexInputAttributeDescription> & attributeDescriptions)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 
GetVertexBindingeDescription(uint32_t bindingIndex,const array_view<const VertexInputDeclaration::VertexInputBindingDescription> & bindingDescriptions)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>
GatherMin(T (& minimum)[N],const T (& value)[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>
GatherMax(T (& minimum)[N],const T (& value)[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>>>
Snorm(float v)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>>>
Snorm(T v)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>>>
Unorm(float v)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>>>
Unorm(T v)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>>>
Sint(float v)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>>>
Sint(T v)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>>>
Uint(float v)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>>>
Uint(T v)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 
convert__anon0e41d9790210::IntegerNorm223     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();
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 
convert__anon0e41d9790210::IntegerToInt241     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 
To__anon0e41d9790210::Norm265     static T To(float f) noexcept
266     {
267         if constexpr (is_signed_v<T>) {
268             return Snorm<T>(f);
269         } else {
270             return Unorm<T>(f);
271         }
272     }
273 
From__anon0e41d9790210::Norm274     static float From(T v) noexcept
275     {
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__anon0e41d9790210::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__anon0e41d9790210::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__anon0e41d9790210::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__anon0e41d9790210::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>
From(const uint8_t * src)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>
To(uint8_t * dst,float f)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 = static_cast<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) * static_cast<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 = static_cast<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_ = static_cast<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 = static_cast<uint32_t>(Align(bufferSizes.indexBuffer, BUFFER_ALIGN));
1064         submesh.jointBufferOffset = static_cast<uint32_t>(Align(bufferSizes.jointBuffer, BUFFER_ALIGN));
1065         submesh.morphTargetBufferOffset = static_cast<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 = static_cast<uint32_t>(Align(
1087                 submesh.info.vertexCount * submesh.info.morphTargetCount * sizeof(uint32_t), BUFFER_ALIGN));
1088             const uint32_t targetSize =
1089                 static_cast<uint32_t>(Align(submesh.info.vertexCount *
1090                 sizeof(MorphInputData) * (submesh.info.morphTargetCount + 1u), BUFFER_ALIGN));
1091             bufferSizes.morphVertexData = submesh.morphTargetBufferOffset + indexSize + targetSize;
1092         }
1093 
1094         vertexCount_ += submesh.info.vertexCount;
1095     }
1096     return bufferSizes;
1097 }
1098 
SetVertexData(size_t submeshIndex,const DataBuffer & positions,const DataBuffer & normals,const DataBuffer & texcoords0,const DataBuffer & texcoords1,const DataBuffer & tangents,const DataBuffer & colors)1099 void MeshBuilder::SetVertexData(size_t submeshIndex, const DataBuffer& positions, const DataBuffer& normals,
1100     const DataBuffer& texcoords0, const DataBuffer& texcoords1, const DataBuffer& tangents, const DataBuffer& colors)
1101 {
1102     if (auto buffer = stagingPtr_; buffer) {
1103         // *Vertex data* | index data | joint data | morph data
1104         SubmeshExt& submesh = submeshInfos_[submeshIndex];
1105 
1106         // Submesh info for this submesh.
1107         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1108 
1109         submeshDesc.material = submesh.info.material;
1110         submeshDesc.vertexCount = submesh.info.vertexCount;
1111         submeshDesc.instanceCount = submesh.info.instanceCount;
1112 
1113         // If we need to generate tangents we need float copies of position, normal and uv0
1114         const bool generateTangents = submesh.info.tangents && tangents.buffer.empty();
1115 
1116         // Process position.
1117         {
1118             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_POS];
1119             WriteData(positions, submesh, MeshComponent::Submesh::DM_VB_POS, acc.offset, acc.byteSize, buffer);
1120             if (normals.buffer.empty() || generateTangents) {
1121                 auto offset = vertexData_.size();
1122                 vertexData_.resize(offset + sizeof(Math::Vec3) * submeshDesc.vertexCount);
1123                 OutputBuffer dst { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1124                     { vertexData_.data() + offset, sizeof(Math::Vec3) * submeshDesc.vertexCount } };
1125                 Fill(dst, positions, submeshDesc.vertexCount);
1126                 submesh.positionOffset = static_cast<int32_t>(offset);
1127                 submesh.positionSize = sizeof(Math::Vec3) * submeshDesc.vertexCount;
1128             }
1129         }
1130 
1131         // Process normal.
1132         if (!normals.buffer.empty()) {
1133             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_NOR];
1134             WriteData(normals, submesh, MeshComponent::Submesh::DM_VB_NOR, acc.offset, acc.byteSize, buffer);
1135             submesh.hasNormals = true;
1136             if (generateTangents) {
1137                 auto offset = vertexData_.size();
1138                 vertexData_.resize(offset + sizeof(Math::Vec3) * submeshDesc.vertexCount);
1139                 OutputBuffer dst { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1140                     { vertexData_.data() + offset, sizeof(Math::Vec3) * submeshDesc.vertexCount } };
1141                 Fill(dst, normals, submeshDesc.vertexCount);
1142                 submesh.normalOffset = static_cast<int32_t>(offset);
1143                 submesh.normalSize = sizeof(Math::Vec3) * submeshDesc.vertexCount;
1144             }
1145         }
1146 
1147         // Process uv.
1148         if (!texcoords0.buffer.empty()) {
1149             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1150             WriteData(texcoords0, submesh, MeshComponent::Submesh::DM_VB_UV0, acc.offset, acc.byteSize, buffer);
1151             submesh.hasUv0 = true;
1152             if (generateTangents) {
1153                 auto offset = vertexData_.size();
1154                 vertexData_.resize(offset + sizeof(Math::Vec2) * submeshDesc.vertexCount);
1155                 OutputBuffer dst { BASE_FORMAT_R32G32_SFLOAT, sizeof(Math::Vec2),
1156                     { vertexData_.data() + offset, sizeof(Math::Vec2) * submeshDesc.vertexCount } };
1157                 Fill(dst, texcoords0, submeshDesc.vertexCount);
1158                 submesh.uvOffset = static_cast<int32_t>(offset);
1159                 submesh.uvSize = sizeof(Math::Vec2) * submeshDesc.vertexCount;
1160             }
1161         }
1162 
1163         if (!texcoords1.buffer.empty()) {
1164             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV1];
1165             if (WriteData(texcoords1, submesh, MeshComponent::Submesh::DM_VB_UV1, acc.offset, acc.byteSize, buffer)) {
1166                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::SECOND_TEXCOORD_BIT;
1167             }
1168         } else {
1169             const auto& uv0 = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1170             auto& uv1 = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV1];
1171             uv1 = uv0;
1172         }
1173 
1174         // Process tangent.
1175         if (!tangents.buffer.empty() && submesh.info.tangents) {
1176             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_TAN];
1177             if (WriteData(tangents, submesh, MeshComponent::Submesh::DM_VB_TAN, acc.offset, acc.byteSize, buffer)) {
1178                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::TANGENTS_BIT;
1179                 submesh.hasTangents = true;
1180             }
1181         }
1182 
1183         // Process vertex colors.
1184         if (!colors.buffer.empty() && submesh.info.colors) {
1185             auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_COL];
1186             if (WriteData(colors, submesh, MeshComponent::Submesh::DM_VB_COL, acc.offset, acc.byteSize, buffer)) {
1187                 submeshDesc.flags |= MeshComponent::Submesh::FlagBits::VERTEX_COLORS_BIT;
1188             }
1189         }
1190     }
1191 }
1192 
SetIndexData(size_t submeshIndex,const DataBuffer & indices)1193 void MeshBuilder::SetIndexData(size_t submeshIndex, const DataBuffer& indices)
1194 {
1195     if (auto buffer = stagingPtr_; buffer) {
1196         // Vertex data | *index data* | joint data | morph data
1197         buffer += vertexDataSize_;
1198         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1199         SubmeshExt& submesh = submeshInfos_[submeshIndex];
1200 
1201         OutputBuffer output { (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16) ? BASE_FORMAT_R16_UINT
1202                                                                                             : BASE_FORMAT_R32_UINT,
1203             static_cast<uint32_t>(
1204                 (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16) ? sizeof(uint16_t) : sizeof(uint32_t)),
1205             {} };
1206         // If we need to generate normals or tangents we need CPU copies of the indices
1207         if (!submesh.hasNormals || (submesh.info.tangents && !submesh.hasTangents)) {
1208             // First convert and write to a plain vector
1209             auto offset = indexData_.size();
1210             indexData_.resize(offset + output.stride * submesh.info.indexCount);
1211             output.buffer = { indexData_.data() + offset, output.stride * submesh.info.indexCount };
1212             Fill(output, indices, submesh.info.indexCount);
1213             submesh.indexOffset = static_cast<int32_t>(offset);
1214             submesh.indexSize = output.stride * submesh.info.indexCount;
1215             // Then copy the data to staging buffer.
1216             std::copy(indexData_.data() + offset, indexData_.data() + offset + output.stride * submesh.info.indexCount,
1217                 buffer + submesh.indexBufferOffset);
1218         } else {
1219             // Convert directly to the staging buffer.
1220             output.buffer = { buffer + submesh.indexBufferOffset, output.stride * submesh.info.indexCount };
1221             Fill(output, indices, submesh.info.indexCount);
1222         }
1223 
1224         submeshDesc.indexCount = submesh.info.indexCount;
1225         submeshDesc.indexBuffer.indexType = submesh.info.indexType;
1226         submeshDesc.indexBuffer.offset = submesh.indexBufferOffset;
1227         submeshDesc.indexBuffer.byteSize = static_cast<uint32_t>(output.buffer.size());
1228     }
1229 }
1230 
SetJointData(size_t submeshIndex,const DataBuffer & jointData,const DataBuffer & weightData,const DataBuffer & vertexPositions)1231 void MeshBuilder::SetJointData(
1232     size_t submeshIndex, const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& vertexPositions)
1233 {
1234     if (auto buffer = stagingPtr_; buffer) {
1235         // Vertex data | index data | *joint data* | morph data
1236         buffer += vertexDataSize_ + indexDataSize_;
1237         MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1238         const SubmeshExt& submesh = submeshInfos_[submeshIndex];
1239         if (const auto* indexAttributeDesc = GetVertexAttributeDescription(
1240                 MeshComponent::Submesh::DM_VB_JOI, vertexInputDeclaration_.attributeDescriptions);
1241             indexAttributeDesc) {
1242             if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc = GetVertexBindingeDescription(
1243                     indexAttributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
1244                 bindingDesc) {
1245                 auto& jointIndexAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOI];
1246                 jointIndexAcc.offset = static_cast<uint32_t>(Align(submesh.jointBufferOffset, BUFFER_ALIGN));
1247                 jointIndexAcc.byteSize = static_cast<uint32_t>(bindingDesc->stride) * submesh.info.vertexCount;
1248 
1249                 OutputBuffer dstData { indexAttributeDesc->format, bindingDesc->stride,
1250                     { buffer + jointIndexAcc.offset, jointIndexAcc.byteSize } };
1251                 Fill(dstData, jointData, submesh.info.vertexCount);
1252             }
1253         }
1254         if (const auto* weightAttributeDesc = GetVertexAttributeDescription(
1255                 MeshComponent::Submesh::DM_VB_JOW, vertexInputDeclaration_.attributeDescriptions);
1256             weightAttributeDesc) {
1257             if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc = GetVertexBindingeDescription(
1258                     weightAttributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
1259                 bindingDesc) {
1260                 auto& jointIndexAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOI];
1261                 // Process joint weights.
1262                 auto& jointWeightAcc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_JOW];
1263                 // index aligned offset + index bytesize -> aligned to offset
1264                 jointWeightAcc.offset =
1265                     static_cast<uint32_t>(Align(jointIndexAcc.offset + jointIndexAcc.byteSize, BUFFER_ALIGN));
1266                 jointWeightAcc.byteSize = static_cast<uint32_t>(bindingDesc->stride) * submesh.info.vertexCount;
1267 
1268                 OutputBuffer dstData { weightAttributeDesc->format, bindingDesc->stride,
1269                     { buffer + jointWeightAcc.offset, jointWeightAcc.byteSize } };
1270                 Fill(dstData, weightData, submesh.info.vertexCount);
1271             }
1272         }
1273         submeshDesc.flags |= MeshComponent::Submesh::FlagBits::SKIN_BIT;
1274         CalculateJointBounds(jointData, weightData, vertexPositions);
1275     }
1276 }
1277 
SetMorphTargetData(size_t submeshIndex,const DataBuffer & basePositions,const DataBuffer & baseNormals,const DataBuffer & baseTangents,const DataBuffer & targetPositions,const DataBuffer & targetNormals,const DataBuffer & targetTangents)1278 void MeshBuilder::SetMorphTargetData(size_t submeshIndex, const DataBuffer& basePositions,
1279     const DataBuffer& baseNormals, const DataBuffer& baseTangents, const DataBuffer& targetPositions,
1280     const DataBuffer& targetNormals, const DataBuffer& targetTangents)
1281 {
1282     // Submesh info for this submesh.
1283     SubmeshExt& submesh = submeshInfos_[submeshIndex];
1284     if (submesh.info.morphTargetCount > 0) {
1285         if (auto buffer = stagingPtr_; buffer) {
1286             // Vertex data | index data | joint data | *morph data*
1287             buffer += vertexDataSize_ + indexDataSize_ + jointDataSize_;
1288 
1289             // Offset to morph index data is previous offset + size (or zero for the first submesh)
1290             uint32_t indexOffset = 0u;
1291             if (submeshIndex) {
1292                 indexOffset = static_cast<uint32_t>(Align(submeshInfos_[submeshIndex - 1u].morphTargetBufferOffset +
1293                                                               submeshInfos_[submeshIndex - 1u].morphTargetBufferSize,
1294                     BUFFER_ALIGN));
1295             }
1296             submesh.morphTargetBufferOffset = indexOffset;
1297 
1298             // 32bit index/offset for each vertex in each morph target
1299             const uint32_t indexSize = sizeof(uint32_t) * submesh.info.vertexCount;
1300             const uint32_t totalIndexSize =
1301                 static_cast<uint32_t>(Align(indexSize * submesh.info.morphTargetCount, BUFFER_ALIGN));
1302 
1303             // Data struct (pos, nor, tan) for each vertex. total amount is target size for each target data and one
1304             // base data
1305             const uint32_t targetSize = submesh.info.vertexCount * sizeof(MorphInputData);
1306 
1307             // Base data starts after index data
1308             const uint32_t baseOffset = indexOffset + totalIndexSize;
1309             {
1310                 OutputBuffer dstData { POSITION_FORMAT, sizeof(MorphInputData), { buffer + baseOffset, targetSize } };
1311                 Fill(dstData, basePositions, submesh.info.vertexCount);
1312             }
1313 
1314             if (!baseNormals.buffer.empty()) {
1315 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1316                 OutputBuffer dstData { NORMAL_FORMAT, sizeof(MorphInputData),
1317                     { buffer + baseOffset + offsetof(MorphInputData, nortan), targetSize } };
1318 #else
1319                 OutputBuffer dstData { NORMAL_FORMAT, sizeof(MorphInputData),
1320                     { buffer + baseOffset + offsetof(MorphInputData, nor), targetSize } };
1321 #endif
1322                 Fill(dstData, baseNormals, submesh.info.vertexCount);
1323             }
1324             if (!baseTangents.buffer.empty()) {
1325 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1326                 OutputBuffer dstData { TANGENT_FORMAT, sizeof(MorphInputData),
1327                     { buffer + baseOffset + offsetof(MorphInputData, nortan) + 8U, targetSize } };
1328 #else
1329                 OutputBuffer dstData { TANGENT_FORMAT, sizeof(MorphInputData),
1330                     { buffer + baseOffset + offsetof(MorphInputData, tan), targetSize } };
1331 #endif
1332                 Fill(dstData, baseTangents, submesh.info.vertexCount);
1333             }
1334             // Gather non-zero deltas.
1335             if (targetNormals.buffer.empty() && targetTangents.buffer.empty()) {
1336                 GatherDeltasP(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions);
1337             } else if (!targetNormals.buffer.empty() && targetTangents.buffer.empty()) {
1338                 GatherDeltasPN(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetNormals);
1339             } else if (targetNormals.buffer.empty() && !targetTangents.buffer.empty()) {
1340                 GatherDeltasPT(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetTangents);
1341             } else {
1342                 GatherDeltasPNT(submesh, buffer, baseOffset, indexOffset, targetSize, targetPositions, targetNormals,
1343                     targetTangents);
1344             }
1345 
1346             // Actual buffer size based on the offset and size of the last morph target.
1347             submesh.morphTargetBufferSize = submesh.morphTargets[submesh.info.morphTargetCount - 1].offset -
1348                                             indexOffset +
1349                                             submesh.morphTargets[submesh.info.morphTargetCount - 1].byteSize;
1350 
1351             // Clamp to actual size which might be less than what was asked for before gathering the non-zero deltas.
1352             targetDataSize_ = static_cast<size_t>(submesh.morphTargetBufferOffset + submesh.morphTargetBufferSize);
1353 
1354             MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1355             submeshDesc.morphTargetBuffer.offset = submesh.morphTargetBufferOffset;
1356             submeshDesc.morphTargetBuffer.byteSize = submesh.morphTargetBufferSize;
1357             submeshDesc.morphTargetCount = static_cast<uint32_t>(submesh.morphTargets.size());
1358         }
1359     }
1360 }
1361 
SetAABB(size_t submeshIndex,const Math::Vec3 & min,const Math::Vec3 & max)1362 void MeshBuilder::SetAABB(size_t submeshIndex, const Math::Vec3& min, const Math::Vec3& max)
1363 {
1364     MeshComponent::Submesh& submeshDesc = submeshes_[submeshIndex];
1365     submeshDesc.aabbMin = min;
1366     submeshDesc.aabbMax = max;
1367 }
1368 
CalculateAABB(size_t submeshIndex,const DataBuffer & positions)1369 void MeshBuilder::CalculateAABB(size_t submeshIndex, const DataBuffer& positions)
1370 {
1371     const auto posFormat = GetFormatSpec(positions.format);
1372     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1373         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1374         return;
1375     }
1376     const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1377     if (posElementSize > positions.stride) {
1378         return;
1379     }
1380     auto count = positions.buffer.size() / positions.stride;
1381 
1382     constexpr float maxLimits = std::numeric_limits<float>::max();
1383     constexpr float minLimits = -std::numeric_limits<float>::max();
1384 
1385     Math::Vec3 finalMinimum = { maxLimits, maxLimits, maxLimits };
1386     Math::Vec3 finalMaximum = { minLimits, minLimits, minLimits };
1387 
1388     auto srcPtr = positions.buffer.data();
1389     switch (posFormat.format) {
1390         case BASE_FORMAT_R16G16_UNORM: {
1391             uint16_t minimum[RG] { std::numeric_limits<uint16_t>::max() };
1392             uint16_t maximum[RG] { std::numeric_limits<uint16_t>::lowest() };
1393             while (count--) {
1394                 uint16_t value[RG] = { reinterpret_cast<const uint16_t*>(srcPtr)[R],
1395                     reinterpret_cast<const uint16_t*>(srcPtr)[G] };
1396                 srcPtr += positions.stride;
1397                 GatherMin(minimum, value);
1398                 GatherMax(maximum, value);
1399             }
1400             for (auto i = 0U; i < RG; ++i) {
1401                 finalMinimum[i] = Norm<uint16_t>::From(minimum[i]);
1402             }
1403             finalMinimum[B] = 0.f;
1404             for (auto i = 0U; i < RG; ++i) {
1405                 finalMaximum[i] = Norm<uint16_t>::From(maximum[i]);
1406             }
1407             finalMaximum[B] = 0.f;
1408         } break;
1409 
1410         case BASE_FORMAT_R8G8B8_SNORM: {
1411             int8_t minimum[RGB] { std::numeric_limits<int8_t>::max() };
1412             int8_t maximum[RGB] { std::numeric_limits<int8_t>::lowest() };
1413             while (count--) {
1414                 int8_t value[RGB] = { reinterpret_cast<const int8_t*>(srcPtr)[R],
1415                     reinterpret_cast<const int8_t*>(srcPtr)[G], reinterpret_cast<const int8_t*>(srcPtr)[B] };
1416                 srcPtr += positions.stride;
1417                 GatherMin(minimum, value);
1418                 GatherMax(maximum, value);
1419             }
1420             for (auto i = 0U; i < RGB; ++i) {
1421                 finalMinimum[i] = Norm<int8_t>::From(minimum[i]);
1422             }
1423             for (auto i = 0U; i < RGB; ++i) {
1424                 finalMaximum[i] = Norm<int8_t>::From(maximum[i]);
1425             }
1426         } break;
1427 
1428         case BASE_FORMAT_R16G16B16_UINT:
1429         case BASE_FORMAT_R16G16B16A16_UINT: {
1430             uint16_t minimum[RGB] { std::numeric_limits<uint16_t>::max() };
1431             uint16_t maximum[RGB] { std::numeric_limits<uint16_t>::lowest() };
1432             while (count--) {
1433                 uint16_t value[RGB] = { reinterpret_cast<const uint16_t*>(srcPtr)[R],
1434                     reinterpret_cast<const uint16_t*>(srcPtr)[G], reinterpret_cast<const uint16_t*>(srcPtr)[B] };
1435                 srcPtr += positions.stride;
1436                 GatherMin(minimum, value);
1437                 GatherMax(maximum, value);
1438             }
1439             for (auto i = 0U; i < RGB; ++i) {
1440                 finalMinimum[i] = Int<uint16_t>::From(minimum[i]);
1441             }
1442             for (auto i = 0U; i < RGB; ++i) {
1443                 finalMaximum[i] = Int<uint16_t>::From(maximum[i]);
1444             }
1445         } break;
1446 
1447         case BASE_FORMAT_R32G32_SFLOAT: {
1448             while (count--) {
1449                 float value[RG] = { reinterpret_cast<const float*>(srcPtr)[R],
1450                     reinterpret_cast<const float*>(srcPtr)[G] };
1451                 srcPtr += positions.stride;
1452                 GatherMin(finalMinimum.data, value);
1453                 GatherMax(finalMaximum.data, value);
1454             }
1455         } break;
1456 
1457         case BASE_FORMAT_R32G32B32_SFLOAT:
1458         case BASE_FORMAT_R32G32B32A32_SFLOAT: {
1459             while (count--) {
1460                 float value[RGB] = { reinterpret_cast<const float*>(srcPtr)[R],
1461                     reinterpret_cast<const float*>(srcPtr)[G], reinterpret_cast<const float*>(srcPtr)[B] };
1462                 srcPtr += positions.stride;
1463                 GatherMin(finalMinimum.data, value);
1464                 GatherMax(finalMaximum.data, value);
1465             }
1466         } break;
1467 
1468         default:
1469             CORE_LOG_W("CalculateAABB: position format %u not handled.", posFormat.format);
1470             break;
1471     }
1472     SetAABB(submeshIndex, finalMinimum, finalMaximum);
1473 }
1474 
GetVertexData() const1475 array_view<const uint8_t> MeshBuilder::GetVertexData() const
1476 {
1477     return array_view<const uint8_t>(stagingPtr_, vertexDataSize_);
1478 }
1479 
GetIndexData() const1480 array_view<const uint8_t> MeshBuilder::GetIndexData() const
1481 {
1482     return array_view<const uint8_t>(stagingPtr_ ? (stagingPtr_ + vertexDataSize_) : nullptr, indexDataSize_);
1483 }
1484 
GetJointData() const1485 array_view<const uint8_t> MeshBuilder::GetJointData() const
1486 {
1487     return array_view<const uint8_t>(
1488         stagingPtr_ ? (stagingPtr_ + vertexDataSize_ + indexDataSize_) : nullptr, jointDataSize_);
1489 }
1490 
GetMorphTargetData() const1491 array_view<const uint8_t> MeshBuilder::GetMorphTargetData() const
1492 {
1493     return array_view<const uint8_t>(
1494         stagingPtr_ ? (stagingPtr_ + vertexDataSize_ + indexDataSize_ + jointDataSize_) : nullptr, targetDataSize_);
1495 }
1496 
GetJointBoundsData() const1497 array_view<const float> MeshBuilder::GetJointBoundsData() const
1498 {
1499     return array_view(reinterpret_cast<const float*>(jointBoundsData_.data()),
1500         jointBoundsData_.size() * SIZE_OF_VALUE_TYPE_V<decltype(jointBoundsData_)> / sizeof(float));
1501 }
1502 
GetSubmeshes() const1503 array_view<const MeshComponent::Submesh> MeshBuilder::GetSubmeshes() const
1504 {
1505     return array_view<const MeshComponent::Submesh>(submeshes_);
1506 }
1507 
GetVertexCount() const1508 uint32_t MeshBuilder::GetVertexCount() const
1509 {
1510     return vertexCount_;
1511 }
1512 
GetIndexCount() const1513 uint32_t MeshBuilder::GetIndexCount() const
1514 {
1515     return indexCount_;
1516 }
1517 
CreateGpuResources(const GpuBufferCreateInfo & createInfo)1518 void MeshBuilder::CreateGpuResources(const GpuBufferCreateInfo& createInfo)
1519 {
1520     GenerateMissingAttributes();
1521 
1522     bufferHandles_ = CreateGpuBuffers(
1523         renderContext_, vertexDataSize_, indexDataSize_, indexCount_, jointDataSize_, targetDataSize_, createInfo);
1524 
1525     StageToBuffers(renderContext_, vertexDataSize_, indexDataSize_, jointDataSize_, targetDataSize_, bufferHandles_,
1526         stagingBuffer_);
1527 }
1528 
CreateGpuResources()1529 void MeshBuilder::CreateGpuResources()
1530 {
1531     CreateGpuResources({});
1532 }
1533 
CreateMesh(IEcs & ecs) const1534 Entity MeshBuilder::CreateMesh(IEcs& ecs) const
1535 {
1536     if (!vertexDataSize_) {
1537         return {};
1538     }
1539 
1540     auto meshManager = GetManager<IMeshComponentManager>(ecs);
1541     if (!meshManager) {
1542         return {};
1543     }
1544 
1545     auto& em = ecs.GetEntityManager();
1546     auto meshEntity = em.Create();
1547     meshManager->Create(meshEntity);
1548     if (auto meshHandle = meshManager->Write(meshEntity); meshHandle) {
1549         MeshComponent& mesh = *meshHandle;
1550 
1551         // Copy skin joint bounding boxes.
1552         const size_t jointBoundsDataSize = jointBoundsData_.size();
1553         if (jointBoundsDataSize != 0) {
1554             mesh.jointBounds.reserve(jointBoundsDataSize * JOINT_BOUNDS_COMPONENTS);
1555             for (const auto& bounds : jointBoundsData_) {
1556                 for (const auto& f : bounds.min.data) {
1557                     mesh.jointBounds.push_back(f);
1558                 }
1559                 for (const auto& f : bounds.max.data) {
1560                     mesh.jointBounds.push_back(f);
1561                 }
1562             }
1563         }
1564 
1565         // Copy submeshes for this mesh.
1566         mesh.submeshes.insert(mesh.submeshes.end(), submeshes_.begin(), submeshes_.end());
1567 
1568         // Create buffers for whole mesh and assign them to submeshes.
1569         const auto bufferEntities = CreateBuffers(ecs);
1570         FillSubmeshBuffers(mesh.submeshes, bufferEntities);
1571 
1572         // AABB for mesh
1573         const auto minMax = CalculateAabb(submeshes_);
1574         mesh.aabbMin = minMax.minAABB;
1575         mesh.aabbMax = minMax.maxAABB;
1576     }
1577     return meshEntity;
1578 }
1579 
GetInterface(const Uid & uid) const1580 const IInterface* MeshBuilder::GetInterface(const Uid& uid) const
1581 {
1582     if ((uid == IMeshBuilder::UID) || (uid == IInterface::UID)) {
1583         return this;
1584     }
1585     return nullptr;
1586 }
1587 
GetInterface(const Uid & uid)1588 IInterface* MeshBuilder::GetInterface(const Uid& uid)
1589 {
1590     if ((uid == IMeshBuilder::UID) || (uid == IInterface::UID)) {
1591         return this;
1592     }
1593     return nullptr;
1594 }
1595 
Ref()1596 void MeshBuilder::Ref()
1597 {
1598     refCount_++;
1599 }
1600 
Unref()1601 void MeshBuilder::Unref()
1602 {
1603     if (--refCount_ == 0) {
1604         delete this;
1605     }
1606 }
1607 
1608 // Private methods
CreateBuffers(IEcs & ecs) const1609 MeshBuilder::BufferEntities MeshBuilder::CreateBuffers(IEcs& ecs) const
1610 {
1611     BufferEntities entities;
1612 
1613     BufferHandles handles;
1614     if (bufferHandles_.vertexBuffer) {
1615         handles = bufferHandles_;
1616     } else {
1617         GenerateMissingAttributes();
1618         handles = CreateGpuBuffers(
1619             renderContext_, vertexDataSize_, indexDataSize_, indexCount_, jointDataSize_, targetDataSize_, {});
1620         StageToBuffers(
1621             renderContext_, vertexDataSize_, indexDataSize_, jointDataSize_, targetDataSize_, handles, stagingBuffer_);
1622     }
1623 
1624     auto renderHandleManager = GetManager<IRenderHandleComponentManager>(ecs);
1625     if (!renderHandleManager) {
1626         return entities;
1627     }
1628 
1629     auto& em = ecs.GetEntityManager();
1630 
1631     // Create vertex buffer for this mesh.
1632     entities.vertexBuffer = CreateBuffer(em, *renderHandleManager, handles.vertexBuffer);
1633 
1634     // Create index buffer for this mesh.
1635     if (handles.indexBuffer) {
1636         entities.indexBuffer = CreateBuffer(em, *renderHandleManager, handles.indexBuffer);
1637     }
1638 
1639     if (handles.jointBuffer) {
1640         entities.jointBuffer = CreateBuffer(em, *renderHandleManager, handles.jointBuffer);
1641     }
1642 
1643     if (handles.morphBuffer) {
1644         entities.morphBuffer = CreateBuffer(em, *renderHandleManager, handles.morphBuffer);
1645     }
1646     return entities;
1647 }
1648 
GenerateMissingAttributes() const1649 void MeshBuilder::GenerateMissingAttributes() const
1650 {
1651     if (auto buffer = stagingPtr_; buffer) {
1652         auto submeshIt = submeshes_.begin();
1653         for (auto& submesh : submeshInfos_) {
1654             if (!vertexData_.empty() &&
1655                 (!submesh.hasNormals || !submesh.hasUv0 || (submesh.info.tangents && !submesh.hasTangents))) {
1656                 MeshComponent::Submesh& submeshDesc = *submeshIt;
1657                 const DataBuffer indexData { (submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16)
1658                                                  ? BASE_FORMAT_R16_UINT
1659                                                  : BASE_FORMAT_R32_UINT,
1660                     static_cast<uint32_t>((submesh.info.indexType == IndexType::CORE_INDEX_TYPE_UINT16)
1661                                               ? sizeof(uint16_t)
1662                                               : sizeof(uint32_t)),
1663                     { indexData_.data() + submesh.indexOffset, submesh.indexSize } };
1664 
1665                 // Reserve space for the to be generated normals and uvs
1666                 vertexData_.reserve(vertexData_.size() +
1667                                     (submesh.hasNormals ? 0 : submesh.info.vertexCount * sizeof(Math::Vec3)) +
1668                                     (submesh.hasUv0 ? 0 : submesh.info.vertexCount * sizeof(Math::Vec2)));
1669 
1670                 DataBuffer positionData { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1671                     { vertexData_.data() + submesh.positionOffset, submesh.positionSize } };
1672 
1673                 DataBuffer normalData { BASE_FORMAT_R32G32B32_SFLOAT, sizeof(Math::Vec3),
1674                     { vertexData_.data() + submesh.normalOffset, submesh.normalSize } };
1675 
1676                 if (!submesh.hasNormals) {
1677                     const auto offset = vertexData_.size();
1678                     GenerateDefaultNormals(vertexData_, indexData, positionData, submesh.info.vertexCount);
1679                     submesh.normalOffset = static_cast<int32_t>(offset);
1680                     submesh.normalSize = static_cast<uint32_t>(vertexData_.size() - offset);
1681                     normalData.buffer = { vertexData_.data() + submesh.normalOffset, submesh.normalSize };
1682 
1683                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_NOR];
1684                     WriteData(normalData, submesh, MeshComponent::Submesh::DM_VB_NOR, acc.offset, acc.byteSize, buffer);
1685                     submesh.hasNormals = true;
1686                 }
1687 
1688                 DataBuffer uvData { BASE_FORMAT_R32G32_SFLOAT, sizeof(Math::Vec2),
1689                     { vertexData_.data() + submesh.uvOffset, submesh.uvSize } };
1690                 if (!submesh.hasUv0) {
1691                     const auto offset = vertexData_.size();
1692                     GenerateDefaultUvs(vertexData_, submesh.info.vertexCount);
1693                     submesh.uvOffset = static_cast<int32_t>(offset);
1694                     submesh.uvSize = static_cast<uint32_t>(vertexData_.size() - offset);
1695                     uvData.buffer = { vertexData_.data() + submesh.uvOffset, submesh.uvSize };
1696 
1697                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_UV0];
1698                     WriteData(uvData, submesh, MeshComponent::Submesh::DM_VB_UV0, acc.offset, acc.byteSize, buffer);
1699                     submesh.hasUv0 = true;
1700                 }
1701 
1702                 if (submesh.info.tangents && !submesh.hasTangents) {
1703                     DataBuffer tangentData;
1704                     vector<uint8_t> generatedTangents;
1705                     GenerateDefaultTangents(tangentData, generatedTangents, indexData, positionData, normalData, uvData,
1706                         submesh.info.vertexCount);
1707 
1708                     auto& acc = submeshDesc.bufferAccess[MeshComponent::Submesh::DM_VB_TAN];
1709                     if (WriteData(tangentData, submesh, MeshComponent::Submesh::DM_VB_TAN, acc.offset, acc.byteSize,
1710                             buffer)) {
1711                         submeshDesc.flags |= MeshComponent::Submesh::FlagBits::TANGENTS_BIT;
1712                         submesh.hasTangents = true;
1713                     }
1714                 }
1715             }
1716             ++submeshIt;
1717         }
1718     }
1719 }
1720 
GatherDeltasP(SubmeshExt & submesh,uint8_t * dst,uint32_t baseOffset,uint32_t indexOffset,uint32_t targetSize,const MeshBuilder::DataBuffer & targetPositions)1721 void MeshBuilder::GatherDeltasP(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1722     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions)
1723 {
1724     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1725         return;
1726     }
1727     const auto posFormat = GetFormatSpec(targetPositions.format);
1728     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1729         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1730         return;
1731     }
1732     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1733         posElementSize > targetPositions.stride) {
1734         return;
1735     }
1736 
1737     // Target data starts after base
1738     uint32_t targetOffset = baseOffset + targetSize;
1739 
1740     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1741     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1742         // special case which matches glTF 2.0. morph targets are three float components.
1743         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1744             submesh.morphTargets[trg].offset = targetOffset;
1745             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1746             auto target = startTarget;
1747             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1748                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1749                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1750                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1751                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1752                 const auto zeroDelta = (pos == Math::Vec3 {});
1753                 // store offset for each non-zero
1754                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1755                 if (zeroDelta) {
1756                     continue;
1757                 }
1758                 targetOffset += sizeof(MorphInputData);
1759 
1760                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1761                 ++target;
1762             }
1763             // Store the size and indexOffset of the gathered deltas.
1764             const auto byteSize =
1765                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1766             submesh.morphTargets[trg].byteSize = byteSize;
1767         }
1768     } else {
1769         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1770             submesh.morphTargets[trg].offset = targetOffset;
1771             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1772             auto target = startTarget;
1773             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1774                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1775                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1776                 Math::Vec3 pos;
1777                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
1778                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
1779                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
1780                 }
1781                 const auto zeroDelta = (pos == Math::Vec3 {});
1782                 // store offset for each non-zero
1783                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1784                 if (zeroDelta) {
1785                     continue;
1786                 }
1787                 targetOffset += sizeof(MorphInputData);
1788 
1789                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1790                 ++target;
1791             }
1792             // Store the size and indexOffset of the gathered deltas.
1793             const auto byteSize =
1794                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1795             submesh.morphTargets[trg].byteSize = byteSize;
1796         }
1797     }
1798 }
1799 
GatherDeltasPN(SubmeshExt & submesh,uint8_t * dst,uint32_t baseOffset,uint32_t indexOffset,uint32_t targetSize,const MeshBuilder::DataBuffer & targetPositions,const MeshBuilder::DataBuffer & targetNormals)1800 void MeshBuilder::GatherDeltasPN(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1801     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals)
1802 {
1803     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1804         return;
1805     }
1806     const auto posFormat = GetFormatSpec(targetPositions.format);
1807     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1808         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1809         return;
1810     }
1811     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1812         posElementSize > targetPositions.stride) {
1813         return;
1814     }
1815 
1816     if (targetNormals.stride > (targetNormals.buffer.size() / submesh.info.vertexCount)) {
1817         return;
1818     }
1819     const auto norFormat = GetFormatSpec(targetNormals.format);
1820     if (norFormat.format == BASE_FORMAT_UNDEFINED) {
1821         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1822         return;
1823     }
1824     if (const auto norElementSize = norFormat.componentCount * norFormat.componentByteSize;
1825         norElementSize > targetNormals.stride) {
1826         return;
1827     }
1828 
1829     // Target data starts after base
1830     uint32_t targetOffset = baseOffset + targetSize;
1831 
1832     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1833     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT && norFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1834         // special case which matches glTF 2.0. morph targets are three float components.
1835         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1836             submesh.morphTargets[trg].offset = targetOffset;
1837             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1838             auto target = startTarget;
1839             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1840                 // for each vertex in target check that position and normal deltas are non-zero.
1841                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1842                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1843                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1844                 auto nor = *reinterpret_cast<const Math::Vec3*>(
1845                     targetNormals.buffer.data() + targetNormals.stride * vertexIndex);
1846                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {});
1847                 // store offset for each non-zero
1848                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1849                 if (zeroDelta) {
1850                     continue;
1851                 }
1852                 targetOffset += sizeof(MorphInputData);
1853 
1854                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1855 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1856                 target->nortan.x = Math::PackHalf2X16({ nor.x, nor.y });
1857                 target->nortan.y = Math::PackHalf2X16({ nor.z, 0.f });
1858 #else
1859                 target->nor = Math::Vec4(nor, 0.f);
1860 #endif
1861                 ++target;
1862             }
1863             // Store the size of the gathered deltas.
1864             const auto byteSize =
1865                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1866             submesh.morphTargets[trg].byteSize = byteSize;
1867         }
1868     } else {
1869         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1870             submesh.morphTargets[trg].offset = targetOffset;
1871             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1872             auto target = startTarget;
1873             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1874                 // for each vertex in target check that position and normal deltas are non-zero.
1875                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1876                 Math::Vec3 pos;
1877                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
1878                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
1879                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
1880                 }
1881                 Math::Vec3 nor;
1882                 ptr = targetNormals.buffer.data() + targetNormals.stride * vertexIndex;
1883                 for (auto i = 0U; i < Math::min(countof(nor.data), norFormat.componentCount); ++i) {
1884                     nor[i] = norFormat.toIntermediate(ptr + i * norFormat.componentByteSize);
1885                 }
1886                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {});
1887                 // store offset for each non-zero
1888                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1889                 if (zeroDelta) {
1890                     continue;
1891                 }
1892                 targetOffset += sizeof(MorphInputData);
1893 
1894                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1895 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1896                 target->nortan.x = Math::PackHalf2X16({ nor.data[R], nor.data[G] });
1897                 target->nortan.y = Math::PackHalf2X16({ nor.data[B], 0.f });
1898 #else
1899                 target->nor = Math::Vec4(nor.data[R], nor.data[G], nor.data[B], 0.f);
1900 #endif
1901                 ++target;
1902             }
1903             // Store the size of the gathered deltas.
1904             const auto byteSize =
1905                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
1906             submesh.morphTargets[trg].byteSize = byteSize;
1907         }
1908     }
1909 }
1910 
GatherDeltasPT(SubmeshExt & submesh,uint8_t * dst,uint32_t baseOffset,uint32_t indexOffset,uint32_t targetSize,const MeshBuilder::DataBuffer & targetPositions,const MeshBuilder::DataBuffer & targetTangents)1911 void MeshBuilder::GatherDeltasPT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1912     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetTangents)
1913 {}
1914 
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)1915 void MeshBuilder::GatherDeltasPNT(SubmeshExt& submesh, uint8_t* dst, uint32_t baseOffset, uint32_t indexOffset,
1916     uint32_t targetSize, const MeshBuilder::DataBuffer& targetPositions, const MeshBuilder::DataBuffer& targetNormals,
1917     const MeshBuilder::DataBuffer& targetTangents)
1918 {
1919     if (targetPositions.stride > (targetPositions.buffer.size() / submesh.info.vertexCount)) {
1920         return;
1921     }
1922     const auto posFormat = GetFormatSpec(targetPositions.format);
1923     if (posFormat.format == BASE_FORMAT_UNDEFINED) {
1924         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1925         return;
1926     }
1927     if (const auto posElementSize = posFormat.componentCount * posFormat.componentByteSize;
1928         posElementSize > targetPositions.stride) {
1929         return;
1930     }
1931 
1932     if (targetNormals.stride > (targetNormals.buffer.size() / submesh.info.vertexCount)) {
1933         return;
1934     }
1935     const auto norFormat = GetFormatSpec(targetNormals.format);
1936     if (norFormat.format == BASE_FORMAT_UNDEFINED) {
1937         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1938         return;
1939     }
1940     if (const auto norElementSize = norFormat.componentCount * norFormat.componentByteSize;
1941         norElementSize > targetNormals.stride) {
1942         return;
1943     }
1944 
1945     if (targetTangents.stride > (targetTangents.buffer.size() / submesh.info.vertexCount)) {
1946         return;
1947     }
1948     const auto tanFormat = GetFormatSpec(targetTangents.format);
1949     if (tanFormat.format == BASE_FORMAT_UNDEFINED) {
1950         CORE_LOG_E("position format (%u) not supported", posFormat.format);
1951         return;
1952     }
1953     if (const auto tanElementSize = tanFormat.componentCount * tanFormat.componentByteSize;
1954         tanElementSize > targetTangents.stride) {
1955         return;
1956     }
1957 
1958     // Target data starts after base
1959     uint32_t targetOffset = baseOffset + targetSize;
1960 
1961     auto index = reinterpret_cast<uint32_t*>(dst + indexOffset);
1962     if (posFormat.format == BASE_FORMAT_R32G32B32_SFLOAT && norFormat.format == BASE_FORMAT_R32G32B32_SFLOAT &&
1963         tanFormat.format == BASE_FORMAT_R32G32B32_SFLOAT) {
1964         // special case which matches glTF 2.0. morph targets are three float components.
1965         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
1966             submesh.morphTargets[trg].offset = targetOffset;
1967             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
1968             auto target = startTarget;
1969             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
1970                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
1971                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
1972                 auto pos = *reinterpret_cast<const Math::Vec3*>(
1973                     targetPositions.buffer.data() + targetPositions.stride * vertexIndex);
1974                 auto nor = *reinterpret_cast<const Math::Vec3*>(
1975                     targetNormals.buffer.data() + targetNormals.stride * vertexIndex);
1976                 auto tan = *reinterpret_cast<const Math::Vec3*>(
1977                     targetTangents.buffer.data() + targetTangents.stride * vertexIndex);
1978                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {} && tan == Math::Vec3 {});
1979                 // store offset for each non-zero
1980                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
1981                 if (zeroDelta) {
1982                     continue;
1983                 }
1984                 targetOffset += sizeof(MorphInputData);
1985                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
1986 
1987 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
1988                 target->nortan.x = Math::PackHalf2X16({ nor.x, nor.y });
1989                 target->nortan.y = Math::PackHalf2X16({ nor.z, 0.f });
1990                 target->nortan.z = Math::PackHalf2X16({ tan.x, tan.y });
1991                 target->nortan.w = Math::PackHalf2X16({ tan.z, 0.f });
1992 #else
1993                 target->nor = Math::Vec4(nor, 0.f);
1994                 target->tan = Math::Vec4(tan, 0.f);
1995 #endif
1996                 ++target;
1997             }
1998             // Store the size of the gathered deltas.
1999             const auto byteSize =
2000                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
2001             submesh.morphTargets[trg].byteSize = byteSize;
2002         }
2003     } else {
2004         for (uint32_t trg = 0; trg < submesh.info.morphTargetCount; trg++) {
2005             submesh.morphTargets[trg].offset = targetOffset;
2006             const auto startTarget = reinterpret_cast<MorphInputData*>(dst + targetOffset);
2007             auto target = startTarget;
2008             for (uint32_t vertex = 0; vertex < submesh.info.vertexCount; ++vertex) {
2009                 // for each vertex in target check that position, normal and tangent deltas are non-zero.
2010                 const auto vertexIndex = vertex + (trg * submesh.info.vertexCount);
2011                 Math::Vec3 pos;
2012                 auto ptr = targetPositions.buffer.data() + targetPositions.stride * vertexIndex;
2013                 for (auto i = 0U; i < Math::min(countof(pos.data), posFormat.componentCount); ++i) {
2014                     pos[i] = posFormat.toIntermediate(ptr + i * posFormat.componentByteSize);
2015                 }
2016                 Math::Vec3 nor;
2017                 ptr = targetNormals.buffer.data() + targetNormals.stride * vertexIndex;
2018                 for (auto i = 0U; i < Math::min(countof(nor.data), norFormat.componentCount); ++i) {
2019                     nor[i] = norFormat.toIntermediate(ptr + i * norFormat.componentByteSize);
2020                 }
2021                 Math::Vec3 tan;
2022                 ptr = targetTangents.buffer.data() + targetTangents.stride * vertexIndex;
2023                 for (auto i = 0U; i < Math::min(countof(tan.data), tanFormat.componentCount); ++i) {
2024                     tan[i] = tanFormat.toIntermediate(ptr + i * tanFormat.componentByteSize);
2025                 }
2026                 const auto zeroDelta = (pos == Math::Vec3 {} && nor == Math::Vec3 {} && tan == Math::Vec3 {});
2027                 // store offset for each non-zero
2028                 *index++ = zeroDelta ? UINT32_MAX : ((targetOffset - baseOffset) / sizeof(MorphInputData));
2029                 if (zeroDelta) {
2030                     continue;
2031                 }
2032                 targetOffset += sizeof(MorphInputData);
2033 
2034                 target->pos = Math::Vec4(pos, static_cast<float>(vertex));
2035 #if defined(CORE_MORPH_USE_PACKED_NOR_TAN)
2036                 target->nortan.x = Math::PackHalf2X16({ nor.data[R], nor.data[G] });
2037                 target->nortan.y = Math::PackHalf2X16({ nor.data[B], 0.f });
2038                 target->nortan.z = Math::PackHalf2X16({ tan.data[R], tan.data[G] });
2039                 target->nortan.w = Math::PackHalf2X16({ tan.data[B], 0.f });
2040 #else
2041                 target->nor = Math::Vec4(nor.data[R], nor.data[G], nor.data[B], 0.f);
2042                 target->tan = Math::Vec4(tan.data[R], tan.data[G], tan.data[B], 0.f);
2043 #endif
2044                 ++target;
2045             }
2046             // Store the size of the gathered deltas.
2047             const auto byteSize =
2048                 static_cast<uint32_t>(reinterpret_cast<ptrdiff_t>(target) - reinterpret_cast<ptrdiff_t>(startTarget));
2049             submesh.morphTargets[trg].byteSize = byteSize;
2050         }
2051     }
2052 }
2053 
CalculateJointBounds(const DataBuffer & jointData,const DataBuffer & weightData,const DataBuffer & positionData)2054 void MeshBuilder::CalculateJointBounds(
2055     const DataBuffer& jointData, const DataBuffer& weightData, const DataBuffer& positionData)
2056 {
2057     // Calculate joint bounds as the bounds of the vertices that the joint references.
2058 
2059     const auto jointFormat = GetFormatSpec(jointData.format);
2060     if (jointFormat.format == BASE_FORMAT_UNDEFINED) {
2061         return;
2062     }
2063     if (const auto jointElementSize = jointFormat.componentCount * jointFormat.componentByteSize;
2064         jointElementSize > jointData.stride) {
2065         return;
2066     }
2067 
2068     const auto weightFormat = GetFormatSpec(weightData.format);
2069     if (weightFormat.format == BASE_FORMAT_UNDEFINED) {
2070         return;
2071     }
2072     if (const auto weightElementSize = weightFormat.componentCount * weightFormat.componentByteSize;
2073         weightElementSize > weightData.stride) {
2074         return;
2075     }
2076 
2077     const auto positionFormat = GetFormatSpec(positionData.format);
2078     if (positionFormat.format == BASE_FORMAT_UNDEFINED) {
2079         return;
2080     }
2081     if (const auto positionElementSize = positionFormat.componentCount * positionFormat.componentByteSize;
2082         positionElementSize > positionData.stride) {
2083         return;
2084     }
2085 
2086     const auto* weights = weightData.buffer.data();
2087     const auto* joints = jointData.buffer.data();
2088 
2089     const size_t jointIndexCount = jointData.buffer.size() / jointData.stride;
2090 
2091     // Find the amount of referenced joints
2092     size_t maxJointIndex = 0;
2093     for (size_t i = 0; i < jointIndexCount; ++i) {
2094         float fWeights[4U];
2095         for (auto j = 0U; j < weightFormat.componentCount; ++j) {
2096             fWeights[j] = weightFormat.toIntermediate(weights + j * weightFormat.componentByteSize);
2097         }
2098         weights += weightData.stride;
2099         for (size_t w = 0; w < countof(fWeights); ++w) {
2100             // Ignore joints with weight that is effectively 0.0
2101             if (fWeights[w] >= Math::EPSILON) {
2102                 const uint8_t jointIndex = joints[jointFormat.componentByteSize * w];
2103 
2104                 if (jointIndex > maxJointIndex) {
2105                     maxJointIndex = jointIndex;
2106                 }
2107             }
2108         }
2109         joints += jointData.stride;
2110     }
2111 
2112     // Make sure bounds data is big enough. Initialize new bounds to min and max values.
2113     const size_t oldSize = jointBoundsData_.size();
2114     const size_t newSize = (maxJointIndex + 1);
2115     if (newSize > 0 && newSize > oldSize) {
2116         constexpr float floatMin = std::numeric_limits<float>::lowest();
2117         constexpr float floatMax = std::numeric_limits<float>::max();
2118 
2119         constexpr const Bounds minMax = { { floatMax, floatMax, floatMax }, { floatMin, floatMin, floatMin } };
2120         jointBoundsData_.resize(newSize, minMax);
2121     }
2122 
2123     weights = weightData.buffer.data();
2124     joints = jointData.buffer.data();
2125     const auto* positions = positionData.buffer.data();
2126     for (auto i = 0U; i < jointIndexCount; ++i) {
2127         // Each vertex can reference 4 joint indices.
2128         Math::Vec3 pos;
2129         auto ptr = positions + i * positionData.stride;
2130         for (auto j = 0U; j < positionFormat.componentCount; ++j) {
2131             pos[j] = positionFormat.toIntermediate(ptr + j * positionFormat.componentByteSize);
2132         }
2133 
2134         float fWeights[4U];
2135         for (auto j = 0U; j < weightFormat.componentCount; ++j) {
2136             fWeights[j] = weightFormat.toIntermediate(weights + j * weightFormat.componentByteSize);
2137         }
2138         weights += weightData.stride;
2139         for (size_t w = 0; w < countof(fWeights); ++w) {
2140             if (fWeights[w] < Math::EPSILON) {
2141                 // Ignore joints with weight that is effectively 0.0
2142                 continue;
2143             }
2144 
2145             auto& boundsData = jointBoundsData_[joints[w]];
2146             boundsData.min = Math::min(boundsData.min, pos);
2147             boundsData.max = Math::max(boundsData.max, pos);
2148         }
2149         joints += jointData.stride;
2150     }
2151 }
2152 
WriteData(const DataBuffer & srcData,const SubmeshExt & submesh,uint32_t attributeLocation,uint32_t & byteOffset,uint32_t & byteSize,uint8_t * dst) const2153 bool MeshBuilder::WriteData(const DataBuffer& srcData, const SubmeshExt& submesh, uint32_t attributeLocation,
2154     uint32_t& byteOffset, uint32_t& byteSize, uint8_t* dst) const
2155 {
2156     if (const VertexInputDeclaration::VertexInputAttributeDescription* attributeDesc =
2157             GetVertexAttributeDescription(attributeLocation, vertexInputDeclaration_.attributeDescriptions);
2158         attributeDesc) {
2159         if (const VertexInputDeclaration::VertexInputBindingDescription* bindingDesc =
2160                 GetVertexBindingeDescription(attributeDesc->binding, vertexInputDeclaration_.bindingDescriptions);
2161             bindingDesc) {
2162             // this offset and size should be aligned
2163             byteOffset = submesh.vertexBindingOffset[bindingDesc->binding] + attributeDesc->offset;
2164             byteSize = submesh.info.vertexCount * bindingDesc->stride;
2165             OutputBuffer dstData { attributeDesc->format, bindingDesc->stride, { dst + byteOffset, byteSize } };
2166             Fill(dstData, srcData, submesh.info.vertexCount);
2167             return true;
2168         }
2169     }
2170     return false;
2171 }
2172 CORE3D_END_NAMESPACE()
2173