Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/AABBTree/TriangleCodec/TriangleCodecIndexed8BitPackSOA4Flags.h
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Geometry/RayTriangle.h>
8
9
JPH_NAMESPACE_BEGIN
10
11
/// Store vertices in 64 bits and indices in 8 bits + 8 bit of flags per triangle like this:
12
///
13
/// TriangleBlockHeader,
14
/// TriangleBlock (4 triangles and their flags in 16 bytes),
15
/// TriangleBlock...
16
/// [Optional] UserData (4 bytes per triangle)
17
///
18
/// Vertices are stored:
19
///
20
/// VertexData (1 vertex in 64 bits),
21
/// VertexData...
22
///
23
/// They're compressed relative to the bounding box as provided by the node codec.
24
class TriangleCodecIndexed8BitPackSOA4Flags
25
{
26
public:
27
class TriangleHeader
28
{
29
public:
30
Float3 mOffset; ///< Offset of all vertices
31
Float3 mScale; ///< Scale of all vertices, vertex_position = mOffset + mScale * compressed_vertex_position
32
};
33
34
/// Size of the header (an empty struct is always > 0 bytes so this needs a separate variable)
35
static constexpr int TriangleHeaderSize = sizeof(TriangleHeader);
36
37
/// If this codec could return a different offset than the current buffer size when calling Pack()
38
static constexpr bool ChangesOffsetOnPack = false;
39
40
/// Amount of bits per component
41
enum EComponentData : uint32
42
{
43
COMPONENT_BITS = 21,
44
COMPONENT_MASK = (1 << COMPONENT_BITS) - 1,
45
};
46
47
/// Packed X and Y coordinate
48
enum EVertexXY : uint32
49
{
50
COMPONENT_X = 0,
51
COMPONENT_Y1 = COMPONENT_BITS,
52
COMPONENT_Y1_BITS = 32 - COMPONENT_BITS,
53
};
54
55
/// Packed Z and Y coordinate
56
enum EVertexZY : uint32
57
{
58
COMPONENT_Z = 0,
59
COMPONENT_Y2 = COMPONENT_BITS,
60
COMPONENT_Y2_BITS = 31 - COMPONENT_BITS,
61
};
62
63
/// A single packed vertex
64
struct VertexData
65
{
66
uint32 mVertexXY;
67
uint32 mVertexZY;
68
};
69
70
static_assert(sizeof(VertexData) == 8, "Compiler added padding");
71
72
/// A block of 4 triangles
73
struct TriangleBlock
74
{
75
uint8 mIndices[3][4]; ///< 8 bit indices to triangle vertices for 4 triangles in the form mIndices[vertex][triangle] where vertex in [0, 2] and triangle in [0, 3]
76
uint8 mFlags[4]; ///< Triangle flags (could contain material and active edges)
77
};
78
79
static_assert(sizeof(TriangleBlock) == 16, "Compiler added padding");
80
81
enum ETriangleBlockHeaderFlags : uint32
82
{
83
OFFSET_TO_VERTICES_BITS = 29, ///< Offset from current block to start of vertices in bytes
84
OFFSET_TO_VERTICES_MASK = (1 << OFFSET_TO_VERTICES_BITS) - 1,
85
OFFSET_NON_SIGNIFICANT_BITS = 2, ///< The offset from the current block to the start of the vertices must be a multiple of 4 bytes
86
OFFSET_NON_SIGNIFICANT_MASK = (1 << OFFSET_NON_SIGNIFICANT_BITS) - 1,
87
OFFSET_TO_USERDATA_BITS = 3, ///< When user data is stored, this is the number of blocks to skip to get to the user data (0 = no user data)
88
OFFSET_TO_USERDATA_MASK = (1 << OFFSET_TO_USERDATA_BITS) - 1,
89
};
90
91
/// A triangle header, will be followed by one or more TriangleBlocks
92
struct TriangleBlockHeader
93
{
94
const VertexData * GetVertexData() const { return reinterpret_cast<const VertexData *>(reinterpret_cast<const uint8 *>(this) + ((mFlags & OFFSET_TO_VERTICES_MASK) << OFFSET_NON_SIGNIFICANT_BITS)); }
95
const TriangleBlock * GetTriangleBlock() const { return reinterpret_cast<const TriangleBlock *>(reinterpret_cast<const uint8 *>(this) + sizeof(TriangleBlockHeader)); }
96
const uint32 * GetUserData() const { uint32 offset = mFlags >> OFFSET_TO_VERTICES_BITS; return offset == 0? nullptr : reinterpret_cast<const uint32 *>(GetTriangleBlock() + offset); }
97
98
uint32 mFlags;
99
};
100
101
static_assert(sizeof(TriangleBlockHeader) == 4, "Compiler added padding");
102
103
/// This class is used to validate that the triangle data will not be degenerate after compression
104
class ValidationContext
105
{
106
public:
107
/// Constructor
108
ValidationContext(const IndexedTriangleList &inTriangles, const VertexList &inVertices) :
109
mVertices(inVertices)
110
{
111
// Only used the referenced triangles, just like EncodingContext::Finalize does
112
for (const IndexedTriangle &i : inTriangles)
113
for (uint32 idx : i.mIdx)
114
mBounds.Encapsulate(Vec3(inVertices[idx]));
115
}
116
117
/// Test if a triangle will be degenerate after quantization
118
bool IsDegenerate(const IndexedTriangle &inTriangle) const
119
{
120
// Quantize the triangle in the same way as EncodingContext::Finalize does
121
UVec4 quantized_vertex[3];
122
Vec3 compress_scale = Vec3::sReplicate(COMPONENT_MASK) / Vec3::sMax(mBounds.GetSize(), Vec3::sReplicate(1.0e-20f));
123
for (int i = 0; i < 3; ++i)
124
quantized_vertex[i] = ((Vec3(mVertices[inTriangle.mIdx[i]]) - mBounds.mMin) * compress_scale + Vec3::sReplicate(0.5f)).ToInt();
125
return quantized_vertex[0] == quantized_vertex[1] || quantized_vertex[1] == quantized_vertex[2] || quantized_vertex[0] == quantized_vertex[2];
126
}
127
128
private:
129
const VertexList & mVertices;
130
AABox mBounds;
131
};
132
133
/// This class is used to encode and compress triangle data into a byte buffer
134
class EncodingContext
135
{
136
public:
137
/// Indicates a vertex hasn't been seen yet in the triangle list
138
static constexpr uint32 cNotFound = 0xffffffff;
139
140
/// Construct the encoding context
141
explicit EncodingContext(const VertexList &inVertices) :
142
mVertexMap(inVertices.size(), cNotFound)
143
{
144
}
145
146
/// Mimics the size a call to Pack() would add to the buffer
147
void PreparePack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, uint64 &ioBufferSize)
148
{
149
// Add triangle block header
150
ioBufferSize += sizeof(TriangleBlockHeader);
151
152
// Compute first vertex that this batch will use (ensuring there's enough room if none of the vertices are shared)
153
uint start_vertex = Clamp((int)mVertexCount - 256 + (int)inNumTriangles * 3, 0, (int)mVertexCount);
154
155
// Pack vertices
156
uint padded_triangle_count = AlignUp(inNumTriangles, 4);
157
for (uint t = 0; t < padded_triangle_count; t += 4)
158
{
159
// Add triangle block header
160
ioBufferSize += sizeof(TriangleBlock);
161
162
for (uint vertex_nr = 0; vertex_nr < 3; ++vertex_nr)
163
for (uint block_tri_idx = 0; block_tri_idx < 4; ++block_tri_idx)
164
{
165
// Fetch vertex index. Create degenerate triangles for padding triangles.
166
bool triangle_available = t + block_tri_idx < inNumTriangles;
167
uint32 src_vertex_index = triangle_available? inTriangles[t + block_tri_idx].mIdx[vertex_nr] : inTriangles[inNumTriangles - 1].mIdx[0];
168
169
// Check if we've seen this vertex before and if it is in the range that we can encode
170
uint32 &vertex_index = mVertexMap[src_vertex_index];
171
if (vertex_index == cNotFound || vertex_index < start_vertex)
172
{
173
// Add vertex
174
vertex_index = mVertexCount;
175
mVertexCount++;
176
}
177
}
178
}
179
180
// Add user data
181
if (inStoreUserData)
182
ioBufferSize += inNumTriangles * sizeof(uint32);
183
}
184
185
/// Mimics the size the Finalize() call would add to ioBufferSize
186
void FinalizePreparePack(uint64 &ioBufferSize)
187
{
188
// Remember where the vertices are going to start in the output buffer
189
JPH_ASSERT(IsAligned(ioBufferSize, 4));
190
mVerticesStartIdx = size_t(ioBufferSize);
191
192
// Add vertices to buffer
193
ioBufferSize += uint64(mVertexCount) * sizeof(VertexData);
194
195
// Reserve the amount of memory we need for the vertices
196
mVertices.reserve(mVertexCount);
197
198
// Set vertex map back to 'not found'
199
for (uint32 &v : mVertexMap)
200
v = cNotFound;
201
}
202
203
/// Pack the triangles in inContainer to ioBuffer. This stores the mMaterialIndex of a triangle in the 8 bit flags.
204
/// Returns size_t(-1) on error.
205
size_t Pack(const IndexedTriangle *inTriangles, uint inNumTriangles, bool inStoreUserData, ByteBuffer &ioBuffer, const char *&outError)
206
{
207
JPH_ASSERT(inNumTriangles > 0);
208
209
// Determine position of triangles start
210
size_t triangle_block_start = ioBuffer.size();
211
212
// Allocate triangle block header
213
TriangleBlockHeader *header = ioBuffer.Allocate<TriangleBlockHeader>();
214
215
// Compute first vertex that this batch will use (ensuring there's enough room if none of the vertices are shared)
216
uint start_vertex = Clamp((int)mVertices.size() - 256 + (int)inNumTriangles * 3, 0, (int)mVertices.size());
217
218
// Store the start vertex offset relative to TriangleBlockHeader
219
size_t offset_to_vertices = mVerticesStartIdx - triangle_block_start + size_t(start_vertex) * sizeof(VertexData);
220
if (offset_to_vertices & OFFSET_NON_SIGNIFICANT_MASK)
221
{
222
outError = "TriangleCodecIndexed8BitPackSOA4Flags: Internal Error: Offset has non-significant bits set";
223
return size_t(-1);
224
}
225
offset_to_vertices >>= OFFSET_NON_SIGNIFICANT_BITS;
226
if (offset_to_vertices > OFFSET_TO_VERTICES_MASK)
227
{
228
outError = "TriangleCodecIndexed8BitPackSOA4Flags: Offset to vertices doesn't fit. Too much data.";
229
return size_t(-1);
230
}
231
header->mFlags = uint32(offset_to_vertices);
232
233
// When we store user data we need to store the offset to the user data in TriangleBlocks
234
uint padded_triangle_count = AlignUp(inNumTriangles, 4);
235
if (inStoreUserData)
236
{
237
uint32 num_blocks = padded_triangle_count >> 2;
238
JPH_ASSERT(num_blocks <= OFFSET_TO_USERDATA_MASK);
239
header->mFlags |= num_blocks << OFFSET_TO_VERTICES_BITS;
240
}
241
242
// Pack vertices
243
for (uint t = 0; t < padded_triangle_count; t += 4)
244
{
245
TriangleBlock *block = ioBuffer.Allocate<TriangleBlock>();
246
for (uint vertex_nr = 0; vertex_nr < 3; ++vertex_nr)
247
for (uint block_tri_idx = 0; block_tri_idx < 4; ++block_tri_idx)
248
{
249
// Fetch vertex index. Create degenerate triangles for padding triangles.
250
bool triangle_available = t + block_tri_idx < inNumTriangles;
251
uint32 src_vertex_index = triangle_available? inTriangles[t + block_tri_idx].mIdx[vertex_nr] : inTriangles[inNumTriangles - 1].mIdx[0];
252
253
// Check if we've seen this vertex before and if it is in the range that we can encode
254
uint32 &vertex_index = mVertexMap[src_vertex_index];
255
if (vertex_index == cNotFound || vertex_index < start_vertex)
256
{
257
// Add vertex
258
vertex_index = (uint32)mVertices.size();
259
mVertices.push_back(src_vertex_index);
260
}
261
262
// Store vertex index
263
uint32 vertex_offset = vertex_index - start_vertex;
264
if (vertex_offset > 0xff)
265
{
266
outError = "TriangleCodecIndexed8BitPackSOA4Flags: Offset doesn't fit in 8 bit";
267
return size_t(-1);
268
}
269
block->mIndices[vertex_nr][block_tri_idx] = (uint8)vertex_offset;
270
271
// Store flags
272
uint32 flags = triangle_available? inTriangles[t + block_tri_idx].mMaterialIndex : 0;
273
if (flags > 0xff)
274
{
275
outError = "TriangleCodecIndexed8BitPackSOA4Flags: Material index doesn't fit in 8 bit";
276
return size_t(-1);
277
}
278
block->mFlags[block_tri_idx] = (uint8)flags;
279
}
280
}
281
282
// Store user data
283
if (inStoreUserData)
284
{
285
uint32 *user_data = ioBuffer.Allocate<uint32>(inNumTriangles);
286
for (uint t = 0; t < inNumTriangles; ++t)
287
user_data[t] = inTriangles[t].mUserData;
288
}
289
290
return triangle_block_start;
291
}
292
293
/// After all triangles have been packed, this finalizes the header and triangle buffer
294
void Finalize(const VertexList &inVertices, TriangleHeader *ioHeader, ByteBuffer &ioBuffer) const
295
{
296
// Assert that our reservations were correct
297
JPH_ASSERT(mVertices.size() == mVertexCount);
298
JPH_ASSERT(ioBuffer.size() == mVerticesStartIdx);
299
300
// Check if anything to do
301
if (mVertices.empty())
302
return;
303
304
// Calculate bounding box
305
AABox bounds;
306
for (uint32 v : mVertices)
307
bounds.Encapsulate(Vec3(inVertices[v]));
308
309
// Compress vertices
310
VertexData *vertices = ioBuffer.Allocate<VertexData>(mVertices.size());
311
Vec3 compress_scale = Vec3::sReplicate(COMPONENT_MASK) / Vec3::sMax(bounds.GetSize(), Vec3::sReplicate(1.0e-20f));
312
for (uint32 v : mVertices)
313
{
314
UVec4 c = ((Vec3(inVertices[v]) - bounds.mMin) * compress_scale + Vec3::sReplicate(0.5f)).ToInt();
315
JPH_ASSERT(c.GetX() <= COMPONENT_MASK);
316
JPH_ASSERT(c.GetY() <= COMPONENT_MASK);
317
JPH_ASSERT(c.GetZ() <= COMPONENT_MASK);
318
vertices->mVertexXY = c.GetX() + (c.GetY() << COMPONENT_Y1);
319
vertices->mVertexZY = c.GetZ() + ((c.GetY() >> COMPONENT_Y1_BITS) << COMPONENT_Y2);
320
++vertices;
321
}
322
323
// Store decompression information
324
bounds.mMin.StoreFloat3(&ioHeader->mOffset);
325
(bounds.GetSize() / Vec3::sReplicate(COMPONENT_MASK)).StoreFloat3(&ioHeader->mScale);
326
}
327
328
private:
329
using VertexMap = Array<uint32>;
330
331
uint32 mVertexCount = 0; ///< Number of vertices calculated during PreparePack
332
size_t mVerticesStartIdx = 0; ///< Start of the vertices in the output buffer, calculated during PreparePack
333
Array<uint32> mVertices; ///< Output vertices as an index into the original vertex list (inVertices), sorted according to occurrence
334
VertexMap mVertexMap; ///< Maps from the original mesh vertex index (inVertices) to the index in our output vertices (mVertices)
335
};
336
337
/// This class is used to decode and decompress triangle data packed by the EncodingContext
338
class DecodingContext
339
{
340
private:
341
/// Private helper function to unpack the 1 vertex of 4 triangles (outX contains the x coordinate of triangle 0 .. 3 etc.)
342
JPH_INLINE void Unpack(const VertexData *inVertices, UVec4Arg inIndex, Vec4 &outX, Vec4 &outY, Vec4 &outZ) const
343
{
344
// Get compressed data
345
UVec4 c1 = UVec4::sGatherInt4<8>(&inVertices->mVertexXY, inIndex);
346
UVec4 c2 = UVec4::sGatherInt4<8>(&inVertices->mVertexZY, inIndex);
347
348
// Unpack the x y and z component
349
UVec4 xc = UVec4::sAnd(c1, UVec4::sReplicate(COMPONENT_MASK));
350
UVec4 yc = UVec4::sOr(c1.LogicalShiftRight<COMPONENT_Y1>(), c2.LogicalShiftRight<COMPONENT_Y2>().LogicalShiftLeft<COMPONENT_Y1_BITS>());
351
UVec4 zc = UVec4::sAnd(c2, UVec4::sReplicate(COMPONENT_MASK));
352
353
// Convert to float
354
outX = Vec4::sFusedMultiplyAdd(xc.ToFloat(), mScaleX, mOffsetX);
355
outY = Vec4::sFusedMultiplyAdd(yc.ToFloat(), mScaleY, mOffsetY);
356
outZ = Vec4::sFusedMultiplyAdd(zc.ToFloat(), mScaleZ, mOffsetZ);
357
}
358
359
/// Private helper function to unpack 4 triangles from a triangle block
360
JPH_INLINE void Unpack(const TriangleBlock *inBlock, const VertexData *inVertices, Vec4 &outX1, Vec4 &outY1, Vec4 &outZ1, Vec4 &outX2, Vec4 &outY2, Vec4 &outZ2, Vec4 &outX3, Vec4 &outY3, Vec4 &outZ3) const
361
{
362
// Get the indices for the three vertices (reads 4 bytes extra, but these are the flags so that's ok)
363
UVec4 indices = UVec4::sLoadInt4(reinterpret_cast<const uint32 *>(&inBlock->mIndices[0]));
364
UVec4 iv1 = indices.Expand4Byte0();
365
UVec4 iv2 = indices.Expand4Byte4();
366
UVec4 iv3 = indices.Expand4Byte8();
367
368
#ifdef JPH_CPU_BIG_ENDIAN
369
// On big endian systems we need to reverse the bytes
370
iv1 = iv1.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
371
iv2 = iv2.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
372
iv3 = iv3.Swizzle<SWIZZLE_W, SWIZZLE_Z, SWIZZLE_Y, SWIZZLE_X>();
373
#endif
374
375
// Decompress the triangle data
376
Unpack(inVertices, iv1, outX1, outY1, outZ1);
377
Unpack(inVertices, iv2, outX2, outY2, outZ2);
378
Unpack(inVertices, iv3, outX3, outY3, outZ3);
379
}
380
381
public:
382
JPH_INLINE explicit DecodingContext(const TriangleHeader *inHeader) :
383
mOffsetX(Vec4::sReplicate(inHeader->mOffset.x)),
384
mOffsetY(Vec4::sReplicate(inHeader->mOffset.y)),
385
mOffsetZ(Vec4::sReplicate(inHeader->mOffset.z)),
386
mScaleX(Vec4::sReplicate(inHeader->mScale.x)),
387
mScaleY(Vec4::sReplicate(inHeader->mScale.y)),
388
mScaleZ(Vec4::sReplicate(inHeader->mScale.z))
389
{
390
}
391
392
/// Unpacks triangles in the format t1v1,t1v2,t1v3, t2v1,t2v2,t2v3, ...
393
JPH_INLINE void Unpack(const void *inTriangleStart, uint32 inNumTriangles, Vec3 *outTriangles) const
394
{
395
JPH_ASSERT(inNumTriangles > 0);
396
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
397
const VertexData *vertices = header->GetVertexData();
398
const TriangleBlock *t = header->GetTriangleBlock();
399
const TriangleBlock *end = t + ((inNumTriangles + 3) >> 2);
400
401
int triangles_left = inNumTriangles;
402
403
do
404
{
405
// Unpack the vertices for 4 triangles
406
Vec4 v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z;
407
Unpack(t, vertices, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
408
409
// Transpose it so we get normal vectors
410
Mat44 v1 = Mat44(v1x, v1y, v1z, Vec4::sZero()).Transposed();
411
Mat44 v2 = Mat44(v2x, v2y, v2z, Vec4::sZero()).Transposed();
412
Mat44 v3 = Mat44(v3x, v3y, v3z, Vec4::sZero()).Transposed();
413
414
// Store triangle data
415
for (int i = 0; i < 4 && triangles_left > 0; ++i, --triangles_left)
416
{
417
*outTriangles++ = v1.GetColumn3(i);
418
*outTriangles++ = v2.GetColumn3(i);
419
*outTriangles++ = v3.GetColumn3(i);
420
}
421
422
++t;
423
}
424
while (t < end);
425
}
426
427
/// Tests a ray against the packed triangles
428
JPH_INLINE float TestRay(Vec3Arg inRayOrigin, Vec3Arg inRayDirection, const void *inTriangleStart, uint32 inNumTriangles, float inClosest, uint32 &outClosestTriangleIndex) const
429
{
430
JPH_ASSERT(inNumTriangles > 0);
431
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
432
const VertexData *vertices = header->GetVertexData();
433
const TriangleBlock *t = header->GetTriangleBlock();
434
const TriangleBlock *end = t + ((inNumTriangles + 3) >> 2);
435
436
Vec4 closest = Vec4::sReplicate(inClosest);
437
UVec4 closest_triangle_idx = UVec4::sZero();
438
439
UVec4 start_triangle_idx = UVec4::sZero();
440
do
441
{
442
// Unpack the vertices for 4 triangles
443
Vec4 v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z;
444
Unpack(t, vertices, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
445
446
// Perform ray vs triangle test
447
Vec4 distance = RayTriangle4(inRayOrigin, inRayDirection, v1x, v1y, v1z, v2x, v2y, v2z, v3x, v3y, v3z);
448
449
// Update closest with the smaller values
450
UVec4 smaller = Vec4::sLess(distance, closest);
451
closest = Vec4::sSelect(closest, distance, smaller);
452
453
// Update triangle index with the smallest values
454
UVec4 triangle_idx = start_triangle_idx + UVec4(0, 1, 2, 3);
455
closest_triangle_idx = UVec4::sSelect(closest_triangle_idx, triangle_idx, smaller);
456
457
// Next block
458
++t;
459
start_triangle_idx += UVec4::sReplicate(4);
460
}
461
while (t < end);
462
463
// Get the smallest component
464
Vec4::sSort4(closest, closest_triangle_idx);
465
outClosestTriangleIndex = closest_triangle_idx.GetX();
466
return closest.GetX();
467
}
468
469
/// Decode a single triangle
470
inline void GetTriangle(const void *inTriangleStart, uint32 inTriangleIdx, Vec3 &outV1, Vec3 &outV2, Vec3 &outV3) const
471
{
472
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
473
const VertexData *vertices = header->GetVertexData();
474
const TriangleBlock *block = header->GetTriangleBlock() + (inTriangleIdx >> 2);
475
uint32 block_triangle_idx = inTriangleIdx & 0b11;
476
477
// Get the 3 vertices
478
const VertexData &v1 = vertices[block->mIndices[0][block_triangle_idx]];
479
const VertexData &v2 = vertices[block->mIndices[1][block_triangle_idx]];
480
const VertexData &v3 = vertices[block->mIndices[2][block_triangle_idx]];
481
482
// Pack the vertices
483
UVec4 c1(v1.mVertexXY, v2.mVertexXY, v3.mVertexXY, 0);
484
UVec4 c2(v1.mVertexZY, v2.mVertexZY, v3.mVertexZY, 0);
485
486
// Unpack the x y and z component
487
UVec4 xc = UVec4::sAnd(c1, UVec4::sReplicate(COMPONENT_MASK));
488
UVec4 yc = UVec4::sOr(c1.LogicalShiftRight<COMPONENT_Y1>(), c2.LogicalShiftRight<COMPONENT_Y2>().LogicalShiftLeft<COMPONENT_Y1_BITS>());
489
UVec4 zc = UVec4::sAnd(c2, UVec4::sReplicate(COMPONENT_MASK));
490
491
// Convert to float
492
Vec4 vx = Vec4::sFusedMultiplyAdd(xc.ToFloat(), mScaleX, mOffsetX);
493
Vec4 vy = Vec4::sFusedMultiplyAdd(yc.ToFloat(), mScaleY, mOffsetY);
494
Vec4 vz = Vec4::sFusedMultiplyAdd(zc.ToFloat(), mScaleZ, mOffsetZ);
495
496
// Transpose it so we get normal vectors
497
Mat44 trans = Mat44(vx, vy, vz, Vec4::sZero()).Transposed();
498
outV1 = trans.GetAxisX();
499
outV2 = trans.GetAxisY();
500
outV3 = trans.GetAxisZ();
501
}
502
503
/// Get user data for a triangle
504
JPH_INLINE uint32 GetUserData(const void *inTriangleStart, uint32 inTriangleIdx) const
505
{
506
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
507
const uint32 *user_data = header->GetUserData();
508
return user_data != nullptr? user_data[inTriangleIdx] : 0;
509
}
510
511
/// Get flags for entire triangle block
512
JPH_INLINE static void sGetFlags(const void *inTriangleStart, uint32 inNumTriangles, uint8 *outTriangleFlags)
513
{
514
JPH_ASSERT(inNumTriangles > 0);
515
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
516
const TriangleBlock *t = header->GetTriangleBlock();
517
const TriangleBlock *end = t + ((inNumTriangles + 3) >> 2);
518
519
int triangles_left = inNumTriangles;
520
do
521
{
522
for (int i = 0; i < 4 && triangles_left > 0; ++i, --triangles_left)
523
*outTriangleFlags++ = t->mFlags[i];
524
525
++t;
526
}
527
while (t < end);
528
}
529
530
/// Get flags for a particular triangle
531
JPH_INLINE static uint8 sGetFlags(const void *inTriangleStart, int inTriangleIndex)
532
{
533
const TriangleBlockHeader *header = reinterpret_cast<const TriangleBlockHeader *>(inTriangleStart);
534
const TriangleBlock *first_block = header->GetTriangleBlock();
535
return first_block[inTriangleIndex >> 2].mFlags[inTriangleIndex & 0b11];
536
}
537
538
/// Unpacks triangles and flags, convenience function
539
JPH_INLINE void Unpack(const void *inTriangleStart, uint32 inNumTriangles, Vec3 *outTriangles, uint8 *outTriangleFlags) const
540
{
541
Unpack(inTriangleStart, inNumTriangles, outTriangles);
542
sGetFlags(inTriangleStart, inNumTriangles, outTriangleFlags);
543
}
544
545
private:
546
Vec4 mOffsetX;
547
Vec4 mOffsetY;
548
Vec4 mOffsetZ;
549
Vec4 mScaleX;
550
Vec4 mScaleY;
551
Vec4 mScaleZ;
552
};
553
};
554
555
JPH_NAMESPACE_END
556
557