--- /dev/null
+/*
+ * Copyright (C) 2016 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 ANDROID_UI_COLOR_SPACE
+#define ANDROID_UI_COLOR_SPACE
+
+#include <array>
+#include <cmath>
+#include <functional>
+#include <string>
+
+#include <ui/mat3.h>
+#include <ui/scalar.h>
+#include <ui/vec2.h>
+#include <ui/vec3.h>
+
+namespace android {
+
+class ColorSpace {
+public:
+ typedef std::function<float(float)> transfer_function;
+ typedef std::function<float(float)> clamping_function;
+
+ /**
+ * Creates a named color space with the specified RGB->XYZ
+ * conversion matrix. The white point and primaries will be
+ * computed from the supplied matrix.
+ *
+ * The default transfer functions are a linear response x->x
+ * and the default clamping function is a simple saturate
+ * (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ transfer_function OETF = linearReponse,
+ transfer_function EOTF = linearReponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ /**
+ * Creates a named color space with the specified primaries
+ * and white point. The RGB<>XYZ conversion matrices are
+ * computed from the primaries and white point.
+ *
+ * The default transfer functions are a linear response x->x
+ * and the default clamping function is a simple saturate
+ * (clamp(x, 0, 1)).
+ */
+ ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ transfer_function OETF = linearReponse,
+ transfer_function EOTF = linearReponse,
+ clamping_function clamper = saturate<float>
+ ) noexcept;
+
+ ColorSpace() noexcept = delete;
+
+ /**
+ * Encodes the supplied RGB value using this color space's
+ * opto-electronic transfer function.
+ */
+ constexpr float3 fromLinear(const float3& v) const noexcept {
+ return apply(v, mOETF);
+ }
+
+ /**
+ * Decodes the supplied RGB value using this color space's
+ * electro-optical transfer function.
+ */
+ constexpr float3 toLinear(const float3& v) const noexcept {
+ return apply(v, mEOTF);
+ }
+
+ /**
+ * Converts the supplied XYZ value to RGB. The returned value
+ * is encoded with this color space's opto-electronic transfer
+ * function and clamped by this color space's clamping function.
+ */
+ constexpr float3 xyzToRGB(const float3& xyz) const noexcept {
+ return apply(fromLinear(mXYZtoRGB * xyz), mClamper);
+ }
+
+ /**
+ * Converts the supplied RGB value to XYZ. The input RGB value
+ * is decoded using this color space's electro-optical function
+ * before being converted to XYZ. The returned result is clamped
+ * by this color space's clamping function.
+ */
+ constexpr float3 rgbToXYZ(const float3& rgb) const noexcept {
+ return apply(mRGBtoXYZ * toLinear(rgb), mClamper);
+ }
+
+ constexpr const std::string& getName() const noexcept {
+ return mName;
+ }
+
+ constexpr const mat3& getRGBtoXYZ() const noexcept {
+ return mRGBtoXYZ;
+ }
+
+ constexpr const mat3& getXYZtoRGB() const noexcept {
+ return mXYZtoRGB;
+ }
+
+ constexpr const transfer_function& getOETF() const noexcept {
+ return mOETF;
+ }
+
+ constexpr const transfer_function& getEOTF() const noexcept {
+ return mEOTF;
+ }
+
+ constexpr const clamping_function& getClamper() const noexcept {
+ return mClamper;
+ }
+
+ constexpr const std::array<float2, 3>& getPrimaries() const noexcept {
+ return mPrimaries;
+ }
+
+ constexpr const float2& getWhitePoint() const noexcept {
+ return mWhitePoint;
+ }
+
+ /**
+ * Converts the supplied XYZ value to xyY.
+ */
+ static constexpr float2 xyY(const float3& XYZ) {
+ return XYZ.xy / dot(XYZ, float3{1});
+ }
+
+ /**
+ * Converts the supplied xyY value to XYZ.
+ */
+ static constexpr float3 XYZ(const float3& xyY) {
+ return float3{(xyY.x * xyY.z) / xyY.y, xyY.z, ((1 - xyY.x - xyY.y) * xyY.z) / xyY.y};
+ }
+
+ static const ColorSpace sRGB();
+ static const ColorSpace linearSRGB();
+ static const ColorSpace extendedSRGB();
+ static const ColorSpace linearExtendedSRGB();
+ static const ColorSpace NTSC();
+ static const ColorSpace BT709();
+ static const ColorSpace BT2020();
+ static const ColorSpace AdobeRGB();
+ static const ColorSpace ProPhotoRGB();
+ static const ColorSpace DisplayP3();
+ static const ColorSpace DCIP3();
+ static const ColorSpace ACES();
+ static const ColorSpace ACEScg();
+
+private:
+ static constexpr mat3 computeXYZMatrix(
+ const std::array<float2, 3>& primaries, const float2& whitePoint);
+
+ static constexpr float linearReponse(float v) {
+ return v;
+ }
+
+ const std::string mName;
+
+ const mat3 mRGBtoXYZ;
+ const mat3 mXYZtoRGB;
+
+ const transfer_function mOETF;
+ const transfer_function mEOTF;
+ const clamping_function mClamper;
+
+ std::array<float2, 3> mPrimaries;
+ float2 mWhitePoint;
+};
+
+}; // namespace android
+
+#endif // ANDROID_UI_COLOR_SPACE
#define PURE __attribute__((pure))
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
namespace details {
// -------------------------------------------------------------------------------------
// Factor out the lower triangle
for (size_t j = 0; j < N; ++j) {
if (j != i) {
- const T t = tmp[j][i];
+ const T d = tmp[j][i];
for (size_t k = 0; k < N; ++k) {
- tmp[j][k] -= tmp[i][k] * t;
- inverted[j][k] -= inverted[i][k] * t;
+ tmp[j][k] -= tmp[i][k] * d;
+ inverted[j][k] -= inverted[i][k] * d;
}
}
}
//------------------------------------------------------------------------------
// 2x2 matrix inverse is easy.
template <typename MATRIX>
-MATRIX PURE fastInverse2(const MATRIX& x) {
+CONSTEXPR MATRIX PURE fastInverse2(const MATRIX& x) {
typedef typename MATRIX::value_type T;
// Assuming the input matrix is:
// matrix inversion:
// http://en.wikipedia.org/wiki/Invertible_matrix#Inversion_of_3.C3.973_matrices
template <typename MATRIX>
-MATRIX PURE fastInverse3(const MATRIX& x) {
+CONSTEXPR MATRIX PURE fastInverse3(const MATRIX& x) {
typedef typename MATRIX::value_type T;
// Assuming the input matrix is:
return inverted;
}
-
/**
* Inversion function which switches on the matrix size.
* @warning This function assumes the matrix is invertible. The result is
}
template<typename MATRIX_R, typename MATRIX_A, typename MATRIX_B>
-MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
+CONSTEXPR MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
// pre-requisite:
// lhs : D columns, R rows
// rhs : C columns, D rows
// transpose. this handles matrices of matrices
template <typename MATRIX>
-MATRIX PURE transpose(const MATRIX& m) {
+CONSTEXPR MATRIX PURE transpose(const MATRIX& m) {
// for now we only handle square matrix transpose
static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "transpose only supports square matrices");
MATRIX result(MATRIX::NO_INIT);
// trace. this handles matrices of matrices
template <typename MATRIX>
-typename MATRIX::value_type PURE trace(const MATRIX& m) {
+CONSTEXPR typename MATRIX::value_type PURE trace(const MATRIX& m) {
static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "trace only defined for square matrices");
typename MATRIX::value_type result(0);
for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
// diag. this handles matrices of matrices
template <typename MATRIX>
-typename MATRIX::col_type PURE diag(const MATRIX& m) {
+CONSTEXPR typename MATRIX::col_type PURE diag(const MATRIX& m) {
static_assert(MATRIX::NUM_COLS == MATRIX::NUM_ROWS, "diag only defined for square matrices");
typename MATRIX::col_type result(MATRIX::col_type::NO_INIT);
for (size_t col = 0; col < MATRIX::NUM_COLS; ++col) {
// matrix * matrix, result is a matrix of the same type than the lhs matrix
template<typename U>
- friend BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
+ friend CONSTEXPR BASE<T> PURE operator *(const BASE<T>& lhs, const BASE<U>& rhs) {
return matrix::multiply<BASE<T> >(lhs, rhs);
}
};
* is instantiated, at which point they're only templated on the 2nd parameter
* (the first one, BASE<T> being known).
*/
- friend inline BASE<T> PURE inverse(const BASE<T>& matrix) {
+ friend inline CONSTEXPR BASE<T> PURE inverse(const BASE<T>& matrix) {
return matrix::inverse(matrix);
}
friend inline constexpr BASE<T> PURE transpose(const BASE<T>& m) {
}
template <typename VEC>
- static BASE<T> translate(const VEC& t) {
+ static CONSTEXPR BASE<T> translate(const VEC& t) {
BASE<T> r;
r[BASE<T>::NUM_COLS-1] = t;
return r;
return BASE<T>(s);
}
- friend inline BASE<T> PURE abs(BASE<T> m) {
+ friend inline CONSTEXPR BASE<T> PURE abs(BASE<T> m) {
for (size_t col = 0; col < BASE<T>::NUM_COLS; ++col) {
m[col] = abs(m[col]);
}
}
template <typename A, typename VEC>
- static BASE<T> rotate(A radian, const VEC& about) {
+ static CONSTEXPR BASE<T> rotate(A radian, const VEC& about) {
BASE<T> r;
T c = std::cos(radian);
T s = std::sin(radian);
typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
>
- static BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
+ static CONSTEXPR BASE<T> eulerYXZ(Y yaw, P pitch, R roll) {
return eulerZYX(roll, pitch, yaw);
}
typename = typename std::enable_if<std::is_arithmetic<P>::value >::type,
typename = typename std::enable_if<std::is_arithmetic<R>::value >::type
>
- static BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
+ static CONSTEXPR BASE<T> eulerZYX(Y yaw, P pitch, R roll) {
BASE<T> r;
T cy = std::cos(yaw);
T sy = std::sin(yaw);
#undef LIKELY
#undef UNLIKELY
#undef PURE
+#undef CONSTEXPR
#endif // UI_TMATHELPERS_H_
#define PURE __attribute__((pure))
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
namespace details {
// -------------------------------------------------------------------------------------
}
return rhs;
}
+
VECTOR<T>& operator --() {
VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
for (size_t i = 0; i < rhs.size(); i++) {
}
return rhs;
}
- VECTOR<T> operator -() const {
+
+ CONSTEXPR VECTOR<T> operator -() const {
VECTOR<T> r(VECTOR<T>::NO_INIT);
VECTOR<T> const& rv(static_cast<VECTOR<T> const&>(*this));
for (size_t i = 0; i < r.size(); i++) {
* (the first one, BASE<T> being known).
*/
template<typename RT>
- friend inline T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
+ friend inline CONSTEXPR T PURE dot(const VECTOR<T>& lv, const VECTOR<RT>& rv) {
T r(0);
for (size_t i = 0; i < lv.size(); i++) {
//r = std::fma(lv[i], rv[i], r);
return lv * (T(1) / length(lv));
}
- friend inline VECTOR<T> PURE rcp(VECTOR<T> v) {
+ friend inline constexpr VECTOR<T> PURE rcp(VECTOR<T> v) {
return T(1) / v;
}
- friend inline VECTOR<T> PURE abs(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE abs(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::abs(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE floor(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE floor(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::floor(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE ceil(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE ceil(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::ceil(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE round(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE round(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::round(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE inversesqrt(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE inversesqrt(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = T(1) / std::sqrt(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE sqrt(VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE sqrt(VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::sqrt(v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE pow(VECTOR<T> v, T p) {
+ friend inline CONSTEXPR VECTOR<T> PURE pow(VECTOR<T> v, T p) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::pow(v[i], p);
}
return v;
}
- friend inline VECTOR<T> PURE saturate(const VECTOR<T>& lv) {
+ friend inline CONSTEXPR VECTOR<T> PURE saturate(const VECTOR<T>& lv) {
return clamp(lv, T(0), T(1));
}
- friend inline VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) {
+ friend inline CONSTEXPR VECTOR<T> PURE clamp(VECTOR<T> v, T min, T max) {
for (size_t i=0 ; i< v.size() ; i++) {
v[i] = std::min(max, std::max(min, v[i]));
}
return v;
}
- friend inline VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) {
+ friend inline CONSTEXPR VECTOR<T> PURE fma(const VECTOR<T>& lv, const VECTOR<T>& rv, VECTOR<T> a) {
for (size_t i=0 ; i<lv.size() ; i++) {
//a[i] = std::fma(lv[i], rv[i], a[i]);
a[i] += (lv[i] * rv[i]);
return a;
}
- friend inline VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE min(const VECTOR<T>& u, VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::min(u[i], v[i]);
}
return v;
}
- friend inline VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) {
+ friend inline CONSTEXPR VECTOR<T> PURE max(const VECTOR<T>& u, VECTOR<T> v) {
for (size_t i=0 ; i<v.size() ; i++) {
v[i] = std::max(u[i], v[i]);
}
return v;
}
- friend inline T PURE max(const VECTOR<T>& v) {
+ friend inline CONSTEXPR T PURE max(const VECTOR<T>& v) {
T r(std::numeric_limits<T>::lowest());
for (size_t i=0 ; i<v.size() ; i++) {
r = std::max(r, v[i]);
return r;
}
- friend inline T PURE min(const VECTOR<T>& v) {
+ friend inline CONSTEXPR T PURE min(const VECTOR<T>& v) {
T r(std::numeric_limits<T>::max());
for (size_t i=0 ; i<v.size() ; i++) {
r = std::min(r, v[i]);
}
return r;
}
+
+ friend inline CONSTEXPR VECTOR<T> PURE apply(VECTOR<T> v, const std::function<T(T)>& f) {
+ for (size_t i=0 ; i<v.size() ; i++) {
+ v[i] = f(v[i]);
+ }
+ return v;
+ }
};
/*
}
};
+#undef CONSTEXPR
#undef PURE
// -------------------------------------------------------------------------------------
# define UNLIKELY( exp ) (__builtin_expect( !!(exp), 0 ))
#endif
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
/*
struct fp16 {
uint16_t bits = 0;
fp16() noexcept = default;
- explicit constexpr fp16(uint16_t bits) noexcept : bits(bits) { }
+ explicit constexpr fp16(uint16_t b) noexcept : bits(b) { }
void setS(unsigned int s) noexcept { bits = uint16_t((bits & 0x7FFF) | (s<<15)); }
void setE(unsigned int s) noexcept { bits = uint16_t((bits & 0xE3FF) | (s<<10)); }
void setM(unsigned int s) noexcept { bits = uint16_t((bits & 0xFC00) | (s<< 0)); }
- unsigned int getS() const noexcept { return bits >> 15u; }
- unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; }
- unsigned int getM() const noexcept { return bits & 0x3FFu; }
+ constexpr unsigned int getS() const noexcept { return bits >> 15u; }
+ constexpr unsigned int getE() const noexcept { return (bits >> 10u) & 0x1Fu; }
+ constexpr unsigned int getM() const noexcept { return bits & 0x3FFu; }
};
struct fp32 {
union {
void setS(unsigned int s) noexcept { bits = uint32_t((bits & 0x7FFFFFFF) | (s<<31)); }
void setE(unsigned int s) noexcept { bits = uint32_t((bits & 0x807FFFFF) | (s<<23)); }
void setM(unsigned int s) noexcept { bits = uint32_t((bits & 0xFF800000) | (s<< 0)); }
- unsigned int getS() const noexcept { return bits >> 31u; }
- unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; }
- unsigned int getM() const noexcept { return bits & 0x7FFFFFu; }
+ constexpr unsigned int getS() const noexcept { return bits >> 31u; }
+ constexpr unsigned int getE() const noexcept { return (bits >> 23u) & 0xFFu; }
+ constexpr unsigned int getM() const noexcept { return bits & 0x7FFFFFu; }
};
public:
- half(float v) noexcept : mBits(ftoh(v)) { }
- operator float() const noexcept { return htof(mBits); }
+ CONSTEXPR half(float v) noexcept : mBits(ftoh(v)) { }
+ CONSTEXPR operator float() const noexcept { return htof(mBits); }
uint16_t getBits() const noexcept { return mBits.bits; }
unsigned int getExponent() const noexcept { return mBits.getE(); }
private:
friend class std::numeric_limits<half>;
- friend half operator"" _hf(long double v);
+ friend CONSTEXPR half operator"" _hf(long double v);
enum Binary { binary };
explicit constexpr half(Binary, uint16_t bits) noexcept : mBits(bits) { }
- static fp16 ftoh(float v) noexcept;
- static float htof(fp16 v) noexcept;
+ static CONSTEXPR fp16 ftoh(float v) noexcept;
+ static CONSTEXPR float htof(fp16 v) noexcept;
fp16 mBits;
};
-inline /* constexpr */ half::fp16 half::ftoh(float v) noexcept {
+inline CONSTEXPR half::fp16 half::ftoh(float v) noexcept {
fp16 out;
fp32 in(v);
if (UNLIKELY(in.getE() == 0xFF)) { // inf or nan
out.setE(0x1F);
out.setM(in.getM() ? 0x200 : 0);
} else {
- int e = in.getE() - 127 + 15;
+ int e = static_cast<int>(in.getE()) - 127 + 15;
if (e >= 0x1F) {
// overflow
out.setE(0x31); // +/- inf
return out;
}
-inline float half::htof(half::fp16 in) noexcept {
+inline CONSTEXPR float half::htof(half::fp16 in) noexcept {
fp32 out;
if (UNLIKELY(in.getE() == 0x1F)) { // inf or nan
out.setE(0xFF);
// (it's stupid because they can be represented as regular float)
}
} else {
- int e = in.getE() - 15 + 127;
+ int e = static_cast<int>(in.getE()) - 15 + 127;
unsigned int m = in.getM();
out.setE(uint32_t(e));
out.setM(m << 13);
return out.fp;
}
-inline /* constexpr */ android::half operator"" _hf(long double v) {
- return android::half(android::half::binary, android::half::ftoh(v).bits);
+inline CONSTEXPR android::half operator"" _hf(long double v) {
+ return android::half(android::half::binary, android::half::ftoh(static_cast<float>(v)).bits);
}
} // namespace android
#undef LIKELY
#undef UNLIKELY
+#undef CONSTEXPR
#endif // UI_HALF_H
#define PURE __attribute__((pure))
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
// -------------------------------------------------------------------------------------
namespace details {
/**
* leaves object uninitialized. use with caution.
*/
- explicit
- constexpr TMat22(no_init)
+ explicit constexpr TMat22(no_init)
: m_value{ col_type(col_type::NO_INIT),
col_type(col_type::NO_INIT) } {}
* \right)
* \f$
*/
- TMat22();
+ CONSTEXPR TMat22();
/**
* initialize to Identity*scalar.
* \f$
*/
template<typename U>
- explicit TMat22(U v);
+ explicit CONSTEXPR TMat22(U v);
/**
* sets the diagonal to a vector.
* \f$
*/
template <typename U>
- explicit TMat22(const TVec2<U>& v);
+ explicit CONSTEXPR TMat22(const TVec2<U>& v);
/**
* construct from another matrix of the same size
*/
template <typename U>
- explicit TMat22(const TMat22<U>& rhs);
+ explicit CONSTEXPR TMat22(const TMat22<U>& rhs);
/**
* construct from 2 column vectors.
* \f$
*/
template <typename A, typename B>
- TMat22(const TVec2<A>& v0, const TVec2<B>& v1);
+ CONSTEXPR TMat22(const TVec2<A>& v0, const TVec2<B>& v1);
/** construct from 4 elements in column-major form.
*
template <
typename A, typename B,
typename C, typename D>
- TMat22(A m00, B m01,
- C m10, D m11);
+ CONSTEXPR TMat22(A m00, B m01, C m10, D m11);
/**
* construct from a C array in column major form.
*/
template <typename U>
- explicit TMat22(U const* rawArray);
+ explicit CONSTEXPR TMat22(U const* rawArray);
/**
* Rotate by radians in the 2D plane
*/
- static TMat22<T> rotate(T radian) {
+ static CONSTEXPR TMat22<T> rotate(T radian) {
TMat22<T> r(TMat22<T>::NO_INIT);
T c = std::cos(radian);
T s = std::sin(radian);
// operations.
template <typename T>
-TMat22<T>::TMat22() {
+CONSTEXPR TMat22<T>::TMat22() {
m_value[0] = col_type(1, 0);
m_value[1] = col_type(0, 1);
}
template <typename T>
template <typename U>
-TMat22<T>::TMat22(U v) {
+CONSTEXPR TMat22<T>::TMat22(U v) {
m_value[0] = col_type(v, 0);
m_value[1] = col_type(0, v);
}
template<typename T>
template<typename U>
-TMat22<T>::TMat22(const TVec2<U>& v) {
+CONSTEXPR TMat22<T>::TMat22(const TVec2<U>& v) {
m_value[0] = col_type(v.x, 0);
m_value[1] = col_type(0, v.y);
}
template <
typename A, typename B,
typename C, typename D>
-TMat22<T>::TMat22(A m00, B m01,
- C m10, D m11) {
+CONSTEXPR TMat22<T>::TMat22( A m00, B m01, C m10, D m11) {
m_value[0] = col_type(m00, m01);
m_value[1] = col_type(m10, m11);
}
template <typename T>
template <typename U>
-TMat22<T>::TMat22(const TMat22<U>& rhs) {
+CONSTEXPR TMat22<T>::TMat22(const TMat22<U>& rhs) {
for (size_t col = 0; col < NUM_COLS; ++col) {
m_value[col] = col_type(rhs[col]);
}
// Construct from 2 column vectors.
template <typename T>
template <typename A, typename B>
-TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) {
+CONSTEXPR TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& v1) {
m_value[0] = v0;
m_value[1] = v1;
}
// Construct from raw array, in column-major form.
template <typename T>
template <typename U>
-TMat22<T>::TMat22(U const* rawArray) {
+CONSTEXPR TMat22<T>::TMat22(U const* rawArray) {
for (size_t col = 0; col < NUM_COLS; ++col) {
for (size_t row = 0; row < NUM_ROWS; ++row) {
m_value[col][row] = *rawArray++;
// matrix * column-vector, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U>& rhs) {
+CONSTEXPR typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U>& rhs) {
// Result is initialized to zero.
typename TMat22<U>::col_type result;
for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) {
// row-vector * matrix, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat22<U>::row_type PURE operator *(const TVec2<U>& lhs, const TMat22<T>& rhs) {
+CONSTEXPR typename TMat22<U>::row_type PURE operator *(const TVec2<U>& lhs, const TMat22<T>& rhs) {
typename TMat22<U>::row_type result(TMat22<U>::row_type::NO_INIT);
for (size_t col = 0; col < TMat22<T>::NUM_COLS; ++col) {
result[col] = dot(lhs, rhs[col]);
* BASE<T>::col_type is not accessible from there (???)
*/
template<typename T>
-typename TMat22<T>::col_type PURE diag(const TMat22<T>& m) {
+CONSTEXPR typename TMat22<T>::col_type PURE diag(const TMat22<T>& m) {
return matrix::diag(m);
}
} // namespace android
#undef PURE
+#undef CONSTEXPR
#endif // UI_MAT2_H_
#define PURE __attribute__((pure))
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
// -------------------------------------------------------------------------------------
namespace details {
/**
* leaves object uninitialized. use with caution.
*/
- explicit
- constexpr TMat33(no_init)
+ explicit constexpr TMat33(no_init)
: m_value{ col_type(col_type::NO_INIT),
col_type(col_type::NO_INIT),
col_type(col_type::NO_INIT) } {}
* \right)
* \f$
*/
- TMat33();
+ CONSTEXPR TMat33();
/**
* initialize to Identity*scalar.
* \f$
*/
template<typename U>
- explicit TMat33(U v);
+ explicit CONSTEXPR TMat33(U v);
/**
* sets the diagonal to a vector.
* \f$
*/
template <typename U>
- explicit TMat33(const TVec3<U>& v);
+ explicit CONSTEXPR TMat33(const TVec3<U>& v);
/**
* construct from another matrix of the same size
*/
template <typename U>
- explicit TMat33(const TMat33<U>& rhs);
+ explicit CONSTEXPR TMat33(const TMat33<U>& rhs);
/**
* construct from 3 column vectors.
* \f$
*/
template <typename A, typename B, typename C>
- TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2);
+ CONSTEXPR TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2);
/** construct from 9 elements in column-major form.
*
typename A, typename B, typename C,
typename D, typename E, typename F,
typename G, typename H, typename I>
- TMat33(A m00, B m01, C m02,
+ CONSTEXPR TMat33(
+ A m00, B m01, C m02,
D m10, E m11, F m12,
G m20, H m21, I m22);
* construct from a quaternion
*/
template <typename U>
- explicit TMat33(const TQuaternion<U>& q);
+ explicit CONSTEXPR TMat33(const TQuaternion<U>& q);
/**
* construct from a C array in column major form.
*/
template <typename U>
- explicit TMat33(U const* rawArray);
+ explicit CONSTEXPR TMat33(U const* rawArray);
/**
* orthogonalize only works on matrices of size 3x3
*/
friend inline
- TMat33 orthogonalize(const TMat33& m) {
+ CONSTEXPR TMat33 orthogonalize(const TMat33& m) {
TMat33 ret(TMat33::NO_INIT);
ret[0] = normalize(m[0]);
ret[2] = normalize(cross(ret[0], m[1]));
// operations.
template <typename T>
-TMat33<T>::TMat33() {
+CONSTEXPR TMat33<T>::TMat33() {
m_value[0] = col_type(1, 0, 0);
m_value[1] = col_type(0, 1, 0);
m_value[2] = col_type(0, 0, 1);
template <typename T>
template <typename U>
-TMat33<T>::TMat33(U v) {
+CONSTEXPR TMat33<T>::TMat33(U v) {
m_value[0] = col_type(v, 0, 0);
m_value[1] = col_type(0, v, 0);
m_value[2] = col_type(0, 0, v);
template<typename T>
template<typename U>
-TMat33<T>::TMat33(const TVec3<U>& v) {
+CONSTEXPR TMat33<T>::TMat33(const TVec3<U>& v) {
m_value[0] = col_type(v.x, 0, 0);
m_value[1] = col_type(0, v.y, 0);
m_value[2] = col_type(0, 0, v.z);
typename A, typename B, typename C,
typename D, typename E, typename F,
typename G, typename H, typename I>
-TMat33<T>::TMat33(A m00, B m01, C m02,
- D m10, E m11, F m12,
- G m20, H m21, I m22) {
+CONSTEXPR TMat33<T>::TMat33(
+ A m00, B m01, C m02,
+ D m10, E m11, F m12,
+ G m20, H m21, I m22) {
m_value[0] = col_type(m00, m01, m02);
m_value[1] = col_type(m10, m11, m12);
m_value[2] = col_type(m20, m21, m22);
template <typename T>
template <typename U>
-TMat33<T>::TMat33(const TMat33<U>& rhs) {
+CONSTEXPR TMat33<T>::TMat33(const TMat33<U>& rhs) {
for (size_t col = 0; col < NUM_COLS; ++col) {
m_value[col] = col_type(rhs[col]);
}
// Construct from 3 column vectors.
template <typename T>
template <typename A, typename B, typename C>
-TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) {
+CONSTEXPR TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& v2) {
m_value[0] = v0;
m_value[1] = v1;
m_value[2] = v2;
// Construct from raw array, in column-major form.
template <typename T>
template <typename U>
-TMat33<T>::TMat33(U const* rawArray) {
+CONSTEXPR TMat33<T>::TMat33(U const* rawArray) {
for (size_t col = 0; col < NUM_COLS; ++col) {
for (size_t row = 0; row < NUM_ROWS; ++row) {
m_value[col][row] = *rawArray++;
template <typename T>
template <typename U>
-TMat33<T>::TMat33(const TQuaternion<U>& q) {
+CONSTEXPR TMat33<T>::TMat33(const TQuaternion<U>& q) {
const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
const U s = n > 0 ? 2/n : 0;
const U x = s*q.x;
// matrix * column-vector, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U>& rhs) {
+CONSTEXPR typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U>& rhs) {
// Result is initialized to zero.
typename TMat33<U>::col_type result;
for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) {
// row-vector * matrix, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat33<U>::row_type PURE operator *(const TVec3<U>& lhs, const TMat33<T>& rhs) {
+CONSTEXPR typename TMat33<U>::row_type PURE operator *(const TVec3<U>& lhs, const TMat33<T>& rhs) {
typename TMat33<U>::row_type result(TMat33<U>::row_type::NO_INIT);
for (size_t col = 0; col < TMat33<T>::NUM_COLS; ++col) {
result[col] = dot(lhs, rhs[col]);
//------------------------------------------------------------------------------
template <typename T>
-TMat33<T> orthogonalize(const TMat33<T>& m) {
+CONSTEXPR TMat33<T> orthogonalize(const TMat33<T>& m) {
TMat33<T> ret(TMat33<T>::NO_INIT);
ret[0] = normalize(m[0]);
ret[2] = normalize(cross(ret[0], m[1]));
* BASE<T>::col_type is not accessible from there (???)
*/
template<typename T>
-typename TMat33<T>::col_type PURE diag(const TMat33<T>& m) {
+CONSTEXPR typename TMat33<T>::col_type PURE diag(const TMat33<T>& m) {
return matrix::diag(m);
}
} // namespace android
#undef PURE
+#undef CONSTEXPR
#endif // UI_MAT3_H_
#define PURE __attribute__((pure))
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
namespace android {
// -------------------------------------------------------------------------------------
namespace details {
*/
// leaves object uninitialized. use with caution.
- explicit
- constexpr TMat44(no_init)
+ explicit constexpr TMat44(no_init)
: m_value{ col_type(col_type::NO_INIT),
col_type(col_type::NO_INIT),
col_type(col_type::NO_INIT),
* \right)
* \f$
*/
- TMat44();
+ CONSTEXPR TMat44();
/** initialize to Identity*scalar.
*
* \f$
*/
template<typename U>
- explicit TMat44(U v);
+ explicit CONSTEXPR TMat44(U v);
/** sets the diagonal to a vector.
*
* \f$
*/
template <typename U>
- explicit TMat44(const TVec4<U>& v);
+ explicit CONSTEXPR TMat44(const TVec4<U>& v);
// construct from another matrix of the same size
template <typename U>
- explicit TMat44(const TMat44<U>& rhs);
+ explicit CONSTEXPR TMat44(const TMat44<U>& rhs);
/** construct from 4 column vectors.
*
* \f$
*/
template <typename A, typename B, typename C, typename D>
- TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3);
+ CONSTEXPR TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3);
/** construct from 16 elements in column-major form.
*
typename E, typename F, typename G, typename H,
typename I, typename J, typename K, typename L,
typename M, typename N, typename O, typename P>
- TMat44(A m00, B m01, C m02, D m03,
- E m10, F m11, G m12, H m13,
- I m20, J m21, K m22, L m23,
- M m30, N m31, O m32, P m33);
+ CONSTEXPR TMat44(
+ A m00, B m01, C m02, D m03,
+ E m10, F m11, G m12, H m13,
+ I m20, J m21, K m22, L m23,
+ M m30, N m31, O m32, P m33);
/**
* construct from a quaternion
*/
template <typename U>
- explicit TMat44(const TQuaternion<U>& q);
+ explicit CONSTEXPR TMat44(const TQuaternion<U>& q);
/**
* construct from a C array in column major form.
*/
template <typename U>
- explicit TMat44(U const* rawArray);
+ explicit CONSTEXPR TMat44(U const* rawArray);
/**
* construct from a 3x3 matrix
*/
template <typename U>
- explicit TMat44(const TMat33<U>& matrix);
+ explicit CONSTEXPR TMat44(const TMat33<U>& matrix);
/**
* construct from a 3x3 matrix and 3d translation
*/
template <typename U, typename V>
- TMat44(const TMat33<U>& matrix, const TVec3<V>& translation);
+ CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec3<V>& translation);
/**
* construct from a 3x3 matrix and 4d last column.
*/
template <typename U, typename V>
- TMat44(const TMat33<U>& matrix, const TVec4<V>& column3);
+ CONSTEXPR TMat44(const TMat33<U>& matrix, const TVec4<V>& column3);
/*
* helpers
*/
- static TMat44 ortho(T left, T right, T bottom, T top, T near, T far);
+ static CONSTEXPR TMat44 ortho(T left, T right, T bottom, T top, T near, T far);
- static TMat44 frustum(T left, T right, T bottom, T top, T near, T far);
+ static CONSTEXPR TMat44 frustum(T left, T right, T bottom, T top, T near, T far);
enum class Fov {
HORIZONTAL,
VERTICAL
};
- static TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL);
+ static CONSTEXPR TMat44 perspective(T fov, T aspect, T near, T far, Fov direction = Fov::VERTICAL);
template <typename A, typename B, typename C>
- static TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up);
+ static CONSTEXPR TMat44 lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up);
template <typename A>
- static TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) {
+ static CONSTEXPR TVec3<A> project(const TMat44& projectionMatrix, TVec3<A> vertice) {
TVec4<A> r = projectionMatrix * TVec4<A>{ vertice, 1 };
return r.xyz / r.w;
}
template <typename A>
- static TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) {
+ static CONSTEXPR TVec4<A> project(const TMat44& projectionMatrix, TVec4<A> vertice) {
vertice = projectionMatrix * vertice;
return { vertice.xyz / vertice.w, 1 };
}
// operations.
template <typename T>
-TMat44<T>::TMat44() {
+CONSTEXPR TMat44<T>::TMat44() {
m_value[0] = col_type(1, 0, 0, 0);
m_value[1] = col_type(0, 1, 0, 0);
m_value[2] = col_type(0, 0, 1, 0);
template <typename T>
template <typename U>
-TMat44<T>::TMat44(U v) {
+CONSTEXPR TMat44<T>::TMat44(U v) {
m_value[0] = col_type(v, 0, 0, 0);
m_value[1] = col_type(0, v, 0, 0);
m_value[2] = col_type(0, 0, v, 0);
template<typename T>
template<typename U>
-TMat44<T>::TMat44(const TVec4<U>& v) {
+CONSTEXPR TMat44<T>::TMat44(const TVec4<U>& v) {
m_value[0] = col_type(v.x, 0, 0, 0);
m_value[1] = col_type(0, v.y, 0, 0);
m_value[2] = col_type(0, 0, v.z, 0);
typename E, typename F, typename G, typename H,
typename I, typename J, typename K, typename L,
typename M, typename N, typename O, typename P>
-TMat44<T>::TMat44(A m00, B m01, C m02, D m03,
- E m10, F m11, G m12, H m13,
- I m20, J m21, K m22, L m23,
- M m30, N m31, O m32, P m33) {
+CONSTEXPR TMat44<T>::TMat44(
+ A m00, B m01, C m02, D m03,
+ E m10, F m11, G m12, H m13,
+ I m20, J m21, K m22, L m23,
+ M m30, N m31, O m32, P m33) {
m_value[0] = col_type(m00, m01, m02, m03);
m_value[1] = col_type(m10, m11, m12, m13);
m_value[2] = col_type(m20, m21, m22, m23);
template <typename T>
template <typename U>
-TMat44<T>::TMat44(const TMat44<U>& rhs) {
+CONSTEXPR TMat44<T>::TMat44(const TMat44<U>& rhs) {
for (size_t col = 0; col < NUM_COLS; ++col) {
m_value[col] = col_type(rhs[col]);
}
// Construct from 4 column vectors.
template <typename T>
template <typename A, typename B, typename C, typename D>
-TMat44<T>::TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, const TVec4<D>& v3) {
+CONSTEXPR TMat44<T>::TMat44(
+ const TVec4<A>& v0, const TVec4<B>& v1,
+ const TVec4<C>& v2, const TVec4<D>& v3) {
m_value[0] = col_type(v0);
m_value[1] = col_type(v1);
m_value[2] = col_type(v2);
// Construct from raw array, in column-major form.
template <typename T>
template <typename U>
-TMat44<T>::TMat44(U const* rawArray) {
+CONSTEXPR TMat44<T>::TMat44(U const* rawArray) {
for (size_t col = 0; col < NUM_COLS; ++col) {
for (size_t row = 0; row < NUM_ROWS; ++row) {
m_value[col][row] = *rawArray++;
template <typename T>
template <typename U>
-TMat44<T>::TMat44(const TQuaternion<U>& q) {
+CONSTEXPR TMat44<T>::TMat44(const TQuaternion<U>& q) {
const U n = q.x*q.x + q.y*q.y + q.z*q.z + q.w*q.w;
const U s = n > 0 ? 2/n : 0;
const U x = s*q.x;
template <typename T>
template <typename U>
-TMat44<T>::TMat44(const TMat33<U>& m) {
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m) {
m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
template <typename T>
template <typename U, typename V>
-TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0);
m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0);
m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0);
template <typename T>
template <typename U, typename V>
-TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
+CONSTEXPR TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
m_value[0] = col_type(m[0][0], m[0][1], m[0][2], 0); // NOLINT
m_value[1] = col_type(m[1][0], m[1][1], m[1][2], 0); // NOLINT
m_value[2] = col_type(m[2][0], m[2][1], m[2][2], 0); // NOLINT
// ----------------------------------------------------------------------------------------
template <typename T>
-TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
+CONSTEXPR TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
TMat44<T> m;
m[0][0] = 2 / (right - left);
m[1][1] = 2 / (top - bottom);
}
template <typename T>
-TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
+CONSTEXPR TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
TMat44<T> m;
m[0][0] = (2 * near) / (right - left);
m[1][1] = (2 * near) / (top - bottom);
}
template <typename T>
-TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) {
+CONSTEXPR TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov direction) {
T h;
T w;
*/
template <typename T>
template <typename A, typename B, typename C>
-TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) {
+CONSTEXPR TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const TVec3<C>& up) {
TVec3<T> z_axis(normalize(center - eye));
TVec3<T> norm_up(normalize(up));
if (std::abs(dot(z_axis, norm_up)) > 0.999) {
// matrix * column-vector, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) {
+CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U>& rhs) {
// Result is initialized to zero.
typename TMat44<T>::col_type result;
for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
// mat44 * vec3, result is vec3( mat44 * {vec3, 1} )
template <typename T, typename U>
-typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) {
+CONSTEXPR typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec3<U>& rhs) {
return lhs * TVec4<U>{ rhs, 1 };
}
// row-vector * matrix, result is a vector of the same type than the input vector
template <typename T, typename U>
-typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) {
+CONSTEXPR typename TMat44<U>::row_type PURE operator *(const TVec4<U>& lhs, const TMat44<T>& rhs) {
typename TMat44<U>::row_type result(TMat44<U>::row_type::NO_INIT);
for (size_t col = 0; col < TMat44<T>::NUM_COLS; ++col) {
result[col] = dot(lhs, rhs[col]);
} // namespace android
#undef PURE
+#undef CONSTEXPR
#endif // UI_MAT4_H_
#define PURE __attribute__((pure))
#endif
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
+
namespace android {
// -------------------------------------------------------------------------------------
typedef details::TQuaternion<half> quath;
constexpr inline quat operator"" _i(long double v) {
- return quat(0, v, 0, 0);
+ return quat(0, static_cast<float>(v), 0, 0);
}
constexpr inline quat operator"" _j(long double v) {
- return quat(0, 0, v, 0);
+ return quat(0, 0, static_cast<float>(v), 0);
}
constexpr inline quat operator"" _k(long double v) {
- return quat(0, 0, 0, v);
+ return quat(0, 0, 0, static_cast<float>(v));
}
constexpr inline quat operator"" _i(unsigned long long v) { // NOLINT
- return quat(0, v, 0, 0);
+ return quat(0, static_cast<float>(v), 0, 0);
}
constexpr inline quat operator"" _j(unsigned long long v) { // NOLINT
- return quat(0, 0, v, 0);
+ return quat(0, 0, static_cast<float>(v), 0);
}
constexpr inline quat operator"" _k(unsigned long long v) { // NOLINT
- return quat(0, 0, 0, v);
+ return quat(0, 0, 0, static_cast<float>(v));
}
constexpr inline quatd operator"" _id(long double v) {
- return quatd(0, v, 0, 0);
+ return quatd(0, static_cast<double>(v), 0, 0);
}
constexpr inline quatd operator"" _jd(long double v) {
- return quatd(0, 0, v, 0);
+ return quatd(0, 0, static_cast<double>(v), 0);
}
constexpr inline quatd operator"" _kd(long double v) {
- return quatd(0, 0, 0, v);
+ return quatd(0, 0, 0, static_cast<double>(v));
}
constexpr inline quatd operator"" _id(unsigned long long v) { // NOLINT
- return quatd(0, v, 0, 0);
+ return quatd(0, static_cast<double>(v), 0, 0);
}
constexpr inline quatd operator"" _jd(unsigned long long v) { // NOLINT
- return quatd(0, 0, v, 0);
+ return quatd(0, 0, static_cast<double>(v), 0);
}
constexpr inline quatd operator"" _kd(unsigned long long v) { // NOLINT
- return quatd(0, 0, 0, v);
+ return quatd(0, 0, 0, static_cast<double>(v));
}
// ----------------------------------------------------------------------------------------
} // namespace android
+#pragma clang diagnostic pop
+
#undef PURE
#endif // UI_QUAT_H_
return mix(x, y, a);
}
-namespace details {
- static int asInt(float x) {
- return *reinterpret_cast<int*>(&x);
- }
-
- static float asFloat(int x) {
- return *reinterpret_cast<float*>(&x);
- }
-
- static constexpr float inversesqrtNewtonRaphson(float x, float inverseSqrtX) {
- return inverseSqrtX * (-x * 0.5f * (inverseSqrtX * inverseSqrtX) + 1.5f);
- }
-
- static constexpr float rcpNewtonRaphson(float x, float rcpX) {
- return rcpX * (-rcpX * x + 2.0f);
- }
-
- static const float inverseSqrtFast(float f, int c) {
- int v = details::asInt(f);
- v = c - (v >> 1);
- return details::asFloat(v);
- }
-
- static const float rcpFast(float f, int c) {
- int v = details::asInt(f);
- v = c - v;
- return details::asFloat(v);
- }
-} // namespace details
-
-/**
- * Approximates an inverse square root using a specified
- * number of Newton-Raphson iterations. The number of iterations
- * can be:
- *
- * - 0, with a precision of ~3.4% over the full range
- * - 1, with a precision of ~0.2% over the full range
- * - 2, with a precision of ~4e-4% over the full range
- */
-template<int>
-static float inversesqrtFast(float f) noexcept;
-
-template<>
-float inversesqrtFast<0>(float f) noexcept {
- return details::inverseSqrtFast(f, 0x5f3759df);
-}
-
-template<>
-float inversesqrtFast<1>(float f) noexcept {
- float x = details::inverseSqrtFast(f, 0x5f375a86);
- return details::inversesqrtNewtonRaphson(f, x);
-}
-
-template<>
-float inversesqrtFast<2>(float f) noexcept {
- float x = details::inverseSqrtFast(f, 0x5f375a86);
- x = details::inversesqrtNewtonRaphson(f, x);
- x = details::inversesqrtNewtonRaphson(f, x);
- return x;
-}
-
-/**
- * Approximates a square root using a specified number of
- * Newton-Raphson iterations. The number of iterations can be:
- *
- * - 0, with a precision of ~0.7% over the full range
- * - 1, with a precision of ~0.2% over the full range
- * - 2, with a precision of ~4e-4% over the full range
- */
-template<int>
-static float sqrtFast(float f) noexcept;
-
-template<>
-float sqrtFast<0>(float f) noexcept {
- int v = details::asInt(f);
- v = 0x1fbd1df5 + (v >> 1);
- return details::asFloat(v);
-}
-
-template<>
-float sqrtFast<1>(float f) noexcept {
- return f * inversesqrtFast<1>(f);
-}
-
-template<>
-float sqrtFast<2>(float f) noexcept {
- return f * inversesqrtFast<2>(f);
-}
-
-/**
- * Approximates a reciprocal using a specified number
- * of Newton-Raphson iterations. The number of iterations
- * can be:
- *
- * - 0, with a precision of ~0.4% over the full range
- * - 1, with a precision of ~0.02% over the full range
- * - 2, with a precision of ~5e-5% over the full range
- */
-template<int>
-static float rcpFast(float f) noexcept;
-
-template<>
-float rcpFast<0>(float f) noexcept {
- return details::rcpFast(f, 0x7ef311c2);
-}
-
-template<>
-float rcpFast<1>(float f) noexcept {
- float x = details::rcpFast(f, 0x7ef311c3);
- return details::rcpNewtonRaphson(f, x);
-}
-
-template<>
-float rcpFast<2>(float f) noexcept {
- float x = details::rcpFast(f, 0x7ef312ac);
- x = details::rcpNewtonRaphson(f, x);
- x = details::rcpNewtonRaphson(f, x);
- return x;
-}
-
} // namespace std
#endif // UI_SCALAR_H
#include <sys/types.h>
#include <type_traits>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
namespace android {
// -------------------------------------------------------------------------------------
constexpr TVec2(const TVec2<A>& v) : x(v.x), y(v.y) { }
// cross product works only on vectors of size 2 or 3
- template <typename RT>
+ template<typename RT>
friend inline
constexpr value_type cross(const TVec2& u, const TVec2<RT>& v) {
return value_type(u.x*v.y - u.y*v.x);
// ----------------------------------------------------------------------------------------
} // namespace android
+#pragma clang diagnostic pop
+
#endif // UI_VEC2_H_
#include <stdint.h>
#include <sys/types.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
namespace android {
// -------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
} // namespace android
+#pragma clang diagnostic pop
+
#endif // UI_VEC3_H_
#include <stdint.h>
#include <sys/types.h>
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#pragma clang diagnostic ignored "-Wnested-anon-types"
namespace android {
// -------------------------------------------------------------------------------------
// ----------------------------------------------------------------------------------------
} // namespace android
+#pragma clang diagnostic pop
+
#endif // UI_VEC4_H_
},
srcs: [
+ "ColorSpace.cpp",
"Fence.cpp",
"FrameStats.cpp",
"Gralloc1.cpp",
--- /dev/null
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <ui/ColorSpace.h>
+
+using namespace std::placeholders;
+
+namespace android {
+
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const mat3& rgbToXYZ,
+ transfer_function OETF,
+ transfer_function EOTF,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(rgbToXYZ)
+ , mXYZtoRGB(inverse(rgbToXYZ))
+ , mOETF(std::move(OETF))
+ , mEOTF(std::move(EOTF))
+ , mClamper(std::move(clamper)) {
+
+ float3 r(rgbToXYZ * float3{1, 0, 0});
+ float3 g(rgbToXYZ * float3{0, 1, 0});
+ float3 b(rgbToXYZ * float3{0, 0, 1});
+
+ mPrimaries[0] = r.xy / dot(r, float3{1});
+ mPrimaries[1] = g.xy / dot(g, float3{1});
+ mPrimaries[2] = b.xy / dot(b, float3{1});
+
+ float3 w(rgbToXYZ * float3{1});
+ mWhitePoint = w.xy / dot(w, float3{1});
+}
+
+ColorSpace::ColorSpace(
+ const std::string& name,
+ const std::array<float2, 3>& primaries,
+ const float2& whitePoint,
+ transfer_function OETF,
+ transfer_function EOTF,
+ clamping_function clamper) noexcept
+ : mName(name)
+ , mRGBtoXYZ(computeXYZMatrix(primaries, whitePoint))
+ , mXYZtoRGB(inverse(mRGBtoXYZ))
+ , mOETF(std::move(OETF))
+ , mEOTF(std::move(EOTF))
+ , mClamper(std::move(clamper))
+ , mPrimaries(primaries)
+ , mWhitePoint(whitePoint) {
+}
+
+constexpr mat3 ColorSpace::computeXYZMatrix(
+ const std::array<float2, 3>& primaries, const float2& whitePoint) {
+ const float2& R = primaries[0];
+ const float2& G = primaries[1];
+ const float2& B = primaries[2];
+ const float2& W = whitePoint;
+
+ float oneRxRy = (1 - R.x) / R.y;
+ float oneGxGy = (1 - G.x) / G.y;
+ float oneBxBy = (1 - B.x) / B.y;
+ float oneWxWy = (1 - W.x) / W.y;
+
+ float RxRy = R.x / R.y;
+ float GxGy = G.x / G.y;
+ float BxBy = B.x / B.y;
+ float WxWy = W.x / W.y;
+
+ float BY =
+ ((oneWxWy - oneRxRy) * (GxGy - RxRy) - (WxWy - RxRy) * (oneGxGy - oneRxRy)) /
+ ((oneBxBy - oneRxRy) * (GxGy - RxRy) - (BxBy - RxRy) * (oneGxGy - oneRxRy));
+ float GY = (WxWy - RxRy - BY * (BxBy - RxRy)) / (GxGy - RxRy);
+ float RY = 1 - GY - BY;
+
+ float RYRy = RY / R.y;
+ float GYGy = GY / G.y;
+ float BYBy = BY / B.y;
+
+ return {
+ float3{RYRy * R.x, RY, RYRy * (1 - R.x - R.y)},
+ float3{GYGy * G.x, GY, GYGy * (1 - G.x - G.y)},
+ float3{BYBy * B.x, BY, BYBy * (1 - B.x - B.y)}
+ };
+}
+
+static constexpr float rcpResponse(float x, float g,float a, float b, float c, float d) {
+ return x >= d * c ? std::pow(x / a, 1.0f / g) - b / a : x / c;
+}
+
+static constexpr float response(float x, float g, float a, float b, float c, float d) {
+ return x >= d ? std::pow(a * x + b, g) : c * x;
+}
+
+static float absRcpResponse(float x, float g,float a, float b, float c, float d) {
+ return std::copysign(rcpResponse(std::abs(x), g, a, b, c, d), x);
+}
+
+static float absResponse(float x, float g, float a, float b, float c, float d) {
+ return std::copysign(response(std::abs(x), g, a, b, c, d), x);
+}
+
+const ColorSpace ColorSpace::sRGB() {
+ return {
+ "sRGB IEC61966-2.1",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
+ std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+ };
+}
+
+const ColorSpace ColorSpace::linearSRGB() {
+ return {
+ "sRGB IEC61966-2.1 (Linear)",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f}
+ };
+}
+
+const ColorSpace ColorSpace::extendedSRGB() {
+ return {
+ "scRGB-nl IEC 61966-2-2:2003",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ std::bind(absRcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
+ std::bind(absResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
+ [](float x){return x;}
+ };
+}
+
+const ColorSpace ColorSpace::linearExtendedSRGB() {
+ return {
+ "scRGB IEC 61966-2-2:2003",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ linearReponse,
+ linearReponse,
+ [](float x){return x;}
+ };
+}
+
+const ColorSpace ColorSpace::NTSC() {
+ return {
+ "NTSC (1953)",
+ {{float2{0.67f, 0.33f}, {0.21f, 0.71f}, {0.14f, 0.08f}}},
+ {0.310f, 0.316f},
+ std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
+ std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ };
+}
+
+const ColorSpace ColorSpace::BT709() {
+ return {
+ "Rec. ITU-R BT.709-5",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
+ std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ };
+}
+
+const ColorSpace ColorSpace::BT2020() {
+ return {
+ "Rec. ITU-R BT.2020-1",
+ {{float2{0.708f, 0.292f}, {0.170f, 0.797f}, {0.131f, 0.046f}}},
+ {0.3127f, 0.3290f},
+ std::bind(rcpResponse, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f),
+ std::bind(response, _1, 1 / 0.45f, 1 / 1.099f, 0.099f / 1.099f, 1 / 4.5f, 0.081f)
+ };
+}
+
+const ColorSpace ColorSpace::AdobeRGB() {
+ return {
+ "Adobe RGB (1998)",
+ {{float2{0.64f, 0.33f}, {0.21f, 0.71f}, {0.15f, 0.06f}}},
+ {0.3127f, 0.3290f},
+ std::bind(saturate<float>, std::bind(powf, _1, 1.0f / 2.2f)),
+ std::bind(saturate<float>, std::bind(powf, _1, 2.2f))
+ };
+}
+
+const ColorSpace ColorSpace::ProPhotoRGB() {
+ return {
+ "ROMM RGB ISO 22028-2:2013",
+ {{float2{0.7347f, 0.2653f}, {0.1596f, 0.8404f}, {0.0366f, 0.0001f}}},
+ {0.3457f, 0.3585f},
+ std::bind(rcpResponse, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f),
+ std::bind(response, _1, 1.8f, 1.0f, 0.0f, 1 / 16.0f, 0.031248f)
+ };
+}
+
+const ColorSpace ColorSpace::DisplayP3() {
+ return {
+ "Display P3",
+ {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ std::bind(rcpResponse, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f),
+ std::bind(response, _1, 2.4f, 1 / 1.055f, 0.055f / 1.055f, 1 / 12.92f, 0.04045f)
+ };
+}
+
+const ColorSpace ColorSpace::DCIP3() {
+ return {
+ "SMPTE RP 431-2-2007 DCI (P3)",
+ {{float2{0.680f, 0.320f}, {0.265f, 0.690f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f},
+ std::bind(saturate<float>, std::bind(powf, _1, 1.0f / 2.6f)),
+ std::bind(saturate<float>, std::bind(powf, _1, 2.6f))
+ };
+}
+
+const ColorSpace ColorSpace::ACES() {
+ return {
+ "SMPTE ST 2065-1:2012 ACES",
+ {{float2{0.73470f, 0.26530f}, {0.0f, 1.0f}, {0.00010f, -0.0770f}}},
+ {0.32168f, 0.33767f}
+ };
+}
+
+const ColorSpace ColorSpace::ACEScg() {
+ return {
+ "Academy S-2014-004 ACEScg",
+ {{float2{0.713f, 0.293f}, {0.165f, 0.830f}, {0.128f, 0.044f}}},
+ {0.32168f, 0.33767f}
+ };
+}
+
+}; // namespace android
name: "quat_test",
srcs: ["quat_test.cpp"],
}
+
+cc_test {
+ name: "colorspace_test",
+ shared_libs: ["libui"],
+ srcs: ["colorspace_test.cpp"],
+}
--- /dev/null
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ColorSpaceTest"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include <ui/ColorSpace.h>
+
+#include <gtest/gtest.h>
+
+namespace android {
+
+class ColorSpaceTest : public testing::Test {
+protected:
+};
+
+TEST_F(ColorSpaceTest, XYZ) {
+ mat3 sRGBToXYZ(transpose(mat3{
+ 0.412391f, 0.357584f, 0.180481f,
+ 0.212639f, 0.715169f, 0.072192f,
+ 0.019331f, 0.119195f, 0.950532f
+ }));
+
+ mat3 XYZtoSRGB(inverse(sRGBToXYZ));
+
+ ColorSpace sRGB("sRGB", sRGBToXYZ);
+
+ EXPECT_EQ(sRGBToXYZ, sRGB.getRGBtoXYZ());
+ EXPECT_EQ(XYZtoSRGB, sRGB.getXYZtoRGB());
+}
+
+TEST_F(ColorSpaceTest, XYZPrimaries) {
+ mat3 sRGBToXYZ(transpose(mat3{
+ 0.412391f, 0.357584f, 0.180481f,
+ 0.212639f, 0.715169f, 0.072192f,
+ 0.019331f, 0.119195f, 0.950532f
+ }));
+
+ ColorSpace sRGB("sRGB", sRGBToXYZ);
+
+ EXPECT_NEAR(0.640f, sRGB.getPrimaries()[0].x, 1e-5f);
+ EXPECT_NEAR(0.330f, sRGB.getPrimaries()[0].y, 1e-5f);
+
+ EXPECT_NEAR(0.300f, sRGB.getPrimaries()[1].x, 1e-5f);
+ EXPECT_NEAR(0.600f, sRGB.getPrimaries()[1].y, 1e-5f);
+
+ EXPECT_NEAR(0.150f, sRGB.getPrimaries()[2].x, 1e-5f);
+ EXPECT_NEAR(0.060f, sRGB.getPrimaries()[2].y, 1e-5f);
+}
+
+TEST_F(ColorSpaceTest, XYZWhitePoint) {
+ mat3 sRGBToXYZ(transpose(mat3{
+ 0.412391f, 0.357584f, 0.180481f,
+ 0.212639f, 0.715169f, 0.072192f,
+ 0.019331f, 0.119195f, 0.950532f
+ }));
+
+ ColorSpace sRGB("sRGB", sRGBToXYZ);
+
+ EXPECT_NEAR(0.3127f, sRGB.getWhitePoint().x, 1e-5f);
+ EXPECT_NEAR(0.3290f, sRGB.getWhitePoint().y, 1e-5f);
+}
+
+TEST_F(ColorSpaceTest, XYZFromPrimaries) {
+ mat3 sRGBToXYZ(transpose(mat3{
+ 0.412391f, 0.357584f, 0.180481f,
+ 0.212639f, 0.715169f, 0.072192f,
+ 0.019331f, 0.119195f, 0.950532f
+ }));
+
+ ColorSpace sRGB1("sRGB", sRGBToXYZ);
+ ColorSpace sRGB2(
+ "sRGB",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f}
+ );
+
+ for (size_t i = 0; i < 3; i++) {
+ for (size_t j= 0; j < 3; j++) {
+ ASSERT_NEAR(sRGB1.getRGBtoXYZ()[i][j], sRGB2.getRGBtoXYZ()[i][j], 1e-5f);
+ }
+ }
+
+ for (size_t i = 0; i < 3; i++) {
+ for (size_t j= 0; j < 3; j++) {
+ ASSERT_NEAR(sRGB2.getXYZtoRGB()[i][j], sRGB2.getXYZtoRGB()[i][j], 1e-5f);
+ }
+ }
+}
+
+TEST_F(ColorSpaceTest, TransferFunctions) {
+ ColorSpace sRGB = ColorSpace::sRGB();
+
+ for (float v = 0.0f; v <= 0.5f; v += 1e-3f) {
+ ASSERT_TRUE(v >= sRGB.getEOTF()(v));
+ ASSERT_TRUE(v <= sRGB.getOETF()(v));
+ }
+
+ float previousEOTF = std::numeric_limits<float>::lowest();
+ float previousOETF = std::numeric_limits<float>::lowest();
+ for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
+ ASSERT_TRUE(previousEOTF < sRGB.getEOTF()(v));
+ previousEOTF = sRGB.getEOTF()(v);
+ ASSERT_TRUE(previousOETF < sRGB.getOETF()(v));
+ previousOETF = sRGB.getOETF()(v);
+ }
+
+ ColorSpace sRGB2(
+ "sRGB",
+ {{float2{0.640f, 0.330f}, {0.300f, 0.600f}, {0.150f, 0.060f}}},
+ {0.3127f, 0.3290f}
+ // linear transfer functions
+ );
+ for (float v = 0.0f; v <= 1.0f; v += 1e-3f) {
+ ASSERT_EQ(v, sRGB2.getEOTF()(v));
+ ASSERT_EQ(v, sRGB2.getOETF()(v));
+ }
+}
+
+TEST_F(ColorSpaceTest, Clamping) {
+ // Pick a color outside of sRGB
+ float3 c(ColorSpace::DCIP3().rgbToXYZ(float3{0, 1, 0}));
+
+ // The color will be clamped
+ float3 sRGB(ColorSpace::sRGB().xyzToRGB(c));
+ EXPECT_TRUE(sRGB > float3{0.0} && sRGB < float3{1.0});
+
+ // The color will not be clamped
+ float3 extendedSRGB(ColorSpace::linearExtendedSRGB().xyzToRGB(c));
+ EXPECT_TRUE(extendedSRGB.g > 1.0f);
+}
+
+}; // namespace android
TEST_F(HalfTest, Basics) {
- EXPECT_EQ(2, sizeof(half));
+ EXPECT_EQ(2UL, sizeof(half));
// test +/- zero
EXPECT_EQ(0x0000, half( 0.0f).getBits());