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