blob: d55136d5cef801643ba3153b5e9b6e7b2f495580 [file] [log] [blame]
// 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_VECTOR_H_
#define FLUTTER_IMPELLER_GEOMETRY_VECTOR_H_
#include <cmath>
#include <string>
#include "impeller/geometry/color.h"
#include "impeller/geometry/point.h"
#include "impeller/geometry/scalar.h"
#include "impeller/geometry/size.h"
namespace impeller {
// NOLINTBEGIN(google-explicit-constructor)
struct Vector3 {
union {
struct {
Scalar x = 0.0f;
Scalar y = 0.0f;
Scalar z = 0.0f;
};
Scalar e[3];
};
constexpr Vector3(){};
constexpr Vector3(const Color& c) : x(c.red), y(c.green), z(c.blue) {}
constexpr Vector3(const Point& p) : x(p.x), y(p.y) {}
constexpr Vector3(const Size& s) : x(s.width), y(s.height) {}
constexpr Vector3(Scalar x, Scalar y) : x(x), y(y) {}
constexpr Vector3(Scalar x, Scalar y, Scalar z) : x(x), y(y), z(z) {}
/**
* The length (or magnitude of the vector).
*
* @return the calculated length.
*/
constexpr Scalar Length() const { return sqrt(x * x + y * y + z * z); }
constexpr Vector3 Normalize() const {
const auto len = Length();
return {x / len, y / len, z / len};
}
constexpr Scalar Dot(const Vector3& other) const {
return ((x * other.x) + (y * other.y) + (z * other.z));
}
constexpr Vector3 Abs() const {
return {std::fabs(x), std::fabs(y), std::fabs(z)};
}
constexpr Vector3 Cross(const Vector3& other) const {
return {
(y * other.z) - (z * other.y), //
(z * other.x) - (x * other.z), //
(x * other.y) - (y * other.x) //
};
}
constexpr Vector3 Min(const Vector3& p) const {
return {std::min(x, p.x), std::min(y, p.y), std::min(z, p.z)};
}
constexpr Vector3 Max(const Vector3& p) const {
return {std::max(x, p.x), std::max(y, p.y), std::max(z, p.z)};
}
constexpr Vector3 Floor() const {
return {std::floor(x), std::floor(y), std::floor(z)};
}
constexpr Vector3 Ceil() const {
return {std::ceil(x), std::ceil(y), std::ceil(z)};
}
constexpr Vector3 Round() const {
return {std::round(x), std::round(y), std::round(z)};
}
constexpr bool operator==(const Vector3& v) const {
return v.x == x && v.y == y && v.z == z;
}
constexpr bool operator!=(const Vector3& v) const {
return v.x != x || v.y != y || v.z != z;
}
constexpr Vector3 operator+=(const Vector3& p) {
x += p.x;
y += p.y;
z += p.z;
return *this;
}
constexpr Vector3 operator-=(const Vector3& p) {
x -= p.x;
y -= p.y;
z -= p.z;
return *this;
}
constexpr Vector3 operator*=(const Vector3& p) {
x *= p.x;
y *= p.y;
z *= p.z;
return *this;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator*=(U scale) {
x *= scale;
y *= scale;
z *= scale;
return *this;
}
constexpr Vector3 operator/=(const Vector3& p) {
x /= p.x;
y /= p.y;
z /= p.z;
return *this;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator/=(U scale) {
x /= scale;
y /= scale;
z /= scale;
return *this;
}
constexpr Vector3 operator-() const { return Vector3(-x, -y, -z); }
constexpr Vector3 operator+(const Vector3& v) const {
return Vector3(x + v.x, y + v.y, z + v.z);
}
constexpr Vector3 operator-(const Vector3& v) const {
return Vector3(x - v.x, y - v.y, z - v.z);
}
constexpr Vector3 operator+(Scalar s) const {
return Vector3(x + s, y + s, z + s);
}
constexpr Vector3 operator-(Scalar s) const {
return Vector3(x - s, y - s, z - s);
}
constexpr Vector3 operator*(const Vector3& v) const {
return Vector3(x * v.x, y * v.y, z * v.z);
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator*(U scale) const {
return Vector3(x * scale, y * scale, z * scale);
}
constexpr Vector3 operator/(const Vector3& v) const {
return Vector3(x / v.x, y / v.y, z / v.z);
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator/(U scale) const {
return Vector3(x / scale, y / scale, z / scale);
}
constexpr Vector3 Lerp(const Vector3& v, Scalar t) const {
return *this + (v - *this) * t;
}
/**
* Make a linear combination of two vectors and return the result.
*
* @param a the first vector.
* @param aScale the scale to use for the first vector.
* @param b the second vector.
* @param bScale the scale to use for the second vector.
*
* @return the combined vector.
*/
static constexpr Vector3 Combine(const Vector3& a,
Scalar aScale,
const Vector3& b,
Scalar bScale) {
return {
aScale * a.x + bScale * b.x, //
aScale * a.y + bScale * b.y, //
aScale * a.z + bScale * b.z, //
};
}
std::string ToString() const;
};
// RHS algebraic operations with arithmetic types.
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator*(U s, const Vector3& p) {
return p * s;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator+(U s, const Vector3& p) {
return p + s;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator-(U s, const Vector3& p) {
return -p + s;
}
template <class U, class = std::enable_if_t<std::is_arithmetic_v<U>>>
constexpr Vector3 operator/(U s, const Vector3& p) {
return {
static_cast<Scalar>(s) / p.x,
static_cast<Scalar>(s) / p.y,
static_cast<Scalar>(s) / p.z,
};
}
struct Vector4 {
union {
struct {
Scalar x = 0.0f;
Scalar y = 0.0f;
Scalar z = 0.0f;
Scalar w = 1.0f;
};
Scalar e[4];
};
constexpr Vector4() {}
constexpr Vector4(const Color& c)
: x(c.red), y(c.green), z(c.blue), w(c.alpha) {}
constexpr Vector4(Scalar x, Scalar y, Scalar z, Scalar w)
: x(x), y(y), z(z), w(w) {}
constexpr Vector4(const Vector3& v) : x(v.x), y(v.y), z(v.z) {}
constexpr Vector4(const Point& p) : x(p.x), y(p.y) {}
constexpr Vector4(std::array<Scalar, 4> values)
: x(values[0]), y(values[1]), z(values[2]), w(values[3]) {}
Vector4 Normalize() const {
const Scalar inverse = 1.0f / sqrt(x * x + y * y + z * z + w * w);
return Vector4(x * inverse, y * inverse, z * inverse, w * inverse);
}
constexpr bool operator==(const Vector4& v) const {
return (x == v.x) && (y == v.y) && (z == v.z) && (w == v.w);
}
constexpr bool operator!=(const Vector4& v) const {
return (x != v.x) || (y != v.y) || (z != v.z) || (w != v.w);
}
constexpr Vector4 operator+(const Vector4& v) const {
return Vector4(x + v.x, y + v.y, z + v.z, w + v.w);
}
constexpr Vector4 operator-(const Vector4& v) const {
return Vector4(x - v.x, y - v.y, z - v.z, w - v.w);
}
constexpr Vector4 operator*(Scalar f) const {
return Vector4(x * f, y * f, z * f, w * f);
}
constexpr Vector4 operator*(const Vector4& v) const {
return Vector4(x * v.x, y * v.y, z * v.z, w * v.w);
}
constexpr Vector4 Min(const Vector4& p) const {
return {std::min(x, p.x), std::min(y, p.y), std::min(z, p.z),
std::min(w, p.w)};
}
constexpr Vector4 Max(const Vector4& p) const {
return {std::max(x, p.x), std::max(y, p.y), std::max(z, p.z),
std::max(w, p.w)};
}
constexpr Vector4 Floor() const {
return {std::floor(x), std::floor(y), std::floor(z), std::floor(w)};
}
constexpr Vector4 Ceil() const {
return {std::ceil(x), std::ceil(y), std::ceil(z), std::ceil(w)};
}
constexpr Vector4 Round() const {
return {std::round(x), std::round(y), std::round(z), std::round(w)};
}
constexpr Vector4 Lerp(const Vector4& v, Scalar t) const {
return *this + (v - *this) * t;
}
std::string ToString() const;
};
static_assert(sizeof(Vector3) == 3 * sizeof(Scalar));
static_assert(sizeof(Vector4) == 4 * sizeof(Scalar));
} // namespace impeller
namespace std {
inline std::ostream& operator<<(std::ostream& out, const impeller::Vector3& p) {
out << "(" << p.x << ", " << p.y << ", " << p.z << ")";
return out;
}
inline std::ostream& operator<<(std::ostream& out, const impeller::Vector4& p) {
out << "(" << p.x << ", " << p.y << ", " << p.z << ", " << p.w << ")";
return out;
}
// NOLINTEND(google-explicit-constructor)
} // namespace std
#endif // FLUTTER_IMPELLER_GEOMETRY_VECTOR_H_