GCC Code Coverage Report


Directory: ./
File: openvdb/openvdb/math/QuantizedUnitVec.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 26 26 100.0%
Functions: 2 2 100.0%
Branches: 22 24 91.7%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 #ifndef OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED
5 #define OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED
6
7 #include <openvdb/Platform.h>
8 #include <openvdb/version.h>
9 #include "Vec3.h"
10
11 namespace openvdb {
12 OPENVDB_USE_VERSION_NAMESPACE
13 namespace OPENVDB_VERSION_NAME {
14 namespace math {
15
16 /// @brief Unit vector occupying only 16 bits
17 /// @details Stores two quantized components. Based on the
18 /// "Higher Accuracy Quantized Normals" article from GameDev.Net LLC, 2000
19 class OPENVDB_API QuantizedUnitVec
20 {
21 public:
22 template<typename T> static uint16_t pack(const Vec3<T>& vec);
23 static Vec3s unpack(const uint16_t data);
24
25 static void flipSignBits(uint16_t&);
26
27 private:
28 QuantizedUnitVec() {}
29
30 // bit masks
31 static const uint16_t MASK_SLOTS = 0x1FFF; // 0001111111111111
32 static const uint16_t MASK_XSLOT = 0x1F80; // 0001111110000000
33 static const uint16_t MASK_YSLOT = 0x007F; // 0000000001111111
34 static const uint16_t MASK_XSIGN = 0x8000; // 1000000000000000
35 static const uint16_t MASK_YSIGN = 0x4000; // 0100000000000000
36 static const uint16_t MASK_ZSIGN = 0x2000; // 0010000000000000
37
38 // normalization weights, 32 kilobytes.
39 static float sNormalizationWeights[MASK_SLOTS + 1];
40 }; // class QuantizedUnitVec
41
42
43 ////////////////////////////////////////
44
45
46 template<typename T>
47 inline uint16_t
48
2/2
✓ Branch 0 taken 324 times.
✓ Branch 1 taken 40007 times.
40331 QuantizedUnitVec::pack(const Vec3<T>& vec)
49 {
50 if (math::isZero(vec)) return 0;
51
52 uint16_t data = 0;
53 T x(vec[0]), y(vec[1]), z(vec[2]);
54
55 // The sign of the three components are first stored using
56 // 3-bits and can then safely be discarded.
57
2/2
✓ Branch 0 taken 20001 times.
✓ Branch 1 taken 20006 times.
40007 if (x < T(0.0)) { data |= MASK_XSIGN; x = -x; }
58
2/2
✓ Branch 0 taken 20002 times.
✓ Branch 1 taken 20005 times.
40007 if (y < T(0.0)) { data |= MASK_YSIGN; y = -y; }
59
2/2
✓ Branch 0 taken 20002 times.
✓ Branch 1 taken 20005 times.
40007 if (z < T(0.0)) { data |= MASK_ZSIGN; z = -z; }
60
61 // The z component is discarded and x & y are quantized in
62 // the 0 to 126 range.
63 40007 T w = T(126.0) / (x + y + z);
64 40007 uint16_t xbits = static_cast<uint16_t>((x * w));
65 40007 uint16_t ybits = static_cast<uint16_t>((y * w));
66
67 // The remaining 13 bits in our 16 bit word are dividied into a
68 // 6-bit x-slot and a 7-bit y-slot. Both the xbits and the ybits
69 // can still be represented using (2^7 - 1) quantization levels.
70
71 // If the xbits requre more than 6-bits, store the complement.
72 // (xbits + ybits < 127, thus if xbits > 63 => ybits <= 63)
73
2/2
✓ Branch 0 taken 5584 times.
✓ Branch 1 taken 34423 times.
40007 if (xbits > 63) {
74 5584 xbits = static_cast<uint16_t>(127 - xbits);
75 5584 ybits = static_cast<uint16_t>(127 - ybits);
76 }
77
78 // Pack components into their respective slots.
79 40007 data = static_cast<uint16_t>(data | (xbits << 7));
80 40007 data = static_cast<uint16_t>(data | ybits);
81 40007 return data;
82 }
83
84
85 inline Vec3s
86 40009 QuantizedUnitVec::unpack(const uint16_t data)
87 {
88 40009 const float w = sNormalizationWeights[data & MASK_SLOTS];
89
90 40009 uint16_t xbits = static_cast<uint16_t>((data & MASK_XSLOT) >> 7);
91 40009 uint16_t ybits = static_cast<uint16_t>(data & MASK_YSLOT);
92
93 // Check if the complement components where stored and revert.
94
2/2
✓ Branch 0 taken 5586 times.
✓ Branch 1 taken 34423 times.
40009 if ((xbits + ybits) > 126) {
95 5586 xbits = static_cast<uint16_t>(127 - xbits);
96 5586 ybits = static_cast<uint16_t>(127 - ybits);
97 }
98
99
2/2
✓ Branch 0 taken 20000 times.
✓ Branch 1 taken 20009 times.
40009 Vec3s vec(float(xbits) * w, float(ybits) * w, float(126 - xbits - ybits) * w);
100
101
2/2
✓ Branch 0 taken 20000 times.
✓ Branch 1 taken 20009 times.
40009 if (data & MASK_XSIGN) vec[0] = -vec[0];
102
2/2
✓ Branch 0 taken 20000 times.
✓ Branch 1 taken 20009 times.
40009 if (data & MASK_YSIGN) vec[1] = -vec[1];
103
2/2
✓ Branch 0 taken 20000 times.
✓ Branch 1 taken 20009 times.
40009 if (data & MASK_ZSIGN) vec[2] = -vec[2];
104 40009 return vec;
105 }
106
107
108 ////////////////////////////////////////
109
110
111 inline void
112 QuantizedUnitVec::flipSignBits(uint16_t& v)
113 {
114
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
2 v = static_cast<uint16_t>((v & MASK_SLOTS) | (~v & ~MASK_SLOTS));
115 }
116
117 } // namespace math
118 } // namespace OPENVDB_VERSION_NAME
119 } // namespace openvdb
120
121 #endif // OPENVDB_MATH_QUANTIZED_UNIT_VEC_HAS_BEEN_INCLUDED
122