From 30b1a1b25f381486686b891b3ac305a2b36dd4c6 Mon Sep 17 00:00:00 2001 From: LordGrey Date: Thu, 22 Dec 2022 20:10:44 +0100 Subject: [PATCH 01/11] Add Temperature adjustment --- assets/webconfig/i18n/en.json | 9 +- assets/webconfig/js/content_remote.js | 7 +- assets/webconfig/js/wizard.js | 7 +- cmake/packages.cmake | 2 +- config/hyperion.config.json.default | 3 +- include/hyperion/ColorAdjustment.h | 2 +- include/hyperion/ColorCorrection.h | 18 +++ include/hyperion/Hyperion.h | 20 +++ include/hyperion/MultiColorCorrection.h | 69 ++++++++++ include/utils/KelvinToRgb.h | 72 +++++++++++ include/utils/RgbChannelCorrection.h | 66 ++++++++++ include/utils/hyperion.h | 101 +++++++++++++++ .../api/JSONRPC_schema/schema-adjustment.json | 7 + libsrc/api/JsonAPI.cpp | 14 ++ libsrc/hyperion/Hyperion.cpp | 40 ++++++ libsrc/hyperion/MultiColorCorrection.cpp | 103 +++++++++++++++ libsrc/hyperion/schema/schema-color.json | 18 ++- libsrc/utils/RgbChannelCorrection.cpp | 120 ++++++++++++++++++ 18 files changed, 666 insertions(+), 12 deletions(-) create mode 100644 include/hyperion/ColorCorrection.h create mode 100644 include/hyperion/MultiColorCorrection.h create mode 100644 include/utils/KelvinToRgb.h create mode 100644 include/utils/RgbChannelCorrection.h create mode 100644 libsrc/hyperion/MultiColorCorrection.cpp create mode 100644 libsrc/utils/RgbChannelCorrection.cpp diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index bb3453b8d..455979b4d 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -227,6 +227,7 @@ "edt_append_degree": "°", "edt_append_frames": "frames", "edt_append_hz": "Hz", + "edt_append_kelvin": "K", "edt_append_leds": "LEDs", "edt_append_ms": "ms", "edt_append_ns": "ns", @@ -261,6 +262,8 @@ "edt_conf_color_blue_title": "Blue", "edt_conf_color_brightnessComp_expl": "Compensates brightness differences between red green blue, cyan magenta yellow and white. 100 means full compensation, 0 no compensation", "edt_conf_color_brightnessComp_title": "Brightness compensation", + "edt_conf_color_brightnessGain_expl": "Adjusts the brightness of colors. 1.0 means no change, over 1.0 increases brightness, under 1.0 decreases brightness.", + "edt_conf_color_brightnessGain_title": "Brightness gain", "edt_conf_color_brightness_expl": "set overall brightness of LEDs", "edt_conf_color_brightness_title": "Brightness", "edt_conf_color_channelAdjustment_header_expl": "Create color profiles that could be assigned to a specific component. Adjust color, gamma, brightness, compensation and more.", @@ -287,10 +290,10 @@ "edt_conf_color_magenta_title": "Magenta", "edt_conf_color_red_expl": "The calibrated red value.", "edt_conf_color_red_title": "Red", + "edt_conf_color_temperature_expl": "Adjusts the corlor temperature.", + "edt_conf_color_temperature_title": "Temperature", "edt_conf_color_saturationGain_expl": "Adjusts the saturation of colors. 1.0 means no change, over 1.0 increases saturation, under 1.0 desaturates.", "edt_conf_color_saturationGain_title": "Saturation gain", - "edt_conf_color_brightnessGain_expl": "Adjusts the brightness of colors. 1.0 means no change, over 1.0 increases brightness, under 1.0 decreases brightness.", - "edt_conf_color_brightnessGain_title": "Brightness gain", "edt_conf_color_white_expl": "The calibrated white value.", "edt_conf_color_white_title": "White", "edt_conf_color_yellow_expl": "The calibrated yellow value.", @@ -446,6 +449,8 @@ "edt_conf_smooth_heading_title": "Smoothing", "edt_conf_smooth_interpolationRate_expl": "Speed of the calculation of smooth intermediate frames.", "edt_conf_smooth_interpolationRate_title": "Interpolation Rate", + "edt_conf_smooth_outputRate_expl": "The output speed to your LED controller.", + "edt_conf_smooth_outputRate_title": "Output Rate", "edt_conf_smooth_time_ms_expl": "How long should the smoothing gather pictures?", "edt_conf_smooth_time_ms_title": "Time", "edt_conf_smooth_type_expl": "Type of smoothing.", diff --git a/assets/webconfig/js/content_remote.js b/assets/webconfig/js/content_remote.js index d0c1d9c2a..a999b5fcd 100644 --- a/assets/webconfig/js/content_remote.js +++ b/assets/webconfig/js/content_remote.js @@ -75,11 +75,12 @@ $(document).ready(function () { sColor[key].key == "brightnessCompensation" || sColor[key].key == "backlightThreshold" || sColor[key].key == "saturationGain" || - sColor[key].key == "brightnessGain") { + sColor[key].key == "brightnessGain" || + sColor[key].key == "temperature" ) { property = ''; - if (sColor[key].append === "edt_append_percent") { - property = '
' + property + '' + $.i18n("edt_append_percent") + '
'; + if (sColor[key].append && sColor[key].append !== "" ) { + property = '
' + property + '' + $.i18n(sColor[key].append) + '
'; } } else { diff --git a/assets/webconfig/js/wizard.js b/assets/webconfig/js/wizard.js index dedd50edc..e977e4028 100755 --- a/assets/webconfig/js/wizard.js +++ b/assets/webconfig/js/wizard.js @@ -854,7 +854,12 @@ function checkUserResult(reply, usr) { function useGroupId(id) { $('#groupId').val(id); - groupLights = hueGroups[id].lights; + + //Ensure ligthIDs are strings + groupLights = hueGroups[id].lights.map(num => { + return String(num); + }); + groupLightsLocations = hueGroups[id].locations; get_hue_lights(); } diff --git a/cmake/packages.cmake b/cmake/packages.cmake index bc73057d3..1dd8f6a64 100644 --- a/cmake/packages.cmake +++ b/cmake/packages.cmake @@ -72,7 +72,7 @@ endif() # .deb files for apt # https://cmake.org/cmake/help/latest/cpack_gen/deb.html SET ( CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA "${CMAKE_SOURCE_DIR}/cmake/package-scripts/preinst;${CMAKE_SOURCE_DIR}/cmake/package-scripts/postinst;${CMAKE_SOURCE_DIR}/cmake/package-scripts/prerm" ) -SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4" ) +SET ( CPACK_DEBIAN_PACKAGE_DEPENDS "libcec6 | libcec4 | libcec (>= 4.0)" ) SET ( CPACK_DEBIAN_PACKAGE_SECTION "Miscellaneous" ) # .rpm for rpm diff --git a/config/hyperion.config.json.default b/config/hyperion.config.json.default index a52f64bab..14333eb9a 100644 --- a/config/hyperion.config.json.default +++ b/config/hyperion.config.json.default @@ -48,7 +48,8 @@ "brightness" : 100, "brightnessCompensation" : 100, "saturationGain" : 1.0, - "brightnessGain" : 1.0 + "brightnessGain" : 1.0, + "temperature" : 6600 } ] }, diff --git a/include/hyperion/ColorAdjustment.h b/include/hyperion/ColorAdjustment.h index 3e9b8dc8b..99dd93152 100644 --- a/include/hyperion/ColorAdjustment.h +++ b/include/hyperion/ColorAdjustment.h @@ -1,7 +1,7 @@ #ifndef COLORADJUSTMENT_H #define COLORADJUSTMENT_H -// STL includes +// Qt includes #include // Utils includes diff --git a/include/hyperion/ColorCorrection.h b/include/hyperion/ColorCorrection.h new file mode 100644 index 000000000..478cd35d3 --- /dev/null +++ b/include/hyperion/ColorCorrection.h @@ -0,0 +1,18 @@ +#pragma once + +// Qt includes +#include + +// Utils includes +#include + +class ColorCorrection +{ +public: + + /// Unique identifier for this color correction + QString _id; + + /// The RGB correction + RgbChannelCorrection _rgbCorrection; +}; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 343515027..ca812f904 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -22,6 +22,7 @@ #include #include #include +#include #include #if defined(ENABLE_EFFECTENGINE) @@ -48,6 +49,7 @@ class LinearColorSmoothing; class EffectEngine; #endif class MultiColorAdjustment; +class MultiColorCorrection; class ColorAdjustment; class SettingsManager; class BGEffectHandler; @@ -181,15 +183,30 @@ public slots: /// QStringList getAdjustmentIds() const; + /// + /// Returns the list with unique correction identifiers + /// @return The list with correction identifiers + /// + QStringList getTemperatureIds() const; + /// /// Returns the ColorAdjustment with the given identifier /// @return The adjustment with the given identifier (or nullptr if the identifier does not exist) /// ColorAdjustment * getAdjustment(const QString& id) const; + /// + /// Returns the ColorCorrection with the given identifier + /// @return The correction with the given identifier (or nullptr if the identifier does not exist) + /// + ColorCorrection * getTemperature(const QString& id) const; + /// Tell Hyperion that the corrections have changed and the leds need to be updated void adjustmentsUpdated(); + /// Tell Hyperion that the corrections have changed and the leds need to be updated + void temperaturesUpdated(); + /// /// Clears the given priority channel. This will switch the led-colors to the colors of the next /// lower priority channel (or off if no more channels are set) @@ -566,6 +583,9 @@ private slots: /// The adjustment from raw colors to led colors MultiColorAdjustment * _raw2ledAdjustment; + /// The temperature from raw colors to led colors + MultiColorCorrection * _raw2ledTemperature; + /// The actual LedDeviceWrapper LedDeviceWrapper* _ledDeviceWrapper; diff --git a/include/hyperion/MultiColorCorrection.h b/include/hyperion/MultiColorCorrection.h new file mode 100644 index 000000000..364228710 --- /dev/null +++ b/include/hyperion/MultiColorCorrection.h @@ -0,0 +1,69 @@ +#pragma once + +// STL includes + +#include + +// Utils includes +#include +#include "utils/Logger.h" + +// Hyperion includes +#include + +/// +/// The LedColorCorrection is responsible for performing color correction from 'raw' colors +/// received as input to colors mapped to match the color-properties of the leds. +/// +class MultiColorCorrection +{ +public: + MultiColorCorrection(int ledCnt); + ~MultiColorCorrection(); + + /** + * Adds a new ColorCorrection to this MultiColorCorrection + * + * @param Correction The new ColorCorrection (ownership is transfered) + */ + void addCorrection(ColorCorrection * correction); + + void setCorrectionForLed(const QString& id, int startLed, int endLed); + + bool verifyCorrections() const; + + /// + /// Returns the identifier of all the unique ColorCorrection + /// + /// @return The list with unique id's of the ColorCorrections + QStringList & getCorrectionIds(); + + /// + /// Returns the pointer to the ColorCorrection with the given id + /// + /// @param id The identifier of the ColorCorrection + /// + /// @return The ColorCorrection with the given id (or nullptr if it does not exist) + /// + ColorCorrection* getCorrection(const QString& id); + + /// + /// Performs the color transoformation from raw-color to led-color + /// + /// @param ledColors The list with raw colors + /// + void applyCorrection(std::vector& ledColors); + +private: + /// List with Correction ids + QStringList _correctionIds; + + /// List with unique ColorCorrections + std::vector _correction; + + /// List with a pointer to the ColorCorrection for each individual led + std::vector _ledCorrections; + + // logger instance + Logger * _log; +}; diff --git a/include/utils/KelvinToRgb.h b/include/utils/KelvinToRgb.h new file mode 100644 index 000000000..e044375a4 --- /dev/null +++ b/include/utils/KelvinToRgb.h @@ -0,0 +1,72 @@ +#ifndef KELVINTORGB_H +#define KELVINTORGB_H + +#include + +#include + + +// Constants +namespace { +const int TEMPERATURE_MINIMUM = 1000; +const int TEMPERATUR_MAXIMUM = 40000; +} //End of constants + +static ColorRgb getRgbFromTemperature(int temperature) +{ + //Temperature input in Kelvin valid in the range 1000 K to 40000 K. White light = 6600K + temperature = qBound(TEMPERATURE_MINIMUM, temperature, TEMPERATUR_MAXIMUM); + + // All calculations require temperature / 100, so only do the conversion once. + temperature /= 100; + + // Compute each color in turn. + int red, green, blue; + + // red + if (temperature <= 66) + { + red = 255; + } + else + { + // Note: the R-squared value for this approximation is 0.988. + red = static_cast(329.698727446 * (pow(temperature - 60, -0.1332047592))); + } + + // green + if (temperature <= 66) + { + // Note: the R-squared value for this approximation is 0.996. + green = static_cast(99.4708025861 * log(temperature) - 161.1195681661); + + } + else + { + // Note: the R-squared value for this approximation is 0.987. + green = static_cast(288.1221695283 * (pow(temperature - 60, -0.0755148492))); + } + + // blue + if (temperature >= 66) + { + blue = 255; + } + else if (temperature <= 19) + { + blue = 0; + } + else + { + // Note: the R-squared value for this approximation is 0.998. + blue = static_cast(138.5177312231 * log(temperature - 10) - 305.0447927307); + } + + return { + static_cast(qBound(0, red, 255)), + static_cast(qBound(0, green, 255)), + static_cast(qBound(0, blue, 255)), + }; +} + +#endif // KELVINTORGB_H diff --git a/include/utils/RgbChannelCorrection.h b/include/utils/RgbChannelCorrection.h new file mode 100644 index 000000000..f09b9cef5 --- /dev/null +++ b/include/utils/RgbChannelCorrection.h @@ -0,0 +1,66 @@ +#pragma once + +// STL includes +#include + +/// Correction for a single color byte value +/// All configuration values are unsigned int and assume the color value to be between 0 and 255 +class RgbChannelCorrection +{ +public: + /// Default constructor + RgbChannelCorrection(); + + /// Constructor + /// @param correctionR + /// @param correctionG + /// @param correctionB + + RgbChannelCorrection(int correctionR, int correctionG, int correctionB); + + /// Destructor + ~RgbChannelCorrection(); + + /// @return The current correctionR value + uint8_t getcorrectionR() const; + + /// @param threshold New correctionR value + void setcorrectionR(uint8_t correctionR); + + /// @return The current correctionG value + uint8_t getcorrectionG() const; + + /// @param gamma New correctionG value + void setcorrectionG(uint8_t correctionG); + + /// @return The current correctionB value + uint8_t getcorrectionB() const; + + /// @param blacklevel New correctionB value + void setcorrectionB(uint8_t correctionB); + + /// Transform the given array value + /// @param input The input color bytes + /// @return The corrected byte value + uint8_t correctionR(uint8_t inputR) const; + uint8_t correctionG(uint8_t inputG) const; + uint8_t correctionB(uint8_t inputB) const; + + +private: + /// (re)-initilize the color mapping + void initializeMapping(); + +private: + /// The correction of R channel + int _correctionR; + /// The correction of G channel + int _correctionG; + /// The correction of B channel + int _correctionB; + + /// The mapping from input color to output color + int _mappingR[256]; + int _mappingG[256]; + int _mappingB[256]; +}; diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index 5349d38d4..704c121a9 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -4,8 +4,10 @@ #include #include +#include "hyperion/MultiColorCorrection.h" #include #include +#include // fg effect #include @@ -14,6 +16,8 @@ #include #endif +#include + /// /// @brief Provide utility methods for Hyperion class /// @@ -100,6 +104,32 @@ namespace hyperion { ); } + RgbChannelCorrection* createRgbChannelCorrection(const QJsonObject& colorConfig) + { + int varR = colorConfig["red"].toInt(255); + int varG = colorConfig["green"].toInt(255); + int varB = colorConfig["blue"].toInt(255); + + RgbChannelCorrection* correction = new RgbChannelCorrection(varR, varG, varB); + return correction; + } + + ColorCorrection * createColorCorrection(const QJsonObject& correctionConfig) + { + const QString id = correctionConfig["id"].toString("default"); + + RgbChannelCorrection * rgbCorrection = createRgbChannelCorrection(correctionConfig); + + ColorCorrection * correction = new ColorCorrection(); + correction->_id = id; + correction->_rgbCorrection = *rgbCorrection; + + // Cleanup the allocated individual transforms + delete rgbCorrection; + + return correction; + } + ColorAdjustment* createColorAdjustment(const QJsonObject & adjustmentConfig) { const QString id = adjustmentConfig["id"].toString("default"); @@ -179,6 +209,77 @@ namespace hyperion { return adjustment; } + MultiColorCorrection * createLedColorsTemperature(int ledCnt, const QJsonObject & colorConfig) + { + // Create the result, the corrections are added to this + MultiColorCorrection * correction = new MultiColorCorrection(ledCnt); + + const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"]; + const QRegularExpression overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); + + const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray(); + for (signed i = 0; i < adjustmentConfigArray.size(); ++i) + { + const QJsonObject & config = adjustmentConfigArray.at(i).toObject(); + ColorAdjustment * colorAdjustment = createColorAdjustment(config); + + int temperature = config["temperature"].toInt(); + + ColorRgb rgb = getRgbFromTemperature(temperature); + + qDebug() << "createLedColorsTemperature: adjustment[temperture]: " << temperature << "-> " << rgb.toQString(); + + QJsonObject correctionConfig { + {"red", rgb.red}, + {"green", rgb.green}, + {"blue", rgb.blue} + }; + + ColorCorrection * colorCorrection = createColorCorrection(correctionConfig); + correction->addCorrection(colorCorrection); + + const QString ledIndicesStr = config["leds"].toString("").trimmed(); + if (ledIndicesStr.compare("*") == 0) + { + // Special case for indices '*' => all leds + correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); + Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [0-%d]", QSTRING_CSTR(colorCorrection->_id), ledCnt-1); + continue; + } + + if (!overallExp.match(ledIndicesStr).hasMatch()) + { + Error(Logger::getInstance("HYPERION"), "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr)); + continue; + } + + std::stringstream ss; + const QStringList ledIndexList = ledIndicesStr.split(","); + for (int i=0; i 0) + { + ss << ", "; + } + if (ledIndexList[i].contains("-")) + { + QStringList ledIndices = ledIndexList[i].split("-"); + int startInd = ledIndices[0].toInt(); + int endInd = ledIndices[1].toInt(); + correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd); + ss << startInd << "-" << endInd; + } + else + { + int index = ledIndexList[i].toInt(); + correction->setCorrectionForLed(colorCorrection->_id, index, index); + ss << index; + } + } + Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str()); + } + return correction; + } + /** * Construct the 'led-string' with the integration area definition per led and the color * ordering of the RGB channels diff --git a/libsrc/api/JSONRPC_schema/schema-adjustment.json b/libsrc/api/JSONRPC_schema/schema-adjustment.json index b8856ef92..b06637362 100644 --- a/libsrc/api/JSONRPC_schema/schema-adjustment.json +++ b/libsrc/api/JSONRPC_schema/schema-adjustment.json @@ -146,6 +146,13 @@ "required" : false, "minimum" : 0.1, "maximum": 10.0 + }, + "temperature" : + { + "type" : "integer", + "required" : false, + "minimum" : 1000, + "maximum": 40000 } }, "additionalProperties": false diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 60a832b48..f937873c3 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -519,6 +520,8 @@ void JsonAPI::handleServerInfoCommand(const QJsonObject &message, const QString adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain(); adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain(); + adjustment["temperature"] = 6600; + adjustmentArray.append(adjustment); } @@ -936,6 +939,17 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const QString if (adjustment.contains("brightnessGain")) { colorAdjustment->_okhsvTransform.setBrightnessGain(adjustment["brightnessGain"].toDouble()); + } + + if (adjustment.contains("temperature")) + { + int temperature = adjustment["temperature"].toInt(6500); + ColorRgb rgb = getRgbFromTemperature(temperature); + + ColorCorrection *colorCorrection = _hyperion->getTemperature(adjustmentId); + colorCorrection->_rgbCorrection.setcorrectionR(rgb.red); + colorCorrection->_rgbCorrection.setcorrectionG(rgb.green); + colorCorrection->_rgbCorrection.setcorrectionB(rgb.blue); } // commit the changes diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 52216f022..26a262419 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #if defined(ENABLE_EFFECTENGINE) @@ -56,6 +57,7 @@ Hyperion::Hyperion(quint8 instance, bool readonlyMode) , _imageProcessor(nullptr) , _muxer(nullptr) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) + , _raw2ledTemperature(hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) , _ledDeviceWrapper(nullptr) , _deviceSmooth(nullptr) #if defined(ENABLE_EFFECTENGINE) @@ -100,6 +102,11 @@ void Hyperion::start() // get newVideoMode from HyperionIManager connect(this, &Hyperion::newVideoMode, this, &Hyperion::handleNewVideoMode); + if (!_raw2ledTemperature->verifyCorrections()) + { + Warning(_log, "Color temperature incorrectly set"); + } + if (!_raw2ledAdjustment->verifyAdjustments()) { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); @@ -219,6 +226,9 @@ void Hyperion::freeObjects() delete _raw2ledAdjustment; + // delete the color temperature correction + delete _raw2ledTemperature; + #if defined(ENABLE_FORWARDER) delete _messageForwarder; #endif @@ -247,6 +257,15 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); } + + // change in color recreate ledTemperature + delete _raw2ledTemperature; + _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), obj); + + if (!_raw2ledTemperature->verifyCorrections()) + { + Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); + } } else if(type == settings::LEDS) { @@ -279,6 +298,10 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co delete _raw2ledAdjustment; _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); + // change in leds recreate ledTemperature + delete _raw2ledTemperature; + _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); + #if defined(ENABLE_EFFECTENGINE) // start cached effects _effectEngine->startCachedEffects(); @@ -494,17 +517,33 @@ QStringList Hyperion::getAdjustmentIds() const return _raw2ledAdjustment->getAdjustmentIds(); } +QStringList Hyperion::getTemperatureIds() const +{ + return _raw2ledTemperature->getCorrectionIds(); +} + ColorAdjustment * Hyperion::getAdjustment(const QString& id) const { return _raw2ledAdjustment->getAdjustment(id); } +ColorCorrection * Hyperion::getTemperature(const QString& id) const +{ + return _raw2ledTemperature->getCorrection(id); +} + void Hyperion::adjustmentsUpdated() { emit adjustmentChanged(); update(); } +void Hyperion::temperaturesUpdated() +{ + emit adjustmentChanged(); + update(); +} + bool Hyperion::clear(int priority, bool forceClearAll) { bool isCleared = false; @@ -680,6 +719,7 @@ void Hyperion::update() emit rawLedColors(_ledBuffer); _raw2ledAdjustment->applyAdjustment(_ledBuffer); + _raw2ledTemperature->applyCorrection(_ledBuffer); int i = 0; for (ColorRgb& color : _ledBuffer) diff --git a/libsrc/hyperion/MultiColorCorrection.cpp b/libsrc/hyperion/MultiColorCorrection.cpp new file mode 100644 index 000000000..74148e431 --- /dev/null +++ b/libsrc/hyperion/MultiColorCorrection.cpp @@ -0,0 +1,103 @@ +// Hyperion includes +#include +#include + +MultiColorCorrection::MultiColorCorrection(int ledCnt) : + _ledCorrections(ledCnt, nullptr) +, _log(Logger::getInstance("CORRECTION")) +{ +} + +MultiColorCorrection::~MultiColorCorrection() +{ + // Clean up all the correctinos + for (ColorCorrection * correction : _correction) + { + delete correction; + } +} + +void MultiColorCorrection::addCorrection(ColorCorrection * correction) +{ + _correctionIds.push_back(correction->_id); + _correction.push_back(correction); +} + +void MultiColorCorrection::setCorrectionForLed(const QString& id, int startLed, int endLed) +{ + // abort + if(startLed > endLed) + { + Error(_log,"startLed > endLed -> %d > %d", startLed, endLed); + return; + } + // catch wrong values + if(endLed > static_cast(_ledCorrections.size()-1)) + { + Warning(_log,"The color correction 'LED index' field has LEDs specified which aren't part of your led layout"); + endLed = static_cast(_ledCorrections.size()-1); + } + + // Get the identified correction (don't care if is nullptr) + ColorCorrection * correction = getCorrection(id); + for (int iLed=startLed; iLed<=endLed; ++iLed) + { + _ledCorrections[iLed] = correction; + } +} + +bool MultiColorCorrection::verifyCorrections() const +{ + bool ok = true; + for (unsigned iLed=0; iLed<_ledCorrections.size(); ++iLed) + { + ColorCorrection* adjustment = _ledCorrections[iLed]; + + if (adjustment == nullptr) + { + Warning(_log, "No correction set for led %d", iLed); + ok = false; + } + } + return ok; +} + +QStringList & MultiColorCorrection::getCorrectionIds() +{ + return _correctionIds; +} + +ColorCorrection* MultiColorCorrection::getCorrection(const QString& id) +{ + // Iterate through the unique corrections until we find the one with the given id + for (ColorCorrection * correction : _correction) + { + if (correction->_id == id) + { + return correction; + } + } + + // The ColorCorrection was not found + return nullptr; +} + +void MultiColorCorrection::applyCorrection(std::vector& ledColors) +{ + const size_t itCnt = qMin(_ledCorrections.size(), ledColors.size()); + for (size_t i=0; i_rgbCorrection.correctionR(color.red); + color.green = correction->_rgbCorrection.correctionG(color.green); + color.blue = correction->_rgbCorrection.correctionB(color.blue); + } +} diff --git a/libsrc/hyperion/schema/schema-color.json b/libsrc/hyperion/schema/schema-color.json index abe395600..33b1bdfe4 100644 --- a/libsrc/hyperion/schema/schema-color.json +++ b/libsrc/hyperion/schema/schema-color.json @@ -221,6 +221,18 @@ "step" : 0.1, "propertyOrder" : 16 }, + "temperature" : + { + "type" : "integer", + "title" : "edt_conf_color_temperature_title", + "required" : true, + "minimum" : 1000, + "maximum": 40000, + "default" : 6600, + "step" : 100, + "append" : "edt_append_kelvin", + "propertyOrder" : 17 + }, "gammaRed" : { "type" : "number", @@ -230,7 +242,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 17 + "propertyOrder" : 18 }, "gammaGreen" : { @@ -241,7 +253,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 18 + "propertyOrder" : 19 }, "gammaBlue" : { @@ -252,7 +264,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 19 + "propertyOrder" : 20 } }, "additionalProperties" : false diff --git a/libsrc/utils/RgbChannelCorrection.cpp b/libsrc/utils/RgbChannelCorrection.cpp new file mode 100644 index 000000000..7fb168848 --- /dev/null +++ b/libsrc/utils/RgbChannelCorrection.cpp @@ -0,0 +1,120 @@ +// STL includes +#include + +// Utils includes +#include + +RgbChannelCorrection::RgbChannelCorrection() : + _correctionR(255), + _correctionG(255), + _correctionB(255) +{ + initializeMapping(); +} + +RgbChannelCorrection::RgbChannelCorrection(int correctionR, int correctionG, int correctionB) : + _correctionR(correctionR), + _correctionG(correctionG), + _correctionB(correctionB) +{ + initializeMapping(); +} + +RgbChannelCorrection::~RgbChannelCorrection() +{ +} + +uint8_t RgbChannelCorrection::getcorrectionR() const +{ + return _correctionR; +} + +void RgbChannelCorrection::setcorrectionR(uint8_t correctionR) +{ + _correctionR = correctionR; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::getcorrectionG() const +{ + return _correctionG; +} + +void RgbChannelCorrection::setcorrectionG(uint8_t correctionG) +{ + _correctionG = correctionG; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::getcorrectionB() const +{ + return _correctionB; +} + +void RgbChannelCorrection::setcorrectionB(uint8_t correctionB) +{ + _correctionB = correctionB; + initializeMapping(); +} + +uint8_t RgbChannelCorrection::correctionR(uint8_t inputR) const +{ + return _mappingR[inputR]; +} + +uint8_t RgbChannelCorrection::correctionG(uint8_t inputG) const +{ + return _mappingG[inputG]; +} + +uint8_t RgbChannelCorrection::correctionB(uint8_t inputB) const +{ + return _mappingB[inputB]; +} + +void RgbChannelCorrection::initializeMapping() +{ + // initialize the mapping + for (int i = 0; i < 256; ++i) + { + int outputR = (i * _correctionR) / 255; + if (outputR < -255) + { + outputR = -255; + } + else if (outputR > 255) + { + outputR = 255; + } + _mappingR[i] = outputR; + } + for (int i = 0; i < 256; ++i) + { + int outputG = (i * _correctionG) / 255; + if (outputG < -255) + { + outputG = -255; + } + else if (outputG > 255) + { + outputG = 255; + } + _mappingG[i] = outputG; + } + for (int i = 0; i < 256; ++i) + { + int outputB = (i * _correctionB) / 255; + if (outputB < -255) + { + outputB = -255; + } + else if (outputB > 255) + { + outputB = 255; + } + _mappingB[i] = outputB; + } + + +} + From e52d73be5c284d3c4a957ca6dfb9123ad6e768fa Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Sun, 3 Mar 2024 12:12:40 +0100 Subject: [PATCH 02/11] Add Temperature adjustment - add missing cmake updates --- CMakeLists.txt | 29 ++++++++++++++++++++--------- libsrc/hyperion/CMakeLists.txt | 3 +++ libsrc/utils/CMakeLists.txt | 3 +++ 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7818a6f1d..f9e835656 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,7 +110,7 @@ set(DEFAULT_USE_SYSTEM_QMDNS_LIBS OFF) set(DEFAULT_TESTS OFF) # Build Hyperion with a reduced set of functionality, overwrites other default values -set(DEFAULT_HYPERION_LIGHT OFF) +set(DEFAULT_HYPERION_LIGHT ON ) if(${CMAKE_SYSTEM} MATCHES "Linux") set(DEFAULT_FB ON) @@ -232,23 +232,34 @@ if(HYPERION_LIGHT) SET ( DEFAULT_OSX OFF ) SET ( DEFAULT_QT OFF ) SET ( DEFAULT_V4L2 OFF ) + SET ( DEFAULT_AUDIO OFF ) SET ( DEFAULT_X11 OFF ) SET ( DEFAULT_XCB OFF ) - SET ( DEFAULT_AUDIO OFF ) + # LED-Devices + SET ( DEFAULT_DEV_NETWORK OFF ) + SET ( DEFAULT_DEV_SERIAL OFF ) + SET ( DEFAULT_DEV_SPI OFF ) + SET ( DEFAULT_DEV_TINKERFORGE OFF ) + SET ( DEFAULT_DEV_USB_HID OFF ) + SET ( DEFAULT_DEV_WS281XPWM OFF ) # Disable Input Servers - set(DEFAULT_BOBLIGHT_SERVER OFF) - set(DEFAULT_CEC OFF) - set(DEFAULT_FLATBUF_SERVER OFF) - set(DEFAULT_PROTOBUF_SERVER OFF) + SET ( DEFAULT_BOBLIGHT_SERVER OFF ) + SET ( DEFAULT_CEC OFF ) + SET ( DEFAULT_FLATBUF_SERVER OFF ) + SET ( DEFAULT_PROTOBUF_SERVER OFF ) # Disable Output Connectors - set(DEFAULT_FORWARDER OFF) - set(DEFAULT_FLATBUF_CONNECT OFF) + SET ( DEFAULT_FORWARDER OFF ) + SET ( DEFAULT_FLATBUF_CONNECT OFF ) # Disable Services - set(DEFAULT_EFFECTENGINE OFF) + SET ( DEFAULT_EXPERIMENTAL OFF ) + SET ( DEFAULT_MDNS ON ) + SET ( DEFAULT_REMOTE_CTL OFF ) + SET ( DEFAULT_EFFECTENGINE OFF ) + endif() message(STATUS "Grabber options:") diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index b073dcf4b..7c4264f99 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -39,6 +39,9 @@ add_library(hyperion # Led Color Transform ${CMAKE_SOURCE_DIR}/include/hyperion/MultiColorAdjustment.h ${CMAKE_SOURCE_DIR}/libsrc/hyperion/MultiColorAdjustment.cpp + ${CMAKE_SOURCE_DIR}/include/hyperion/ColorCorrection.h + ${CMAKE_SOURCE_DIR}/include/hyperion/MultiColorCorrection.h + ${CMAKE_SOURCE_DIR}/libsrc/hyperion/MultiColorCorrection.cpp # Priority Muxer ${CMAKE_SOURCE_DIR}/include/hyperion/PriorityMuxer.h ${CMAKE_SOURCE_DIR}/libsrc/hyperion/PriorityMuxer.cpp diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index b7d28eebb..f8dda6314 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -57,11 +57,14 @@ add_library(hyperion-utils # Rgb single color adjustment/correction ${CMAKE_SOURCE_DIR}/include/utils/RgbChannelAdjustment.h ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelAdjustment.cpp + ${CMAKE_SOURCE_DIR}/include/utils/RgbChannelCorrection.h + ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelCorrection.cpp # Color conversion/transformation ${CMAKE_SOURCE_DIR}/include/utils/RgbToRgbw.h ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbToRgbw.cpp ${CMAKE_SOURCE_DIR}/include/utils/RgbTransform.h ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbTransform.cpp + ${CMAKE_SOURCE_DIR}/include/utils/KelvinToRgb.h # System info class ${CMAKE_SOURCE_DIR}/include/utils/SysInfo.h ${CMAKE_SOURCE_DIR}/libsrc/utils/SysInfo.cpp From 106ce8b3f825097293986c4eeffba4d28f94e7c4 Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Sun, 3 Mar 2024 12:16:12 +0100 Subject: [PATCH 03/11] Add missing ENABLE_MDNS guards --- src/hyperiond/hyperiond.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hyperiond/hyperiond.cpp b/src/hyperiond/hyperiond.cpp index d12d9a206..ded489054 100644 --- a/src/hyperiond/hyperiond.cpp +++ b/src/hyperiond/hyperiond.cpp @@ -295,7 +295,9 @@ void HyperionDaemon::startNetworkServices() _webserver->thread()->start(); _sslWebserver->thread()->start(); +#ifdef ENABLE_MDNS _mDNSProvider->thread()->start(); +#endif _ssdp->thread()->start(); #if defined(ENABLE_FLATBUF_SERVER) @@ -315,7 +317,9 @@ void HyperionDaemon::stopNetworkServices() _flatBufferServer.reset(nullptr); #endif +#ifdef ENABLE_MDNS _mDNSProvider.reset(nullptr); +#endif _ssdp.reset(nullptr); _sslWebserver.reset(nullptr); From 07dfce68f6b760cf5277fbe24eb8e8979500e397 Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Sat, 25 May 2024 19:53:48 +0200 Subject: [PATCH 04/11] Reapply temperature on JSONAPI --- include/api/JsonAPI.h | 1 + libsrc/api/JsonAPI.cpp | 21 +++++++++++++++++++++ libsrc/api/JsonInfo.cpp | 10 ++++++++++ 3 files changed, 32 insertions(+) diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index 35d7e2043..a7b0dd583 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -281,6 +281,7 @@ private slots: void applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); void applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment); void applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel); + void applyTemperatureAdjustment(const QJsonObject &adjustment, ColorCorrection *colorCorrection); void applyTransforms(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); template diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 5c1a7ded0..0a0e158db 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -598,8 +598,16 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiC return; } + ColorCorrection *temperatureColorCorrection = _hyperion->getTemperature(adjustmentId); + if (temperatureColorCorrection == nullptr) { + Warning(_log, "Incorrect temperature adjustment identifier: %s", adjustmentId.toStdString().c_str()); + return; + } + + applyColorAdjustments(adjustment, colorAdjustment); applyTransforms(adjustment, colorAdjustment); + applyTemperatureAdjustment(adjustment, temperatureColorCorrection); _hyperion->adjustmentsUpdated(); sendSuccessReply(cmd); } @@ -673,6 +681,19 @@ void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &ad } } +void JsonAPI::applyTemperatureAdjustment(const QJsonObject &adjustment, ColorCorrection *colorCorrection) +{ + if (adjustment.contains("temperature")) + { + int temperature = adjustment["temperature"].toInt(6500); + ColorRgb rgb = getRgbFromTemperature(temperature); + + colorCorrection->_rgbCorrection.setcorrectionR(rgb.red); + colorCorrection->_rgbCorrection.setcorrectionG(rgb.green); + colorCorrection->_rgbCorrection.setcorrectionB(rgb.blue); + } +} + void JsonAPI::handleSourceSelectCommand(const QJsonObject &message, const JsonApiCommand& cmd) { if (message.contains("auto")) diff --git a/libsrc/api/JsonInfo.cpp b/libsrc/api/JsonInfo.cpp index e2a73ffe1..8c74579e1 100644 --- a/libsrc/api/JsonInfo.cpp +++ b/libsrc/api/JsonInfo.cpp @@ -83,6 +83,16 @@ QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log) adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain(); adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain(); + + ColorCorrection *temperatureColorCorrection = hyperion->getTemperature(adjustmentId); + if (temperatureColorCorrection == nullptr) { + Error(log, "Incorrect temperature adjustment id: %s", QSTRING_CSTR(adjustmentId)); + continue; + } + + // TODO: Return current Temperature in Kelvin + adjustment["temperature"] = 6600; + adjustmentArray.append(adjustment); } return adjustmentArray; From 5897e24316635bc2f97917f887a6f2dd11cc3e86 Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Thu, 30 May 2024 19:11:51 +0200 Subject: [PATCH 05/11] Integrate color temperature into RGB transformations --- include/api/JsonAPI.h | 4 +- include/hyperion/ColorCorrection.h | 18 ---- include/hyperion/Hyperion.h | 16 --- include/hyperion/MultiColorAdjustment.h | 6 +- include/hyperion/MultiColorCorrection.h | 69 ------------- include/utils/RgbChannelCorrection.h | 66 ------------- include/utils/RgbTransform.h | 62 ++++++++---- include/utils/hyperion.h | 99 +------------------ libsrc/api/JsonAPI.cpp | 26 ++--- libsrc/api/JsonInfo.cpp | 10 +- libsrc/hyperion/CMakeLists.txt | 3 - libsrc/hyperion/Hyperion.cpp | 40 -------- libsrc/hyperion/MultiColorAdjustment.cpp | 96 ++++++++++-------- libsrc/hyperion/MultiColorCorrection.cpp | 103 ------------------- libsrc/utils/CMakeLists.txt | 2 - libsrc/utils/RgbChannelCorrection.cpp | 120 ----------------------- libsrc/utils/RgbTransform.cpp | 93 +++++++++++++----- 17 files changed, 178 insertions(+), 655 deletions(-) delete mode 100644 include/hyperion/ColorCorrection.h delete mode 100644 include/hyperion/MultiColorCorrection.h delete mode 100644 include/utils/RgbChannelCorrection.h delete mode 100644 libsrc/hyperion/MultiColorCorrection.cpp delete mode 100644 libsrc/utils/RgbChannelCorrection.cpp diff --git a/include/api/JsonAPI.h b/include/api/JsonAPI.h index a7b0dd583..083a68509 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -277,11 +277,9 @@ private slots: /// void handleSystemCommand(const QJsonObject &message, const JsonApiCommand& cmd); - void applyColorAdjustments(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); void applyColorAdjustment(const QString &colorName, const QJsonObject &adjustment, RgbChannelAdjustment &rgbAdjustment); void applyGammaTransform(const QString &transformName, const QJsonObject &adjustment, RgbTransform &rgbTransform, char channel); - void applyTemperatureAdjustment(const QJsonObject &adjustment, ColorCorrection *colorCorrection); void applyTransforms(const QJsonObject &adjustment, ColorAdjustment *colorAdjustment); template @@ -289,6 +287,8 @@ private slots: template void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(double)); template + void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(int)); + template void applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)); void handleTokenRequired(const JsonApiCommand& cmd); diff --git a/include/hyperion/ColorCorrection.h b/include/hyperion/ColorCorrection.h deleted file mode 100644 index 478cd35d3..000000000 --- a/include/hyperion/ColorCorrection.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -// Qt includes -#include - -// Utils includes -#include - -class ColorCorrection -{ -public: - - /// Unique identifier for this color correction - QString _id; - - /// The RGB correction - RgbChannelCorrection _rgbCorrection; -}; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 2348072a0..9bea27f4c 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #if defined(ENABLE_EFFECTENGINE) @@ -184,30 +183,15 @@ public slots: /// QStringList getAdjustmentIds() const; - /// - /// Returns the list with unique correction identifiers - /// @return The list with correction identifiers - /// - QStringList getTemperatureIds() const; - /// /// Returns the ColorAdjustment with the given identifier /// @return The adjustment with the given identifier (or nullptr if the identifier does not exist) /// ColorAdjustment * getAdjustment(const QString& id) const; - /// - /// Returns the ColorCorrection with the given identifier - /// @return The correction with the given identifier (or nullptr if the identifier does not exist) - /// - ColorCorrection * getTemperature(const QString& id) const; - /// Tell Hyperion that the corrections have changed and the leds need to be updated void adjustmentsUpdated(); - /// Tell Hyperion that the corrections have changed and the leds need to be updated - void temperaturesUpdated(); - /// /// Clears the given priority channel. This will switch the led-colors to the colors of the next /// lower priority channel (or off if no more channels are set) diff --git a/include/hyperion/MultiColorAdjustment.h b/include/hyperion/MultiColorAdjustment.h index 8ef15d259..2edd549ff 100644 --- a/include/hyperion/MultiColorAdjustment.h +++ b/include/hyperion/MultiColorAdjustment.h @@ -26,7 +26,7 @@ class MultiColorAdjustment */ void addAdjustment(ColorAdjustment * adjustment); - void setAdjustmentForLed(const QString& id, int startLed, int endLed); + void setAdjustmentForLed(const QString& adjutmentId, int startLed, int endLed); bool verifyAdjustments() const; @@ -41,11 +41,11 @@ class MultiColorAdjustment /// /// Returns the pointer to the ColorAdjustment with the given id /// - /// @param id The identifier of the ColorAdjustment + /// @param adjutmentId The identifier of the ColorAdjustment /// /// @return The ColorAdjustment with the given id (or nullptr if it does not exist) /// - ColorAdjustment* getAdjustment(const QString& id); + ColorAdjustment* getAdjustment(const QString& adjutmentId); /// /// Performs the color adjustment from raw-color to led-color diff --git a/include/hyperion/MultiColorCorrection.h b/include/hyperion/MultiColorCorrection.h deleted file mode 100644 index 364228710..000000000 --- a/include/hyperion/MultiColorCorrection.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -// STL includes - -#include - -// Utils includes -#include -#include "utils/Logger.h" - -// Hyperion includes -#include - -/// -/// The LedColorCorrection is responsible for performing color correction from 'raw' colors -/// received as input to colors mapped to match the color-properties of the leds. -/// -class MultiColorCorrection -{ -public: - MultiColorCorrection(int ledCnt); - ~MultiColorCorrection(); - - /** - * Adds a new ColorCorrection to this MultiColorCorrection - * - * @param Correction The new ColorCorrection (ownership is transfered) - */ - void addCorrection(ColorCorrection * correction); - - void setCorrectionForLed(const QString& id, int startLed, int endLed); - - bool verifyCorrections() const; - - /// - /// Returns the identifier of all the unique ColorCorrection - /// - /// @return The list with unique id's of the ColorCorrections - QStringList & getCorrectionIds(); - - /// - /// Returns the pointer to the ColorCorrection with the given id - /// - /// @param id The identifier of the ColorCorrection - /// - /// @return The ColorCorrection with the given id (or nullptr if it does not exist) - /// - ColorCorrection* getCorrection(const QString& id); - - /// - /// Performs the color transoformation from raw-color to led-color - /// - /// @param ledColors The list with raw colors - /// - void applyCorrection(std::vector& ledColors); - -private: - /// List with Correction ids - QStringList _correctionIds; - - /// List with unique ColorCorrections - std::vector _correction; - - /// List with a pointer to the ColorCorrection for each individual led - std::vector _ledCorrections; - - // logger instance - Logger * _log; -}; diff --git a/include/utils/RgbChannelCorrection.h b/include/utils/RgbChannelCorrection.h deleted file mode 100644 index f09b9cef5..000000000 --- a/include/utils/RgbChannelCorrection.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -// STL includes -#include - -/// Correction for a single color byte value -/// All configuration values are unsigned int and assume the color value to be between 0 and 255 -class RgbChannelCorrection -{ -public: - /// Default constructor - RgbChannelCorrection(); - - /// Constructor - /// @param correctionR - /// @param correctionG - /// @param correctionB - - RgbChannelCorrection(int correctionR, int correctionG, int correctionB); - - /// Destructor - ~RgbChannelCorrection(); - - /// @return The current correctionR value - uint8_t getcorrectionR() const; - - /// @param threshold New correctionR value - void setcorrectionR(uint8_t correctionR); - - /// @return The current correctionG value - uint8_t getcorrectionG() const; - - /// @param gamma New correctionG value - void setcorrectionG(uint8_t correctionG); - - /// @return The current correctionB value - uint8_t getcorrectionB() const; - - /// @param blacklevel New correctionB value - void setcorrectionB(uint8_t correctionB); - - /// Transform the given array value - /// @param input The input color bytes - /// @return The corrected byte value - uint8_t correctionR(uint8_t inputR) const; - uint8_t correctionG(uint8_t inputG) const; - uint8_t correctionB(uint8_t inputB) const; - - -private: - /// (re)-initilize the color mapping - void initializeMapping(); - -private: - /// The correction of R channel - int _correctionR; - /// The correction of G channel - int _correctionG; - /// The correction of B channel - int _correctionB; - - /// The mapping from input color to output color - int _mappingR[256]; - int _mappingG[256]; - int _mappingB[256]; -}; diff --git a/include/utils/RgbTransform.h b/include/utils/RgbTransform.h index ec493a2dc..f1d84456b 100644 --- a/include/utils/RgbTransform.h +++ b/include/utils/RgbTransform.h @@ -3,6 +3,8 @@ // STL includes #include +#include + /// /// Color transformation to adjust the saturation and value of a RGB color value /// @@ -23,8 +25,9 @@ class RgbTransform /// @param backlightThreshold The used lower brightness /// @param backlightColored use color in backlight /// @param brightnessHigh The used higher brightness + /// @param temeprature The given color temperature (in Kelvin) /// - RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation); + RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature); /// @return The current red gamma value double getGammaR() const; @@ -79,10 +82,10 @@ class RgbTransform /// /// @note The values are updated in place. /// - void getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & w) const; + void getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & white) const; /// - /// Apply the transform the the given RGB values. + /// Apply Gamma the the given RGB values. /// /// @param red The red color component /// @param green The green color component @@ -90,7 +93,22 @@ class RgbTransform /// /// @note The values are updated in place. /// - void transform(uint8_t & red, uint8_t & green, uint8_t & blue); + void applyGamma(uint8_t & red, uint8_t & green, uint8_t & blue); + + /// + /// Apply Backlight the the given RGB values. + /// + /// @param red The red color component + /// @param green The green color component + /// @param blue The blue color component + /// + /// @note The values are updated in place. + /// + void applyBacklight(uint8_t & red, uint8_t & green, uint8_t & blue) const; + + int getTemperature() const; + void setTemperature(int temperature); + void applyTemperature(ColorRgb& color) const; private: /// @@ -103,8 +121,9 @@ class RgbTransform /// @param backlightColored en/disable color in backlight /// @param brightness The used brightness /// @param brightnessCompensation The used brightness compensation + /// @param temeprature apply the given color temperature (in Kelvin) /// - void init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation); + void init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature); /// (re)-initilize the color mapping void initializeMapping(); /// The saturation gain @@ -112,25 +131,28 @@ class RgbTransform void updateBrightnessComponents(); /// backlight variables - bool _backLightEnabled - , _backlightColored; - double _backlightThreshold - , _sumBrightnessLow; + bool _backLightEnabled; + bool _backlightColored; + double _backlightThreshold; + double _sumBrightnessLow; /// gamma variables - double _gammaR - , _gammaG - , _gammaB; + double _gammaR; + double _gammaG; + double _gammaB; /// The mapping from input color to output color - uint8_t _mappingR[256] - , _mappingG[256] - , _mappingB[256]; + uint8_t _mappingR[256]; + uint8_t _mappingG[256]; + uint8_t _mappingB[256]; /// brightness variables - uint8_t _brightness - , _brightnessCompensation - , _brightness_rgb - , _brightness_cmy - , _brightness_w; + uint8_t _brightness; + uint8_t _brightnessCompensation; + uint8_t _brightness_rgb; + uint8_t _brightness_cmy; + uint8_t _brightness_w; + + int _temperature; + ColorRgb _temperatureRGB; }; diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index d8e9dbf33..a19ff768c 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -4,10 +4,8 @@ #include #include -#include "hyperion/MultiColorCorrection.h" #include #include -#include // fg effect #include @@ -79,8 +77,9 @@ namespace hyperion { const double gammaR = colorConfig["gammaRed"].toDouble(1.0); const double gammaG = colorConfig["gammaGreen"].toDouble(1.0); const double gammaB = colorConfig["gammaBlue"].toDouble(1.0); + const int temperature = colorConfig["temperature"].toInt(6600); - return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast(brightness), static_cast(brightnessComp)); + return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast(brightness), static_cast(brightnessComp), temperature); } static OkhsvTransform createOkhsvTransform(const QJsonObject& colorConfig) @@ -102,32 +101,6 @@ namespace hyperion { ); } - static RgbChannelCorrection* createRgbChannelCorrection(const QJsonObject& colorConfig) - { - int varR = colorConfig["red"].toInt(255); - int varG = colorConfig["green"].toInt(255); - int varB = colorConfig["blue"].toInt(255); - - RgbChannelCorrection* correction = new RgbChannelCorrection(varR, varG, varB); - return correction; - } - - static ColorCorrection * createColorCorrection(const QJsonObject& correctionConfig) - { - const QString id = correctionConfig["id"].toString("default"); - - RgbChannelCorrection * rgbCorrection = createRgbChannelCorrection(correctionConfig); - - ColorCorrection * correction = new ColorCorrection(); - correction->_id = id; - correction->_rgbCorrection = *rgbCorrection; - - // Cleanup the allocated individual transforms - delete rgbCorrection; - - return correction; - } - static ColorAdjustment* createColorAdjustment(const QJsonObject & adjustmentConfig) { const QString id = adjustmentConfig["id"].toString("default"); @@ -205,74 +178,6 @@ namespace hyperion { return adjustment; } - static MultiColorCorrection * createLedColorsTemperature(int ledCnt, const QJsonObject & colorConfig) - { - // Create the result, the corrections are added to this - MultiColorCorrection * correction = new MultiColorCorrection(ledCnt); - - const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"]; - const QRegularExpression overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); - - const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray(); - for (signed i = 0; i < adjustmentConfigArray.size(); ++i) - { - const QJsonObject & config = adjustmentConfigArray.at(i).toObject(); - ColorAdjustment * colorAdjustment = createColorAdjustment(config); - - int temperature = config["temperature"].toInt(); - - ColorRgb rgb = getRgbFromTemperature(temperature); - QJsonObject correctionConfig { - {"red", rgb.red}, - {"green", rgb.green}, - {"blue", rgb.blue} - }; - - ColorCorrection * colorCorrection = createColorCorrection(correctionConfig); - correction->addCorrection(colorCorrection); - - const QString ledIndicesStr = config["leds"].toString("").trimmed(); - if (ledIndicesStr.compare("*") == 0) - { - // Special case for indices '*' => all leds - correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); - Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [0-%d]", QSTRING_CSTR(colorCorrection->_id), ledCnt-1); - continue; - } - - if (!overallExp.match(ledIndicesStr).hasMatch()) - { - Error(Logger::getInstance("HYPERION"), "Given led indices %d not correct format: %s", i, QSTRING_CSTR(ledIndicesStr)); - continue; - } - - std::stringstream ss; - const QStringList ledIndexList = ledIndicesStr.split(","); - for (int i=0; i 0) - { - ss << ", "; - } - if (ledIndexList[i].contains("-")) - { - QStringList ledIndices = ledIndexList[i].split("-"); - int startInd = ledIndices[0].toInt(); - int endInd = ledIndices[1].toInt(); - correction->setCorrectionForLed(colorCorrection->_id, startInd, endInd); - ss << startInd << "-" << endInd; - } - else - { - int index = ledIndexList[i].toInt(); - correction->setCorrectionForLed(colorCorrection->_id, index, index); - ss << index; - } - } - Info(Logger::getInstance("HYPERION"), "ColorCorrection '%s' => [%s]", QSTRING_CSTR(colorAdjustment->_id), ss.str().c_str()); - } - return correction; - } - /** * Construct the 'led-string' with the integration area definition per led and the color * ordering of the RGB channels diff --git a/libsrc/api/JsonAPI.cpp b/libsrc/api/JsonAPI.cpp index 0a0e158db..67cfc49e8 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -598,16 +598,8 @@ void JsonAPI::handleAdjustmentCommand(const QJsonObject &message, const JsonApiC return; } - ColorCorrection *temperatureColorCorrection = _hyperion->getTemperature(adjustmentId); - if (temperatureColorCorrection == nullptr) { - Warning(_log, "Incorrect temperature adjustment identifier: %s", adjustmentId.toStdString().c_str()); - return; - } - - applyColorAdjustments(adjustment, colorAdjustment); applyTransforms(adjustment, colorAdjustment); - applyTemperatureAdjustment(adjustment, temperatureColorCorrection); _hyperion->adjustmentsUpdated(); sendSuccessReply(cmd); } @@ -644,6 +636,7 @@ void JsonAPI::applyTransforms(const QJsonObject &adjustment, ColorAdjustment *co applyTransform("backlightColored", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBacklightColored); applyTransform("brightness", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBrightness); applyTransform("brightnessCompensation", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setBrightnessCompensation); + applyTransform("temperature", adjustment, colorAdjustment->_rgbTransform, &RgbTransform::setTemperature); applyTransform("saturationGain", adjustment, colorAdjustment->_okhsvTransform, &OkhsvTransform::setSaturationGain); applyTransform("brightnessGain", adjustment, colorAdjustment->_okhsvTransform, &OkhsvTransform::setBrightnessGain); } @@ -674,23 +667,18 @@ void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &ad } template -void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)) +void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(int)) { if (adjustment.contains(transformName)) { - (transform.*setFunction)(static_cast(adjustment[transformName].toInt())); + (transform.*setFunction)(adjustment[transformName].toInt()); } } -void JsonAPI::applyTemperatureAdjustment(const QJsonObject &adjustment, ColorCorrection *colorCorrection) +template +void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)) { - if (adjustment.contains("temperature")) - { - int temperature = adjustment["temperature"].toInt(6500); - ColorRgb rgb = getRgbFromTemperature(temperature); - - colorCorrection->_rgbCorrection.setcorrectionR(rgb.red); - colorCorrection->_rgbCorrection.setcorrectionG(rgb.green); - colorCorrection->_rgbCorrection.setcorrectionB(rgb.blue); + if (adjustment.contains(transformName)) { + (transform.*setFunction)(static_cast(adjustment[transformName].toInt())); } } diff --git a/libsrc/api/JsonInfo.cpp b/libsrc/api/JsonInfo.cpp index 8c74579e1..c99852451 100644 --- a/libsrc/api/JsonInfo.cpp +++ b/libsrc/api/JsonInfo.cpp @@ -83,15 +83,7 @@ QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log) adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain(); adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain(); - - ColorCorrection *temperatureColorCorrection = hyperion->getTemperature(adjustmentId); - if (temperatureColorCorrection == nullptr) { - Error(log, "Incorrect temperature adjustment id: %s", QSTRING_CSTR(adjustmentId)); - continue; - } - - // TODO: Return current Temperature in Kelvin - adjustment["temperature"] = 6600; + adjustment["temperature"] = colorAdjustment->_rgbTransform.getTemperature(); adjustmentArray.append(adjustment); } diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index 7c4264f99..b073dcf4b 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -39,9 +39,6 @@ add_library(hyperion # Led Color Transform ${CMAKE_SOURCE_DIR}/include/hyperion/MultiColorAdjustment.h ${CMAKE_SOURCE_DIR}/libsrc/hyperion/MultiColorAdjustment.cpp - ${CMAKE_SOURCE_DIR}/include/hyperion/ColorCorrection.h - ${CMAKE_SOURCE_DIR}/include/hyperion/MultiColorCorrection.h - ${CMAKE_SOURCE_DIR}/libsrc/hyperion/MultiColorCorrection.cpp # Priority Muxer ${CMAKE_SOURCE_DIR}/include/hyperion/PriorityMuxer.h ${CMAKE_SOURCE_DIR}/libsrc/hyperion/PriorityMuxer.cpp diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 25b89e63f..de7195785 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -26,7 +26,6 @@ #include #include -#include #include #if defined(ENABLE_EFFECTENGINE) @@ -57,7 +56,6 @@ Hyperion::Hyperion(quint8 instance, bool readonlyMode) , _imageProcessor(nullptr) , _muxer(nullptr) , _raw2ledAdjustment(hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) - , _raw2ledTemperature(hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object())) , _ledDeviceWrapper(nullptr) , _deviceSmooth(nullptr) #if defined(ENABLE_EFFECTENGINE) @@ -102,11 +100,6 @@ void Hyperion::start() // get newVideoMode from HyperionIManager connect(this, &Hyperion::newVideoMode, this, &Hyperion::handleNewVideoMode); - if (!_raw2ledTemperature->verifyCorrections()) - { - Warning(_log, "Color temperature incorrectly set"); - } - if (!_raw2ledAdjustment->verifyAdjustments()) { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); @@ -229,9 +222,6 @@ void Hyperion::freeObjects() delete _raw2ledAdjustment; - // delete the color temperature correction - delete _raw2ledTemperature; - #if defined(ENABLE_FORWARDER) delete _messageForwarder; #endif @@ -257,15 +247,6 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co { Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); } - - // change in color recreate ledTemperature - delete _raw2ledTemperature; - _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), obj); - - if (!_raw2ledTemperature->verifyCorrections()) - { - Warning(_log, "At least one led has no color calibration, please add all leds from your led layout to an 'LED index' field!"); - } } else if(type == settings::LEDS) { @@ -298,10 +279,6 @@ void Hyperion::handleSettingsUpdate(settings::type type, const QJsonDocument& co delete _raw2ledAdjustment; _raw2ledAdjustment = hyperion::createLedColorsAdjustment(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); - // change in leds recreate ledTemperature - delete _raw2ledTemperature; - _raw2ledTemperature = hyperion::createLedColorsTemperature(static_cast(_ledString.leds().size()), getSetting(settings::COLOR).object()); - #if defined(ENABLE_EFFECTENGINE) // start cached effects _effectEngine->startCachedEffects(); @@ -517,33 +494,17 @@ QStringList Hyperion::getAdjustmentIds() const return _raw2ledAdjustment->getAdjustmentIds(); } -QStringList Hyperion::getTemperatureIds() const -{ - return _raw2ledTemperature->getCorrectionIds(); -} - ColorAdjustment * Hyperion::getAdjustment(const QString& id) const { return _raw2ledAdjustment->getAdjustment(id); } -ColorCorrection * Hyperion::getTemperature(const QString& id) const -{ - return _raw2ledTemperature->getCorrection(id); -} - void Hyperion::adjustmentsUpdated() { emit adjustmentChanged(); update(); } -void Hyperion::temperaturesUpdated() -{ - emit adjustmentChanged(); - update(); -} - bool Hyperion::clear(int priority, bool forceClearAll) { bool isCleared = false; @@ -736,7 +697,6 @@ void Hyperion::update() emit rawLedColors(_ledBuffer); _raw2ledAdjustment->applyAdjustment(_ledBuffer); - _raw2ledTemperature->applyCorrection(_ledBuffer); int i = 0; for (ColorRgb& color : _ledBuffer) diff --git a/libsrc/hyperion/MultiColorAdjustment.cpp b/libsrc/hyperion/MultiColorAdjustment.cpp index 4c761d6a8..9d1a541ed 100644 --- a/libsrc/hyperion/MultiColorAdjustment.cpp +++ b/libsrc/hyperion/MultiColorAdjustment.cpp @@ -1,22 +1,26 @@ +#include +#include + // Hyperion includes + #include #include +constexpr uint32_t UINT8_MAX_SQUARED = static_cast(std::numeric_limits::max()) * static_cast(std::numeric_limits::max()); + MultiColorAdjustment::MultiColorAdjustment(int ledCnt) - : _ledAdjustments(ledCnt, nullptr) + : _ledAdjustments(static_cast(ledCnt), nullptr) , _log(Logger::getInstance("ADJUSTMENT")) { } MultiColorAdjustment::~MultiColorAdjustment() { - // Clean up all the transforms - for (ColorAdjustment * adjustment : _adjustment) + for (ColorAdjustment* adjustment : _adjustment) { delete adjustment; - // BUG: Calling pop_back while iterating is invalid - _adjustment.pop_back(); } + _adjustment.clear(); } void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment) @@ -25,7 +29,7 @@ void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment) _adjustment.push_back(adjustment); } -void MultiColorAdjustment::setAdjustmentForLed(const QString& id, int startLed, int endLed) +void MultiColorAdjustment::setAdjustmentForLed(const QString& adjutmentId, int startLed, int endLed) { // abort if(startLed > endLed) @@ -41,8 +45,8 @@ void MultiColorAdjustment::setAdjustmentForLed(const QString& id, int startLed, } // Get the identified adjustment (don't care if is nullptr) - ColorAdjustment * adjustment = getAdjustment(id); - for (int iLed=startLed; iLed<=endLed; ++iLed) + ColorAdjustment * adjustment = getAdjustment(adjutmentId); + for (size_t iLed=static_cast(startLed); iLed<=static_cast(endLed); ++iLed) { _ledAdjustments[iLed] = adjustment; } @@ -50,18 +54,18 @@ void MultiColorAdjustment::setAdjustmentForLed(const QString& id, int startLed, bool MultiColorAdjustment::verifyAdjustments() const { - bool ok = true; + bool isAdjustmentDefined = true; for (unsigned iLed=0; iLed<_ledAdjustments.size(); ++iLed) { - ColorAdjustment * adjustment = _ledAdjustments[iLed]; + const ColorAdjustment * adjustment = _ledAdjustments[iLed]; if (adjustment == nullptr) { - Warning(_log, "No calibration set for led %d", iLed); - ok = false; + Warning(_log, "No calibration set for LED %d", iLed); + isAdjustmentDefined = false; } } - return ok; + return isAdjustmentDefined; } QStringList MultiColorAdjustment::getAdjustmentIds() const @@ -69,15 +73,14 @@ QStringList MultiColorAdjustment::getAdjustmentIds() const return _adjustmentIds; } -ColorAdjustment* MultiColorAdjustment::getAdjustment(const QString& id) +ColorAdjustment* MultiColorAdjustment::getAdjustment(const QString& adjustmentId) { - // Iterate through the unique adjustments until we find the one with the given id - for (ColorAdjustment* adjustment : _adjustment) - { - if (adjustment->_id == id) - { - return adjustment; - } + auto adjustmentIter = std::find_if(_adjustment.begin(), _adjustment.end(), [&adjustmentId](const ColorAdjustment* adjustment) { + return adjustment->_id == adjustmentId; + }); + + if (adjustmentIter != _adjustment.end()) { + return *adjustmentIter; } // The ColorAdjustment was not found @@ -100,8 +103,7 @@ void MultiColorAdjustment::applyAdjustment(std::vector& ledColors) ColorAdjustment* adjustment = _ledAdjustments[i]; if (adjustment == nullptr) { - //std::cout << "MultiColorAdjustment::applyAdjustment() - No transform set for this led : " << i << std::endl; - // No transform set for this led (do nothing) + // No transform set for this LED (do nothing) continue; } ColorRgb& color = ledColors[i]; @@ -117,27 +119,34 @@ void MultiColorAdjustment::applyAdjustment(std::vector& ledColors) { adjustment->_okhsvTransform.transform(ored, ogreen, oblue); } - adjustment->_rgbTransform.transform(ored,ogreen,oblue); - adjustment->_rgbTransform.getBrightnessComponents(B_RGB, B_CMY, B_W); - - uint32_t nrng = (uint32_t) (255-ored)*(255-ogreen); - uint32_t rng = (uint32_t) (ored) *(255-ogreen); - uint32_t nrg = (uint32_t) (255-ored)*(ogreen); - uint32_t rg = (uint32_t) (ored) *(ogreen); - uint8_t black = nrng*(255-oblue)/65025; - uint8_t red = rng *(255-oblue)/65025; - uint8_t green = nrg *(255-oblue)/65025; - uint8_t blue = nrng*(oblue) /65025; - uint8_t cyan = nrg *(oblue) /65025; - uint8_t magenta = rng *(oblue) /65025; - uint8_t yellow = rg *(255-oblue)/65025; - uint8_t white = rg *(oblue) /65025; - - uint8_t OR, OG, OB, RR, RG, RB, GR, GG, GB, BR, BG, BB; - uint8_t CR, CG, CB, MR, MG, MB, YR, YG, YB, WR, WG, WB; + adjustment->_rgbTransform.applyGamma(ored,ogreen,oblue); + adjustment->_rgbTransform.getBrightnessComponents(B_RGB, B_CMY, B_W); - adjustment->_rgbBlackAdjustment.apply (black , 255 , OR, OG, OB); + uint32_t nr_ng = static_cast((UINT8_MAX - ored) * (UINT8_MAX - ogreen)); + uint32_t r_ng = static_cast(ored * (UINT8_MAX - ogreen)); + uint32_t nr_g = static_cast((UINT8_MAX - ored) * ogreen); + uint32_t r_g = static_cast(ored * ogreen); + + uint8_t black = static_cast(nr_ng * (UINT8_MAX - oblue) / UINT8_MAX_SQUARED); + uint8_t red = static_cast(r_ng * (UINT8_MAX - oblue) / UINT8_MAX_SQUARED); + uint8_t green = static_cast(nr_g * (UINT8_MAX - oblue) / UINT8_MAX_SQUARED); + uint8_t blue = static_cast(nr_ng * (oblue) / UINT8_MAX_SQUARED); + uint8_t cyan = static_cast(nr_g * (oblue) / UINT8_MAX_SQUARED); + uint8_t magenta = static_cast(r_ng * (oblue) / UINT8_MAX_SQUARED); + uint8_t yellow = static_cast(r_g * (UINT8_MAX - oblue) / UINT8_MAX_SQUARED); + uint8_t white = static_cast(r_g * (oblue) / UINT8_MAX_SQUARED); + + uint8_t OR, OG, OB; // Original Colors + uint8_t RR, RG, RB; // Red Adjustments + uint8_t GR, GG, GB; // Green Adjustments + uint8_t BR, BG, BB; // Blue Adjustments + uint8_t CR, CG, CB; // Cyan Adjustments + uint8_t MR, MG, MB; // Magenta Adjustments + uint8_t YR, YG, YB; // Yellow Adjustments + uint8_t WR, WG, WB; // White Adjustments + + adjustment->_rgbBlackAdjustment.apply (black , UINT8_MAX, OR, OG, OB); adjustment->_rgbRedAdjustment.apply (red , B_RGB, RR, RG, RB); adjustment->_rgbGreenAdjustment.apply (green , B_RGB, GR, GG, GB); adjustment->_rgbBlueAdjustment.apply (blue , B_RGB, BR, BG, BB); @@ -149,5 +158,8 @@ void MultiColorAdjustment::applyAdjustment(std::vector& ledColors) color.red = OR + RR + GR + BR + CR + MR + YR + WR; color.green = OG + RG + GG + BG + CG + MG + YG + WG; color.blue = OB + RB + GB + BB + CB + MB + YB + WB; + + adjustment->_rgbTransform.applyTemperature(color); + adjustment->_rgbTransform.applyBacklight(color.red, color.green, color.green); } } diff --git a/libsrc/hyperion/MultiColorCorrection.cpp b/libsrc/hyperion/MultiColorCorrection.cpp deleted file mode 100644 index 74148e431..000000000 --- a/libsrc/hyperion/MultiColorCorrection.cpp +++ /dev/null @@ -1,103 +0,0 @@ -// Hyperion includes -#include -#include - -MultiColorCorrection::MultiColorCorrection(int ledCnt) : - _ledCorrections(ledCnt, nullptr) -, _log(Logger::getInstance("CORRECTION")) -{ -} - -MultiColorCorrection::~MultiColorCorrection() -{ - // Clean up all the correctinos - for (ColorCorrection * correction : _correction) - { - delete correction; - } -} - -void MultiColorCorrection::addCorrection(ColorCorrection * correction) -{ - _correctionIds.push_back(correction->_id); - _correction.push_back(correction); -} - -void MultiColorCorrection::setCorrectionForLed(const QString& id, int startLed, int endLed) -{ - // abort - if(startLed > endLed) - { - Error(_log,"startLed > endLed -> %d > %d", startLed, endLed); - return; - } - // catch wrong values - if(endLed > static_cast(_ledCorrections.size()-1)) - { - Warning(_log,"The color correction 'LED index' field has LEDs specified which aren't part of your led layout"); - endLed = static_cast(_ledCorrections.size()-1); - } - - // Get the identified correction (don't care if is nullptr) - ColorCorrection * correction = getCorrection(id); - for (int iLed=startLed; iLed<=endLed; ++iLed) - { - _ledCorrections[iLed] = correction; - } -} - -bool MultiColorCorrection::verifyCorrections() const -{ - bool ok = true; - for (unsigned iLed=0; iLed<_ledCorrections.size(); ++iLed) - { - ColorCorrection* adjustment = _ledCorrections[iLed]; - - if (adjustment == nullptr) - { - Warning(_log, "No correction set for led %d", iLed); - ok = false; - } - } - return ok; -} - -QStringList & MultiColorCorrection::getCorrectionIds() -{ - return _correctionIds; -} - -ColorCorrection* MultiColorCorrection::getCorrection(const QString& id) -{ - // Iterate through the unique corrections until we find the one with the given id - for (ColorCorrection * correction : _correction) - { - if (correction->_id == id) - { - return correction; - } - } - - // The ColorCorrection was not found - return nullptr; -} - -void MultiColorCorrection::applyCorrection(std::vector& ledColors) -{ - const size_t itCnt = qMin(_ledCorrections.size(), ledColors.size()); - for (size_t i=0; i_rgbCorrection.correctionR(color.red); - color.green = correction->_rgbCorrection.correctionG(color.green); - color.blue = correction->_rgbCorrection.correctionB(color.blue); - } -} diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index f8dda6314..83a177f1b 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -57,8 +57,6 @@ add_library(hyperion-utils # Rgb single color adjustment/correction ${CMAKE_SOURCE_DIR}/include/utils/RgbChannelAdjustment.h ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelAdjustment.cpp - ${CMAKE_SOURCE_DIR}/include/utils/RgbChannelCorrection.h - ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbChannelCorrection.cpp # Color conversion/transformation ${CMAKE_SOURCE_DIR}/include/utils/RgbToRgbw.h ${CMAKE_SOURCE_DIR}/libsrc/utils/RgbToRgbw.cpp diff --git a/libsrc/utils/RgbChannelCorrection.cpp b/libsrc/utils/RgbChannelCorrection.cpp deleted file mode 100644 index 7fb168848..000000000 --- a/libsrc/utils/RgbChannelCorrection.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// STL includes -#include - -// Utils includes -#include - -RgbChannelCorrection::RgbChannelCorrection() : - _correctionR(255), - _correctionG(255), - _correctionB(255) -{ - initializeMapping(); -} - -RgbChannelCorrection::RgbChannelCorrection(int correctionR, int correctionG, int correctionB) : - _correctionR(correctionR), - _correctionG(correctionG), - _correctionB(correctionB) -{ - initializeMapping(); -} - -RgbChannelCorrection::~RgbChannelCorrection() -{ -} - -uint8_t RgbChannelCorrection::getcorrectionR() const -{ - return _correctionR; -} - -void RgbChannelCorrection::setcorrectionR(uint8_t correctionR) -{ - _correctionR = correctionR; - initializeMapping(); -} - -uint8_t RgbChannelCorrection::getcorrectionG() const -{ - return _correctionG; -} - -void RgbChannelCorrection::setcorrectionG(uint8_t correctionG) -{ - _correctionG = correctionG; - initializeMapping(); -} - -uint8_t RgbChannelCorrection::getcorrectionB() const -{ - return _correctionB; -} - -void RgbChannelCorrection::setcorrectionB(uint8_t correctionB) -{ - _correctionB = correctionB; - initializeMapping(); -} - -uint8_t RgbChannelCorrection::correctionR(uint8_t inputR) const -{ - return _mappingR[inputR]; -} - -uint8_t RgbChannelCorrection::correctionG(uint8_t inputG) const -{ - return _mappingG[inputG]; -} - -uint8_t RgbChannelCorrection::correctionB(uint8_t inputB) const -{ - return _mappingB[inputB]; -} - -void RgbChannelCorrection::initializeMapping() -{ - // initialize the mapping - for (int i = 0; i < 256; ++i) - { - int outputR = (i * _correctionR) / 255; - if (outputR < -255) - { - outputR = -255; - } - else if (outputR > 255) - { - outputR = 255; - } - _mappingR[i] = outputR; - } - for (int i = 0; i < 256; ++i) - { - int outputG = (i * _correctionG) / 255; - if (outputG < -255) - { - outputG = -255; - } - else if (outputG > 255) - { - outputG = 255; - } - _mappingG[i] = outputG; - } - for (int i = 0; i < 256; ++i) - { - int outputB = (i * _correctionB) / 255; - if (outputB < -255) - { - outputB = -255; - } - else if (outputB > 255) - { - outputB = 255; - } - _mappingB[i] = outputB; - } - - -} - diff --git a/libsrc/utils/RgbTransform.cpp b/libsrc/utils/RgbTransform.cpp index 9a988ed5e..e88e3b8b5 100644 --- a/libsrc/utils/RgbTransform.cpp +++ b/libsrc/utils/RgbTransform.cpp @@ -1,19 +1,22 @@ #include #include +#include + +#include RgbTransform::RgbTransform() - : RgbTransform::RgbTransform(1.0, 1.0, 1.0, 0.0, false, 100, 100) + : RgbTransform::RgbTransform(1.0, 1.0, 1.0, 0.0, false, 100, 100, 6600) { } -RgbTransform::RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation) +RgbTransform::RgbTransform(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature) : _brightness(brightness) , _brightnessCompensation(brightnessCompensation) { - init(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, _brightness, _brightnessCompensation); + init(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, _brightness, _brightnessCompensation, temperature); } -void RgbTransform::init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation) +void RgbTransform::init(double gammaR, double gammaG, double gammaB, double backlightThreshold, bool backlightColored, uint8_t brightness, uint8_t brightnessCompensation, int temperature) { _backLightEnabled = true; setGamma(gammaR,gammaG,gammaB); @@ -21,6 +24,7 @@ void RgbTransform::init(double gammaR, double gammaG, double gammaB, double back setBacklightColored(backlightColored); setBrightness(brightness); setBrightnessCompensation(brightnessCompensation); + setTemperature(temperature); initializeMapping(); } @@ -49,18 +53,34 @@ void RgbTransform::setGamma(double gammaR, double gammaG, double gammaB) void RgbTransform::initializeMapping() { - for (int i = 0; i < 256; ++i) + for (int i = 0; i <= UINT8_MAX; ++i) { - _mappingR[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaR) * 255), 0), 255); - _mappingG[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaG) * 255), 0), 255); - _mappingB[i] = qMin(qMax((int)(qPow(i / 255.0, _gammaB) * 255), 0), 255); + // Calculate normalized value + double normalizedValueR = static_cast(i) / UINT8_MAX; + double normalizedValueG = static_cast(i) / UINT8_MAX; + double normalizedValueB = static_cast(i) / UINT8_MAX; + + // Apply gamma correction + double gammaCorrectedValueR = qPow(normalizedValueR, _gammaR) * UINT8_MAX; + double gammaCorrectedValueG = qPow(normalizedValueG, _gammaG) * UINT8_MAX; + double gammaCorrectedValueB = qPow(normalizedValueB, _gammaB) * UINT8_MAX; + + // Clamp values to valid range [0, UINT8_MAX] + quint8 clampedValueR = static_cast(qMin(qMax(gammaCorrectedValueR, 0.0), static_cast(UINT8_MAX))); + quint8 clampedValueG = static_cast(qMin(qMax(gammaCorrectedValueG, 0.0), static_cast(UINT8_MAX))); + quint8 clampedValueB = static_cast(qMin(qMax(gammaCorrectedValueB, 0.0), static_cast(UINT8_MAX))); + + // Assign clamped values to _mapping arrays + _mappingR[i] = clampedValueR; + _mappingG[i] = clampedValueG; + _mappingB[i] = clampedValueB; } } int RgbTransform::getBacklightThreshold() const { - return _backlightThreshold; + return static_cast(_backlightThreshold); } void RgbTransform::setBacklightThreshold(double backlightThreshold) @@ -116,60 +136,81 @@ void RgbTransform::updateBrightnessComponents() double Fw = _brightnessCompensation*2.0/100.0+1.0; double Fcmy = _brightnessCompensation/100.0+1.0; - double B_in= 0; _brightness_rgb = 0; _brightness_cmy = 0; _brightness_w = 0; if (_brightness > 0) { - B_in = (_brightness<50)? -0.09*_brightness+7.5 : -0.04*_brightness+5.0; + double B_in = (_brightness < 50) ? -0.09 * _brightness + 7.5 : -0.04 * _brightness + 5.0; - _brightness_rgb = std::ceil(qMin(255.0,255.0/B_in)); - _brightness_cmy = std::ceil(qMin(255.0,255.0/(B_in*Fcmy))); - _brightness_w = std::ceil(qMin(255.0,255.0/(B_in*Fw))); + // Ensure that the result is converted to an integer before assigning to uint8_t + _brightness_rgb = static_cast(std::ceil(qMin(static_cast(UINT8_MAX), UINT8_MAX / B_in))); + _brightness_cmy = static_cast(std::ceil(qMin(static_cast(UINT8_MAX), UINT8_MAX / (B_in * Fcmy)))); + _brightness_w = static_cast(std::ceil(qMin(static_cast(UINT8_MAX), UINT8_MAX / (B_in * Fw)))); } } -void RgbTransform::getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & w) const +void RgbTransform::getBrightnessComponents(uint8_t & rgb, uint8_t & cmy, uint8_t & white) const { rgb = _brightness_rgb; cmy = _brightness_cmy; - w = _brightness_w; + white = _brightness_w; } -void RgbTransform::transform(uint8_t & red, uint8_t & green, uint8_t & blue) +void RgbTransform::applyGamma(uint8_t & red, uint8_t & green, uint8_t & blue) { // apply gamma red = _mappingR[red]; green = _mappingG[green]; blue = _mappingB[blue]; +} +void RgbTransform::applyBacklight(uint8_t & red, uint8_t & green, uint8_t & blue) const +{ // apply brightnesss int rgbSum = red+green+blue; - if ( _backLightEnabled && _sumBrightnessLow>0 && rgbSum < _sumBrightnessLow) + if ( _backLightEnabled && _sumBrightnessLow > 0 && rgbSum < _sumBrightnessLow) { if (_backlightColored) { if (rgbSum == 0) { - if (red ==0) red = 1; - if (green==0) green = 1; - if (blue ==0) blue = 1; + if (red ==0) { red = 1; } + if (green==0) { green = 1; } + if (blue ==0) { blue = 1; } rgbSum = red+green+blue; } - double cL =qMin((int)(_sumBrightnessLow /rgbSum), 255); - red *= cL; - green *= cL; - blue *= cL; + uint8_t cLow = static_cast(qMin(static_cast(_sumBrightnessLow / rgbSum), UINT8_MAX)); + red *= cLow; + green *= cLow; + blue *= cLow; } else { - red = qMin((int)(_sumBrightnessLow/3.0), 255); + red = static_cast(qMin(static_cast(_sumBrightnessLow/3.0), UINT8_MAX)); green = red; blue = red; } } } + +void RgbTransform::setTemperature(int temperature) +{ + _temperature = temperature; + _temperatureRGB = getRgbFromTemperature(_temperature); +} + +int RgbTransform::getTemperature() const +{ + return _temperature; +} + +void RgbTransform::applyTemperature(ColorRgb& color) const +{ + color.red = color.red * _temperatureRGB.red / UINT8_MAX; + color.green = color.green * _temperatureRGB.green / UINT8_MAX; + color.blue = color.blue * _temperatureRGB.blue / UINT8_MAX; +} From 31321411ad5fd96a0d640bf91280d29bb2a79d66 Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Thu, 30 May 2024 19:27:24 +0200 Subject: [PATCH 06/11] Fix imagestream update --- assets/webconfig/js/content_leds.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assets/webconfig/js/content_leds.js b/assets/webconfig/js/content_leds.js index a0f216a0f..c9ec2eacd 100755 --- a/assets/webconfig/js/content_leds.js +++ b/assets/webconfig/js/content_leds.js @@ -977,7 +977,7 @@ $(document).ready(function () { //Only update Image, if LED Layout Tab is visible if (onLedLayoutTab && window.imageStreamActive) { setClassByBool('#leds_prev_toggle_live_video', window.imageStreamActive, "btn-danger", "btn-success"); - var imageData = (event.response.result.image); + var imageData = (event.response.data.image); var image = new Image(); image.onload = function () { From 4e77d4a0d49a40536428162e633cd8b6e0c512e3 Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Thu, 30 May 2024 19:48:37 +0200 Subject: [PATCH 07/11] fix cast --- libsrc/utils/RgbTransform.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libsrc/utils/RgbTransform.cpp b/libsrc/utils/RgbTransform.cpp index e88e3b8b5..97a72c348 100644 --- a/libsrc/utils/RgbTransform.cpp +++ b/libsrc/utils/RgbTransform.cpp @@ -183,14 +183,14 @@ void RgbTransform::applyBacklight(uint8_t & red, uint8_t & green, uint8_t & blue rgbSum = red+green+blue; } - uint8_t cLow = static_cast(qMin(static_cast(_sumBrightnessLow / rgbSum), UINT8_MAX)); + uint8_t cLow = static_cast(qMin(static_cast(_sumBrightnessLow/rgbSum), static_cast(UINT8_MAX))); red *= cLow; green *= cLow; blue *= cLow; } else { - red = static_cast(qMin(static_cast(_sumBrightnessLow/3.0), UINT8_MAX)); + red = static_cast(qMin(static_cast(_sumBrightnessLow/3.0), static_cast(UINT8_MAX))); green = red; blue = red; } From 1eed23f765bf43bc8d631cf654e2b997e1e8eeef Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Fri, 31 May 2024 17:27:30 +0200 Subject: [PATCH 08/11] Cleanups --- CMakeLists.txt | 2 +- include/hyperion/Hyperion.h | 4 -- include/utils/ColorRgb.h | 4 ++ include/utils/KelvinToRgb.h | 27 ++++---- include/utils/RgbChannelAdjustment.h | 31 +++++---- include/utils/global_defines.h | 2 + include/utils/hyperion.h | 81 +++++++----------------- libsrc/hyperion/MultiColorAdjustment.cpp | 3 - libsrc/utils/ColorRgb.cpp | 2 + libsrc/utils/RgbChannelAdjustment.cpp | 43 ++++++++----- libsrc/utils/RgbTransform.cpp | 10 ++- 11 files changed, 97 insertions(+), 112 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 611068cb6..30e971480 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,7 +111,7 @@ set(DEFAULT_USE_SYSTEM_QMDNS_LIBS OFF) set(DEFAULT_TESTS OFF) # Build Hyperion with a reduced set of functionality, overwrites other default values -set(DEFAULT_HYPERION_LIGHT ON ) +set(DEFAULT_HYPERION_LIGHT OFF) if(${CMAKE_SYSTEM} MATCHES "Linux") set(DEFAULT_FB ON) diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 9bea27f4c..a15eda8ea 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -48,7 +48,6 @@ class LinearColorSmoothing; class EffectEngine; #endif class MultiColorAdjustment; -class MultiColorCorrection; class ColorAdjustment; class SettingsManager; class BGEffectHandler; @@ -578,9 +577,6 @@ private slots: /// The adjustment from raw colors to led colors MultiColorAdjustment * _raw2ledAdjustment; - /// The temperature from raw colors to led colors - MultiColorCorrection * _raw2ledTemperature; - /// The actual LedDeviceWrapper LedDeviceWrapper* _ledDeviceWrapper; diff --git a/include/utils/ColorRgb.h b/include/utils/ColorRgb.h index b9a91038e..05e710931 100644 --- a/include/utils/ColorRgb.h +++ b/include/utils/ColorRgb.h @@ -33,6 +33,10 @@ struct ColorRgb static const ColorRgb YELLOW; /// 'White' RgbColor (255, 255, 255) static const ColorRgb WHITE; + /// 'Cyan' RgbColor (0, 255, 255) + static const ColorRgb CYAN; + /// 'Magenta' RgbColor (255, 0,255) + static const ColorRgb MAGENTA; ColorRgb() = default; diff --git a/include/utils/KelvinToRgb.h b/include/utils/KelvinToRgb.h index e044375a4..7bd4d162d 100644 --- a/include/utils/KelvinToRgb.h +++ b/include/utils/KelvinToRgb.h @@ -5,28 +5,31 @@ #include - // Constants -namespace { -const int TEMPERATURE_MINIMUM = 1000; -const int TEMPERATUR_MAXIMUM = 40000; -} //End of constants +namespace ColorTemperature { + constexpr int MINIMUM {1000}; + constexpr int MAXIMUM {40000}; + constexpr int DEFAULT {6600}; +} +//End of constants static ColorRgb getRgbFromTemperature(int temperature) { //Temperature input in Kelvin valid in the range 1000 K to 40000 K. White light = 6600K - temperature = qBound(TEMPERATURE_MINIMUM, temperature, TEMPERATUR_MAXIMUM); + temperature = qBound(ColorTemperature::MINIMUM, temperature, ColorTemperature::MAXIMUM); // All calculations require temperature / 100, so only do the conversion once. temperature /= 100; // Compute each color in turn. - int red, green, blue; + int red; + int green; + int blue; // red if (temperature <= 66) { - red = 255; + red = UINT8_MAX; } else { @@ -50,7 +53,7 @@ static ColorRgb getRgbFromTemperature(int temperature) // blue if (temperature >= 66) { - blue = 255; + blue = UINT8_MAX; } else if (temperature <= 19) { @@ -63,9 +66,9 @@ static ColorRgb getRgbFromTemperature(int temperature) } return { - static_cast(qBound(0, red, 255)), - static_cast(qBound(0, green, 255)), - static_cast(qBound(0, blue, 255)), + static_cast(qBound(0, red, UINT8_MAX)), + static_cast(qBound(0, green, UINT8_MAX)), + static_cast(qBound(0, blue, UINT8_MAX)), }; } diff --git a/include/utils/RgbChannelAdjustment.h b/include/utils/RgbChannelAdjustment.h index 3ccc2d351..7b40bf01a 100644 --- a/include/utils/RgbChannelAdjustment.h +++ b/include/utils/RgbChannelAdjustment.h @@ -1,23 +1,27 @@ #pragma once -// STL includes #include + #include #include +#include /// Correction for a single color byte value /// All configuration values are unsigned int and assume the color value to be between 0 and 255 class RgbChannelAdjustment { public: + /// Default constructor - RgbChannelAdjustment(QString channelName=""); + explicit RgbChannelAdjustment(const QString& channelName=""); + + explicit RgbChannelAdjustment(const ColorRgb& adjust, const QString& channelName=""); /// Constructor /// @param adjustR /// @param adjustG /// @param adjustB - RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName=""); + explicit RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, const QString& channelName=""); /// /// Transform the given array value @@ -40,6 +44,7 @@ class RgbChannelAdjustment /// @param adjustB /// void setAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB); + void setAdjustment(const ColorRgb& adjust); /// @return The current adjustR value uint8_t getAdjustmentR() const; @@ -51,24 +56,28 @@ class RgbChannelAdjustment uint8_t getAdjustmentB() const; private: - /// color channels - enum ColorChannel { RED=0, GREEN=1, BLUE=2 }; + + struct ColorMapping { + uint8_t red[256]; + uint8_t green[256]; + uint8_t blue[256]; + }; /// reset init of color mapping void resetInitialized(); - /// The adjustment of RGB channel - uint8_t _adjust[3]; - - /// The mapping from input color to output color - uint8_t _mapping[3][256]; - /// Name of this channel, usefull for debug messages QString _channelName; /// Logger instance Logger * _log; + /// The adjustment of RGB channel + ColorRgb _adjust; + + /// The mapping from input color to output color + ColorMapping _mapping; + /// bitfield to determine white value is alreade initialized bool _initialized[256]; diff --git a/include/utils/global_defines.h b/include/utils/global_defines.h index e948fb975..08c4a79a5 100644 --- a/include/utils/global_defines.h +++ b/include/utils/global_defines.h @@ -3,4 +3,6 @@ #define QSTRING_CSTR(str) str.toUtf8().constData() typedef QList< int > QIntList; +constexpr uint32_t UINT8_MAX_SQUARED = static_cast(std::numeric_limits::max()) * static_cast(std::numeric_limits::max()); + diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index a19ff768c..0ce59f458 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -5,6 +5,7 @@ #include #include #include +#include #include // fg effect @@ -77,7 +78,7 @@ namespace hyperion { const double gammaR = colorConfig["gammaRed"].toDouble(1.0); const double gammaG = colorConfig["gammaGreen"].toDouble(1.0); const double gammaB = colorConfig["gammaBlue"].toDouble(1.0); - const int temperature = colorConfig["temperature"].toInt(6600); + const int temperature = colorConfig["temperature"].toInt(ColorTemperature::DEFAULT); return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast(brightness), static_cast(brightnessComp), temperature); } @@ -90,13 +91,13 @@ namespace hyperion { return OkhsvTransform(saturationGain, brightnessGain); } - static RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB) + static RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, const ColorRgb& color) { const QJsonArray& channelConfig = colorConfig[channelName].toArray(); return RgbChannelAdjustment( - static_cast(channelConfig[0].toInt(defaultR)), - static_cast(channelConfig[1].toInt(defaultG)), - static_cast(channelConfig[2].toInt(defaultB)), + static_cast(channelConfig[0].toInt(color.red)), + static_cast(channelConfig[1].toInt(color.green)), + static_cast(channelConfig[2].toInt(color.blue)), channelName ); } @@ -107,14 +108,14 @@ namespace hyperion { ColorAdjustment * adjustment = new ColorAdjustment(); adjustment->_id = id; - adjustment->_rgbBlackAdjustment = createRgbChannelAdjustment(adjustmentConfig, "black" , 0, 0, 0); - adjustment->_rgbWhiteAdjustment = createRgbChannelAdjustment(adjustmentConfig, "white" , 255,255,255); - adjustment->_rgbRedAdjustment = createRgbChannelAdjustment(adjustmentConfig, "red" , 255, 0, 0); - adjustment->_rgbGreenAdjustment = createRgbChannelAdjustment(adjustmentConfig, "green" , 0,255, 0); - adjustment->_rgbBlueAdjustment = createRgbChannelAdjustment(adjustmentConfig, "blue" , 0, 0,255); - adjustment->_rgbCyanAdjustment = createRgbChannelAdjustment(adjustmentConfig, "cyan" , 0,255,255); - adjustment->_rgbMagentaAdjustment = createRgbChannelAdjustment(adjustmentConfig, "magenta", 255, 0,255); - adjustment->_rgbYellowAdjustment = createRgbChannelAdjustment(adjustmentConfig, "yellow" , 255,255, 0); + adjustment->_rgbBlackAdjustment = createRgbChannelAdjustment(adjustmentConfig, "black" , ColorRgb::BLACK); + adjustment->_rgbWhiteAdjustment = createRgbChannelAdjustment(adjustmentConfig, "white" , ColorRgb::WHITE); + adjustment->_rgbRedAdjustment = createRgbChannelAdjustment(adjustmentConfig, "red" , ColorRgb::RED); + adjustment->_rgbGreenAdjustment = createRgbChannelAdjustment(adjustmentConfig, "green" , ColorRgb::GREEN); + adjustment->_rgbBlueAdjustment = createRgbChannelAdjustment(adjustmentConfig, "blue" , ColorRgb::BLUE); + adjustment->_rgbCyanAdjustment = createRgbChannelAdjustment(adjustmentConfig, "cyan" , ColorRgb::CYAN); + adjustment->_rgbMagentaAdjustment = createRgbChannelAdjustment(adjustmentConfig, "magenta", ColorRgb::MAGENTA); + adjustment->_rgbYellowAdjustment = createRgbChannelAdjustment(adjustmentConfig, "yellow" , ColorRgb::YELLOW); adjustment->_rgbTransform = createRgbTransform(adjustmentConfig); adjustment->_okhsvTransform = createOkhsvTransform(adjustmentConfig); @@ -150,27 +151,27 @@ namespace hyperion { continue; } - std::stringstream ss; + std::stringstream sStream; const QStringList ledIndexList = ledIndicesStr.split(","); - for (int i=0; i 0) + for (int j=0; j 0) { - ss << ", "; + sStream << ", "; } - if (ledIndexList[i].contains("-")) + if (ledIndexList[j].contains("-")) { - QStringList ledIndices = ledIndexList[i].split("-"); + QStringList ledIndices = ledIndexList[j].split("-"); int startInd = ledIndices[0].toInt(); int endInd = ledIndices[1].toInt(); adjustment->setAdjustmentForLed(colorAdjustment->_id, startInd, endInd); - ss << startInd << "-" << endInd; + sStream << startInd << "-" << endInd; } else { int index = ledIndexList[i].toInt(); adjustment->setAdjustmentForLed(colorAdjustment->_id, index, index); - ss << index; + sStream << index; } } } @@ -178,44 +179,6 @@ namespace hyperion { return adjustment; } - /** - * Construct the 'led-string' with the integration area definition per led and the color - * ordering of the RGB channels - * @param ledsConfig The configuration of the led areas - * @param deviceOrder The default RGB channel ordering - * @return The constructed ledstring - */ - static LedString createLedString(const QJsonArray& ledConfigArray, const ColorOrder deviceOrder) - { - LedString ledString; - const QString deviceOrderStr = colorOrderToString(deviceOrder); - - for (signed i = 0; i < ledConfigArray.size(); ++i) - { - const QJsonObject& ledConfig = ledConfigArray[i].toObject(); - Led led; - - led.minX_frac = qMax(0.0, qMin(1.0, ledConfig["hmin"].toDouble())); - led.maxX_frac = qMax(0.0, qMin(1.0, ledConfig["hmax"].toDouble())); - led.minY_frac = qMax(0.0, qMin(1.0, ledConfig["vmin"].toDouble())); - led.maxY_frac = qMax(0.0, qMin(1.0, ledConfig["vmax"].toDouble())); - // Fix if the user swapped min and max - if (led.minX_frac > led.maxX_frac) - { - std::swap(led.minX_frac, led.maxX_frac); - } - if (led.minY_frac > led.maxY_frac) - { - std::swap(led.minY_frac, led.maxY_frac); - } - - // Get the order of the rgb channels for this led (default is device order) - led.colorOrder = stringToColorOrder(ledConfig["colorOrder"].toString(deviceOrderStr)); - ledString.leds().push_back(led); - } - return ledString; - } - static QSize getLedLayoutGridSize(const QJsonArray& ledConfigArray) { std::vector midPointsX; diff --git a/libsrc/hyperion/MultiColorAdjustment.cpp b/libsrc/hyperion/MultiColorAdjustment.cpp index 9d1a541ed..3f2d34124 100644 --- a/libsrc/hyperion/MultiColorAdjustment.cpp +++ b/libsrc/hyperion/MultiColorAdjustment.cpp @@ -1,13 +1,10 @@ #include -#include // Hyperion includes #include #include -constexpr uint32_t UINT8_MAX_SQUARED = static_cast(std::numeric_limits::max()) * static_cast(std::numeric_limits::max()); - MultiColorAdjustment::MultiColorAdjustment(int ledCnt) : _ledAdjustments(static_cast(ledCnt), nullptr) , _log(Logger::getInstance("ADJUSTMENT")) diff --git a/libsrc/utils/ColorRgb.cpp b/libsrc/utils/ColorRgb.cpp index 157fcf29d..9ff592728 100644 --- a/libsrc/utils/ColorRgb.cpp +++ b/libsrc/utils/ColorRgb.cpp @@ -7,3 +7,5 @@ const ColorRgb ColorRgb::GREEN = { 0, 255, 0 }; const ColorRgb ColorRgb::BLUE = { 0, 0, 255 }; const ColorRgb ColorRgb::YELLOW = { 255, 255, 0 }; const ColorRgb ColorRgb::WHITE = { 255, 255, 255 }; +const ColorRgb ColorRgb::CYAN = { 0, 255, 255 }; +const ColorRgb ColorRgb::MAGENTA= { 255, 0, 255 }; diff --git a/libsrc/utils/RgbChannelAdjustment.cpp b/libsrc/utils/RgbChannelAdjustment.cpp index 2079c7aaa..fa899f727 100644 --- a/libsrc/utils/RgbChannelAdjustment.cpp +++ b/libsrc/utils/RgbChannelAdjustment.cpp @@ -1,44 +1,54 @@ #include -RgbChannelAdjustment::RgbChannelAdjustment(QString channelName) + +RgbChannelAdjustment::RgbChannelAdjustment(const QString& channelName) : RgbChannelAdjustment(0, 0, 0, channelName) { } -RgbChannelAdjustment::RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, QString channelName ) +RgbChannelAdjustment::RgbChannelAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB, const QString& channelName ) + : RgbChannelAdjustment({adjustR, adjustG, adjustB}, channelName) +{ +} + +RgbChannelAdjustment::RgbChannelAdjustment(const ColorRgb& adjust, const QString& channelName ) : _channelName(channelName) , _log(Logger::getInstance("CHANNEL_" + channelName.toUpper())) + , _mapping{ {0}, {0}, {0} } , _brightness(0) { - setAdjustment(adjustR, adjustG, adjustB); + setAdjustment(adjust); } void RgbChannelAdjustment::resetInitialized() { - memset(_initialized, false, sizeof(_initialized)); + memset(_initialized, 0, sizeof(_initialized)); } void RgbChannelAdjustment::setAdjustment(uint8_t adjustR, uint8_t adjustG, uint8_t adjustB) { - _adjust[RED] = adjustR; - _adjust[GREEN] = adjustG; - _adjust[BLUE] = adjustB; + setAdjustment( {adjustR, adjustG, adjustB} ); +} + +void RgbChannelAdjustment::setAdjustment(const ColorRgb& adjust) +{ + _adjust = adjust; resetInitialized(); } uint8_t RgbChannelAdjustment::getAdjustmentR() const { - return _adjust[RED]; + return _adjust.red; } uint8_t RgbChannelAdjustment::getAdjustmentG() const { - return _adjust[GREEN]; + return _adjust.green; } uint8_t RgbChannelAdjustment::getAdjustmentB() const { - return _adjust[BLUE]; + return _adjust.blue; } void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & red, uint8_t & green, uint8_t & blue) @@ -51,12 +61,13 @@ void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & re if (!_initialized[input]) { - _mapping[RED ][input] = qMin( ((_brightness * input * _adjust[RED ]) / 65025), (int)UINT8_MAX); - _mapping[GREEN][input] = qMin( ((_brightness * input * _adjust[GREEN]) / 65025), (int)UINT8_MAX); - _mapping[BLUE ][input] = qMin( ((_brightness * input * _adjust[BLUE ]) / 65025), (int)UINT8_MAX); + const int adjustedInput = static_cast(_brightness * input / UINT8_MAX_SQUARED); + _mapping.red[input] = static_cast(qBound(0, _adjust.red * adjustedInput, UINT8_MAX)); + _mapping.green[input] = static_cast(qBound(0 ,_adjust.green * adjustedInput, UINT8_MAX)); + _mapping.blue[input] = static_cast(qBound(0, _adjust.blue * adjustedInput, UINT8_MAX)); _initialized[input] = true; } - red = _mapping[RED ][input]; - green = _mapping[GREEN][input]; - blue = _mapping[BLUE ][input]; + red = _mapping.red[input]; + green = _mapping.green[input]; + blue = _mapping.blue[input]; } diff --git a/libsrc/utils/RgbTransform.cpp b/libsrc/utils/RgbTransform.cpp index 97a72c348..086e2d82f 100644 --- a/libsrc/utils/RgbTransform.cpp +++ b/libsrc/utils/RgbTransform.cpp @@ -2,10 +2,8 @@ #include #include -#include - RgbTransform::RgbTransform() - : RgbTransform::RgbTransform(1.0, 1.0, 1.0, 0.0, false, 100, 100, 6600) + : RgbTransform::RgbTransform(1.0, 1.0, 1.0, 0.0, false, 100, 100, ColorTemperature::DEFAULT) { } @@ -66,9 +64,9 @@ void RgbTransform::initializeMapping() double gammaCorrectedValueB = qPow(normalizedValueB, _gammaB) * UINT8_MAX; // Clamp values to valid range [0, UINT8_MAX] - quint8 clampedValueR = static_cast(qMin(qMax(gammaCorrectedValueR, 0.0), static_cast(UINT8_MAX))); - quint8 clampedValueG = static_cast(qMin(qMax(gammaCorrectedValueG, 0.0), static_cast(UINT8_MAX))); - quint8 clampedValueB = static_cast(qMin(qMax(gammaCorrectedValueB, 0.0), static_cast(UINT8_MAX))); + quint8 clampedValueR = static_cast(qBound(0.0, gammaCorrectedValueR, static_cast(UINT8_MAX))); + quint8 clampedValueG = static_cast(qBound(0.0, gammaCorrectedValueG, static_cast(UINT8_MAX))); + quint8 clampedValueB = static_cast(qBound(0.0, gammaCorrectedValueB, static_cast(UINT8_MAX))); // Assign clamped values to _mapping arrays _mappingR[i] = clampedValueR; From 77c9cf03023c9e8a47028506ed4037f90944cb1a Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Fri, 31 May 2024 17:55:40 +0200 Subject: [PATCH 09/11] Windows Fix --- include/utils/KelvinToRgb.h | 6 +++--- include/utils/global_defines.h | 23 +++++++++++++++++++++++ libsrc/utils/RgbChannelAdjustment.cpp | 6 +++--- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/include/utils/KelvinToRgb.h b/include/utils/KelvinToRgb.h index 7bd4d162d..1f05d4053 100644 --- a/include/utils/KelvinToRgb.h +++ b/include/utils/KelvinToRgb.h @@ -66,9 +66,9 @@ static ColorRgb getRgbFromTemperature(int temperature) } return { - static_cast(qBound(0, red, UINT8_MAX)), - static_cast(qBound(0, green, UINT8_MAX)), - static_cast(qBound(0, blue, UINT8_MAX)), + static_cast(qBound(0, red, static_cast(UINT8_MAX))), + static_cast(qBound(0, green, static_cast(UINT8_MAX))), + static_cast(qBound(0, blue, static_cast(UINT8_MAX))), }; } diff --git a/include/utils/global_defines.h b/include/utils/global_defines.h index 08c4a79a5..a79e7ea05 100644 --- a/include/utils/global_defines.h +++ b/include/utils/global_defines.h @@ -1,8 +1,31 @@ #pragma once +#include +#include + +#include + #define QSTRING_CSTR(str) str.toUtf8().constData() typedef QList< int > QIntList; +// Undefine the max macro if it's defined (Windows-specific) +#ifdef max +#undef max +#endif + +// Define your constexpr variable constexpr uint32_t UINT8_MAX_SQUARED = static_cast(std::numeric_limits::max()) * static_cast(std::numeric_limits::max()); +// Restore the max macro only if it was previously defined (Windows-specific) +#ifdef _MSC_VER +#define NOMINMAX // Prevent Windows.h from defining min and max macros +#endif + +// Restore the max macro if needed (Windows-specific) +#ifdef _MSC_VER +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif +#endif + diff --git a/libsrc/utils/RgbChannelAdjustment.cpp b/libsrc/utils/RgbChannelAdjustment.cpp index fa899f727..8b2228327 100644 --- a/libsrc/utils/RgbChannelAdjustment.cpp +++ b/libsrc/utils/RgbChannelAdjustment.cpp @@ -62,9 +62,9 @@ void RgbChannelAdjustment::apply(uint8_t input, uint8_t brightness, uint8_t & re if (!_initialized[input]) { const int adjustedInput = static_cast(_brightness * input / UINT8_MAX_SQUARED); - _mapping.red[input] = static_cast(qBound(0, _adjust.red * adjustedInput, UINT8_MAX)); - _mapping.green[input] = static_cast(qBound(0 ,_adjust.green * adjustedInput, UINT8_MAX)); - _mapping.blue[input] = static_cast(qBound(0, _adjust.blue * adjustedInput, UINT8_MAX)); + _mapping.red[input] = static_cast(qBound(0, _adjust.red * adjustedInput, static_cast(UINT8_MAX))); + _mapping.green[input] = static_cast(qBound(0 ,_adjust.green * adjustedInput, static_cast(UINT8_MAX))); + _mapping.blue[input] = static_cast(qBound(0, _adjust.blue * adjustedInput, static_cast(UINT8_MAX))); _initialized[input] = true; } red = _mapping.red[input]; From c0abad581a39af846f3a56137ba8d3ae8893ba8a Mon Sep 17 00:00:00 2001 From: LordGrey <48840279+Lord-Grey@users.noreply.github.com> Date: Fri, 31 May 2024 19:59:35 +0200 Subject: [PATCH 10/11] Fix inner loop --- include/utils/hyperion.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index 0ce59f458..cdb0fd2f3 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -153,7 +153,7 @@ namespace hyperion { std::stringstream sStream; const QStringList ledIndexList = ledIndicesStr.split(","); - for (int j=0; j 0) { sStream << ", "; From 1b875f3f7ec615d97e06eaa8b46f24ae996ce7d6 Mon Sep 17 00:00:00 2001 From: Lord-Grey Date: Sat, 1 Jun 2024 07:48:47 +0200 Subject: [PATCH 11/11] Simplify --- include/utils/global_defines.h | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/include/utils/global_defines.h b/include/utils/global_defines.h index a79e7ea05..e250f4565 100644 --- a/include/utils/global_defines.h +++ b/include/utils/global_defines.h @@ -8,24 +8,4 @@ #define QSTRING_CSTR(str) str.toUtf8().constData() typedef QList< int > QIntList; -// Undefine the max macro if it's defined (Windows-specific) -#ifdef max -#undef max -#endif - -// Define your constexpr variable -constexpr uint32_t UINT8_MAX_SQUARED = static_cast(std::numeric_limits::max()) * static_cast(std::numeric_limits::max()); - -// Restore the max macro only if it was previously defined (Windows-specific) -#ifdef _MSC_VER -#define NOMINMAX // Prevent Windows.h from defining min and max macros -#endif - -// Restore the max macro if needed (Windows-specific) -#ifdef _MSC_VER -#ifndef max -#define max(a,b) (((a) > (b)) ? (a) : (b)) -#endif -#endif - - +constexpr uint32_t UINT8_MAX_SQUARED = static_cast(UINT8_MAX) * UINT8_MAX;