It used to be that operations e.g. like:
float3{} + double{} would be computed as
float3{} + float3{double{}} instead of
float3{} + double3{double{}}
I other words, when an implicit conversion was involved on the right
it would be converted to the left side’s type, possibly losing
precision.
Another problem was that swiping the operands could produce different
Results, e.g.:
float3{1} * 5.0 -> float3{5.0f}
5.0 * float3{1} -> double3{5.0}
This is no longer the case, now both expressions would return a double3.
Note:
float3 r{};
r *= 5;
Is now equivalent to:
r[0] *= 5;
r[1] *= 5;
r[2] *= 5;
Instead of before:
r[0] *= 5.0f;
r[1] *= 5.0f;
r[2] *= 5.0f;
It turns out that most of libmath couldn't be used in constexpr
expression due to our use of union{}. The C++ standard requires that
all accesses to a union{} in a constexpr expression be the same
element.
Also because libm and cmath are not constexpr some functions such
as length() or normalize() can't be constexpr. The same is true for
anything needing things like sqrt, cos, sin, ceil, floor.
This change mainly does the following:
- replace all accesses to vector elements by operator[]
(this ensure all of libmath uses the same union element)
- avoid use of std::min / std::max / std::abs
- avoid uninitialized variables, which can't be constexpr
- remove 'constexpr' keyword on functions that can never be
It is now possible to write things like:
constexpr mat4f I = inverse(
transpose(mat4f::translation(float3{ 1, 2, 3 })
* mat4f::scaling(4)));