Blender V5.0
mikk_util.hh
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2022-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
8
9#pragma once
10
11#include <cassert>
12#include <cfloat>
13#include <cmath>
14#include <vector>
15
16#ifndef M_PI_F
17# define M_PI_F (3.1415926535897932f) /* pi */
18#endif
19
20namespace mikk {
21
22inline bool not_zero(const float fX)
23{
24 return fabsf(fX) > FLT_MIN;
25}
26
27/* Helpers for (un)packing a 2-bit vertex index and a 30-bit face index to one integer. */
28static uint pack_index(const uint face, const uint vert)
29{
30 assert((vert & 0x3) == vert);
31 return (face << 2) | (vert & 0x3);
32}
33
34static void unpack_index(uint &face, uint &vert, const uint indexIn)
35{
36 vert = indexIn & 0x3;
37 face = indexIn >> 2;
38}
39
40/* From intern/cycles/util/math_fast.h */
41inline float fast_acosf(float x)
42{
43 const float f = fabsf(x);
44 /* clamp and crush denormals. */
45 const float m = (f < 1.0f) ? 1.0f - (1.0f - f) : 1.0f;
46 /* Based on http://www.pouet.net/topic.php?which=9132&page=2
47 * 85% accurate (ULP 0)
48 * Examined 2130706434 values of acos:
49 * 15.2000597 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // without "denormal crush"
50 * Examined 2130706434 values of acos:
51 * 15.2007108 avg ULP diff, 4492 max ULP, 4.51803e-05 max error // with "denormal crush"
52 */
53 const float a = sqrtf(1.0f - m) *
54 (1.5707963267f + m * (-0.213300989f + m * (0.077980478f + m * -0.02164095f)));
55 return x < 0 ? M_PI_F - a : a;
56}
57
58static uint rotl(uint x, uint k)
59{
60 return (x << k) | (x >> (32 - k));
61}
62
63static uint hash_uint3(uint kx, uint ky, uint kz)
64{
65 uint a, b, c;
66 a = b = c = 0xdeadbeef + (2 << 2) + 13;
67
68 c += kz;
69 b += ky;
70 a += kx;
71
72 c = (c ^ b) - rotl(b, 14);
73 a = (a ^ c) - rotl(c, 11);
74 b = (b ^ a) - rotl(a, 25);
75 c = (c ^ b) - rotl(b, 16);
76
77 return c;
78}
79
80static uint hash_uint3_fast(const uint x, const uint y, const uint z)
81{
82 return (x * 73856093) ^ (y * 19349663) ^ (z * 83492791);
83}
84
85static uint float_as_uint(const float v)
86{
87 return *((uint *)(&v));
88}
89
90static float uint_as_float(const uint v)
91{
92 return *((float *)(&v));
93}
94
95static uint hash_float3_fast(const float x, const float y, const float z)
96{
98}
99
100static uint hash_float3x3(const float3 &x, const float3 &y, const float3 &z)
101{
102 return hash_uint3(hash_float3_fast(x.x, x.y, x.z),
103 hash_float3_fast(y.x, y.y, y.z),
104 hash_float3_fast(z.x, z.y, z.z));
105}
106
107template<typename T, typename KeyGetter>
108void radixsort(std::vector<T> &data, std::vector<T> &data2, KeyGetter getKey)
109{
110 using key_t = decltype(getKey(data[0]));
111 constexpr size_t datasize = sizeof(key_t);
112 static_assert(datasize % 2 == 0);
113 static_assert(std::is_integral_v<key_t>);
114
115 uint bins[datasize][257] = {{0}};
116
117 /* Count number of elements per bin. */
118 for (const T &item : data) {
119 key_t key = getKey(item);
120 for (uint pass = 0; pass < datasize; pass++) {
121 bins[pass][((key >> (8 * pass)) & 0xff) + 1]++;
122 }
123 }
124
125 /* Compute prefix sum to find position of each bin in the sorted array. */
126 for (uint pass = 0; pass < datasize; pass++) {
127 for (uint i = 2; i < 256; i++) {
128 bins[pass][i] += bins[pass][i - 1];
129 }
130 }
131
132 int shift = 0;
133 for (uint pass = 0; pass < datasize; pass++, shift += 8) {
134 /* Insert the elements in their correct location based on their bin. */
135 for (const T &item : data) {
136 uint pos = bins[pass][(getKey(item) >> shift) & 0xff]++;
137 data2[pos] = item;
138 }
139
140 /* Swap arrays. */
141 std::swap(data, data2);
142 }
143}
144
145static void float_add_atomic(float *val, float add)
146{
147 /* Hacky, but atomic floats are only supported from C++20 onward.
148 * This works in practice since `std::atomic<uint32_t>` is really just an `uint32_t` in memory,
149 * so this cast lets us do a 32-bit CAS operation (which is used to build the atomic float
150 * operation) without needing any external libraries or compiler-specific builtins. */
151 std::atomic<uint32_t> *atomic_val = reinterpret_cast<std::atomic<uint32_t> *>(val);
152 for (;;) {
153 uint32_t old_v = atomic_val->load();
154 uint32_t new_v = float_as_uint(uint_as_float(old_v) + add);
155 if (atomic_val->compare_exchange_weak(old_v, new_v)) {
156 return;
157 }
158 }
159}
160
161} // namespace mikk
unsigned int uint
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
Definition btQuadWord.h:117
uint pos
#define assert(assertion)
#define T
static void add(blender::Map< std::string, std::string > &messages, Message &msg)
Definition msgfmt.cc:222
static uint hash_uint3(uint kx, uint ky, uint kz)
Definition mikk_util.hh:63
static uint pack_index(const uint face, const uint vert)
Definition mikk_util.hh:28
bool not_zero(const float fX)
Definition mikk_util.hh:22
static uint float_as_uint(const float v)
Definition mikk_util.hh:85
static uint hash_float3_fast(const float x, const float y, const float z)
Definition mikk_util.hh:95
static void unpack_index(uint &face, uint &vert, const uint indexIn)
Definition mikk_util.hh:34
static uint rotl(uint x, uint k)
Definition mikk_util.hh:58
static uint hash_float3x3(const float3 &x, const float3 &y, const float3 &z)
Definition mikk_util.hh:100
static void float_add_atomic(float *val, float add)
Definition mikk_util.hh:145
static float uint_as_float(const uint v)
Definition mikk_util.hh:90
void radixsort(std::vector< T > &data, std::vector< T > &data2, KeyGetter getKey)
Definition mikk_util.hh:108
static uint hash_uint3_fast(const uint x, const uint y, const uint z)
Definition mikk_util.hh:80
float fast_acosf(float x)
Definition mikk_util.hh:41
#define fabsf
#define sqrtf
#define M_PI_F
i
Definition text_draw.cc:230