96 lines
3.4 KiB
C++
96 lines
3.4 KiB
C++
/*
|
|
enoki/color.h -- Color space transformations (only sRGB so far)
|
|
|
|
Enoki is a C++ template library that enables transparent vectorization
|
|
of numerical kernels using SIMD instruction sets available on current
|
|
processor architectures.
|
|
|
|
Copyright (c) 2019 Wenzel Jakob <wenzel.jakob@epfl.ch>
|
|
|
|
All rights reserved. Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <enoki/array.h>
|
|
|
|
NAMESPACE_BEGIN(enoki)
|
|
|
|
template <typename T> expr_t<T> linear_to_srgb(const T &x) {
|
|
using Value = expr_t<T>;
|
|
using Mask = mask_t<Value>;
|
|
using Scalar = scalar_t<Value>;
|
|
constexpr bool Single = std::is_same_v<Scalar, float>;
|
|
|
|
Value r = Scalar(12.92);
|
|
Mask large_mask = x > Scalar(0.0031308);
|
|
|
|
if (ENOKI_LIKELY(any(large_mask))) {
|
|
Value y = sqrt(x), p, q;
|
|
|
|
if constexpr (Single) {
|
|
p = poly5(y, -0.0016829072605308378, 0.03453868659826638,
|
|
0.7642611304733891, 2.0041169284241644,
|
|
0.7551545191665577, -0.016202083165206348);
|
|
q = poly5(y, 4.178892964897981e-7, -0.00004375359692957097,
|
|
0.03467195408529984, 0.6085338522168684,
|
|
1.8970238036421054, 1.);
|
|
} else {
|
|
p = poly10(y, -3.7113872202050023e-6, -0.00021805827098915798,
|
|
0.002531335520959116, 0.2263810267005674,
|
|
3.0477578489880823, 15.374469584296442,
|
|
32.44669922192121, 27.901125077137042, 8.450947414259522,
|
|
0.5838023820686707, -0.0031151377052754843);
|
|
q = poly10(y, 2.2380622409188757e-11, -8.387527630781522e-9,
|
|
0.00007045228641004039, 0.007244514696840552,
|
|
0.21749170309546628, 2.575446652731678,
|
|
13.297981743005433, 30.50364355650628, 29.70548706952188,
|
|
10.723011300050162, 1.);
|
|
}
|
|
|
|
masked(r, large_mask) = p / q;
|
|
}
|
|
|
|
return r * x;
|
|
}
|
|
|
|
template <typename T> expr_t<T> srgb_to_linear(const T &x) {
|
|
using Value = expr_t<T>;
|
|
using Mask = mask_t<Value>;
|
|
using Scalar = scalar_t<Value>;
|
|
constexpr bool Single = std::is_same_v<Scalar, float>;
|
|
|
|
Value r = Scalar(1.0 / 12.92);
|
|
Mask large_mask = x > Scalar(0.04045);
|
|
|
|
if (ENOKI_LIKELY(any(large_mask))) {
|
|
Value p, q;
|
|
|
|
if constexpr (Single) {
|
|
p = poly4(x, -0.0163933279112946, -0.7386328024653209,
|
|
-11.199318357635072, -47.46726633009393,
|
|
-36.04572663838034);
|
|
q = poly4(x, -0.004261480793199332, -19.140923959601675,
|
|
-59.096406619244426, -18.225745396846637, 1.);
|
|
} else {
|
|
p = poly9(x, -0.008042950896814532, -0.5489744177844188,
|
|
-14.786385491859248, -200.19589605282445,
|
|
-1446.951694673217, -5548.704065887224,
|
|
-10782.158977031822, -9735.250875334352,
|
|
-3483.4445569178347, -342.62884098034357);
|
|
q = poly9(x, -2.2132610916769585e-8, -9.646075249097724,
|
|
-237.47722999429413, -2013.8039726540235,
|
|
-7349.477378676199, -11916.470977597566,
|
|
-8059.219012060384, -1884.7738197074218,
|
|
-84.8098437770271, 1.);
|
|
}
|
|
|
|
masked(r, large_mask) = p / q;
|
|
}
|
|
|
|
return r * x;
|
|
}
|
|
|
|
NAMESPACE_END(enoki)
|