Source browser
tests/test_math.cpp
Read the complete file below or download its original bytes. Line numbers provide stable links to a declaration or processing step.
File fingerprint
1/** @file test_math.cpp
2 * Regression checks for GLSL formulas, packed layout and alias-safe swizzles.
3 * Exception-based checks execute in both Debug and Release builds.
4 */
5#include "../detail/math.hpp" // Include ../detail/math.hpp declarations.
6#include <iostream> // Include iostream declarations.
7#include <stdexcept> // Include stdexcept declarations.
8#include <type_traits> // Include type_traits declarations.
9#include <cfenv> // Include cfenv declarations.
10
11namespace g = shdr::glsl; // Group these helpers within their namespace.
12static void require(bool condition, const char* message) { // Check that this operation satisfies the expected behavior.
13 if (!condition) // Check this condition before entering the following branch.
14 throw std::runtime_error(message); // Report this failed operation.
15} // End this block.
16static bool near(double a, double b, double tolerance = 1e-5) { // Set tolerance from this expression.
17 return std::abs(a - b) < tolerance; // Return std::abs(a - b) < tolerance.
18} // End this block.
19template <class T, std::size_t N> // Accept the value types or dimensions used by this template.
20static bool near(const g::vec<T, N>& a, const g::vec<T, N>& b, double tolerance = 1e-5) { // Set tolerance from this expression.
21 for (std::size_t i = 0; i < N; ++i) // Iterate over i for this calculation.
22 if (!near(a[i], b[i], tolerance)) // Check this condition before entering the following branch.
23 return false; // Return false.
24 return true; // Return true.
25} // End this block.
26template <class T, std::size_t C, std::size_t R> // Accept the value types or dimensions used by this template.
27static bool near(const g::mat<T, C, R>& a, const g::mat<T, C, R>& b, double tolerance = 1e-5) { // Set tolerance from this expression.
28 for (std::size_t c = 0; c < C; ++c) // Iterate over c for this calculation.
29 if (!near(a[c], b[c], tolerance)) // Check this condition before entering the following branch.
30 return false; // Return false.
31 return true; // Return true.
32} // End this block.
33
34static void vectors() { // Implement vectors for the operations below.
35 static_assert(sizeof(g::vec2) == 8, "vec2 packed layout"); // Verify this invariant before proceeding.
36 static_assert(sizeof(g::vec3) == 12, "vec3 packed host layout"); // Verify this invariant before proceeding.
37 static_assert(sizeof(g::vec4) == 16, "vec4 packed layout"); // Verify this invariant before proceeding.
38 static_assert(sizeof(g::uvec4) == 16, "uvec4 packed layout"); // Verify this invariant before proceeding.
39 static_assert(sizeof(g::uint) == 4, "portable GLSL unsigned scalar"); // Verify this invariant before proceeding.
40 static_assert(std::is_standard_layout<g::vec4>::value, "standard layout vectors"); // Verify this invariant before proceeding.
41 static_assert(std::is_trivially_copyable<g::vec4>::value, "trivially copyable vectors"); // Verify this invariant before proceeding.
42 require(g::vec4() == g::vec4(0), "value initialization"); // Check that this operation satisfies the expected behavior.
43 require(g::vec4(2) == g::vec4(2, 2, 2, 2), "scalar broadcast"); // Check that this operation satisfies the expected behavior.
44 require(g::vec4(g::vec2(1, 2), 3, 4) == g::vec4(1, 2, 3, 4), "flatten vector/scalars"); // Check that this operation satisfies the expected behavior.
45 require(g::vec4(1, g::vec2(2, 3), 4) == g::vec4(1, 2, 3, 4), "flatten mixed components"); // Check that this operation satisfies the expected behavior.
46 require(g::vec3(g::vec2(1, 2), g::vec2(3, 4)) == g::vec3(1, 2, 3), // Check that this operation satisfies the expected behavior.
47 "truncate the final vector constructor argument"); // Provide this text argument for the operation above.
48 require(g::vec4(1, 2, g::vec4(3, 4, 5, 6)) == g::vec4(1, 2, 3, 4), // Check that this operation satisfies the expected behavior.
49 "flatten and truncate tail components"); // Provide this text argument for the operation above.
50 require(g::vec3(g::ivec4(1, 2, 3, 4)) == g::vec3(1, 2, 3), "convert and truncate"); // Check that this operation satisfies the expected behavior.
51 require(g::bvec4(g::vec2(0, -1), g::ivec2(3, 0)) == g::bvec4(false, true, true, false), // Check that this operation satisfies the expected behavior.
52 "boolean conversion"); // Provide this text argument for the operation above.
53 g::vec4 v(1, 2, 3, 4); // Construct v with these initial values.
54 v.swizzle<0>() = 1; // Continue the expression using v, swizzle.
55 require(v.swizzle<0>() == v.x, "scalar swizzle read/write"); // Check that this operation satisfies the expected behavior.
56 require(v.r() == 1 && v.g() == 2 && v.b() == 3 && v.a() == 4, "color accessors"); // Check that this operation satisfies the expected behavior.
57 require(v.s() == 1 && v.t() == 2 && v.p() == 3 && v.q() == 4, "texture accessors"); // Check that this operation satisfies the expected behavior.
58 require(g::vec2(v.swizzle<3, 3>()) == g::vec2(4), "duplicate swizzle read"); // Check that this operation satisfies the expected behavior.
59 v.swizzle<0, 1>() = v.swizzle<1, 0>(); // Continue the expression using v, swizzle, v.
60 require(v == g::vec4(2, 1, 3, 4), "alias-safe swizzle assignment"); // Check that this operation satisfies the expected behavior.
61 v.swizzle<0, 2>() = 8; // Continue the expression using v, swizzle.
62 require(v == g::vec4(8, 1, 8, 4), "scalar swizzle assignment"); // Check that this operation satisfies the expected behavior.
63 v.swizzle<0, 1>() += v.swizzle<1, 0>(); // Continue the expression using v, swizzle, v.
64 require(v == g::vec4(9, 9, 8, 4), "alias-safe swizzle compound assignment"); // Check that this operation satisfies the expected behavior.
65 g::vec2 q(1, 2); // Construct q with these initial values.
66 q += q.swizzle<1, 0>(); // Update q with this contribution.
67 require(q == g::vec2(3, 3), "vector compound assignment snapshots alias"); // Check that this operation satisfies the expected behavior.
68 require(v.swizzle<0, 1>() * 2.0f == g::vec2(18), "swizzle expression arithmetic"); // Check that this operation satisfies the expected behavior.
69 const g::vec4 constant(1, 2, 3, 4); // Construct constant with these initial values.
70 require(constant.swizzle<3, 2, 1, 0>() == g::vec4(4, 3, 2, 1), "const swizzle copies values"); // Check that this operation satisfies the expected behavior.
71 require(g::vec4(v.swizzle<0, 1>(), constant.swizzle<2, 3>()) == g::vec4(9, 9, 3, 4), // Check that this operation satisfies the expected behavior.
72 "swizzle constructor flattening"); // Provide this text argument for the operation above.
73 require(g::vec3(1, 2, 3) + g::vec3(4, 5, 6) == g::vec3(5, 7, 9), "vector addition"); // Check that this operation satisfies the expected behavior.
74 require(2.0f * g::vec2(3, 4) == g::vec2(6, 8), "scalar-left multiply"); // Check that this operation satisfies the expected behavior.
75 require(12.0f / g::vec2(3, 4) == g::vec2(4, 3), "scalar-left divide"); // Check that this operation satisfies the expected behavior.
76 require(g::ivec2(5, 9) % 4 == g::ivec2(1), "integer remainder"); // Check that this operation satisfies the expected behavior.
77 require((g::uvec2(1, 2) << 3) == g::uvec2(8, 16), "integer shifts"); // Check that this operation satisfies the expected behavior.
78 require((g::ivec2(5, 6) & 3) == g::ivec2(1, 2), "integer and"); // Check that this operation satisfies the expected behavior.
79 require((~g::uvec2(0)) == g::uvec2(UINT32_MAX), "integer complement"); // Check that this operation satisfies the expected behavior.
80 require(g::all(g::equal(g::vec2(1), g::vec2(1))), "component equality"); // Check that this operation satisfies the expected behavior.
81 require(g::any(g::lessThan(g::vec2(1, 5), g::vec2(2, 4))), "component ordering"); // Check that this operation satisfies the expected behavior.
82 require(g::logicalNot(g::bvec2(true, false)) == g::bvec2(false, true), "logical not"); // Check that this operation satisfies the expected behavior.
83} // End this block.
84
85static void geometry_and_common() { // Implement geometry and common for the operations below.
86 require(near(g::cross(g::vec3(1, 0, 0), g::vec3(0, 1, 0)), g::vec3(0, 0, 1)), "cross product"); // Check that this operation satisfies the expected behavior.
87 require(near(g::cross(g::vec3(2, 3, 4), g::vec3(5, 6, 7)), g::vec3(-3, 6, -3)), // Check that this operation satisfies the expected behavior.
88 "general cross product"); // Provide this text argument for the operation above.
89 g::vec4 cross_lhs(2, 3, 4, 0), cross_rhs(5, 6, 7, 0); // Construct cross lhs with these initial values.
90 require(g::cross(cross_lhs.swizzle<0, 1, 2>(), cross_rhs.swizzle<0, 1, 2>()) == // Check that this operation satisfies the expected behavior.
91 g::vec3(-3, 6, -3), // Apply vec3 to these arguments.
92 "cross swizzle expressions"); // Provide this text argument for the operation above.
93 require(near(g::dot(g::vec3(1, 2, 3), g::vec3(4, 5, 6)), 32), "dot product"); // Check that this operation satisfies the expected behavior.
94 require(near(g::length(g::vec2(3, 4)), 5), "length"); // Check that this operation satisfies the expected behavior.
95 require(near(g::normalize(g::vec2(3, 4)), g::vec2(0.6f, 0.8f)), "normalize"); // Check that this operation satisfies the expected behavior.
96 require(near(g::length(-3.0f), 3), "scalar length"); // Check that this operation satisfies the expected behavior.
97 require(near(g::distance(g::vec2(1, 1), g::vec2(4, 5)), 5), "distance"); // Check that this operation satisfies the expected behavior.
98 require(g::reflect(g::vec3(1, -1, 0), g::vec3(0, 1, 0)) == g::vec3(1, 1, 0), "reflect"); // Check that this operation satisfies the expected behavior.
99 require(g::faceforward(g::vec3(0, 1, 0), g::vec3(0, 1, 0), g::vec3(0, 1, 0)) == // Check that this operation satisfies the expected behavior.
100 g::vec3(0, -1, 0), // Apply vec3 to these arguments.
101 "faceforward"); // Provide this text argument for the operation above.
102 require(near(g::refract(g::vec2(0, -1), g::vec2(0, 1), 0.5f), g::vec2(0, -1)), // Check that this operation satisfies the expected behavior.
103 "refract normal incidence"); // Provide this text argument for the operation above.
104 require(g::refract(g::vec2(1, 0), g::vec2(0, 1), 2.0f) == g::vec2(0), // Check that this operation satisfies the expected behavior.
105 "total internal reflection"); // Provide this text argument for the operation above.
106 require(near(g::mod(-3.5f, 2.0f), 0.5), "GLSL mod negative dividend"); // Check that this operation satisfies the expected behavior.
107 require(near(g::mod(3.5f, -2.0f), -0.5), "GLSL mod negative divisor"); // Check that this operation satisfies the expected behavior.
108 require(near(g::mod(g::vec2(-3.5f, 4.5f), 2.0f), g::vec2(0.5f)), "vector mod"); // Check that this operation satisfies the expected behavior.
109 require(near(g::fract(-1.25f), 0.75), "negative fract"); // Check that this operation satisfies the expected behavior.
110 require(g::roundEven(g::vec4(0.5f, 1.5f, 2.5f, -1.5f)) == g::vec4(0, 2, 2, -2), "ties to even"); // Check that this operation satisfies the expected behavior.
111 int rounding = std::fegetround(); // Set rounding from this expression.
112 if (std::fesetround(FE_UPWARD) == 0) { // Check this condition before entering the following branch.
113 bool same = g::roundEven(g::vec4(0.5f, 1.5f, 2.5f, -1.5f)) == g::vec4(0, 2, 2, -2); // Set same from this expression.
114 std::fesetround(rounding); // Apply fesetround to these arguments.
115 require(same, "roundEven independent of ambient rounding mode"); // Check that this operation satisfies the expected behavior.
116 } // End this block.
117 require(g::clamp(g::vec3(-1, 0.5f, 2), 0.0f, 1.0f) == g::vec3(0, 0.5f, 1), "clamp"); // Check that this operation satisfies the expected behavior.
118 require(std::signbit(g::min(-0.0f, 0.0f)) && std::signbit(g::max(-0.0f, 0.0f)), // Check that this operation satisfies the expected behavior.
119 "min/max equality preserve first argument"); // Provide this text argument for the operation above.
120 require(near(g::mix(g::vec2(2), g::vec2(4), 0.25f), g::vec2(2.5f)), "mix numeric"); // Check that this operation satisfies the expected behavior.
121 require(near(g::mix(g::vec2(2), g::vec2(4), 0.25), g::vec2(2.5f)), // Check that this operation satisfies the expected behavior.
122 "mix C++ double literal remains numeric"); // Provide this text argument for the operation above.
123 require(near(g::mix(2.0f, 4.0f, 0.25), 2.5), "scalar mix double literal remains numeric"); // Check that this operation satisfies the expected behavior.
124 require(g::mix(g::ivec2(2, 3), g::ivec2(4, 5), g::bvec2(true, false)) == g::ivec2(4, 3), // Check that this operation satisfies the expected behavior.
125 "mix boolean"); // Provide this text argument for the operation above.
126 require(g::step(1.0f, g::vec2(0.5f, 1.0f)) == g::vec2(0, 1), "step scalar edge"); // Check that this operation satisfies the expected behavior.
127 require(near(g::smoothstep(0.0f, 1.0f, g::vec3(0, 0.5f, 1)), g::vec3(0, 0.5f, 1)), // Check that this operation satisfies the expected behavior.
128 "smoothstep"); // Provide this text argument for the operation above.
129 require(near(g::degrees(g::radians(g::vec2(90, 180))), g::vec2(90, 180)), "angle conversions"); // Check that this operation satisfies the expected behavior.
130 require(near(g::atan(g::vec2(1, -1), g::vec2(0)), g::vec2(1.57079633f, -1.57079633f)), // Check that this operation satisfies the expected behavior.
131 "atan quadrant"); // Provide this text argument for the operation above.
132 require(near(g::pow(g::vec2(2, 3), 2.0f), g::vec2(4, 9)), "vector power"); // Check that this operation satisfies the expected behavior.
133 require(near(g::inversesqrt(g::vec2(4, 16)), g::vec2(0.5f, 0.25f)), "inverse square root"); // Check that this operation satisfies the expected behavior.
134 g::vec2 integer; // Declare integer for the following calculation.
135 require(g::modf(g::vec2(-1.25f, 2.5f), integer) == g::vec2(-0.25f, 0.5f) && // Check that this operation satisfies the expected behavior.
136 integer == g::vec2(-1, 2), // Apply vec2 to these arguments.
137 "modf outputs"); // Provide this text argument for the operation above.
138 g::vec2 alias(-1.25f, 2.5f); // Construct alias with these initial values.
139 g::vec2 fraction = g::modf(alias.swizzle<1, 0>(), alias.swizzle<0, 1>()); // Set fraction from this expression.
140 require(fraction == g::vec2(0.5f, -0.25f) && alias == g::vec2(2, -1), // Check that this operation satisfies the expected behavior.
141 "modf swizzle outputs snapshot aliased input"); // Provide this text argument for the operation above.
142 g::ivec2 exponent; // Declare exponent for the following calculation.
143 g::vec2 mantissa = g::frexp(g::vec2(4, 0.125f), exponent); // Set mantissa from this expression.
144 require(g::ldexp(mantissa, exponent) == g::vec2(4, 0.125f), "frexp/ldexp"); // Check that this operation satisfies the expected behavior.
145 g::ivec4 powers; // Declare powers for the following calculation.
146 g::vec4 frexp_input(4, 0.125f, 8, 0.25f); // Construct frexp input with these initial values.
147 g::vec2 significands = g::frexp(frexp_input.swizzle<0, 1>(), powers.swizzle<3, 2>()); // Set significands from this expression.
148 require(g::ldexp(significands, powers.swizzle<3, 2>()) == g::vec2(4, 0.125f), // Check that this operation satisfies the expected behavior.
149 "frexp and ldexp swizzle arguments"); // Provide this text argument for the operation above.
150 require(g::isinf(g::vec2(std::numeric_limits<float>::infinity(), 1)) == g::bvec2(true, false), // Check that this operation satisfies the expected behavior.
151 "isinf mask"); // Provide this text argument for the operation above.
152 require(g::isnan(g::vec2(std::numeric_limits<float>::quiet_NaN(), 1)) == g::bvec2(true, false), // Check that this operation satisfies the expected behavior.
153 "isnan mask"); // Provide this text argument for the operation above.
154} // End this block.
155
156static void matrices() { // Implement matrices for the operations below.
157 g::mat2 a(1, 2, 3, 4); // Construct a with these initial values.
158 require(g::vec4(a) == g::vec4(1, 2, 3, 4), "matrix to vector constructor column order"); // Check that this operation satisfies the expected behavior.
159 require(g::vec4(9, a) == g::vec4(9, 1, 2, 3), "mixed matrix/vector component construction"); // Check that this operation satisfies the expected behavior.
160 require(g::mat2(g::vec4(1, 2, 3, 4)) == a, "single vector matrix constructor"); // Check that this operation satisfies the expected behavior.
161 require(g::mat2(g::vec3(1, 2, 3), g::vec2(4, 5)) == a, // Check that this operation satisfies the expected behavior.
162 "matrix constructor discards final excess component"); // Provide this text argument for the operation above.
163 require(g::scalar_cast<float>(g::vec3(5, 6, 7)) == 5, "vector to scalar constructor"); // Check that this operation satisfies the expected behavior.
164 require(g::scalar_cast<int>(a) == 1, "matrix to scalar constructor"); // Check that this operation satisfies the expected behavior.
165 require(g::scalar_cast<g::uint>(-1) == UINT32_MAX, "signed to unsigned scalar constructor"); // Check that this operation satisfies the expected behavior.
166 const std::size_t& vector_length = g::vec4::length_value; // Set vector length from this expression.
167 const std::size_t& column_count = g::mat2::columns; // Set column count from this expression.
168 require(vector_length == 4 && column_count == 2, "public dimension constants have definitions"); // Check that this operation satisfies the expected behavior.
169 require(a[0] == g::vec2(1, 2) && a[1] == g::vec2(3, 4), "matrix column order"); // Check that this operation satisfies the expected behavior.
170 require(a * g::vec2(2, 3) == g::vec2(11, 16), "matrix-vector multiplication"); // Check that this operation satisfies the expected behavior.
171 g::vec4 vector(2, 3, 2, 3); // Construct vector with these initial values.
172 require(a * vector.swizzle<0, 1>() == g::vec2(11, 16), "matrix-swizzle multiplication"); // Check that this operation satisfies the expected behavior.
173 require(vector.swizzle<2, 3>() * a == g::vec2(8, 18), "swizzle-matrix multiplication"); // Check that this operation satisfies the expected behavior.
174 require(g::vec2(2, 3) * a == g::vec2(8, 18), "vector-matrix multiplication"); // Check that this operation satisfies the expected behavior.
175 require(a * g::mat2(1) == a, "matrix multiplication identity"); // Check that this operation satisfies the expected behavior.
176 require(a * a == g::mat2(7, 10, 15, 22), "matrix algebra multiplication"); // Check that this operation satisfies the expected behavior.
177 require(near(g::determinant(a), -2), "determinant 2x2"); // Check that this operation satisfies the expected behavior.
178 require(near(a * g::inverse(a), g::mat2(1)), "inverse 2x2"); // Check that this operation satisfies the expected behavior.
179 require(g::transpose(a) == g::mat2(1, 3, 2, 4), "transpose"); // Check that this operation satisfies the expected behavior.
180 require(g::matrixCompMult(a, a) == g::mat2(1, 4, 9, 16), "component matrix multiply"); // Check that this operation satisfies the expected behavior.
181 require(g::outerProduct(g::vec3(1, 2, 3), g::vec2(4, 5)) == g::mat2x3(4, 8, 12, 5, 10, 15), // Check that this operation satisfies the expected behavior.
182 "outer product columns"); // Provide this text argument for the operation above.
183 g::mat3x2 rectangular(1, 2, 3, 4, 5, 6); // Construct rectangular with these initial values.
184 require(rectangular * g::mat2x3(1, 0, 0, 0, 1, 0) == g::mat2(1, 2, 3, 4), // Check that this operation satisfies the expected behavior.
185 "rectangular multiplication"); // Provide this text argument for the operation above.
186 require(g::transpose(rectangular) == g::mat2x3(1, 3, 5, 2, 4, 6), "rectangular transpose"); // Check that this operation satisfies the expected behavior.
187 require(g::mat3(a) == g::mat3(1, 2, 0, 3, 4, 0, 0, 0, 1), "matrix conversion identity fill"); // Check that this operation satisfies the expected behavior.
188 g::mat3 b(3, 1, 3, 5, 5, 9, 2, 8, 2); // Construct b with these initial values.
189 require(near(g::determinant(b), -88), "determinant 3x3"); // Check that this operation satisfies the expected behavior.
190 require(near(b * g::inverse(b), g::mat3(1)), "inverse 3x3"); // Check that this operation satisfies the expected behavior.
191 g::mat4 c(0, 2, 0, 0, 1, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4); // Construct c with these initial values.
192 require(near(g::determinant(c), -24), "determinant 4x4 pivot exchange"); // Check that this operation satisfies the expected behavior.
193 require(near(c * g::inverse(c), g::mat4(1)), "inverse 4x4 pivot exchange"); // Check that this operation satisfies the expected behavior.
194 require(g::all(g::isnan(g::inverse(g::mat2(0))[0])), "singular host inverse NaNs"); // Check that this operation satisfies the expected behavior.
195 require(a + 2 == g::mat2(3, 4, 5, 6), "matrix scalar addition"); // Check that this operation satisfies the expected behavior.
196 require(5 - a == g::mat2(4, 3, 2, 1), "scalar matrix subtraction"); // Check that this operation satisfies the expected behavior.
197 require(12 / g::mat2(2, 3, 4, 6) == g::mat2(6, 4, 3, 2), "scalar matrix division"); // Check that this operation satisfies the expected behavior.
198 a *= g::mat2(1); // Update a with this contribution.
199 require(a == g::mat2(1, 2, 3, 4), "compound matrix multiplication"); // Check that this operation satisfies the expected behavior.
200} // End this block.
201
202static void arrays() { // Implement arrays for the operations below.
203 g::array<float, 4> values(1, 2, 3, 4); // Construct values with these initial values.
204 require(values.length() == 4 && values[2] == 3, "fixed array construction and length"); // Check that this operation satisfies the expected behavior.
205 g::array<float, 4> zero; // Declare zero for the following calculation.
206 require(zero[0] == 0 && zero[3] == 0, "fixed array zero initialization"); // Check that this operation satisfies the expected behavior.
207 g::array<float, 4> copy = values; // Set copy from this expression.
208 copy[0] = 7; // Set copy[0] from this expression.
209 require(values[0] == 1 && copy[0] == 7, "array copy is independent"); // Check that this operation satisfies the expected behavior.
210 zero = values; // Set zero from this expression.
211 require(zero == values && zero != copy, "whole-array assignment and equality"); // Check that this operation satisfies the expected behavior.
212 g::array<g::vec2, 2> vectors(g::vec2(1, 2), g::vec2(3, 4)); // Construct vectors with these initial values.
213 require(vectors[1] == g::vec2(3, 4), "array vector elements are not flattened"); // Check that this operation satisfies the expected behavior.
214 g::array<int, 3> braces = {1, 2, 3}; // Set braces from this expression.
215 require(braces[2] == 3, "array brace initialization"); // Check that this operation satisfies the expected behavior.
216 const std::size_t& count = g::array<int, 3>::size_value; // Set count from this expression.
217 require(count == 3, "array dimension constant has a definition"); // Check that this operation satisfies the expected behavior.
218 bool mismatch = false; // Set mismatch from this expression.
219 try { // Run the operation while retaining the error handling below.
220 g::array<int, 3> invalid = {1, 2}; // Set invalid from this expression.
221 (void)invalid; // Continue the expression using void, invalid.
222 } catch (const std::invalid_argument&) { // Report the exception from the preceding operation.
223 mismatch = true; // Set mismatch from this expression.
224 } // End this block.
225 require(mismatch, "array initializer list rejects wrong element count"); // Check that this operation satisfies the expected behavior.
226} // End this block.
227
228static void bits_and_packing() { // Implement bits and packing for the operations below.
229 require(g::floatBitsToUint(1.0f) == 0x3f800000u, "float bit encoding"); // Check that this operation satisfies the expected behavior.
230 require(g::uintBitsToFloat(0xbf800000u) == -1.0f, "float bit decoding"); // Check that this operation satisfies the expected behavior.
231 require(g::uintBitsToFloat(g::floatBitsToUint(g::vec2(1, -1))) == g::vec2(1, -1), // Check that this operation satisfies the expected behavior.
232 "vector bit roundtrip"); // Provide this text argument for the operation above.
233 require(g::bitCount(g::ivec2(-1, 5)) == g::ivec2(32, 2), "bit counts"); // Check that this operation satisfies the expected behavior.
234 require(g::findLSB(g::uvec3(0, 8, 0x80000000u)) == g::ivec3(-1, 3, 31), // Check that this operation satisfies the expected behavior.
235 "least significant set bits"); // Provide this text argument for the operation above.
236 require(g::findMSB(g::ivec4(0, -1, -2, 16)) == g::ivec4(-1, -1, 0, 4), // Check that this operation satisfies the expected behavior.
237 "signed most significant bit semantics"); // Provide this text argument for the operation above.
238 require(g::bitfieldReverse(1u) == 0x80000000u, "bit reversal"); // Check that this operation satisfies the expected behavior.
239 require(g::bitfieldExtract(std::int32_t(0xf0), 4, 4) == -1, "signed bitfield extension"); // Check that this operation satisfies the expected behavior.
240 require(g::bitfieldExtract(std::uint32_t(0xf0), 4, 4) == 15u, "unsigned bitfield extraction"); // Check that this operation satisfies the expected behavior.
241 require(g::bitfieldExtract(std::int32_t(-2), 0, 32) == -2, "full signed field"); // Check that this operation satisfies the expected behavior.
242 require(g::bitfieldExtract(3u, 32, 0) == 0u, "empty bitfield"); // Check that this operation satisfies the expected behavior.
243 require(g::bitfieldInsert(0xff00u, 3u, 0, 4) == 0xff03u, "bitfield insertion"); // Check that this operation satisfies the expected behavior.
244 std::uint32_t carry, borrow, hi, lo; // Declare carry for the following calculation.
245 require(g::uaddCarry(UINT32_MAX, 2u, carry) == 1u && carry == 1u, "unsigned carry"); // Check that this operation satisfies the expected behavior.
246 g::uvec4 vector_carry(UINT32_MAX, 1, 0, 0); // Construct vector carry with these initial values.
247 g::uvec2 vector_sum = // Set vector sum from this expression.
248 g::uaddCarry(vector_carry.swizzle<0, 1>(), g::uvec2(2, 3), vector_carry.swizzle<1, 0>()); // Apply uadd Carry to these arguments.
249 require(vector_sum == g::uvec2(1, 4) && vector_carry.swizzle<0, 1>() == g::uvec2(0, 1), // Check that this operation satisfies the expected behavior.
250 "vector carry with aliased swizzle output"); // Provide this text argument for the operation above.
251 require(g::usubBorrow(0u, 1u, borrow) == UINT32_MAX && borrow == 1u, "unsigned borrow"); // Check that this operation satisfies the expected behavior.
252 g::umulExtended(UINT32_MAX, UINT32_MAX, hi, lo); // Apply umul Extended to these arguments.
253 require(hi == UINT32_MAX - 1u && lo == 1u, "unsigned extended product"); // Check that this operation satisfies the expected behavior.
254 g::uvec4 product; // Declare product for the following calculation.
255 g::umulExtended(g::uvec2(UINT32_MAX), // Apply umul Extended to these arguments.
256 g::uvec2(UINT32_MAX), // Apply uvec2 to these arguments.
257 product.swizzle<0, 1>(), // Continue the expression using product, swizzle.
258 product.swizzle<2, 3>()); // Continue the expression using product, swizzle.
259 require(product == g::uvec4(UINT32_MAX - 1u, UINT32_MAX - 1u, 1u, 1u), // Check that this operation satisfies the expected behavior.
260 "extended vector product swizzle outputs"); // Provide this text argument for the operation above.
261 std::int32_t signed_hi, signed_lo; // Declare signed hi for the following calculation.
262 g::imulExtended(-1, 2, signed_hi, signed_lo); // Apply imul Extended to these arguments.
263 require(signed_hi == -1 && signed_lo == -2, "signed extended product"); // Check that this operation satisfies the expected behavior.
264 require(g::packUnorm2x16(g::vec2(0, 1)) == 0xffff0000u, "pack normalized halves"); // Check that this operation satisfies the expected behavior.
265 require(g::unpackUnorm2x16(0xffff0000u) == g::vec2(0, 1), "unpack normalized halves"); // Check that this operation satisfies the expected behavior.
266 require(near(g::unpackSnorm2x16(g::packSnorm2x16(g::vec2(-1, 1))), g::vec2(-1, 1)), // Check that this operation satisfies the expected behavior.
267 "signed normalized halves"); // Provide this text argument for the operation above.
268 require(g::packUnorm4x8(g::vec4(1, 0, 1, 0)) == 0x00ff00ffu, "packed byte order"); // Check that this operation satisfies the expected behavior.
269 require(near(g::unpackSnorm4x8(g::packSnorm4x8(g::vec4(-1, 0, 1, 0))), g::vec4(-1, 0, 1, 0)), // Check that this operation satisfies the expected behavior.
270 "signed normalized bytes"); // Provide this text argument for the operation above.
271 require(g::packHalf2x16(g::vec2(1, -2)) == 0xc0003c00u, "half bit encoding"); // Check that this operation satisfies the expected behavior.
272 require(g::unpackHalf2x16(0xc0003c00u) == g::vec2(1, -2), "half bit decoding"); // Check that this operation satisfies the expected behavior.
273 require(g::unpackHalf2x16(g::packHalf2x16(g::vec2(65504, 0.00006103515625f))) == // Check that this operation satisfies the expected behavior.
274 g::vec2(65504, 0.00006103515625f), // Apply vec2 to these arguments.
275 "half finite limits"); // Provide this text argument for the operation above.
276 require(g::unpackHalf2x16(g::packHalf2x16(g::vec2(0.000000059604644775390625f, 0))) == // Check that this operation satisfies the expected behavior.
277 g::vec2(0.000000059604644775390625f, 0), // Apply vec2 to these arguments.
278 "half subnormal"); // Provide this text argument for the operation above.
279 require(g::packHalf2x16(g::vec2(1.00048828125f, 1.00146484375f)) == 0x3c023c00u, // Check that this operation satisfies the expected behavior.
280 "half ties to even"); // Provide this text argument for the operation above.
281 require(g::isinf(g::unpackHalf2x16(g::packHalf2x16( // Check that this operation satisfies the expected behavior.
282 g::vec2(std::numeric_limits<float>::infinity())))) == g::bvec2(true), // Apply vec2 to these arguments.
283 "half infinities"); // Provide this text argument for the operation above.
284} // End this block.
285
286int main() { // Run this example and validate its results.
287 try { // Run the operation while retaining the error handling below.
288 vectors(); // Apply vectors to these arguments.
289 geometry_and_common(); // Apply geometry and common to these arguments.
290 matrices(); // Apply matrices to these arguments.
291 arrays(); // Apply arrays to these arguments.
292 bits_and_packing(); // Apply bits and packing to these arguments.
293 std::cout << "GLSL math checks passed\n"; // Write this part of the example result or diagnostic.
294 } catch (const std::exception& e) { // Report the exception from the preceding operation.
295 std::cerr << "GLSL math check failed: " << e.what() << '\n'; // Write this part of the example result or diagnostic.
296 return 1; // Report a failed check or operation.
297 } // End this block.
298} // End this block.