blob: c938d5cda2539d07a962eb0b22a3e5acc017a062 [file] [log] [blame]
/*
* 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 UI_SCALAR_H
#define UI_SCALAR_H
#include <algorithm>
#include <cmath>
namespace android {
template<typename T>
static constexpr T saturate(T v) noexcept {
return T(std::min(T(1), std::max(T(0), v)));
}
template<typename T>
static constexpr T clamp(T v, T min, T max) noexcept {
return T(std::min(max, std::max(min, v)));
}
template<typename T>
static constexpr T mix(T x, T y, T a) noexcept {
return x * (T(1) - a) + y * a;
}
template<typename T>
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