| // Copyright 2013 The Flutter Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef FLUTTER_IMPELLER_GEOMETRY_HALF_H_ |
| #define FLUTTER_IMPELLER_GEOMETRY_HALF_H_ |
| |
| #include <cstdint> |
| |
| #include "flutter/fml/build_config.h" |
| |
| #include "impeller/geometry/color.h" |
| #include "impeller/geometry/point.h" |
| #include "impeller/geometry/scalar.h" |
| #include "impeller/geometry/vector.h" |
| |
| // NOLINTBEGIN(google-explicit-constructor) |
| |
| #if defined(FML_OS_MACOSX) || defined(FML_OS_IOS) || \ |
| defined(FML_OS_IOS_SIMULATOR) |
| using InternalHalf = _Float16; |
| #else |
| using InternalHalf = uint16_t; |
| #endif |
| |
| namespace impeller { |
| |
| /// @brief Convert a scalar to a half precision float. |
| /// |
| /// See also: https://clang.llvm.org/docs/LanguageExtensions.html |
| /// This is not currently supported on Windows toolchains. |
| inline constexpr InternalHalf ScalarToHalf(Scalar f) { |
| #ifdef FML_OS_WIN |
| return static_cast<InternalHalf>(0); |
| #else |
| return static_cast<InternalHalf>(f); |
| #endif |
| } |
| |
| /// @brief A storage only class for half precision floating point. |
| struct Half { |
| InternalHalf x = 0; |
| |
| constexpr Half() {} |
| |
| constexpr Half(double value) : x(ScalarToHalf(static_cast<Scalar>(value))) {} |
| |
| constexpr Half(Scalar value) : x(ScalarToHalf(value)) {} |
| |
| constexpr Half(int value) : x(ScalarToHalf(static_cast<Scalar>(value))) {} |
| |
| constexpr Half(InternalHalf x) : x(x) {} |
| |
| constexpr bool operator==(const Half& v) const { return v.x == x; } |
| |
| constexpr bool operator!=(const Half& v) const { return v.x != x; } |
| }; |
| |
| /// @brief A storage only class for half precision floating point vector 4. |
| struct HalfVector4 { |
| union { |
| struct { |
| InternalHalf x = 0; |
| InternalHalf y = 0; |
| InternalHalf z = 0; |
| InternalHalf w = 0; |
| }; |
| InternalHalf e[4]; |
| }; |
| |
| constexpr HalfVector4() {} |
| |
| constexpr HalfVector4(const Color& a) |
| : x(ScalarToHalf(a.red)), |
| y(ScalarToHalf(a.green)), |
| z(ScalarToHalf(a.blue)), |
| w(ScalarToHalf(a.alpha)) {} |
| |
| constexpr HalfVector4(const Vector4& a) |
| : x(ScalarToHalf(a.x)), |
| y(ScalarToHalf(a.y)), |
| z(ScalarToHalf(a.z)), |
| w(ScalarToHalf(a.w)) {} |
| |
| constexpr HalfVector4(InternalHalf x, |
| InternalHalf y, |
| InternalHalf z, |
| InternalHalf w) |
| : x(x), y(y), z(z), w(w) {} |
| |
| constexpr bool operator==(const HalfVector4& v) const { |
| return v.x == x && v.y == y && v.z == z && v.w == w; |
| } |
| |
| constexpr bool operator!=(const HalfVector4& v) const { |
| return v.x != x || v.y != y || v.z != z || v.w != w; |
| } |
| }; |
| |
| /// @brief A storage only class for half precision floating point vector 3. |
| struct HalfVector3 { |
| union { |
| struct { |
| InternalHalf x = 0; |
| InternalHalf y = 0; |
| InternalHalf z = 0; |
| }; |
| InternalHalf e[3]; |
| }; |
| |
| constexpr HalfVector3() {} |
| |
| constexpr HalfVector3(const Vector3& a) |
| : x(ScalarToHalf(a.x)), y(ScalarToHalf(a.y)), z(ScalarToHalf(a.z)) {} |
| |
| constexpr HalfVector3(InternalHalf x, InternalHalf y, InternalHalf z) |
| : x(x), y(y), z(z) {} |
| |
| constexpr bool operator==(const HalfVector3& v) const { |
| return v.x == x && v.y == y && v.z == z; |
| } |
| |
| constexpr bool operator!=(const HalfVector3& v) const { |
| return v.x != x || v.y != y || v.z != z; |
| } |
| }; |
| |
| /// @brief A storage only class for half precision floating point vector 2. |
| struct HalfVector2 { |
| union { |
| struct { |
| InternalHalf x = 0; |
| InternalHalf y = 0; |
| }; |
| InternalHalf e[2]; |
| }; |
| |
| constexpr HalfVector2() {} |
| |
| constexpr HalfVector2(const Vector2& a) |
| : x(ScalarToHalf(a.x)), y(ScalarToHalf(a.y)) {} |
| |
| constexpr HalfVector2(InternalHalf x, InternalHalf y) : x(x), y(y){}; |
| |
| constexpr bool operator==(const HalfVector2& v) const { |
| return v.x == x && v.y == y; |
| } |
| |
| constexpr bool operator!=(const HalfVector2& v) const { |
| return v.x != x || v.y != y; |
| } |
| }; |
| |
| static_assert(sizeof(Half) == sizeof(uint16_t)); |
| static_assert(sizeof(HalfVector2) == 2 * sizeof(Half)); |
| static_assert(sizeof(HalfVector3) == 3 * sizeof(Half)); |
| static_assert(sizeof(HalfVector4) == 4 * sizeof(Half)); |
| |
| } // namespace impeller |
| |
| namespace std { |
| |
| inline std::ostream& operator<<(std::ostream& out, const impeller::Half& p) { |
| out << "(" << static_cast<impeller::Scalar>(p.x) << ")"; |
| return out; |
| } |
| |
| inline std::ostream& operator<<(std::ostream& out, |
| const impeller::HalfVector2& p) { |
| out << "(" << static_cast<impeller::Scalar>(p.x) << ", " |
| << static_cast<impeller::Scalar>(p.y) << ")"; |
| return out; |
| } |
| |
| inline std::ostream& operator<<(std::ostream& out, |
| const impeller::HalfVector3& p) { |
| out << "(" << static_cast<impeller::Scalar>(p.x) << ", " |
| << static_cast<impeller::Scalar>(p.y) << ", " |
| << static_cast<impeller::Scalar>(p.z) << ")"; |
| return out; |
| } |
| |
| inline std::ostream& operator<<(std::ostream& out, |
| const impeller::HalfVector4& p) { |
| out << "(" << static_cast<impeller::Scalar>(p.x) << ", " |
| << static_cast<impeller::Scalar>(p.y) << ", " |
| << static_cast<impeller::Scalar>(p.z) << ", " |
| << static_cast<impeller::Scalar>(p.w) << ")"; |
| return out; |
| } |
| |
| // NOLINTEND(google-explicit-constructor) |
| |
| } // namespace std |
| |
| #endif // FLUTTER_IMPELLER_GEOMETRY_HALF_H_ |