Skip to content

Commit

Permalink
Add BT.709 and BT.2020 color spaces. Improve RGB color space functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
cjhoward committed Apr 18, 2024
1 parent 539276c commit 743e9cc
Show file tree
Hide file tree
Showing 19 changed files with 428 additions and 102 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ bin
build
res/data
.~lock*
.cache
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ endif()
cmake_minimum_required(VERSION 3.27)
include(FetchContent)
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

project(Antkeeper
VERSION 0.0.1
Expand Down Expand Up @@ -354,7 +355,7 @@ target_compile_definitions(${PROJECT_NAME}
# Set compile options
target_compile_options(${PROJECT_NAME}
PRIVATE
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -pedantic>
$<$<CXX_COMPILER_ID:GNU,Clang>:-Wall -Wextra -Wpedantic -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-c++11-compat -Wno-c++11-compat-pedantic -Wno-c++14-compat -Wno-c++14-compat-pedantic -Wno-c++17-compat -Wno-c++17-compat-pedantic -Wno-c++20-compat -Wno-c++20-compat-pedantic>
$<$<CXX_COMPILER_ID:MSVC>:
/W4 /we4265 /we5204 /we5263 /we4946 /we4822 /we4355 /we4061 /we4062 /EHsc /GR-
$<$<NOT:$<CONFIG:Debug>>:/GL>
Expand Down
41 changes: 39 additions & 2 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@
"architecture":
{
"value": "x64",
"strategy": "set"
"strategy": "external"
},
"binaryDir": "${sourceDir}/build/windows-x64"
},
{
"name": "windows-clang-x64",
"inherits": "windows-x64",
"hidden": true,
"toolset": "ClangCL",
"binaryDir": "${sourceDir}/build/windows-clang-x64"
},
{
"name": "linux-x64",
"hidden": true,
Expand Down Expand Up @@ -48,6 +55,24 @@
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "windows-clang-x64-debug",
"displayName": "Windows Clang 64-bit Debug",
"inherits": "windows-clang-x64",
"cacheVariables":
{
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "windows-clang-x64-release",
"displayName": "Windows Clang 64-bit Release",
"inherits": "windows-clang-x64",
"cacheVariables":
{
"CMAKE_BUILD_TYPE": "Release"
}
},
{
"name": "linux-x64-debug",
"displayName": "Linux 64-bit Debug",
Expand Down Expand Up @@ -81,6 +106,18 @@
"configurePreset": "windows-x64-release",
"configuration": "Release"
},
{
"name": "windows-clang-x64-debug",
"displayName": "Windows Clang 64-bit Debug",
"configurePreset": "windows-clang-x64-debug",
"configuration": "Debug"
},
{
"name": "windows-clang-x64-release",
"displayName": "Windows Clang 64-bit Release",
"configurePreset": "windows-clang-x64-release",
"configuration": "Release"
},
{
"name": "linux-x64-debug",
"displayName": "Linux 64-bit Debug",
Expand All @@ -94,4 +131,4 @@
"configuration": "Release"
}
]
}
}
5 changes: 5 additions & 0 deletions src/engine/app/sdl/sdl-window-manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,11 @@ sdl_window_manager::sdl_window_manager()
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, config::opengl_min_depth_size);
SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, config::opengl_min_stencil_size);
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0);

// for HDR support
// SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 16);
// SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 16);
// SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 16);
}

sdl_window_manager::~sdl_window_manager()
Expand Down
115 changes: 115 additions & 0 deletions src/engine/color/bt2020.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// SPDX-FileCopyrightText: 2023 C. J. Howard
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ANTKEEPER_COLOR_BT2020_HPP
#define ANTKEEPER_COLOR_BT2020_HPP

#include <engine/color/rgb.hpp>
#include <cmath>

namespace color {

/// @name ITU-R BT.2020 color space
/// @{

/// @{
/**
* ITU-R BT.2020 Opto-Electronic Transfer Function (OETF).
*
* @param x Linear BT.2020 tristimulus.
* @param alpha OETF alpha constant.
* @param beta OETF beta constant.
*
* @return Non-linear BT.2020 signal.
*/
template <class T>
[[nodiscard]] math::vec3<T> bt2020_oetf(const math::vec3<T>& x, T alpha, T beta)
{
auto f = [alpha, beta](T x) -> T
{
return x < beta ? T{4.5} * x : alpha * std::pow(x, T{0.45}) - (alpha - T{1});
};

return {f(x[0]), f(x[1]), f(x[2])};
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_oetf_precise(const math::vec3<T>& x)
{
return bt2020_oetf(x, T{1} + T{5.5} * T{0.018053968510807}, T{0.018053968510807});
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_oetf_12_bits(const math::vec3<T>& x)
{
return bt2020_oetf(x, T{1.0993}, T{0.0181});
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_oetf_10_bits(const math::vec3<T>& x)
{
return bt2020_oetf(x, T{1.099}, T{0.018});
}
/// @}

/// @{
/**
* ITU-R BT.2020 inverse OETF.
*
* @param x Non-linear BT.2020 signal.
* @param alpha OETF alpha constant.
* @param beta OETF beta constant.
*
* @return Linear BT.2020 tristimulus.
*/
template <class T>
[[nodiscard]] math::vec3<T> bt2020_inverse_oetf(const math::vec3<T>& x, T alpha, T beta)
{
const auto oetf_beta = alpha * std::pow(beta, T{0.45}) - (alpha - T{1});

auto f = [alpha, oetf_beta](T x) -> T
{
return x < oetf_beta ? x / T{4.5} : std::pow((x + alpha - T{1}) / alpha, T{1} / T{0.45});
};

return {f(x[0]), f(x[1]), f(x[2])};
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_inverse_oetf_precise(const math::vec3<T>& x)
{
return bt2020_inverse_oetf(x, T{1} + T{5.5} * T{0.018053968510807}, T{0.018053968510807});
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_inverse_oetf_12_bits(const math::vec3<T>& x)
{
return bt2020_inverse_oetf(x, T{1.0993}, T{0.0181});
}

template <class T>
[[nodiscard]] math::vec3<T> bt2020_inverse_oetf_10_bits(const math::vec3<T>& x)
{
return bt2020_inverse_oetf(x, T{1.099}, T{0.018});
}
/// @}

/**
* ITU-R BT.2020 color space.
*/
template <class T>
constexpr rgb_color_space<T> bt2020
(
{T{0.7080}, T{0.2920}},
{T{0.1700}, T{0.7970}},
{T{0.1310}, T{0.0460}},
{T{0.3127}, T{0.3290}},
&bt2020_oetf_10_bits<T>,
&bt2020_inverse_oetf_10_bits<T>
);

/// @}

} // namespace color

#endif // ANTKEEPER_COLOR_BT2020_HPP
71 changes: 71 additions & 0 deletions src/engine/color/bt709.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// SPDX-FileCopyrightText: 2023 C. J. Howard
// SPDX-License-Identifier: GPL-3.0-or-later

#ifndef ANTKEEPER_COLOR_BT709_HPP
#define ANTKEEPER_COLOR_BT709_HPP

#include <engine/color/rgb.hpp>
#include <cmath>

namespace color {

/// @name ITU-R BT.709 color space
/// @{

/**
* ITU-R BT.709 Opto-Electronic Transfer Function (OETF).
*
* @param x Linear BT.709 tristimulus.
*
* @return Non-linear BT.709 signal.
*/
template <class T>
[[nodiscard]] math::vec3<T> bt709_oetf(const math::vec3<T>& x)
{
auto f = [](T x) -> T
{
return x < T{0.018} ? T{4.5} * x : T{1.099} * std::pow(x, T{0.45}) - T{0.099};
};

return {f(x[0]), f(x[1]), f(x[2])};
}

/**
* ITU-R BT.709 inverse OETF.
*
* @param x Non-linear BT.709 signal.
*
* @return Linear BT.709 tristimulus.
*/
template <class T>
[[nodiscard]] math::vec3<T> bt709_inverse_oetf(const math::vec3<T>& x)
{
const auto oetf_beta = T{1.099} * std::pow(T{0.018}, T{0.45}) - T{0.099};

auto f = [oetf_beta](T x) -> T
{
return x < oetf_beta ? x / T{4.5} : std::pow((x + T{0.099}) / T{1.099}, T{1} / T{0.45});
};

return {f(x[0]), f(x[1]), f(x[2])};
}

/**
* ITU-R BT.709 color space.
*/
template <class T>
constexpr rgb_color_space<T> bt709
(
{T{0.6400}, T{0.3300}},
{T{0.3000}, T{0.6000}},
{T{0.1500}, T{0.0600}},
{T{0.3127}, T{0.3290}},
&bt709_oetf<T>,
&bt709_inverse_oetf<T>
);

/// @}

} // namespace color

#endif // ANTKEEPER_COLOR_BT709_HPP
14 changes: 7 additions & 7 deletions src/engine/color/cat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,18 @@ template <class T>
[[nodiscard]] constexpr math::mat3<T> cat_matrix(const math::vec2<T>& w0, const math::vec2<T>& w1, const math::mat3<T>& cone_response = bradford_cone_response<T>) noexcept
{
// Convert CIE xy chromaticity coordinates to CIE XYZ colors
const math::vec3<T> w0_xyz = {w0[0] / w0[1], T{1}, (T{1} - w0[0] - w0[1]) / w0[1]};
const math::vec3<T> w1_xyz = {w1[0] / w1[1], T{1}, (T{1} - w1[0] - w1[1]) / w1[1]};
const math::vec3<T> w0_xyz = {w0.x() / w0.y(), T{1}, (T{1} - w0.x() - w0.y()) / w0.y()};
const math::vec3<T> w1_xyz = {w1.x() / w1.y(), T{1}, (T{1} - w1.x() - w1.y()) / w1.y()};

// Calculate cone response of CIE XYZ colors
const math::vec3<T> w0_cone_response = cone_response * w0_xyz;
const math::vec3<T> w1_cone_response = cone_response * w1_xyz;
const auto cone_response_w0 = cone_response * w0_xyz;
const auto cone_response_w1 = cone_response * w1_xyz;

const math::mat3<T> scale =
{
w1_cone_response[0] / w0_cone_response[0], T{0}, T{0},
T{0}, w1_cone_response[1] / w0_cone_response[1], T{0},
T{0}, T{0}, w1_cone_response[2] / w0_cone_response[2],
cone_response_w1.x() / cone_response_w0.x(), T{0}, T{0},
T{0}, cone_response_w1.y() / cone_response_w0.y(), T{0},
T{0}, T{0}, cone_response_w1.z() / cone_response_w0.z(),
};

return math::inverse(cone_response) * scale * cone_response;
Expand Down
2 changes: 2 additions & 0 deletions src/engine/color/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
namespace color {}

#include <engine/color/aces.hpp>
#include <engine/color/bt2020.hpp>
#include <engine/color/bt709.hpp>
#include <engine/color/cat.hpp>
#include <engine/color/cct.hpp>
#include <engine/color/illuminants.hpp>
Expand Down
6 changes: 3 additions & 3 deletions src/engine/color/illuminants.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ inline constexpr math::vec2<T> deg2_d50 = {T{0.34567}, T{0.35850}};
template <class T>
inline constexpr math::vec2<T> deg2_d55 = {T{0.33242}, T{0.34743}};
template <class T>
inline constexpr math::vec2<T> deg2_d65 = {T{0.31271}, T{0.32902}};
inline constexpr math::vec2<T> deg2_d65 = {T{0.31270}, T{0.32900}};
template <class T>
inline constexpr math::vec2<T> deg2_d75 = {T{0.29902}, T{0.31485}};
template <class T>
inline constexpr math::vec2<T> deg2_d93 = {T{0.28315}, T{0.29711}};
template <class T>
inline constexpr math::vec2<T> deg2_e = {T{0.33333}, T{0.33333}};
inline constexpr math::vec2<T> deg2_e = {T{1} / T{3}, T{1} / T{3}};
template <class T>
inline constexpr math::vec2<T> deg2_f1 = {T{0.31310}, T{0.33727}};
template <class T>
Expand Down Expand Up @@ -97,7 +97,7 @@ inline constexpr math::vec2<T> deg10_d75 = {T{0.29968}, T{0.31740}};
template <class T>
inline constexpr math::vec2<T> deg10_d93 = {T{0.28327}, T{0.30043}};
template <class T>
inline constexpr math::vec2<T> deg10_e = {T{0.33333}, T{0.33333}};
inline constexpr math::vec2<T> deg10_e = {T{1} / T{3}, T{1} / T{3}};
template <class T>
inline constexpr math::vec2<T> deg10_f1 = {T{0.31811}, T{0.33559}};
template <class T>
Expand Down
Loading

0 comments on commit 743e9cc

Please sign in to comment.