/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef MATH_TVECHELPERS_H_ #define MATH_TVECHELPERS_H_ #include #include // for std:: namespace #include #include #include namespace filament { namespace math { namespace details { // ------------------------------------------------------------------------------------- template inline constexpr U min(U a, U b) noexcept { return a < b ? a : b; } template inline constexpr U max(U a, U b) noexcept { return a > b ? a : b; } template struct arithmetic_result { using type = decltype(std::declval() + std::declval()); }; template using arithmetic_result_t = typename arithmetic_result::type; template using enable_if_arithmetic_t = std::enable_if_t< is_arithmetic::value && is_arithmetic::value && is_arithmetic::value && is_arithmetic::value>; /* * No user serviceable parts here. * * Don't use this file directly, instead include math/vec{2|3|4}.h */ /* * TVec{Add|Product}Operators implements basic arithmetic and basic compound assignments * operators on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVec{Add|Product}Operators BASE will automatically * get all the functionality here. */ template class VECTOR, typename T> class TVecAddOperators { public: /* compound assignment from a another vector of the same size but different * element type. */ template constexpr VECTOR& operator+=(const VECTOR& v) { VECTOR& lhs = static_cast&>(*this); for (size_t i = 0; i < lhs.size(); i++) { lhs[i] += v[i]; } return lhs; } template> constexpr VECTOR& operator+=(U v) { return operator+=(VECTOR(v)); } template constexpr VECTOR& operator-=(const VECTOR& v) { VECTOR& lhs = static_cast&>(*this); for (size_t i = 0; i < lhs.size(); i++) { lhs[i] -= v[i]; } return lhs; } template> constexpr VECTOR& operator-=(U v) { return operator-=(VECTOR(v)); } private: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline constexpr VECTOR> MATH_PURE operator+(const VECTOR& lv, const VECTOR& rv) { VECTOR> res(lv); res += rv; return res; } template> friend inline constexpr VECTOR> MATH_PURE operator+(const VECTOR& lv, U rv) { return lv + VECTOR(rv); } template> friend inline constexpr VECTOR> MATH_PURE operator+(U lv, const VECTOR& rv) { return VECTOR(lv) + rv; } template friend inline constexpr VECTOR> MATH_PURE operator-(const VECTOR& lv, const VECTOR& rv) { VECTOR> res(lv); res -= rv; return res; } template> friend inline constexpr VECTOR> MATH_PURE operator-(const VECTOR& lv, U rv) { return lv - VECTOR(rv); } template> friend inline constexpr VECTOR> MATH_PURE operator-(U lv, const VECTOR& rv) { return VECTOR(lv) - rv; } }; template class VECTOR, typename T> class TVecProductOperators { public: /* compound assignment from a another vector of the same size but different * element type. */ template constexpr VECTOR& operator*=(const VECTOR& v) { VECTOR& lhs = static_cast&>(*this); for (size_t i = 0; i < lhs.size(); i++) { lhs[i] *= v[i]; } return lhs; } template> constexpr VECTOR& operator*=(U v) { return operator*=(VECTOR(v)); } template constexpr VECTOR& operator/=(const VECTOR& v) { VECTOR& lhs = static_cast&>(*this); for (size_t i = 0; i < lhs.size(); i++) { lhs[i] /= v[i]; } return lhs; } template> constexpr VECTOR& operator/=(U v) { return operator/=(VECTOR(v)); } private: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline constexpr VECTOR> MATH_PURE operator*(const VECTOR& lv, const VECTOR& rv) { VECTOR> res(lv); res *= rv; return res; } template> friend inline constexpr VECTOR> MATH_PURE operator*(const VECTOR& lv, U rv) { return lv * VECTOR(rv); } template> friend inline constexpr VECTOR> MATH_PURE operator*(U lv, const VECTOR& rv) { return VECTOR(lv) * rv; } template friend inline constexpr VECTOR> MATH_PURE operator/(const VECTOR& lv, const VECTOR& rv) { VECTOR> res(lv); res /= rv; return res; } template> friend inline constexpr VECTOR> MATH_PURE operator/(const VECTOR& lv, U rv) { return lv / VECTOR(rv); } template> friend inline constexpr VECTOR> MATH_PURE operator/(U lv, const VECTOR& rv) { return VECTOR(lv) / rv; } }; /* * TVecUnaryOperators implements unary operators on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecUnaryOperators BASE will automatically * get all the functionality here. * * These operators are implemented as friend functions of TVecUnaryOperators */ template class VECTOR, typename T> class TVecUnaryOperators { public: constexpr VECTOR operator-() const { VECTOR r{}; VECTOR const& rv(static_cast const&>(*this)); for (size_t i = 0; i < r.size(); i++) { r[i] = -rv[i]; } return r; } }; /* * TVecComparisonOperators implements relational/comparison operators * on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecComparisonOperators BASE will automatically * get all the functionality here. */ template class VECTOR, typename T> class TVecComparisonOperators { private: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend inline constexpr bool MATH_PURE operator==(const VECTOR& lv, const VECTOR& rv) { // w/ inlining we end-up with many branches that will pollute the BPU cache MATH_NOUNROLL for (size_t i = 0; i < lv.size(); i++) { if (lv[i] != rv[i]) { return false; } } return true; } template friend inline constexpr bool MATH_PURE operator!=(const VECTOR& lv, const VECTOR& rv) { return !operator==(lv, rv); } template friend inline constexpr VECTOR MATH_PURE equal(const VECTOR& lv, const VECTOR& rv) { VECTOR r{}; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] == rv[i]; } return r; } template friend inline constexpr VECTOR MATH_PURE notEqual(const VECTOR& lv, const VECTOR& rv) { VECTOR r{}; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] != rv[i]; } return r; } template friend inline constexpr VECTOR MATH_PURE lessThan(const VECTOR& lv, const VECTOR& rv) { VECTOR r{}; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] < rv[i]; } return r; } template friend inline constexpr VECTOR MATH_PURE lessThanEqual(const VECTOR& lv, const VECTOR& rv) { VECTOR r{}; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] <= rv[i]; } return r; } template friend inline constexpr VECTOR MATH_PURE greaterThan(const VECTOR& lv, const VECTOR& rv) { VECTOR r; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] > rv[i]; } return r; } template friend inline VECTOR MATH_PURE greaterThanEqual(const VECTOR& lv, const VECTOR& rv) { VECTOR r{}; for (size_t i = 0; i < lv.size(); i++) { r[i] = lv[i] >= rv[i]; } return r; } }; /* * TVecFunctions implements functions on a vector of type BASE. * * BASE only needs to implement operator[] and size(). * By simply inheriting from TVecFunctions BASE will automatically * get all the functionality here. */ template class VECTOR, typename T> class TVecFunctions { private: /* * NOTE: the functions below ARE NOT member methods. They are friend functions * with they definition inlined with their declaration. This makes these * template functions available to the compiler when (and only when) this class * is instantiated, at which point they're only templated on the 2nd parameter * (the first one, BASE being known). */ template friend constexpr inline arithmetic_result_t MATH_PURE dot(const VECTOR& lv, const VECTOR& rv) { arithmetic_result_t r{}; for (size_t i = 0; i < lv.size(); i++) { r += lv[i] * rv[i]; } return r; } friend inline T MATH_PURE norm(const VECTOR& lv) { return std::sqrt(dot(lv, lv)); } friend inline T MATH_PURE length(const VECTOR& lv) { return norm(lv); } friend inline constexpr T MATH_PURE norm2(const VECTOR& lv) { return dot(lv, lv); } friend inline constexpr T MATH_PURE length2(const VECTOR& lv) { return norm2(lv); } template friend inline constexpr arithmetic_result_t MATH_PURE distance(const VECTOR& lv, const VECTOR& rv) { return length(rv - lv); } template friend inline constexpr arithmetic_result_t MATH_PURE distance2(const VECTOR& lv, const VECTOR& rv) { return length2(rv - lv); } friend inline VECTOR MATH_PURE normalize(const VECTOR& lv) { return lv * (T(1) / length(lv)); } friend inline VECTOR MATH_PURE rcp(VECTOR v) { return T(1) / v; } friend inline constexpr VECTOR MATH_PURE abs(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = v[i] < 0 ? -v[i] : v[i]; } return v; } friend inline VECTOR MATH_PURE floor(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::floor(v[i]); } return v; } friend inline VECTOR MATH_PURE ceil(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::ceil(v[i]); } return v; } friend inline VECTOR MATH_PURE round(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::round(v[i]); } return v; } friend inline VECTOR MATH_PURE inversesqrt(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = T(1) / std::sqrt(v[i]); } return v; } friend inline VECTOR MATH_PURE sqrt(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::sqrt(v[i]); } return v; } friend inline VECTOR MATH_PURE exp(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::exp(v[i]); } return v; } friend inline VECTOR MATH_PURE pow(VECTOR v, T p) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::pow(v[i], p); } return v; } friend inline VECTOR MATH_PURE pow(T v, VECTOR p) { for (size_t i = 0; i < p.size(); i++) { p[i] = std::pow(v, p[i]); } return p; } friend inline VECTOR MATH_PURE pow(VECTOR v, VECTOR p) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::pow(v[i], p[i]); } return v; } friend inline VECTOR MATH_PURE log(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::log(v[i]); } return v; } friend inline VECTOR MATH_PURE log10(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::log10(v[i]); } return v; } friend inline VECTOR MATH_PURE log2(VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = std::log2(v[i]); } return v; } friend inline constexpr VECTOR MATH_PURE saturate(const VECTOR& lv) { return clamp(lv, T(0), T(1)); } friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, T min, T max) { for (size_t i = 0; i < v.size(); i++) { v[i] = details::min(max, details::max(min, v[i])); } return v; } friend inline constexpr VECTOR MATH_PURE clamp(VECTOR v, VECTOR min, VECTOR max) { for (size_t i = 0; i < v.size(); i++) { v[i] = details::min(max[i], details::max(min[i], v[i])); } return v; } friend inline constexpr VECTOR MATH_PURE fma(const VECTOR& lv, const VECTOR& rv, VECTOR a) { for (size_t i = 0; i < lv.size(); i++) { a[i] += (lv[i] * rv[i]); } return a; } friend inline constexpr VECTOR MATH_PURE min(const VECTOR& u, VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = details::min(u[i], v[i]); } return v; } friend inline constexpr VECTOR MATH_PURE max(const VECTOR& u, VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = details::max(u[i], v[i]); } return v; } friend inline constexpr T MATH_PURE max(const VECTOR& v) { T r(v[0]); for (size_t i = 1; i < v.size(); i++) { r = max(r, v[i]); } return r; } friend inline constexpr T MATH_PURE min(const VECTOR& v) { T r(v[0]); for (size_t i = 1; i < v.size(); i++) { r = min(r, v[i]); } return r; } friend inline constexpr VECTOR MATH_PURE mix(const VECTOR& u, VECTOR v, T a) { for (size_t i = 0; i < v.size(); i++) { v[i] = u[i] * (T(1) - a) + v[i] * a; } return v; } friend inline constexpr VECTOR MATH_PURE smoothstep(T edge0, T edge1, VECTOR v) { VECTOR t = saturate((v - edge0) / (edge1 - edge0)); return t * t * (T(3) - T(2) * t); } friend inline constexpr VECTOR MATH_PURE step(T edge, VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = v[i] < edge ? T(0) : T(1); } return v; } friend inline constexpr VECTOR MATH_PURE step(VECTOR edge, VECTOR v) { for (size_t i = 0; i < v.size(); i++) { v[i] = v[i] < edge[i] ? T(0) : T(1); } return v; } friend inline constexpr bool MATH_PURE any(const VECTOR& v) { for (size_t i = 0; i < v.size(); i++) { if (v[i] != T(0)) return true; } return false; } friend inline constexpr bool MATH_PURE all(const VECTOR& v) { bool result = true; for (size_t i = 0; i < v.size(); i++) { result &= (v[i] != T(0)); } return result; } }; // ------------------------------------------------------------------------------------- } // namespace details } // namespace math } // namespace filament #endif // MATH_TVECHELPERS_H_