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