diff --git a/CMakeLists.txt b/CMakeLists.txt index f2ca768e5..50e5faa8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -263,12 +263,12 @@ if(HYPERION_LIGHT) # Disable Services SET ( DEFAULT_EFFECTENGINE OFF ) - #SET ( DEFAULT_EXPERIMENTAL OFF ) - #SET ( DEFAULT_MDNS OFF ) - #SET ( DEFAULT_REMOTE_CTL OFF ) - - #SET ( ENABLE_JSONCHECKS OFF ) - #SET ( ENABLE_DEPLOY_DEPENDENCIES OFF ) + SET ( DEFAULT_EXPERIMENTAL OFF ) + #SET ( DEFAULT_MDNS OFF ) + SET ( DEFAULT_REMOTE_CTL OFF ) + + SET ( ENABLE_JSONCHECKS ON ) + SET ( ENABLE_DEPLOY_DEPENDENCIES ON ) endif() message(STATUS "Grabber options:") diff --git a/assets/webconfig/i18n/en.json b/assets/webconfig/i18n/en.json index 18543c884..14fae3e6c 100644 --- a/assets/webconfig/i18n/en.json +++ b/assets/webconfig/i18n/en.json @@ -248,6 +248,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", @@ -319,6 +320,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.", @@ -345,10 +348,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_reducedPixelSetFactorFactor_expl": "Evaluate only a set of pixels per LED area defined, Low ~25%, Medium ~10%, High ~6%", "edt_conf_color_reducedPixelSetFactorFactor_title": "Reduced pixel processing", "edt_conf_color_white_expl": "The calibrated white value.", @@ -535,6 +538,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 09fc475cf..45d7912a2 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/include/api/JsonAPI.h b/include/api/JsonAPI.h index 3ac43269f..a5a540659 100644 --- a/include/api/JsonAPI.h +++ b/include/api/JsonAPI.h @@ -285,7 +285,6 @@ 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); @@ -296,6 +295,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/ColorAdjustment.h b/include/hyperion/ColorAdjustment.h index 2d846fd75..1884517da 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/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/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 new file mode 100644 index 000000000..1f05d4053 --- /dev/null +++ b/include/utils/KelvinToRgb.h @@ -0,0 +1,75 @@ +#ifndef KELVINTORGB_H +#define KELVINTORGB_H + +#include + +#include + +// 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(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; + int green; + int blue; + + // red + if (temperature <= 66) + { + red = UINT8_MAX; + } + 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 = UINT8_MAX; + } + 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, static_cast(UINT8_MAX))), + static_cast(qBound(0, green, static_cast(UINT8_MAX))), + static_cast(qBound(0, blue, static_cast(UINT8_MAX))), + }; +} + +#endif // KELVINTORGB_H 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/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/global_defines.h b/include/utils/global_defines.h index e948fb975..b3cbae41a 100644 --- a/include/utils/global_defines.h +++ b/include/utils/global_defines.h @@ -1,6 +1,10 @@ #pragma once +#include + +#include + #define QSTRING_CSTR(str) str.toUtf8().constData() typedef QList< int > QIntList; - +constexpr double DOUBLE_UINT8_MAX_SQUARED = static_cast(UINT8_MAX) * UINT8_MAX; diff --git a/include/utils/hyperion.h b/include/utils/hyperion.h index eeb5be5fb..cdb0fd2f3 100644 --- a/include/utils/hyperion.h +++ b/include/utils/hyperion.h @@ -5,6 +5,7 @@ #include #include #include +#include #include // fg effect @@ -77,8 +78,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(ColorTemperature::DEFAULT); - 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) @@ -89,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 ); } @@ -106,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); @@ -149,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; } } } diff --git a/libsrc/api/JSONRPC_schema/schema-adjustment.json b/libsrc/api/JSONRPC_schema/schema-adjustment.json index 5efed868a..3afe5bcd4 100644 --- a/libsrc/api/JSONRPC_schema/schema-adjustment.json +++ b/libsrc/api/JSONRPC_schema/schema-adjustment.json @@ -152,6 +152,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 ac5fcdc1e..ebb399655 100644 --- a/libsrc/api/JsonAPI.cpp +++ b/libsrc/api/JsonAPI.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -640,6 +641,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); } @@ -669,6 +671,14 @@ void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &ad } } +template +void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(int)) +{ + if (adjustment.contains(transformName)) { + (transform.*setFunction)(adjustment[transformName].toInt()); + } +} + template void JsonAPI::applyTransform(const QString &transformName, const QJsonObject &adjustment, T &transform, void (T::*setFunction)(uint8_t)) { diff --git a/libsrc/api/JsonInfo.cpp b/libsrc/api/JsonInfo.cpp index ab0a2dc3d..baab3862e 100644 --- a/libsrc/api/JsonInfo.cpp +++ b/libsrc/api/JsonInfo.cpp @@ -84,6 +84,8 @@ QJsonArray JsonInfo::getAdjustmentInfo(const Hyperion* hyperion, Logger* log) adjustment["saturationGain"] = colorAdjustment->_okhsvTransform.getSaturationGain(); adjustment["brightnessGain"] = colorAdjustment->_okhsvTransform.getBrightnessGain(); + adjustment["temperature"] = colorAdjustment->_rgbTransform.getTemperature(); + adjustmentArray.append(adjustment); } return adjustmentArray; diff --git a/libsrc/hyperion/MultiColorAdjustment.cpp b/libsrc/hyperion/MultiColorAdjustment.cpp index 4c761d6a8..31b261f84 100644 --- a/libsrc/hyperion/MultiColorAdjustment.cpp +++ b/libsrc/hyperion/MultiColorAdjustment.cpp @@ -1,22 +1,23 @@ +#include + // Hyperion includes + #include #include 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 +26,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 +42,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 +51,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 +70,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 +100,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 +116,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) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t red = static_cast(r_ng * (UINT8_MAX - oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t green = static_cast(nr_g * (UINT8_MAX - oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t blue = static_cast(nr_ng * (oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t cyan = static_cast(nr_g * (oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t magenta = static_cast(r_ng * (oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t yellow = static_cast(r_g * (UINT8_MAX - oblue) / DOUBLE_UINT8_MAX_SQUARED); + uint8_t white = static_cast(r_g * (oblue) / DOUBLE_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 +155,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/schema/schema-color.json b/libsrc/hyperion/schema/schema-color.json index 8068036b7..43ff8eb7c 100644 --- a/libsrc/hyperion/schema/schema-color.json +++ b/libsrc/hyperion/schema/schema-color.json @@ -244,6 +244,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", @@ -253,7 +265,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 17 + "propertyOrder" : 18 }, "gammaGreen" : { @@ -264,7 +276,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 18 + "propertyOrder" : 19 }, "gammaBlue" : { @@ -275,7 +287,7 @@ "maximum": 100.0, "default" : 2.2, "step" : 0.1, - "propertyOrder" : 19 + "propertyOrder" : 20 } }, "additionalProperties" : false diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index b7d28eebb..83a177f1b 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -62,6 +62,7 @@ add_library(hyperion-utils ${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 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..1e5723f05 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 double adjustedInput = _brightness * input / DOUBLE_UINT8_MAX_SQUARED; + _mapping.red[input] = static_cast(qBound(0, static_cast(_adjust.red * adjustedInput), static_cast(UINT8_MAX))); + _mapping.green[input] = static_cast(qBound(0 ,static_cast(_adjust.green * adjustedInput), static_cast(UINT8_MAX))); + _mapping.blue[input] = static_cast(qBound(0, static_cast(_adjust.blue * adjustedInput), static_cast(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 9a988ed5e..086e2d82f 100644 --- a/libsrc/utils/RgbTransform.cpp +++ b/libsrc/utils/RgbTransform.cpp @@ -1,19 +1,20 @@ #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, ColorTemperature::DEFAULT) { } -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 +22,7 @@ void RgbTransform::init(double gammaR, double gammaG, double gammaB, double back setBacklightColored(backlightColored); setBrightness(brightness); setBrightnessCompensation(brightnessCompensation); + setTemperature(temperature); initializeMapping(); } @@ -49,18 +51,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(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; + _mappingG[i] = clampedValueG; + _mappingB[i] = clampedValueB; } } int RgbTransform::getBacklightThreshold() const { - return _backlightThreshold; + return static_cast(_backlightThreshold); } void RgbTransform::setBacklightThreshold(double backlightThreshold) @@ -116,60 +134,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), static_cast(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), static_cast(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; +} diff --git a/settings/hyperion.settings.json.default b/settings/hyperion.settings.json.default index 0f79800d7..6e6293914 100644 --- a/settings/hyperion.settings.json.default +++ b/settings/hyperion.settings.json.default @@ -211,7 +211,8 @@ "brightness":100, "brightnessCompensation":100, "saturationGain":1.0, - "brightnessGain":1.0 + "brightnessGain":1.0, + "temperature" : 6600 } ] },