OSDN Git Service

Add ColorSpace class
authorRomain Guy <romainguy@google.com>
Thu, 10 Nov 2016 19:45:58 +0000 (11:45 -0800)
committerRomain Guy <romainguy@google.com>
Thu, 10 Nov 2016 21:06:18 +0000 (13:06 -0800)
The ColorSpace class can be used to create an RGB color space from
either primaries/whitepoint or an RGB->XYZ matrix.

The primaries and whitepoint are in xyY space. A utility function
is provided to compute xyY coordinates from XYZ coordinats.

The class contains numerous functions to create common RGB color
spaces (sRGB, DCI-P3, etc.).

Test: colorspace_test
Bug: 29940137
Change-Id: Ifba8701377d058f5877176dabf4183e904a4cde0

17 files changed:
include/ui/ColorSpace.h [new file with mode: 0644]
include/ui/TMatHelpers.h
include/ui/TVecHelpers.h
include/ui/half.h
include/ui/mat2.h
include/ui/mat3.h
include/ui/mat4.h
include/ui/quat.h
include/ui/scalar.h
include/ui/vec2.h
include/ui/vec3.h
include/ui/vec4.h
libs/ui/Android.bp
libs/ui/ColorSpace.cpp [new file with mode: 0644]
libs/ui/tests/Android.bp
libs/ui/tests/colorspace_test.cpp [new file with mode: 0644]
libs/ui/tests/half_test.cpp

diff --git a/include/ui/ColorSpace.h b/include/ui/ColorSpace.h
new file mode 100644 (file)
index 0000000..2543e7f
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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
index 9daca08..8edf5f8 100644 (file)
 
 #define PURE __attribute__((pure))
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 namespace details {
 // -------------------------------------------------------------------------------------
@@ -103,10 +109,10 @@ MATRIX PURE gaussJordanInverse(const MATRIX& src) {
         // 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;
                 }
             }
         }
@@ -119,7 +125,7 @@ MATRIX PURE gaussJordanInverse(const MATRIX& src) {
 //------------------------------------------------------------------------------
 // 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:
@@ -153,7 +159,7 @@ MATRIX PURE fastInverse2(const MATRIX& x) {
 // 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:
@@ -216,7 +222,6 @@ MATRIX PURE fastInverse3(const MATRIX& x) {
     return inverted;
 }
 
-
 /**
  * Inversion function which switches on the matrix size.
  * @warning This function assumes the matrix is invertible. The result is
@@ -232,7 +237,7 @@ inline constexpr MATRIX PURE inverse(const MATRIX& matrix) {
 }
 
 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
@@ -254,7 +259,7 @@ MATRIX_R PURE multiply(const MATRIX_A& lhs, const MATRIX_B& rhs) {
 
 // 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);
@@ -268,7 +273,7 @@ MATRIX PURE transpose(const MATRIX& m) {
 
 // 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) {
@@ -279,7 +284,7 @@ typename MATRIX::value_type PURE trace(const MATRIX& m) {
 
 // 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) {
@@ -389,7 +394,7 @@ public:
 
     // 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);
     }
 };
@@ -419,7 +424,7 @@ public:
      * 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) {
@@ -454,7 +459,7 @@ public:
     }
 
     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;
@@ -465,7 +470,7 @@ public:
         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]);
         }
@@ -482,7 +487,7 @@ public:
     }
 
     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);
@@ -533,7 +538,7 @@ public:
         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);
     }
 
@@ -552,7 +557,7 @@ public:
     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);
@@ -630,5 +635,6 @@ public:
 #undef LIKELY
 #undef UNLIKELY
 #undef PURE
+#undef CONSTEXPR
 
 #endif  // UI_TMATHELPERS_H_
index 1eaa6e6..de1d9ff 100644 (file)
 
 #define PURE __attribute__((pure))
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 namespace details {
 // -------------------------------------------------------------------------------------
@@ -228,6 +234,7 @@ public:
         }
         return rhs;
     }
+
     VECTOR<T>& operator --() {
         VECTOR<T>& rhs = static_cast<VECTOR<T>&>(*this);
         for (size_t i = 0; i < rhs.size(); i++) {
@@ -235,7 +242,8 @@ public:
         }
         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++) {
@@ -333,7 +341,7 @@ public:
      * (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);
@@ -372,71 +380,71 @@ public:
         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]);
@@ -444,21 +452,21 @@ public:
         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]);
@@ -466,13 +474,20 @@ public:
         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;
+    }
 };
 
 /*
@@ -502,6 +517,7 @@ public:
     }
 };
 
+#undef CONSTEXPR
 #undef PURE
 
 // -------------------------------------------------------------------------------------
index cbc1ef0..7a271dc 100644 (file)
 #   define UNLIKELY( exp )  (__builtin_expect( !!(exp), 0 ))
 #endif
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 
 /*
@@ -50,13 +56,13 @@ class half {
     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 {
@@ -68,14 +74,14 @@ class half {
         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(); }
@@ -83,23 +89,23 @@ public:
 
 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
@@ -120,7 +126,7 @@ inline /* constexpr */ half::fp16 half::ftoh(float v) noexcept {
     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);
@@ -132,7 +138,7 @@ inline float half::htof(half::fp16 in) noexcept {
                 // (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);
@@ -142,8 +148,8 @@ inline float half::htof(half::fp16 in) noexcept {
     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
@@ -197,5 +203,6 @@ public:
 
 #undef LIKELY
 #undef UNLIKELY
+#undef CONSTEXPR
 
 #endif // UI_HALF_H
index 5ae73dc..37c7221 100644 (file)
 
 #define PURE __attribute__((pure))
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 // -------------------------------------------------------------------------------------
 namespace details {
@@ -130,8 +136,7 @@ public:
     /**
      * 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) } {}
 
@@ -148,7 +153,7 @@ public:
      *      \right)
      *      \f$
      */
-    TMat22();
+    CONSTEXPR TMat22();
 
     /**
      * initialize to Identity*scalar.
@@ -163,7 +168,7 @@ public:
      *      \f$
      */
     template<typename U>
-    explicit TMat22(U v);
+    explicit CONSTEXPR TMat22(U v);
 
     /**
      * sets the diagonal to a vector.
@@ -178,13 +183,13 @@ public:
      *      \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.
@@ -198,7 +203,7 @@ public:
      *      \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.
      *
@@ -214,19 +219,18 @@ public:
     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);
@@ -244,21 +248,21 @@ public:
 // 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);
 }
@@ -270,15 +274,14 @@ template<typename T>
 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]);
     }
@@ -287,7 +290,7 @@ TMat22<T>::TMat22(const TMat22<U>& rhs) {
 // 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;
 }
@@ -295,7 +298,7 @@ TMat22<T>::TMat22(const TVec2<A>& v0, const TVec2<B>& 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++;
@@ -317,7 +320,7 @@ TMat22<T>::TMat22(U const* 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) {
@@ -328,7 +331,7 @@ typename TMat22<U>::col_type PURE operator *(const TMat22<T>& lhs, const TVec2<U
 
 // 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]);
@@ -356,7 +359,7 @@ operator*(U lhs, const TMat22<T>& rhs) {
  * 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);
 }
 
@@ -372,5 +375,6 @@ typedef details::TMat22<float> mat2f;
 }  // namespace android
 
 #undef PURE
+#undef CONSTEXPR
 
 #endif  // UI_MAT2_H_
index 6a071c1..cd24a44 100644 (file)
 
 #define PURE __attribute__((pure))
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 // -------------------------------------------------------------------------------------
 namespace details {
@@ -137,8 +143,7 @@ public:
     /**
      * 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) } {}
@@ -157,7 +162,7 @@ public:
      *      \right)
      *      \f$
      */
-    TMat33();
+    CONSTEXPR TMat33();
 
     /**
      * initialize to Identity*scalar.
@@ -173,7 +178,7 @@ public:
      *      \f$
      */
     template<typename U>
-    explicit TMat33(U v);
+    explicit CONSTEXPR TMat33(U v);
 
     /**
      * sets the diagonal to a vector.
@@ -189,13 +194,13 @@ public:
      *      \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.
@@ -209,7 +214,7 @@ public:
      *      \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.
      *
@@ -227,7 +232,8 @@ public:
         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);
 
@@ -235,19 +241,19 @@ public:
      * 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]));
@@ -264,7 +270,7 @@ public:
 // 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);
@@ -272,7 +278,7 @@ TMat33<T>::TMat33() {
 
 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);
@@ -280,7 +286,7 @@ TMat33<T>::TMat33(U 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);
@@ -294,9 +300,10 @@ template <
     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);
@@ -304,7 +311,7 @@ TMat33<T>::TMat33(A m00, B m01, C m02,
 
 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]);
     }
@@ -313,7 +320,7 @@ TMat33<T>::TMat33(const TMat33<U>& rhs) {
 // 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;
@@ -322,7 +329,7 @@ TMat33<T>::TMat33(const TVec3<A>& v0, const TVec3<B>& v1, const TVec3<C>& 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++;
@@ -332,7 +339,7 @@ TMat33<T>::TMat33(U const* 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;
@@ -366,7 +373,7 @@ TMat33<T>::TMat33(const TQuaternion<U>& q) {
 
 // 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) {
@@ -377,7 +384,7 @@ typename TMat33<U>::col_type PURE operator *(const TMat33<T>& lhs, const TVec3<U
 
 // 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]);
@@ -401,7 +408,7 @@ operator*(U lhs, const TMat33<T>& rhs) {
 
 //------------------------------------------------------------------------------
 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]));
@@ -415,7 +422,7 @@ TMat33<T> orthogonalize(const TMat33<T>& m) {
  * 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);
 }
 
@@ -431,5 +438,6 @@ typedef details::TMat33<float> mat3f;
 }  // namespace android
 
 #undef PURE
+#undef CONSTEXPR
 
 #endif  // UI_MAT3_H_
index a607023..f63d40a 100644 (file)
 
 #define PURE __attribute__((pure))
 
+#if __cplusplus >= 201402L
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
 namespace android {
 // -------------------------------------------------------------------------------------
 namespace details {
@@ -141,8 +147,7 @@ public:
      */
 
     // 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),
@@ -161,7 +166,7 @@ public:
      *      \right)
      *      \f$
      */
-    TMat44();
+    CONSTEXPR TMat44();
 
     /** initialize to Identity*scalar.
      *
@@ -177,7 +182,7 @@ public:
      *      \f$
      */
     template<typename U>
-    explicit TMat44(U v);
+    explicit CONSTEXPR TMat44(U v);
 
     /** sets the diagonal to a vector.
      *
@@ -193,11 +198,11 @@ public:
      *      \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.
      *
@@ -210,7 +215,7 @@ public:
      *      \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.
      *
@@ -230,66 +235,67 @@ public:
         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 };
     }
@@ -310,7 +316,7 @@ public:
 // 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);
@@ -319,7 +325,7 @@ TMat44<T>::TMat44() {
 
 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);
@@ -328,7 +334,7 @@ TMat44<T>::TMat44(U v) {
 
 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);
@@ -342,10 +348,11 @@ template <
     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);
@@ -354,7 +361,7 @@ TMat44<T>::TMat44(A m00, B m01, C m02, D m03,
 
 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]);
     }
@@ -363,7 +370,9 @@ TMat44<T>::TMat44(const TMat44<U>& rhs) {
 // 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);
@@ -373,7 +382,7 @@ TMat44<T>::TMat44(const TVec4<A>& v0, const TVec4<B>& v1, const TVec4<C>& v2, co
 // 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++;
@@ -383,7 +392,7 @@ TMat44<T>::TMat44(U const* 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;
@@ -406,7 +415,7 @@ TMat44<T>::TMat44(const TQuaternion<U>& q) {
 
 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);
@@ -415,7 +424,7 @@ TMat44<T>::TMat44(const TMat33<U>& m) {
 
 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);
@@ -424,7 +433,7 @@ TMat44<T>::TMat44(const TMat33<U>& m, const TVec3<V>& v) {
 
 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
@@ -436,7 +445,7 @@ TMat44<T>::TMat44(const TMat33<U>& m, const TVec4<V>& v) {
 // ----------------------------------------------------------------------------------------
 
 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);
@@ -448,7 +457,7 @@ TMat44<T> TMat44<T>::ortho(T left, T right, T bottom, T top, T near, T far) {
 }
 
 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);
@@ -462,7 +471,7 @@ TMat44<T> TMat44<T>::frustum(T left, T right, T bottom, T top, T near, T far) {
 }
 
 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;
 
@@ -483,7 +492,7 @@ TMat44<T> TMat44<T>::perspective(T fov, T aspect, T near, T far, TMat44::Fov dir
  */
 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) {
@@ -513,7 +522,7 @@ TMat44<T> TMat44<T>::lookAt(const TVec3<A>& eye, const TVec3<B>& center, const T
 
 // 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) {
@@ -524,14 +533,14 @@ typename TMat44<T>::col_type PURE operator *(const TMat44<T>& lhs, const TVec4<U
 
 // 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]);
@@ -575,5 +584,6 @@ typedef details::TMat44<float> mat4f;
 }  // namespace android
 
 #undef PURE
+#undef CONSTEXPR
 
 #endif  // UI_MAT4_H_
index 8c89cd7..5b8cd8b 100644 (file)
 #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 {
 // -------------------------------------------------------------------------------------
 
@@ -142,48 +146,50 @@ typedef details::TQuaternion<float> quatf;
 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_
index c938d5c..5f8329e 100644 (file)
@@ -42,126 +42,6 @@ static constexpr T lerp(T x, T y, T a) noexcept {
     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
index a88d026..fdd2e20 100644 (file)
@@ -24,6 +24,9 @@
 #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 {
 // -------------------------------------------------------------------------------------
@@ -94,7 +97,7 @@ public:
     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);
@@ -119,4 +122,6 @@ typedef details::TVec2<uint8_t> ubyte2;
 // ----------------------------------------------------------------------------------------
 }  // namespace android
 
+#pragma clang diagnostic pop
+
 #endif  // UI_VEC2_H_
index 0254f5a..f76b2ec 100644 (file)
@@ -22,6 +22,9 @@
 #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 {
 // -------------------------------------------------------------------------------------
@@ -125,4 +128,6 @@ typedef details::TVec3<uint8_t> ubyte3;
 // ----------------------------------------------------------------------------------------
 }  // namespace android
 
+#pragma clang diagnostic pop
+
 #endif  // UI_VEC3_H_
index 1281aa4..e13ad96 100644 (file)
@@ -22,6 +22,9 @@
 #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 {
 // -------------------------------------------------------------------------------------
@@ -122,4 +125,6 @@ typedef details::TVec4<uint8_t> ubyte4;
 // ----------------------------------------------------------------------------------------
 }  // namespace android
 
+#pragma clang diagnostic pop
+
 #endif  // UI_VEC4_H_
index 0d1f604..087e877 100644 (file)
@@ -41,6 +41,7 @@ cc_library_shared {
     },
 
     srcs: [
+        "ColorSpace.cpp",
         "Fence.cpp",
         "FrameStats.cpp",
         "Gralloc1.cpp",
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
new file mode 100644 (file)
index 0000000..081aca9
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * 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
index 9594466..c4f34d5 100644 (file)
@@ -39,3 +39,9 @@ cc_test {
     name: "quat_test",
     srcs: ["quat_test.cpp"],
 }
+
+cc_test {
+    name: "colorspace_test",
+    shared_libs: ["libui"],
+    srcs: ["colorspace_test.cpp"],
+}
diff --git a/libs/ui/tests/colorspace_test.cpp b/libs/ui/tests/colorspace_test.cpp
new file mode 100644 (file)
index 0000000..5c127ad
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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
index 0ea9265..b2a5e5c 100644 (file)
@@ -32,7 +32,7 @@ protected:
 
 TEST_F(HalfTest, Basics) {
 
-    EXPECT_EQ(2, sizeof(half));
+    EXPECT_EQ(2UL, sizeof(half));
 
     // test +/- zero
     EXPECT_EQ(0x0000, half( 0.0f).getBits());