Skip to content

Commit

Permalink
Implement hue rotation control
Browse files Browse the repository at this point in the history
  • Loading branch information
averne committed Oct 12, 2024
1 parent 0af6a01 commit b615e99
Show file tree
Hide file tree
Showing 15 changed files with 81 additions and 2 deletions.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export FZ_VERSION = 2.5.5
export FZ_VERSION = 2.6.0
export FZ_COMMIT = $(shell git rev-parse --short HEAD)
export FZ_TID = 0100000000000F12

Expand Down
3 changes: 3 additions & 0 deletions application/src/gfx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,9 @@ void render_preview(FizeauSettings &settings, int width, int height, int src_ima
// Apply saturation
coeffs = dot(coeffs, saturation_matrix(settings.saturation));

// Apply hue rotation
coeffs = dot(coeffs, hue_matrix(settings.hue));

auto colormatrix = glm::mat4(
coeffs[0], coeffs[1], coeffs[2], 0,
coeffs[3], coeffs[4], coeffs[5], 0,
Expand Down
7 changes: 7 additions & 0 deletions application/src/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,13 @@ Result draw_color_tab(Config &ctx) {

im::Separator();

// Saturation sliders
im::TextUnformatted("Hue");
ctx.is_editing_day_profile |= new_slider("Day:", "##hued", ctx.profile.day_settings.hue, MIN_HUE, MAX_HUE, "%.2f");
ctx.is_editing_night_profile |= new_slider("Night:", "##huen", ctx.profile.night_settings.hue, MIN_HUE, MAX_HUE, "%.2f");

im::Separator();

// Filter combos
im::TextUnformatted("Filter");
ctx.is_editing_day_profile |= new_combo("Day:", "##filterd", ctx.profile.day_settings.filter, filters_names);
Expand Down
1 change: 1 addition & 0 deletions common/include/color.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ constexpr ColorMatrix dot(const ColorMatrix &r, const ColorMatrix &l) {

ColorMatrix filter_matrix(ColorFilter filter);
std::tuple<float, float, float> whitepoint(Temperature temperature);
ColorMatrix hue_matrix(Hue hue);
ColorMatrix saturation_matrix(Saturation sat);

float degamma(float x, Gamma gamma);
Expand Down
1 change: 1 addition & 0 deletions common/include/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class Config {
constexpr static FizeauSettings default_settings = {
.temperature = DEFAULT_TEMP,
.gamma = DEFAULT_GAMMA,
.hue = DEFAULT_HUE,
.saturation = DEFAULT_SAT,
.luminance = DEFAULT_LUMA,
.range = DEFAULT_RANGE,
Expand Down
1 change: 1 addition & 0 deletions common/include/fizeau.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ typedef enum {
typedef struct {
Temperature temperature;
Gamma gamma;
Hue hue;
Saturation saturation;
Luminance luminance;
ColorRange range;
Expand Down
5 changes: 5 additions & 0 deletions common/include/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ typedef float Luminance;
#define MAX_LUMA 1.0f
#define DEFAULT_LUMA 0.0f

typedef float Hue;
#define MIN_HUE -1.0f
#define MAX_HUE 1.0f
#define DEFAULT_HUE 0.0f

typedef float Saturation;
#define MIN_SAT 0.0f
#define MAX_SAT 2.0f
Expand Down
19 changes: 19 additions & 0 deletions common/src/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <cmath>
#include <algorithm>
#include <tuple>
#include <numbers>

#include <common.hpp>

Expand Down Expand Up @@ -80,7 +81,25 @@ std::tuple<float, float, float> whitepoint(Temperature temperature) {
};
}

ColorMatrix hue_matrix(Hue hue) {
if (hue == DEFAULT_HUE) // Fast path
return { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f };

auto angle = hue * std::numbers::pi_v<float>;
auto c1 = (1.0f + 2.0f * std::cos(angle)) / 3.0f,
c2 = (1.0f - std::cos(angle)) / 3.0f,
c3 = std::sin(angle) / std::numbers::sqrt3_v<float>;
return {
c1, c2 - c3, c2 + c3,
c2 + c3, c1, c2 - c3,
c2 - c3, c2 + c3, c1,
};
}

ColorMatrix saturation_matrix(Saturation sat) {
if (sat == DEFAULT_SAT) // Fast path
return { 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f };

return {
(1.0f - sat) * 0.2126f + sat, (1.0f - sat) * 0.7152f , (1.0f - sat) * 0.0722f,
(1.0f - sat) * 0.2126f , (1.0f - sat) * 0.7152f + sat, (1.0f - sat) * 0.0722f,
Expand Down
7 changes: 7 additions & 0 deletions common/src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ void Config::sanitize_profile() {
sanitize_minmax(this->profile.day_settings .saturation, MIN_SAT, MAX_SAT);
sanitize_minmax(this->profile.night_settings.saturation, MIN_SAT, MAX_SAT);

sanitize_minmax(this->profile.day_settings .hue, MIN_HUE, MAX_HUE);
sanitize_minmax(this->profile.night_settings.hue, MIN_HUE, MAX_HUE);

sanitize_minmax(this->profile.day_settings .luminance, MIN_LUMA, MAX_LUMA);
sanitize_minmax(this->profile.night_settings.luminance, MIN_LUMA, MAX_LUMA);

Expand Down Expand Up @@ -167,6 +170,9 @@ std::string Config::make() {
str += "saturation_day = " + std::to_string(this->profile.day_settings.saturation) + '\n';
str += "saturation_night = " + std::to_string(this->profile.night_settings.saturation) + '\n';

str += "hue_day = " + std::to_string(this->profile.day_settings.hue) + '\n';
str += "hue_night = " + std::to_string(this->profile.night_settings.hue) + '\n';

str += "luminance_day = " + std::to_string(this->profile.day_settings.luminance) + '\n';
str += "luminance_night = " + std::to_string(this->profile.night_settings.luminance) + '\n';

Expand Down Expand Up @@ -216,6 +222,7 @@ Result Config::apply() {
Result Config::reset() {
this->profile.day_settings.temperature = DEFAULT_TEMP, this->profile.night_settings.temperature = DEFAULT_TEMP;
this->profile.day_settings.gamma = DEFAULT_GAMMA, this->profile.night_settings.gamma = DEFAULT_GAMMA;
this->profile.day_settings.hue = DEFAULT_HUE, this->profile.night_settings.hue = DEFAULT_HUE;
this->profile.day_settings.saturation = DEFAULT_SAT, this->profile.night_settings.saturation = DEFAULT_SAT;
this->profile.day_settings.luminance = DEFAULT_LUMA, this->profile.night_settings.luminance = DEFAULT_LUMA;
this->profile.day_settings.range = DEFAULT_RANGE, this->profile.night_settings.range = DEFAULT_RANGE;
Expand Down
2 changes: 2 additions & 0 deletions common/src/config_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,8 @@ int Config::ini_handler(void *user, const char *section, const char *name, const
MATCH_SET(name, "gamma_night", p.night_settings.gamma) ||
MATCH_SET(name, "saturation_day", p.day_settings .saturation) ||
MATCH_SET(name, "saturation_night", p.night_settings.saturation) ||
MATCH_SET(name, "hue_day", p.day_settings .hue) ||
MATCH_SET(name, "hue_night", p.night_settings.hue) ||
MATCH_SET(name, "luminance_day", p.day_settings .luminance) ||
MATCH_SET(name, "luminance_night", p.night_settings.luminance)
) {
Expand Down
7 changes: 7 additions & 0 deletions misc/default.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ gamma_night = 2.4
saturation_day = 1.0
saturation_night = 1.0

; Hue
; Value has to be >=-1.0, and <=1.0
hue_day = 0.0
hue_night = 0.0

; Luminance
; Value has to be >=-1.0, and <=1.0
luminance_day = 0.0
Expand Down Expand Up @@ -63,6 +68,8 @@ gamma_day = 2.4
gamma_night = 2.4
saturation_day = 1.0
saturation_night = 1.0
hue_day = 0.0
hue_night = 0.0
luminance_day = 0.0
luminance_night = -0.3
range_day = 0.0-1.0
Expand Down
21 changes: 21 additions & 0 deletions overlay/src/gui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,22 @@ tsl::elm::Element *FizeauOverlayGui::createUI() {
val * (MAX_SAT - MIN_SAT) / 100 + MIN_SAT;
});

this->hue_slider = new tsl::elm::TrackBar("");
this->hue_slider->setProgress(((this->is_day ? this->config.profile.day_settings.hue : this->config.profile.night_settings.hue) - MIN_HUE)
* 100 / (MAX_HUE - MIN_HUE));
this->hue_slider->setClickListener([this](std::uint64_t keys) {
if (keys & HidNpadButton_Y) {
this->hue_slider->setProgress((DEFAULT_HUE - MIN_HUE) * 100 / (MAX_HUE - MIN_HUE));
(this->is_day ? this->config.profile.day_settings.hue : this->config.profile.night_settings.hue) = DEFAULT_HUE;
return true;
}
return false;
});
this->hue_slider->setValueChangedListener([this](std::uint8_t val) {
(this->is_day ? this->config.profile.day_settings.hue : this->config.profile.night_settings.hue) =
val * (MAX_HUE - MIN_HUE) / 100 + MIN_HUE;
});

this->luma_slider = new tsl::elm::TrackBar("");
this->luma_slider->setProgress(((this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance) - MIN_LUMA)
* 100 / (MAX_LUMA - MIN_LUMA));
Expand Down Expand Up @@ -206,6 +222,7 @@ tsl::elm::Element *FizeauOverlayGui::createUI() {
this->filter_header = new tsl::elm::CategoryHeader("Filter");
this->gamma_header = new tsl::elm::CategoryHeader("");
this->sat_header = new tsl::elm::CategoryHeader("");
this->hue_header = new tsl::elm::CategoryHeader("");
this->luma_header = new tsl::elm::CategoryHeader("");

auto *frame = new tsl::elm::OverlayFrame("Fizeau", VERSION "-" COMMIT);
Expand All @@ -218,6 +235,8 @@ tsl::elm::Element *FizeauOverlayGui::createUI() {
list->addItem(this->temp_slider);
list->addItem(this->sat_header);
list->addItem(this->sat_slider);
list->addItem(this->hue_header);
list->addItem(this->hue_slider);

list->addItem(this->gamma_header);
list->addItem(this->gamma_slider);
Expand All @@ -242,6 +261,8 @@ void FizeauOverlayGui::update() {
this->is_day ? this->config.profile.day_settings.gamma : this->config.profile.night_settings.gamma));
this->sat_header->setText(format("Saturation: %.2f",
this->is_day ? this->config.profile.day_settings.saturation : this->config.profile.night_settings.saturation));
this->hue_header->setText(format("Hue: %.2f",
this->is_day ? this->config.profile.day_settings.hue : this->config.profile.night_settings.hue));
this->luma_header->setText(format("Luminance: %.2f",
this->is_day ? this->config.profile.day_settings.luminance : this->config.profile.night_settings.luminance));
}
Expand Down
3 changes: 2 additions & 1 deletion overlay/src/gui.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ class FizeauOverlayGui: public tsl::Gui {
tsl::elm::TrackBar *brightness_slider;
tsl::elm::TrackBar *gamma_slider;
tsl::elm::TrackBar *sat_slider;
tsl::elm::TrackBar *hue_slider;
tsl::elm::TrackBar *luma_slider;
tsl::elm::ListItem *range_button;

tsl::elm::CategoryHeader *temp_header, *filter_header,
*brightness_header, *gamma_header, *sat_header, *luma_header;
*brightness_header, *gamma_header, *sat_header, *hue_header, *luma_header;
};

} // namespace fz
3 changes: 3 additions & 0 deletions sysmodule/src/nvdisp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ Cmu calculate_cmu(FizeauSettings &settings) {
// Apply saturation
coeffs = dot(coeffs, saturation_matrix(settings.saturation));

// Apply hue rotation
coeffs = dot(coeffs, hue_matrix(settings.hue));

// Copy color matrix to cmu format
std::transform(coeffs.begin(), coeffs.end(), &cmu.krr, [](float c) -> QS18 { return c; });

Expand Down
1 change: 1 addition & 0 deletions sysmodule/src/profile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ FizeauSettings interpolate_profile(FizeauProfile &in, float factor, bool from_da
out = {
.temperature = static_cast<Temperature>(std::lerp(from.temperature, to.temperature, factor)),
.gamma = std::lerp(from.gamma, to.gamma, factor),
.hue = std::lerp(from.hue, to.hue, factor),
.saturation = std::lerp(from.saturation, to.saturation, factor),
.luminance = std::lerp(from.luminance, to.luminance, factor),
.range = {
Expand Down

0 comments on commit b615e99

Please sign in to comment.