From b37cbd26d515dfcecbb47cc62b1dc68c0df20c8d Mon Sep 17 00:00:00 2001 From: AEtHeLsYn Date: Sat, 2 Apr 2016 00:04:11 +0200 Subject: [PATCH] Add color adjustment to all RBG channels * Channel adjustment config * Create RgbChannelAdjustment.h * Delete RgbChannelAdjustment.h * Create RgbChannelAdjustment.cpp * Create RgbChannelAdjustment.h * Delete RgbChannelAdjustment.cpp * Create ColorAdjustment.cpp * Delete RgbChannelAdjustment.h * Create ColorAdjustment.h * Update ColorAdjustment.h * Update ColorAdjustment.h * Update ColorAdjustment.h * Update ColorAdjustment.cpp * Update Hyperion.cpp * Update Hyperion.cpp * Update Hyperion.cpp * Update Hyperion.h * Create RgbChannelAdjustment.cpp * Create RgbChannelAdjustment.h * Create ColorAdjustment.h * Create MultiColorAdjustment.h * Update MultiColorAdjustment.h * Create MultiColorAdjustment.cpp * Delete ColorAdjustment.cpp * Delete ColorAdjustment.h * Update RgbChannelAdjustment.cpp * Update Hyperion.cpp * Update Hyperion.h * Update Hyperion.cpp * Bug fixes * Update hyperion.config.json * Add color adjustment to json server and client and adapt hyperion-remote * Change the color modification order * Minor bug fix * Create calibration Images folder * Create calibration Gamma folder * Create calibration RGB folder * Added files via upload * Delete .gitkeep * Delete .gitkeep * Added files via upload * Delete .gitkeep * Update color effect order and don't correct twice * Uploaded gradient images Former-commit-id: 8ab465e59834f12a21709a6f4546bd6808a2a495 --- config/hyperion.config.json | 25 +++ doc/calibration/Gamma/000000.png | Bin 0 -> 6159 bytes doc/calibration/Gamma/3F3F3F.png | Bin 0 -> 10670 bytes doc/calibration/Gamma/7F7F7F.png | Bin 0 -> 10669 bytes doc/calibration/Gamma/BFBFBF.png | Bin 0 -> 10670 bytes doc/calibration/Gamma/FFFFFF.png | Bin 0 -> 8642 bytes doc/calibration/Gamma/HGradient_1.png | Bin 0 -> 10866 bytes doc/calibration/Gamma/HGradient_2.png | Bin 0 -> 10862 bytes doc/calibration/Gamma/VGradient_1.png | Bin 0 -> 12174 bytes doc/calibration/Gamma/VGradient_2.png | Bin 0 -> 12032 bytes doc/calibration/RGB/blue_00007F.png | Bin 0 -> 10668 bytes doc/calibration/RGB/blue_0000FF.png | Bin 0 -> 8642 bytes doc/calibration/RGB/cyan_007F7F.png | Bin 0 -> 10668 bytes doc/calibration/RGB/cyan_00FFFF.png | Bin 0 -> 8642 bytes doc/calibration/RGB/green_007F00.png | Bin 0 -> 10668 bytes doc/calibration/RGB/green_00FF00.png | Bin 0 -> 8641 bytes doc/calibration/RGB/magenta_7F007F.png | Bin 0 -> 10668 bytes doc/calibration/RGB/magenta_FF00FF.png | Bin 0 -> 8642 bytes doc/calibration/RGB/red_7F0000.png | Bin 0 -> 10668 bytes doc/calibration/RGB/red_FF0000.png | Bin 0 -> 8641 bytes doc/calibration/RGB/yellow_7F7F00.png | Bin 0 -> 10668 bytes doc/calibration/RGB/yellow_FFFF00.png | Bin 0 -> 7964 bytes include/hyperion/ColorAdjustment.h | 22 +++ include/hyperion/Hyperion.h | 31 +++- include/utils/RgbChannelAdjustment.h | 66 +++++++ libsrc/hyperion/CMakeLists.txt | 2 + libsrc/hyperion/Hyperion.cpp | 162 +++++++++++++++++- libsrc/hyperion/MultiColorAdjustment.cpp | 124 ++++++++++++++ libsrc/hyperion/MultiColorAdjustment.h | 66 +++++++ libsrc/jsonserver/JsonClientConnection.cpp | 73 +++++++- libsrc/jsonserver/JsonClientConnection.h | 7 + libsrc/jsonserver/JsonSchemas.qrc | 1 + .../jsonserver/schema/schema-adjustment.json | 56 ++++++ libsrc/jsonserver/schema/schema.json | 2 +- libsrc/utils/CMakeLists.txt | 2 + libsrc/utils/RgbChannelAdjustment.cpp | 107 ++++++++++++ src/hyperion-remote/ColorAdjustmentValues.h | 12 ++ src/hyperion-remote/CustomParameter.h | 33 ++++ src/hyperion-remote/JsonConnection.cpp | 45 +++++ src/hyperion-remote/JsonConnection.h | 16 ++ src/hyperion-remote/hyperion-remote.cpp | 31 +++- 41 files changed, 870 insertions(+), 13 deletions(-) create mode 100644 doc/calibration/Gamma/000000.png create mode 100644 doc/calibration/Gamma/3F3F3F.png create mode 100644 doc/calibration/Gamma/7F7F7F.png create mode 100644 doc/calibration/Gamma/BFBFBF.png create mode 100644 doc/calibration/Gamma/FFFFFF.png create mode 100644 doc/calibration/Gamma/HGradient_1.png create mode 100644 doc/calibration/Gamma/HGradient_2.png create mode 100644 doc/calibration/Gamma/VGradient_1.png create mode 100644 doc/calibration/Gamma/VGradient_2.png create mode 100644 doc/calibration/RGB/blue_00007F.png create mode 100644 doc/calibration/RGB/blue_0000FF.png create mode 100644 doc/calibration/RGB/cyan_007F7F.png create mode 100644 doc/calibration/RGB/cyan_00FFFF.png create mode 100644 doc/calibration/RGB/green_007F00.png create mode 100644 doc/calibration/RGB/green_00FF00.png create mode 100644 doc/calibration/RGB/magenta_7F007F.png create mode 100644 doc/calibration/RGB/magenta_FF00FF.png create mode 100644 doc/calibration/RGB/red_7F0000.png create mode 100644 doc/calibration/RGB/red_FF0000.png create mode 100644 doc/calibration/RGB/yellow_7F7F00.png create mode 100644 doc/calibration/RGB/yellow_FFFF00.png create mode 100644 include/hyperion/ColorAdjustment.h create mode 100644 include/utils/RgbChannelAdjustment.h create mode 100644 libsrc/hyperion/MultiColorAdjustment.cpp create mode 100644 libsrc/hyperion/MultiColorAdjustment.h create mode 100644 libsrc/jsonserver/schema/schema-adjustment.json create mode 100644 libsrc/utils/RgbChannelAdjustment.cpp create mode 100644 src/hyperion-remote/ColorAdjustmentValues.h diff --git a/config/hyperion.config.json b/config/hyperion.config.json index 748781fd..62c7d70e 100644 --- a/config/hyperion.config.json +++ b/config/hyperion.config.json @@ -68,6 +68,31 @@ } } ], + "channelAdjustment" : + [ + { + "id" : "default", + "leds" : "*", + "pureRed" : + { + "redChannel" : 255, + "greenChannel" : 0, + "blueChannel" : 0 + }, + "pureGreen" : + { + "redChannel" : 0, + "greenChannel" : 255, + "blueChannel" : 0 + }, + "pureBlue" : + { + "redChannel" : 0, + "greenChannel" : 0, + "blueChannel" : 255 + } + } + ], "transform" : [ { diff --git a/doc/calibration/Gamma/000000.png b/doc/calibration/Gamma/000000.png new file mode 100644 index 0000000000000000000000000000000000000000..f4c092619af0630387ac55a95f30ad3fbef7fe59 GIT binary patch literal 6159 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}0*a(>3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-4B|^XT^vIy;@%!)VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRH*=T@_ zrVwyu7|jddU>GeNz`-zDT7rXNwE6%C1H)+HFj_c_=7rI`z%W`bjMfXI9VkdaFq#)e z^TKFe7|ja|qs?PTA{gyEgTrC8UKp(xM(c&qdSSF)7@croU>F@Xfs_QJLx|vT7;Phg zgJHCd1P+GL!eO*<7#&lEq=C`AFq#)e^TKFe7+s(>x?&BO3r713;G%#k{e{G5%pXL! U^cOEzJ_s_@)78&qol`;+0GFSwH~;_u literal 0 HcmV?d00001 diff --git a/doc/calibration/Gamma/7F7F7F.png b/doc/calibration/Gamma/7F7F7F.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf7a3f6b28f027378dddd766bf800223e55e43f GIT binary patch literal 10669 zcmeI0F-yZh7>2*lT5W8L9Rw8xN8K_ynt0Miut;%n5sQP1gV@DIDB>ar`b&cT03nLt zAUG%pZjK7o#lgWM-hKBA+@CtxO}u`v`SB9h z^Qe+v?A{ixeooEdt?Xm>wYQn)#7nb@zq#I3cfNExi6&7XHE$O z(SD#qR0fby888Pg1LlA^zyd4?>jLY7ut(A+fCX591>Xa(01L1H3*<;7jg|s3RkZ?Q z6P1DUg37=iNoBwsybPEF<^T(@K&I+@02W{Y7GOchk$e+yUhp~)Ca4aa7gPqq1eM|6 Z=5QW;1<&QMzkNSbb2FsNEt4f%M}NI-`J4a% literal 0 HcmV?d00001 diff --git a/doc/calibration/Gamma/BFBFBF.png b/doc/calibration/Gamma/BFBFBF.png new file mode 100644 index 0000000000000000000000000000000000000000..f61f729782206196a590f3b48ea45ed1c5033652 GIT binary patch literal 10670 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRRa4?LPmf&C*tv zU>I#9frDYRa2PEdM#oekX<#%jjOK;WyfB&FVdQ&MBb@0N|6ZPXGV_ literal 0 HcmV?d00001 diff --git a/doc/calibration/Gamma/FFFFFF.png b/doc/calibration/Gamma/FFFFFF.png new file mode 100644 index 0000000000000000000000000000000000000000..8e5dc2d55055cb8640b0427d7b11ab86fe3f7f6d GIT binary patch literal 8642 zcmeH~y-EW?6ot>481uIlA|i`|0Usa%3+=LDCA&qUL{V(SfUq{AkS67#Hdb2NnKFe0 z^8&hPVIyK;VWIXG=`6Q!jt^mVis3K=!@%&}JKvnIH|uuZ$pf$h-)jLA5s+Taj+vEk zxHWCU>a^-L3|{8G%_JSV4Hp<*6q5G1ndgrEoenVh$YDJl_4k3&cHp_2-QCf9#frFi(^Pd z+}oQMvu-;GI0Wwe|NneuyV;kc%X}wnx%AaifNA$F$^G|_Z_Ab6|8HKE&9h&x&()M) zTc=%Hf91{My2GpfR=>add3X8WXL`n`zK74Py>eT$czucaw|Tq2?r7nA$W;?>&-)9O2a>+Yl;TTy2mR`Y%T=41Ev=dZbE z-}h_p%M94;z;-*3FoCBSTkL(1;A_V07uUX_KP{kMP5zRH@1^4Djdt0}*>PP?}L z%A3Xi4zK!K{r>Lf-RXay=^3B;9zM7B%5Bl&^(E%t=I#Ezr|{akz0Z4X%kO^l&HOL9 z`J0ve>azT~{pok!{#k$iUD#V$d&~H(_3z;WxGd&3U%2@W>tQyS=N=%DV5BU7gmy`+ooKGZI(xk9ED@XPy1#@Bd@3{ytvu z-+JA*zwQ4k%b%_Lcy)JteH|mv%RsQhl2HP}QgC7bg&Yuc2sA)tl~@wMA`A^2qsl-b zF&ZG?^e~!2z`-z@Wx&BOS~!4%VYG071jA_IFj_c_=7rI`FxqGwZAAmSV58j%P*E`2 zMuHTGqa7%4IE=QDz`-zDIDms;v~UI#9frDYRaDW8EXyGtgIE?0n(Y!D^$UHjXGCJXs04WGY+enab l80|oT!-2>)l1GJ29rMfYY;z3x`!YcqJzf1=);T3K0RU*(asB`R literal 0 HcmV?d00001 diff --git a/doc/calibration/Gamma/VGradient_1.png b/doc/calibration/Gamma/VGradient_1.png new file mode 100644 index 0000000000000000000000000000000000000000..974b087ef7454249403e1702c24e085911a00a87 GIT binary patch literal 12174 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 X*)y(~!q+}o)ZF!KPS)ie1#kTqOf8>x literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/blue_00007F.png b/doc/calibration/RGB/blue_00007F.png new file mode 100644 index 0000000000000000000000000000000000000000..8ca29242b821769a765051bb71fcb2bd1524c72a GIT binary patch literal 10668 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRU>F@_hU5w& c2bnoLPgg&ebxsLQ0Cvpx7XSbN literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/blue_0000FF.png b/doc/calibration/RGB/blue_0000FF.png new file mode 100644 index 0000000000000000000000000000000000000000..727f8cf35baf6657a93ec2ad3364adb02e41ea8b GIT binary patch literal 8642 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}0*a(>3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-42t2NE{-7;ac^%JGBy}6967-Lf8Ob) zmbBf`j}*_Bu>o~4Fl^sj&j_L)XfaEH=!O@riIu{z%=Km_R*jlO*WvsFq&mXiwjUX7%eJCs|ip#7_B0K&6CmQ!D#bfw0Qt3 z4n~^?qs;?QIv8ypj5ZHI>0q>ZFxor-CWF!D!D#aUR2+;p4@R2@pmZ?WJQ!^rfYQNe z^I)`j089p>&4bbA0jM|_Z61s^4?yW)w0SVvJOHJG(dGfYn+Gi0_*Y%z%rD<;u^bcu Mp00i_>zopr08hi$bN~PV literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/cyan_007F7F.png b/doc/calibration/RGB/cyan_007F7F.png new file mode 100644 index 0000000000000000000000000000000000000000..334e191b3e73a336013559f51ad4b42bd5db85b5 GIT binary patch literal 10668 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRU>GeNAi*$N zIE)q!qj_O8FN}_5#80|Yl3WCu#5+oc(J5b3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-42t2NE{-7;ac^%JGBPOe9N5rUfBu6) zW8KMM{@CJkKurt`2l9W5f*Jda7BGSs9ugP8d=;JyFfGJp0;V~cr9gB;3nMRxb~x0) z2BH-b9hgD%1cOoSqd~{OFq&)_7)G-Uus9kmE=G&W(Q0C}iX3eoj5du%Ta}=4V6CgVCnZXfG0&3`TpVM%xN zb!1@J*w6hZkrl}2EbxddW?8eRU>F@_hU5w& c2bnoFVdQ&MBb@0AtPd*Z=?k literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/green_00FF00.png b/doc/calibration/RGB/green_00FF00.png new file mode 100644 index 0000000000000000000000000000000000000000..01e18f1254ff8bbdc9879e0696d210cb8018aa43 GIT binary patch literal 8641 zcmeI!u}Z^G7zN;S+geR+6hu&pLj)f{(ZR7PktTyhsuUcw7KFN0$l|1_=-{M_yQ3gf z`vM|5h>La#M~Z!whE!3@j86(wxe#r0HZ! z%;Zel_2~fBM!yW_fyRYKC3~P_!k)}JBEVM%xN zb!1@J*w6hZkrl}2EbxddW?8eRt z;Pfz>LcqZ=nq|PjFj_c(gJHCAfCR&6;V@b_jOK;WyudJ8FO1d;45Mu%a3UDZ3!`~q zG%rBXz-V3=%?qP>VKgs{jx>%Ay#jN==$IR|!0SCiqe*qi}qirN`FpL%skYE@s z97YR=(Y!F47e>caM^`2=jP{)&1;J<=2@(#Y9Vl=(jJA=$!7$o^0tdrr;V@b_kX})G a%-Fe5jw^Sgn(_xw@OirWxvX3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-42t2NE{-7;ac^%JGBPOe9N5rUfBu6) zW8KMM{@C<$Kurt`2l9W5f*Jda7BGSs9ugP8d=;JyFfGJp0;V~cr9gB;3nMRxb~x0) z2BH-b9hgD%1cOoSqd~{OFq&)_7)G-Uus9kmE=G&W(Q0C}iX3eoj5du%Ta}=4V6CgVCnZXfG0&3`TpmdK II;Vst0FI>9KmY&$ literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/red_7F0000.png b/doc/calibration/RGB/red_7F0000.png new file mode 100644 index 0000000000000000000000000000000000000000..7dc59c7d11ec3b2317e768af5324e3214156dff2 GIT binary patch literal 10668 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRU>F@_hU5w& c2bno3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-42of%E{-7;ac^%JGBPOe9N5rUfBu6) zW8KMM{@8S&9tMU7`~QNhWMGJwya1+Ecrw7W5Ss~@=46%v(G4w(ydc`)Py-u?R!DSU z2GJ7?7BGTn4~bFjqd~{OFq&+DIdL@0j20K8MJ1?O7_BBotH{yj!D!QHv}rWjGy;_a zqfMjHo)j<{jP@c&n?|7GV083gbmRn-4n~^?qs;?QIv8ypj5ZH|$zZg3Fxor-6$hiu zgVE*zC>@M84@R2@pmZ?WJQ!^r0F%LJ^I)`j04fd!sCi&e%(&(}XTJO6Q{O?Z@O1Ta JS?83{1OQ{u)Xo3^ literal 0 HcmV?d00001 diff --git a/doc/calibration/RGB/yellow_7F7F00.png b/doc/calibration/RGB/yellow_7F7F00.png new file mode 100644 index 0000000000000000000000000000000000000000..0296764528b0606bb360452f27ad9cca22f022e8 GIT binary patch literal 10668 zcmeAS@N?(olHy`uVBq!ia0y~yU~gbxV6os}1B$%3e9#$4F%}28J29*~C-V}>VM%xN zb!1@J*w6hZkrl}2EbxddW?8eRU>GeNAi*$N zIE)q!qj_O8FN}_5#80|Yl3WCu#5+oc(J5b3=;uTjKx9jP7LeL$-D$|SkfJR z9T^xl_H+M9WCij$3p^r=85sBugD~Uq{1qt-400PiT^vIy;@%!#$je|Lz`XI@{x8$n z<+r3fDrX03VPM#63#L@QfvE{Mm_f8d5AdCjWXh#v4 z21Wy6G!RC6%cC7daCI=+TLuQhXdsLR!sw8}Xm1%@BBBi$Jh;cMqnWu?`}+)OkhG_( KpUXO@geCyAOIi;A literal 0 HcmV?d00001 diff --git a/include/hyperion/ColorAdjustment.h b/include/hyperion/ColorAdjustment.h new file mode 100644 index 00000000..0ce7f1a6 --- /dev/null +++ b/include/hyperion/ColorAdjustment.h @@ -0,0 +1,22 @@ +#pragma once + +// STL includes +#include + +// Utils includes +#include + +class ColorAdjustment +{ +public: + + /// Unique identifier for this color transform + std::string _id; + + /// The RED-Channel (RGB) adjustment + RgbChannelAdjustment _rgbRedAdjustment; + /// The GREEN-Channel (RGB) transform + RgbChannelAdjustment _rgbGreenAdjustment; + /// The BLUE-Channel (RGB) transform + RgbChannelAdjustment _rgbBlueAdjustment; +}; diff --git a/include/hyperion/Hyperion.h b/include/hyperion/Hyperion.h index 88c480d3..57440cf9 100644 --- a/include/hyperion/Hyperion.h +++ b/include/hyperion/Hyperion.h @@ -15,6 +15,7 @@ #include #include #include +#include #include // Effect engine includes @@ -28,10 +29,11 @@ class HsvTransform; class HslTransform; class RgbChannelTransform; class RgbChannelCorrection; +class RgbChannelAdjustment; class MultiColorTransform; class MultiColorCorrection; class MultiColorTemperature; - +class MultiColorAdjustment; /// /// The main class of Hyperion. This gives other 'users' access to the attached LedDevice through /// the priority muxer. @@ -135,6 +137,12 @@ public slots: /// const std::vector & getTemperatureIds() const; + /// + /// Returns the list with unique adjustment identifiers + /// @return The list with adjustment identifiers + /// + const std::vector & getAdjustmentIds() const; + /// /// Returns the ColorTransform with the given identifier /// @return The transform with the given identifier (or nullptr if the identifier does not exist) @@ -153,6 +161,12 @@ public slots: /// ColorCorrection * getTemperature(const std::string& id); + /// + /// 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 std::string& id); + /// /// Returns MessageForwarder Object /// @return instance of message forwarder object @@ -168,6 +182,9 @@ public slots: /// Tell Hyperion that the corrections have changed and the leds need to be updated void temperaturesUpdated(); + /// Tell Hyperion that the corrections have changed and the leds need to be updated + void adjustmentsUpdated(); + /// /// 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) @@ -208,16 +225,19 @@ public: static MultiColorTransform * createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorTransformConfig); static MultiColorCorrection * createLedColorsCorrection(const unsigned ledCnt, const Json::Value & colorCorrectionConfig); static MultiColorCorrection * createLedColorsTemperature(const unsigned ledCnt, const Json::Value & colorTemperatureConfig); + static MultiColorAdjustment * createLedColorsAdjustment(const unsigned ledCnt, const Json::Value & colorAdjustmentConfig); static ColorTransform * createColorTransform(const Json::Value & transformConfig); static ColorCorrection * createColorCorrection(const Json::Value & correctionConfig); + static ColorAdjustment * createColorAdjustment(const Json::Value & adjustmentConfig); static HsvTransform * createHsvTransform(const Json::Value & hsvConfig); static HslTransform * createHslTransform(const Json::Value & hslConfig); static RgbChannelTransform * createRgbChannelTransform(const Json::Value& colorConfig); static RgbChannelCorrection * createRgbChannelCorrection(const Json::Value& colorConfig); + static RgbChannelAdjustment * createRgbChannelAdjustment(const Json::Value& colorConfig, const RgbChannel color); static LedDevice * createColorSmoothing(const Json::Value & smoothingConfig, LedDevice * ledDevice); static MessageForwarder * createMessageForwarder(const Json::Value & forwarderConfig); - + signals: /// Signal which is emitted when a priority channel is actively cleared /// This signal will not be emitted when a priority channel time out @@ -241,15 +261,18 @@ private: /// The priority muxer PriorityMuxer _muxer; - /// The transformation from corrected colors to led colors + /// The transformation from raw colors to led colors MultiColorTransform * _raw2ledTransform; /// The correction from raw colors to led colors MultiColorCorrection * _raw2ledCorrection; - /// The temperature from corrected colors to led colors + /// The temperature from raw colors to led colors MultiColorCorrection * _raw2ledTemperature; + /// The adjustment from raw colors to led colors + MultiColorAdjustment * _raw2ledAdjustment; + /// The actual LedDevice LedDevice * _device; diff --git a/include/utils/RgbChannelAdjustment.h b/include/utils/RgbChannelAdjustment.h new file mode 100644 index 00000000..4b0130bd --- /dev/null +++ b/include/utils/RgbChannelAdjustment.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 RgbChannelAdjustment +{ +public: + /// Default constructor + RgbChannelAdjustment(); + + /// Constructor + /// @param adjustR + /// @param adjustG + /// @param adjustB + + RgbChannelAdjustment(int adjustR, int adjustG, int adjustB); + + /// Destructor + ~RgbChannelAdjustment(); + + /// @return The current adjustR value + uint8_t getadjustmentR() const; + + /// @param threshold New adjustR value + void setadjustmentR(uint8_t adjustR); + + /// @return The current adjustG value + uint8_t getadjustmentG() const; + + /// @param gamma New adjustG value + void setadjustmentG(uint8_t adjustG); + + /// @return The current adjustB value + uint8_t getadjustmentB() const; + + /// @param blacklevel New adjustB value + void setadjustmentB(uint8_t adjustB); + + /// Transform the given array value + /// @param input The input color bytes + /// @return The corrected byte value + uint8_t adjustmentR(uint8_t inputR) const; + uint8_t adjustmentG(uint8_t inputG) const; + uint8_t adjustmentB(uint8_t inputB) const; + + +private: + /// (re)-initilize the color mapping + void initializeMapping(); + +private: + /// The adjustment of R channel + int _adjustR; + /// The adjustment of G channel + int _adjustG; + /// The adjustment of B channel + int _adjustB; + + /// The mapping from input color to output color + int _mappingR[256]; + int _mappingG[256]; + int _mappingB[256]; +}; diff --git a/libsrc/hyperion/CMakeLists.txt b/libsrc/hyperion/CMakeLists.txt index a2188127..b4f53a19 100644 --- a/libsrc/hyperion/CMakeLists.txt +++ b/libsrc/hyperion/CMakeLists.txt @@ -19,6 +19,7 @@ SET(Hyperion_HEADERS ${CURRENT_SOURCE_DIR}/MultiColorTransform.h ${CURRENT_SOURCE_DIR}/MultiColorCorrection.h + ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.h ${CURRENT_HEADER_DIR}/MessageForwarder.h ) @@ -32,6 +33,7 @@ SET(Hyperion_SOURCES ${CURRENT_SOURCE_DIR}/ImageToLedsMap.cpp ${CURRENT_SOURCE_DIR}/MultiColorTransform.cpp ${CURRENT_SOURCE_DIR}/MultiColorCorrection.cpp + ${CURRENT_SOURCE_DIR}/MultiColorAdjustment.cpp ${CURRENT_SOURCE_DIR}/LinearColorSmoothing.cpp ${CURRENT_SOURCE_DIR}/MessageForwarder.cpp ) diff --git a/libsrc/hyperion/Hyperion.cpp b/libsrc/hyperion/Hyperion.cpp index 1d6925da..a5a85ff4 100644 --- a/libsrc/hyperion/Hyperion.cpp +++ b/libsrc/hyperion/Hyperion.cpp @@ -17,6 +17,7 @@ #include #include #include +#include // Leddevice includes #include @@ -24,6 +25,7 @@ #include "MultiColorTransform.h" #include "MultiColorCorrection.h" +#include "MultiColorAdjustment.h" #include "LinearColorSmoothing.h" // effect engine includes @@ -101,6 +103,7 @@ ColorTransform * Hyperion::createColorTransform(const Json::Value & transformCon return transform; } + ColorCorrection * Hyperion::createColorCorrection(const Json::Value & correctionConfig) { const std::string id = correctionConfig.get("id", "default").asString(); @@ -117,6 +120,30 @@ ColorCorrection * Hyperion::createColorCorrection(const Json::Value & correction return correction; } + +ColorAdjustment * Hyperion::createColorAdjustment(const Json::Value & adjustmentConfig) +{ + const std::string id = adjustmentConfig.get("id", "default").asString(); + + RgbChannelAdjustment * redAdjustment = createRgbChannelAdjustment(adjustmentConfig["pureRed"],RED); + RgbChannelAdjustment * greenAdjustment = createRgbChannelAdjustment(adjustmentConfig["pureGreen"],GREEN); + RgbChannelAdjustment * blueAdjustment = createRgbChannelAdjustment(adjustmentConfig["pureBlue"],BLUE); + + ColorAdjustment * adjustment = new ColorAdjustment(); + adjustment->_id = id; + adjustment->_rgbRedAdjustment = *redAdjustment; + adjustment->_rgbGreenAdjustment = *greenAdjustment; + adjustment->_rgbBlueAdjustment = *blueAdjustment; + + // Cleanup the allocated individual adjustments + delete redAdjustment; + delete greenAdjustment; + delete blueAdjustment; + + return adjustment; +} + + MultiColorTransform * Hyperion::createLedColorsTransform(const unsigned ledCnt, const Json::Value & colorConfig) { // Create the result, the transforms are added to this @@ -206,7 +233,7 @@ MultiColorCorrection * Hyperion::createLedColorsCorrection(const unsigned ledCnt } else if (!correctionConfig.isArray()) { - ColorCorrection * colorCorrection = createColorCorrection(colorConfig); + ColorCorrection * colorCorrection = createColorCorrection(correctionConfig); correction->addCorrection(colorCorrection); correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); } @@ -280,7 +307,7 @@ MultiColorCorrection * Hyperion::createLedColorsTemperature(const unsigned ledCn } else if (!correctionConfig.isArray()) { - ColorCorrection * colorCorrection = createColorCorrection(colorConfig); + ColorCorrection * colorCorrection = createColorCorrection(correctionConfig); correction->addCorrection(colorCorrection); correction->setCorrectionForLed(colorCorrection->_id, 0, ledCnt-1); } @@ -339,6 +366,80 @@ MultiColorCorrection * Hyperion::createLedColorsTemperature(const unsigned ledCn return correction; } +MultiColorAdjustment * Hyperion::createLedColorsAdjustment(const unsigned ledCnt, const Json::Value & colorConfig) +{ + // Create the result, the transforms are added to this + MultiColorAdjustment * adjustment = new MultiColorAdjustment(ledCnt); + + const Json::Value adjustmentConfig = colorConfig.get("channelAdjustment", Json::nullValue); + if (adjustmentConfig.isNull()) + { + // Old style color transformation config (just one for all leds) + ColorAdjustment * colorAdjustment = createColorAdjustment(colorConfig); + adjustment->addAdjustment(colorAdjustment); + adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1); + } + else if (!adjustmentConfig.isArray()) + { + ColorAdjustment * colorAdjustment = createColorAdjustment(adjustmentConfig); + adjustment->addAdjustment(colorAdjustment); + adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1); + } + else + { + const QRegExp overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*"); + + for (Json::UInt i = 0; i < adjustmentConfig.size(); ++i) + { + const Json::Value & config = adjustmentConfig[i]; + ColorAdjustment * colorAdjustment = createColorAdjustment(config); + adjustment->addAdjustment(colorAdjustment); + + const QString ledIndicesStr = QString(config.get("leds", "").asCString()).trimmed(); + if (ledIndicesStr.compare("*") == 0) + { + // Special case for indices '*' => all leds + adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1); + std::cout << "HYPERION INFO: ColorAdjustment '" << colorAdjustment->_id << "' => [0; "<< ledCnt-1 << "]" << std::endl; + continue; + } + + if (!overallExp.exactMatch(ledIndicesStr)) + { + std::cerr << "HYPERION ERROR: Given led indices " << i << " not correct format: " << ledIndicesStr.toStdString() << std::endl; + continue; + } + + std::cout << "HYPERION INFO: ColorAdjustment '" << colorAdjustment->_id << "' => ["; + + const QStringList ledIndexList = ledIndicesStr.split(","); + for (int i=0; i 0) + { + std::cout << ", "; + } + if (ledIndexList[i].contains("-")) + { + QStringList ledIndices = ledIndexList[i].split("-"); + int startInd = ledIndices[0].toInt(); + int endInd = ledIndices[1].toInt(); + + adjustment->setAdjustmentForLed(colorAdjustment->_id, startInd, endInd); + std::cout << startInd << "-" << endInd; + } + else + { + int index = ledIndexList[i].toInt(); + adjustment->setAdjustmentForLed(colorAdjustment->_id, index, index); + std::cout << index; + } + } + std::cout << "]" << std::endl; + } + } + return adjustment; +} + HsvTransform * Hyperion::createHsvTransform(const Json::Value & hsvConfig) { const double saturationGain = hsvConfig.get("saturationGain", 1.0).asDouble(); @@ -376,6 +477,32 @@ RgbChannelCorrection* Hyperion::createRgbChannelCorrection(const Json::Value& co return correction; } +RgbChannelAdjustment* Hyperion::createRgbChannelAdjustment(const Json::Value& colorConfig, const RgbChannel color) +{ + int varR, varG, varB; + if (color == RED) + { + varR = colorConfig.get("redChannel", 255).asInt(); + varG = colorConfig.get("greenChannel", 0).asInt(); + varB = colorConfig.get("blueChannel", 0).asInt(); + } + else if (color == GREEN) + { + varR = colorConfig.get("redChannel", 0).asInt(); + varG = colorConfig.get("greenChannel", 255).asInt(); + varB = colorConfig.get("blueChannel", 0).asInt(); + } + else if (color == BLUE) + { + varR = colorConfig.get("redChannel", 0).asInt(); + varG = colorConfig.get("greenChannel", 0).asInt(); + varB = colorConfig.get("blueChannel", 255).asInt(); + } + + RgbChannelAdjustment* adjustment = new RgbChannelAdjustment(varR, varG, varB); + return adjustment; +} + LedString Hyperion::createLedString(const Json::Value& ledsConfig, const ColorOrder deviceOrder) { LedString ledString; @@ -490,6 +617,7 @@ MessageForwarder * Hyperion::getForwarder() Hyperion::Hyperion(const Json::Value &jsonConfig) : _ledString(createLedString(jsonConfig["leds"], createColorOrder(jsonConfig["device"]))), _muxer(_ledString.leds().size()), + _raw2ledAdjustment(createLedColorsAdjustment(_ledString.leds().size(), jsonConfig["color"])), _raw2ledCorrection(createLedColorsCorrection(_ledString.leds().size(), jsonConfig["color"])), _raw2ledTemperature(createLedColorsTemperature(_ledString.leds().size(), jsonConfig["color"])), _raw2ledTransform(createLedColorsTransform(_ledString.leds().size(), jsonConfig["color"])), @@ -498,6 +626,10 @@ Hyperion::Hyperion(const Json::Value &jsonConfig) : _messageForwarder(createMessageForwarder(jsonConfig["forwarder"])), _timer() { + if (!_raw2ledAdjustment->verifyAdjustments()) + { + throw std::runtime_error("HYPERION ERROR: Color adjustment incorrectly set"); + } if (!_raw2ledCorrection->verifyCorrections()) { throw std::runtime_error("HYPERION ERROR: Color correction incorrectly set"); @@ -551,6 +683,9 @@ Hyperion::~Hyperion() // delete the color temperature correction delete _raw2ledTemperature; + + // delete the color adjustment + delete _raw2ledAdjustment; // delete the message forwarder delete _messageForwarder; @@ -609,6 +744,11 @@ const std::vector & Hyperion::getTemperatureIds() const return _raw2ledTemperature->getCorrectionIds(); } +const std::vector & Hyperion::getAdjustmentIds() const +{ + return _raw2ledAdjustment->getAdjustmentIds(); +} + ColorTransform * Hyperion::getTransform(const std::string& id) { return _raw2ledTransform->getTransform(id); @@ -624,6 +764,11 @@ ColorCorrection * Hyperion::getTemperature(const std::string& id) return _raw2ledTemperature->getCorrection(id); } +ColorAdjustment * Hyperion::getAdjustment(const std::string& id) +{ + return _raw2ledAdjustment->getAdjustment(id); +} + void Hyperion::transformsUpdated() { update(); @@ -639,6 +784,11 @@ void Hyperion::temperaturesUpdated() update(); } +void Hyperion::adjustmentsUpdated() +{ + update(); +} + void Hyperion::clear(int priority) { if (_muxer.hasPriority(priority)) @@ -703,9 +853,11 @@ void Hyperion::update() const PriorityMuxer::InputInfo & priorityInfo = _muxer.getInputInfo(priority); // Apply the correction and the transform to each led and color-channel - std::vector correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors); - std::vector temperatureColors = _raw2ledTemperature->applyCorrection(correctedColors); - std::vector ledColors =_raw2ledTransform->applyTransform(temperatureColors); + // Avoid applying correction, the same task is performed by adjustment + // std::vector correctedColors = _raw2ledCorrection->applyCorrection(priorityInfo.ledColors); + std::vector adjustedColors = _raw2ledAdjustment->applyAdjustment(priorityInfo.ledColors); + std::vector transformColors =_raw2ledTransform->applyTransform(adjustedColors); + std::vector ledColors = _raw2ledTemperature->applyCorrection(transformColors); const std::vector& leds = _ledString.leds(); int i = 0; for (ColorRgb& color : ledColors) diff --git a/libsrc/hyperion/MultiColorAdjustment.cpp b/libsrc/hyperion/MultiColorAdjustment.cpp new file mode 100644 index 00000000..79ba1d21 --- /dev/null +++ b/libsrc/hyperion/MultiColorAdjustment.cpp @@ -0,0 +1,124 @@ + +// STL includes +#include + +// Hyperion includes +#include "MultiColorAdjustment.h" + +MultiColorAdjustment::MultiColorAdjustment(const unsigned ledCnt) : + _ledAdjustments(ledCnt, nullptr) +{ +} + +MultiColorAdjustment::~MultiColorAdjustment() +{ + // Clean up all the transforms + for (ColorAdjustment * adjustment : _adjustment) + { + delete adjustment; + } +} + +void MultiColorAdjustment::addAdjustment(ColorAdjustment * adjustment) +{ + _adjustmentIds.push_back(adjustment->_id); + _adjustment.push_back(adjustment); +} + +void MultiColorAdjustment::setAdjustmentForLed(const std::string& id, const unsigned startLed, const unsigned endLed) +{ + assert(startLed <= endLed); + assert(endLed < _ledAdjustments.size()); + + // Get the identified adjustment (don't care if is nullptr) + ColorAdjustment * adjustment = getAdjustment(id); + for (unsigned iLed=startLed; iLed<=endLed; ++iLed) + { + _ledAdjustments[iLed] = adjustment; + } +} + +bool MultiColorAdjustment::verifyAdjustments() const +{ + bool allLedsSet = true; + for (unsigned iLed=0; iLed<_ledAdjustments.size(); ++iLed) + { + if (_ledAdjustments[iLed] == nullptr) + { + std::cerr << "HYPERION (C.adjustment) ERROR: No adjustment set for " << iLed << std::endl; + allLedsSet = false; + } + } + return allLedsSet; +} + +const std::vector & MultiColorAdjustment::getAdjustmentIds() +{ + return _adjustmentIds; +} + +ColorAdjustment* MultiColorAdjustment::getAdjustment(const std::string& id) +{ + // Iterate through the unique adjustments until we find the one with the given id + for (ColorAdjustment* adjustment : _adjustment) + { + if (adjustment->_id == id) + { + return adjustment; + } + } + + // The ColorAdjustment was not found + return nullptr; +} + +std::vector MultiColorAdjustment::applyAdjustment(const std::vector& rawColors) +{ + // Create a copy, as we will do the rest of the adjustment in place + std::vector ledColors(rawColors); + + const size_t itCnt = std::min(_ledAdjustments.size(), rawColors.size()); + for (size_t i=0; i_rgbRedAdjustment.adjustmentR(color.red); + int RG = adjustment->_rgbRedAdjustment.adjustmentG(color.red); + int RB = adjustment->_rgbRedAdjustment.adjustmentB(color.red); + int GR = adjustment->_rgbGreenAdjustment.adjustmentR(color.green); + int GG = adjustment->_rgbGreenAdjustment.adjustmentG(color.green); + int GB = adjustment->_rgbGreenAdjustment.adjustmentB(color.green); + int BR = adjustment->_rgbBlueAdjustment.adjustmentR(color.blue); + int BG = adjustment->_rgbBlueAdjustment.adjustmentG(color.blue); + int BB = adjustment->_rgbBlueAdjustment.adjustmentB(color.blue); + + int ledR = RR + GR + BR; + int maxR = (int)adjustment->_rgbRedAdjustment.getadjustmentR(); + int ledG = RG + GG + BG; + int maxG = (int)adjustment->_rgbGreenAdjustment.getadjustmentG(); + int ledB = RB + GB + BB; + int maxB = (int)adjustment->_rgbBlueAdjustment.getadjustmentB(); + + if (ledR > maxR) + color.red = (uint8_t)maxR; + else + color.red = (uint8_t)ledR; + + if (ledG > maxG) + color.green = (uint8_t)maxG; + else + color.green = (uint8_t)ledG; + + if (ledB > maxB) + color.blue = (uint8_t)maxB; + else + color.blue = (uint8_t)ledB; + } + return ledColors; +} diff --git a/libsrc/hyperion/MultiColorAdjustment.h b/libsrc/hyperion/MultiColorAdjustment.h new file mode 100644 index 00000000..7f02b815 --- /dev/null +++ b/libsrc/hyperion/MultiColorAdjustment.h @@ -0,0 +1,66 @@ +#pragma once + +// STL includes +#include + +// Utils includes +#include + +// Hyperion includes +#include + +/// +/// The LedColorTransform is responsible for performing color transformation from 'raw' colors +/// received as input to colors mapped to match the color-properties of the leds. +/// +class MultiColorAdjustment +{ +public: + MultiColorAdjustment(const unsigned ledCnt); + ~MultiColorAdjustment(); + + /** + * Adds a new ColorAdjustment to this MultiColorTransform + * + * @param adjustment The new ColorAdjustment (ownership is transfered) + */ + void addAdjustment(ColorAdjustment * adjustment); + + void setAdjustmentForLed(const std::string& id, const unsigned startLed, const unsigned endLed); + + bool verifyAdjustments() const; + + /// + /// Returns the identifier of all the unique ColorAdjustment + /// + /// @return The list with unique id's of the ColorAdjustment + const std::vector & getAdjustmentIds(); + + /// + /// Returns the pointer to the ColorAdjustment with the given id + /// + /// @param id The identifier of the ColorAdjustment + /// + /// @return The ColorAdjustment with the given id (or nullptr if it does not exist) + /// + ColorAdjustment* getAdjustment(const std::string& id); + + /// + /// Performs the color adjustment from raw-color to led-color + /// + /// @param rawColors The list with raw colors + /// + /// @return The list with led-colors + /// + std::vector applyAdjustment(const std::vector& rawColors); + +private: + /// List with transform ids + std::vector _adjustmentIds; + + /// List with unique ColorTransforms + std::vector _adjustment; + + /// List with a pointer to the ColorAdjustment for each individual led + std::vector _ledAdjustments; +}; diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index 033f5f6d..62346623 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include // project includes @@ -252,6 +253,8 @@ void JsonClientConnection::handleMessage(const std::string &messageString) handleCorrectionCommand(message); else if (command == "temperature") handleTemperatureCommand(message); + else if (command == "adjustment") + handleAdjustmentCommand(message); else handleNotImplemented(); } @@ -470,6 +473,34 @@ void JsonClientConnection::handleServerInfoCommand(const Json::Value &) whitelevel.append(colorTransform->_rgbGreenTransform.getWhitelevel()); whitelevel.append(colorTransform->_rgbBlueTransform.getWhitelevel()); } + + // collect adjustment information + Json::Value & adjustmentArray = info["adjustment"]; + for (const std::string& adjustmentId : _hyperion->getAdjustmentIds()) + { + const ColorAdjustment * colorAdjustment = _hyperion->getAdjustment(adjustmentId); + if (colorAdjustment == nullptr) + { + std::cerr << "JSONCLIENT ERROR: Incorrect color adjustment id: " << adjustmentId << std::endl; + continue; + } + + Json::Value & adjustment = adjustmentArray.append(Json::Value()); + adjustment["id"] = adjustmentId; + + Json::Value & redAdjust = adjustment["redAdjust"]; + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getadjustmentR()); + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getadjustmentG()); + redAdjust.append(colorAdjustment->_rgbRedAdjustment.getadjustmentB()); + Json::Value & greenAdjust = adjustment["greenAdjust"]; + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getadjustmentR()); + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getadjustmentG()); + greenAdjust.append(colorAdjustment->_rgbGreenAdjustment.getadjustmentB()); + Json::Value & blueAdjust = adjustment["blueAdjust"]; + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getadjustmentR()); + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getadjustmentG()); + blueAdjust.append(colorAdjustment->_rgbBlueAdjustment.getadjustmentB()); + } // collect effect info Json::Value & effects = info["effects"] = Json::Value(Json::arrayValue); @@ -634,6 +665,47 @@ void JsonClientConnection::handleTemperatureCommand(const Json::Value &message) sendSuccessReply(); } + +void JsonClientConnection::handleAdjustmentCommand(const Json::Value &message) +{ + const Json::Value & adjustment = message["adjustment"]; + + const std::string adjustmentId = adjustment.get("id", _hyperion->getAdjustmentIds().front()).asString(); + ColorAdjustment * colorAdjustment = _hyperion->getAdjustment(adjustmentId); + if (colorAdjustment == nullptr) + { + //sendErrorReply(std::string("Incorrect transform identifier: ") + transformId); + return; + } + + if (adjustment.isMember("redAdjust")) + { + const Json::Value & values = adjustment["redAdjust"]; + colorAdjustment->_rgbRedAdjustment.setadjustmentR(values[0u].asInt()); + colorAdjustment->_rgbRedAdjustment.setadjustmentG(values[1u].asInt()); + colorAdjustment->_rgbRedAdjustment.setadjustmentB(values[2u].asInt()); + } + + if (adjustment.isMember("greenAdjust")) + { + const Json::Value & values = adjustment["greenAdjust"]; + colorAdjustment->_rgbGreenAdjustment.setadjustmentR(values[0u].asInt()); + colorAdjustment->_rgbGreenAdjustment.setadjustmentG(values[1u].asInt()); + colorAdjustment->_rgbGreenAdjustment.setadjustmentB(values[2u].asInt()); + } + + if (adjustment.isMember("blueAdjust")) + { + const Json::Value & values = adjustment["blueAdjust"]; + colorAdjustment->_rgbBlueAdjustment.setadjustmentR(values[0u].asInt()); + colorAdjustment->_rgbBlueAdjustment.setadjustmentG(values[1u].asInt()); + colorAdjustment->_rgbBlueAdjustment.setadjustmentB(values[2u].asInt()); + } + // commit the changes + _hyperion->adjustmentsUpdated(); + + sendSuccessReply(); +} void JsonClientConnection::handleNotImplemented() { @@ -712,7 +784,6 @@ void JsonClientConnection::sendMessage(const Json::Value & message, QTcpSocket * } - void JsonClientConnection::sendSuccessReply() { // create reply diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index acf58d7d..ff8da15a 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -126,6 +126,13 @@ private: /// @param message the incoming message /// void handleTemperatureCommand(const Json::Value & message); + + /// + /// Handle an incoming JSON Adjustment message + /// + /// @param message the incoming message + /// + void handleAdjustmentCommand(const Json::Value & message); /// /// Handle an incoming JSON message of unknown type diff --git a/libsrc/jsonserver/JsonSchemas.qrc b/libsrc/jsonserver/JsonSchemas.qrc index 193624ba..6556bf32 100644 --- a/libsrc/jsonserver/JsonSchemas.qrc +++ b/libsrc/jsonserver/JsonSchemas.qrc @@ -9,6 +9,7 @@ schema/schema-transform.json schema/schema-correction.json schema/schema-temperature.json + schema/schema-adjustment.json schema/schema-effect.json diff --git a/libsrc/jsonserver/schema/schema-adjustment.json b/libsrc/jsonserver/schema/schema-adjustment.json new file mode 100644 index 00000000..c6e2ba5d --- /dev/null +++ b/libsrc/jsonserver/schema/schema-adjustment.json @@ -0,0 +1,56 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["adjustment"] + }, + "adjustment": { + "type": "object", + "required": true, + "properties": { + "id" : { + "type" : "string", + "required" : false + }, + "redAdjust": { + "type": "array", + "required": false, + "items" : { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "minItems": 3, + "maxItems": 3 + }, + "greenAdjust": { + "type": "array", + "required": false, + "items" : { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "minItems": 3, + "maxItems": 3 + }, + "blueAdjust": { + "type": "array", + "required": false, + "items" : { + "type": "integer", + "minimum": 0, + "maximum": 255 + }, + "minItems": 3, + "maxItems": 3 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema.json b/libsrc/jsonserver/schema/schema.json index 061339d1..91106162 100644 --- a/libsrc/jsonserver/schema/schema.json +++ b/libsrc/jsonserver/schema/schema.json @@ -5,7 +5,7 @@ "command": { "type" : "string", "required" : true, - "enum" : ["color", "image", "effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature"] + "enum" : ["color", "image", "effect", "serverinfo", "clear", "clearall", "transform", "correction", "temperature", "adjustment"] } } } diff --git a/libsrc/utils/CMakeLists.txt b/libsrc/utils/CMakeLists.txt index 8de00707..5978c2c1 100644 --- a/libsrc/utils/CMakeLists.txt +++ b/libsrc/utils/CMakeLists.txt @@ -29,6 +29,8 @@ add_library(hyperion-utils ${CURRENT_SOURCE_DIR}/RgbChannelTransform.cpp ${CURRENT_HEADER_DIR}/RgbChannelCorrection.h ${CURRENT_SOURCE_DIR}/RgbChannelCorrection.cpp + ${CURRENT_HEADER_DIR}/RgbChannelAdjustment.h + ${CURRENT_SOURCE_DIR}/RgbChannelAdjustment.cpp ${CURRENT_HEADER_DIR}/jsonschema/JsonFactory.h ${CURRENT_HEADER_DIR}/jsonschema/JsonSchemaChecker.h diff --git a/libsrc/utils/RgbChannelAdjustment.cpp b/libsrc/utils/RgbChannelAdjustment.cpp new file mode 100644 index 00000000..0c5468c7 --- /dev/null +++ b/libsrc/utils/RgbChannelAdjustment.cpp @@ -0,0 +1,107 @@ +// STL includes +#include + +// Utils includes +#include + +RgbChannelAdjustment::RgbChannelAdjustment() : + _adjustR(255), + _adjustG(255), + _adjustB(255) +{ + initializeMapping(); +} + +RgbChannelAdjustment::RgbChannelAdjustment(int adjustR, int adjustG, int adjustB) : + _adjustR(adjustR), + _adjustG(adjustG), + _adjustB(adjustB) +{ + initializeMapping(); +} + +RgbChannelAdjustment::~RgbChannelAdjustment() +{ +} + +uint8_t RgbChannelAdjustment::getadjustmentR() const +{ + return _adjustR; +} + +void RgbChannelAdjustment::setadjustmentR(uint8_t adjustR) +{ + _adjustR = adjustR; + initializeMapping(); +} + +uint8_t RgbChannelAdjustment::getadjustmentG() const +{ + return _adjustG; +} + +void RgbChannelAdjustment::setadjustmentG(uint8_t adjustG) +{ + _adjustG = adjustG; + initializeMapping(); +} + +uint8_t RgbChannelAdjustment::getadjustmentB() const +{ + return _adjustB; +} + +void RgbChannelAdjustment::setadjustmentB(uint8_t adjustB) +{ + _adjustB = adjustB; + initializeMapping(); +} + +uint8_t RgbChannelAdjustment::adjustmentR(uint8_t inputR) const +{ + return _mappingR[inputR]; +} + +uint8_t RgbChannelAdjustment::adjustmentG(uint8_t inputG) const +{ + return _mappingG[inputG]; +} + +uint8_t RgbChannelAdjustment::adjustmentB(uint8_t inputB) const +{ + return _mappingB[inputB]; +} + +void RgbChannelAdjustment::initializeMapping() +{ + // initialize the mapping + for (int i = 0; i < 256; ++i) + { + int outputR = (i * _adjustR) / 255; + if (outputR > 255) + { + outputR = 255; + } + _mappingR[i] = outputR; + } + for (int i = 0; i < 256; ++i) + { + int outputG = (i * _adjustG) / 255; + if (outputG > 255) + { + outputG = 255; + } + _mappingG[i] = outputG; + } + for (int i = 0; i < 256; ++i) + { + int outputB = (i * _adjustB) / 255; + if (outputB > 255) + { + outputB = 255; + } + _mappingB[i] = outputB; + } + + +} diff --git a/src/hyperion-remote/ColorAdjustmentValues.h b/src/hyperion-remote/ColorAdjustmentValues.h new file mode 100644 index 00000000..9aaefc7c --- /dev/null +++ b/src/hyperion-remote/ColorAdjustmentValues.h @@ -0,0 +1,12 @@ +#pragma once + +/// Simple structure to contain the values of a color transformation +struct ColorAdjustmentValues +{ + /// The value for the red color-channel + int valueRed; + /// The value for the green color-channel + int valueGreen; + /// The value for the blue color-channel + int valueBlue; +}; diff --git a/src/hyperion-remote/CustomParameter.h b/src/hyperion-remote/CustomParameter.h index af1836a6..3e7dd826 100644 --- a/src/hyperion-remote/CustomParameter.h +++ b/src/hyperion-remote/CustomParameter.h @@ -13,6 +13,7 @@ // hyperion-remote includes #include "ColorTransformValues.h" #include "ColorCorrectionValues.h" +#include "ColorAdjustmentValues.h" /// Data parameter for a color typedef vlofgren::PODParameter> ColorParameter; @@ -26,6 +27,9 @@ typedef vlofgren::PODParameter TransformParameter; /// Data parameter for color correction values (list of three values) typedef vlofgren::PODParameter CorrectionParameter; +/// Data parameter for color correction values (list of three values) +typedef vlofgren::PODParameter AdjustmentParameter; + namespace vlofgren { /// /// Translates a string (as passed on the commandline) to a vector of colors @@ -161,4 +165,33 @@ namespace vlofgren { return correction; } + + template<> + ColorAdjustmentValues AdjustmentParameter::validate(const std::string& s) throw (Parameter::ParameterRejected) + { + ColorAdjustmentValues adjustment; + + // s should be split in 3 parts + // seperators are either a ',' or a space + QStringList components = QString(s.c_str()).split(" ", QString::SkipEmptyParts); + + if (components.size() == 3) + { + bool ok1, ok2, ok3; + adjustment.valueRed = components[0].toInt(&ok1); + adjustment.valueGreen = components[1].toInt(&ok2); + adjustment.valueBlue = components[2].toInt(&ok3); + + if (ok1 && ok2 && ok3) + { + return adjustment; + } + } + + std::stringstream errorMessage; + errorMessage << "Argument " << s << " can not be parsed to 3 integer values"; + throw Parameter::ParameterRejected(errorMessage.str()); + + return adjustment; + } } diff --git a/src/hyperion-remote/JsonConnection.cpp b/src/hyperion-remote/JsonConnection.cpp index 61367104..16438b7e 100644 --- a/src/hyperion-remote/JsonConnection.cpp +++ b/src/hyperion-remote/JsonConnection.cpp @@ -322,6 +322,51 @@ void JsonConnection::setTemperature(std::string * temperatureId, ColorCorrection parseReply(reply); } +void JsonConnection::setAdjustment(std::string * adjustmentId, ColorAdjustmentValues * redAdjustment, ColorAdjustmentValues * greenAdjustment, ColorAdjustmentValues * blueAdjustment) +{ + std::cout << "Set color adjustments" << std::endl; + + // create command + Json::Value command; + command["command"] = "adjustment"; + Json::Value & adjust = command["adjustment"]; + + if (adjustmentId != nullptr) + { + adjust["id"] = *adjustmentId; + } + + if (redAdjustment != nullptr) + { + Json::Value & v = adjust["redAdjust"]; + v.append(redAdjustment->valueRed); + v.append(redAdjustment->valueGreen); + v.append(redAdjustment->valueBlue); + } + + if (greenAdjustment != nullptr) + { + Json::Value & v = adjust["greenAdjust"]; + v.append(greenAdjustment->valueRed); + v.append(greenAdjustment->valueGreen); + v.append(greenAdjustment->valueBlue); + } + + if (blueAdjustment != nullptr) + { + Json::Value & v = adjust["blueAdjust"]; + v.append(blueAdjustment->valueRed); + v.append(blueAdjustment->valueGreen); + v.append(blueAdjustment->valueBlue); + } + + // send command message + Json::Value reply = sendMessage(command); + + // parse reply message + parseReply(reply); +} + Json::Value JsonConnection::sendMessage(const Json::Value & message) { // serialize message (FastWriter already appends a newline) diff --git a/src/hyperion-remote/JsonConnection.h b/src/hyperion-remote/JsonConnection.h index 48455110..d71ff3a3 100644 --- a/src/hyperion-remote/JsonConnection.h +++ b/src/hyperion-remote/JsonConnection.h @@ -15,6 +15,7 @@ // hyperion-remote includes #include "ColorTransformValues.h" #include "ColorCorrectionValues.h" +#include "ColorAdjustmentValues.h" /// /// Connection class to setup an connection to the hyperion server and execute commands @@ -130,6 +131,21 @@ public: std::string * temperatureId, ColorCorrectionValues * temperature); + /// + /// Set the color adjustment of the leds + /// + /// @note Note that providing a NULL will leave the settings on the server unchanged + /// + /// @param adjustmentId The identifier of the correction to set + /// @param redAdjustment The red channel adjustment values + /// @param greenAdjustment The green channel adjustment values + /// @param blueAdjustment The blue channel adjustment values + void setAdjustment( + std::string * adjustmentId, + ColorAdjustmentValues * redAdjustment, + ColorAdjustmentValues * greenAdjustment, + ColorAdjustmentValues * blueAdjustment); + private: /// /// Send a json command message and receive its reply diff --git a/src/hyperion-remote/hyperion-remote.cpp b/src/hyperion-remote/hyperion-remote.cpp index 2da4ecfa..8686a540 100644 --- a/src/hyperion-remote/hyperion-remote.cpp +++ b/src/hyperion-remote/hyperion-remote.cpp @@ -81,6 +81,10 @@ int main(int argc, char * argv[]) CorrectionParameter & argCorrection = parameters.add('Y', "correction" , "Set the correction of the leds (requires 3 space seperated values between 0 and 255)"); StringParameter & argIdT = parameters.add ('z', "qualifier" , "Identifier(qualifier) of the temperature correction to set"); CorrectionParameter & argTemperature = parameters.add('Z', "temperature" , "Set the temperature correction of the leds (requires 3 space seperated values between 0 and 255)"); + StringParameter & argIdA = parameters.add ('j', "qualifier" , "Identifier(qualifier) of the adjustment to set"); + AdjustmentParameter & argRAdjust = parameters.add('R', "redAdjustment" , "Set the adjustment of the red color (requires 3 space seperated values between 0 and 255)"); + AdjustmentParameter & argGAdjust = parameters.add('G', "greenAdjustment", "Set the adjustment of the green color (requires 3 space seperated values between 0 and 255)"); + AdjustmentParameter & argBAdjust = parameters.add('B', "blueAdjustment", "Set the adjustment of the blue color (requires 3 space seperated values between 0 and 255)"); // set the default values argAddress.setDefault(defaultServerAddress.toStdString()); @@ -100,10 +104,11 @@ int main(int argc, char * argv[]) // check if at least one of the available color transforms is set bool colorTransform = argSaturation.isSet() || argValue.isSet() || argSaturationL.isSet() || argLuminance.isSet() || argThreshold.isSet() || argGamma.isSet() || argBlacklevel.isSet() || argWhitelevel.isSet(); - bool colorModding = colorTransform || argCorrection.isSet() || argTemperature.isSet(); + bool colorAdjust = argRAdjust.isSet() || argGAdjust.isSet() || argBAdjust.isSet(); + bool colorModding = colorTransform || colorAdjust || argCorrection.isSet() || argTemperature.isSet(); // check that exactly one command was given - int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorModding}); + int commandCount = count({argColor.isSet(), argImage.isSet(), argEffect.isSet(), argServerInfo.isSet(), argClear.isSet(), argClearAll.isSet(), colorModding}); if (commandCount != 1) { std::cerr << (commandCount == 0 ? "No command found." : "Multiple commands found.") << " Provide exactly one of the following options:" << std::endl; @@ -127,6 +132,10 @@ int main(int argc, char * argv[]) std::cerr << " " << argCorrection.usageLine() << std::endl; std::cerr << " " << argIdT.usageLine() << std::endl; std::cerr << " " << argTemperature.usageLine() << std::endl; + std::cerr << " " << argIdA.usageLine() << std::endl; + std::cerr << " " << argRAdjust.usageLine() << std::endl; + std::cerr << " " << argGAdjust.usageLine() << std::endl; + std::cerr << " " << argBAdjust.usageLine() << std::endl; return 1; } @@ -186,6 +195,24 @@ int main(int argc, char * argv[]) argIdT.isSet() ? &tempId : nullptr, argTemperature.isSet() ? &temperature : nullptr); } + + if (colorAdjust) + { + std::string adjustId; + ColorAdjustmentValues redChannel, greenChannel, blueChannel; + + if (argIdA.isSet()) adjustId = argIdA.getValue(); + if (argRAdjust.isSet()) redChannel = argRAdjust.getValue(); + if (argGAdjust.isSet()) greenChannel = argGAdjust.getValue(); + if (argBAdjust.isSet()) blueChannel = argBAdjust.getValue(); + + connection.setAdjustment( + argIdA.isSet() ? &adjustId : nullptr, + argRAdjust.isSet() ? &redChannel : nullptr, + argGAdjust.isSet() ? &greenChannel : nullptr, + argBAdjust.isSet() ? &blueChannel : nullptr); + + } if (colorTransform) { std::string transId;