hyperion.h 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. #pragma once
  2. #include <sstream>
  3. #include <hyperion/ColorAdjustment.h>
  4. #include <hyperion/MultiColorAdjustment.h>
  5. #include <hyperion/LedString.h>
  6. #include <QRegularExpression>
  7. // fg effect
  8. #include <hyperion/Hyperion.h>
  9. #include <hyperion/PriorityMuxer.h>
  10. #if defined(ENABLE_EFFECTENGINE)
  11. #include <effectengine/Effect.h>
  12. #endif
  13. ///
  14. /// @brief Provide utility methods for Hyperion class
  15. ///
  16. namespace hyperion {
  17. static void handleInitialEffect(Hyperion* hyperion, const QJsonObject& FGEffectConfig)
  18. {
  19. #define FGCONFIG_ARRAY fgColorConfig.toArray()
  20. // initial foreground effect/color
  21. if (FGEffectConfig["enable"].toBool(true))
  22. {
  23. #if defined(ENABLE_EFFECTENGINE)
  24. const QString fgTypeConfig = FGEffectConfig["type"].toString("effect");
  25. const QString fgEffectConfig = FGEffectConfig["effect"].toString("Rainbow swirl fast");
  26. #else
  27. const QString fgTypeConfig = "color";
  28. #endif
  29. const QJsonValue fgColorConfig = FGEffectConfig["color"];
  30. int default_fg_duration_ms = 3000;
  31. int fg_duration_ms = FGEffectConfig["duration_ms"].toInt(default_fg_duration_ms);
  32. if (fg_duration_ms <= PriorityMuxer::ENDLESS )
  33. {
  34. fg_duration_ms = default_fg_duration_ms;
  35. Warning(Logger::getInstance("HYPERION"), "foreground effect duration 'infinity' is forbidden, set to default value %d ms",default_fg_duration_ms);
  36. }
  37. if ( fgTypeConfig.contains("color") )
  38. {
  39. std::vector<ColorRgb> fg_color = {
  40. ColorRgb {
  41. static_cast<uint8_t>(FGCONFIG_ARRAY.at(0).toInt(0)),
  42. static_cast<uint8_t>(FGCONFIG_ARRAY.at(1).toInt(0)),
  43. static_cast<uint8_t>(FGCONFIG_ARRAY.at(2).toInt(0))
  44. }
  45. };
  46. hyperion->setColor(PriorityMuxer::FG_PRIORITY, fg_color, fg_duration_ms);
  47. Info(Logger::getInstance("HYPERION","I"+QString::number(hyperion->getInstanceIndex())),"Initial foreground color set (%d %d %d)",fg_color.at(0).red,fg_color.at(0).green,fg_color.at(0).blue);
  48. }
  49. #if defined(ENABLE_EFFECTENGINE)
  50. else
  51. {
  52. int result = hyperion->setEffect(fgEffectConfig, PriorityMuxer::FG_PRIORITY, fg_duration_ms);
  53. Info(Logger::getInstance("HYPERION","I"+QString::number(hyperion->getInstanceIndex())),"Initial foreground effect '%s' %s", QSTRING_CSTR(fgEffectConfig), ((result == 0) ? "started" : "failed"));
  54. }
  55. #endif
  56. }
  57. #undef FGCONFIG_ARRAY
  58. }
  59. static ColorOrder createColorOrder(const QJsonObject &deviceConfig)
  60. {
  61. return stringToColorOrder(deviceConfig["colorOrder"].toString("rgb"));
  62. }
  63. static RgbTransform createRgbTransform(const QJsonObject& colorConfig)
  64. {
  65. const double backlightThreshold = colorConfig["backlightThreshold"].toDouble(0.0);
  66. const bool backlightColored = colorConfig["backlightColored"].toBool(false);
  67. const int brightness = colorConfig["brightness"].toInt(100);
  68. const int brightnessComp = colorConfig["brightnessCompensation"].toInt(100);
  69. const double gammaR = colorConfig["gammaRed"].toDouble(1.0);
  70. const double gammaG = colorConfig["gammaGreen"].toDouble(1.0);
  71. const double gammaB = colorConfig["gammaBlue"].toDouble(1.0);
  72. return RgbTransform(gammaR, gammaG, gammaB, backlightThreshold, backlightColored, static_cast<uint8_t>(brightness), static_cast<uint8_t>(brightnessComp));
  73. }
  74. static OkhsvTransform createOkhsvTransform(const QJsonObject& colorConfig)
  75. {
  76. const double saturationGain = colorConfig["saturationGain"].toDouble(1.0);
  77. const double brightnessGain = colorConfig["brightnessGain"].toDouble(1.0);
  78. return OkhsvTransform(saturationGain, brightnessGain);
  79. }
  80. static RgbChannelAdjustment createRgbChannelAdjustment(const QJsonObject& colorConfig, const QString& channelName, int defaultR, int defaultG, int defaultB)
  81. {
  82. const QJsonArray& channelConfig = colorConfig[channelName].toArray();
  83. return RgbChannelAdjustment(
  84. static_cast<uint8_t>(channelConfig[0].toInt(defaultR)),
  85. static_cast<uint8_t>(channelConfig[1].toInt(defaultG)),
  86. static_cast<uint8_t>(channelConfig[2].toInt(defaultB)),
  87. "ChannelAdjust_" + channelName.toUpper()
  88. );
  89. }
  90. static ColorAdjustment* createColorAdjustment(const QJsonObject & adjustmentConfig)
  91. {
  92. const QString id = adjustmentConfig["id"].toString("default");
  93. ColorAdjustment * adjustment = new ColorAdjustment();
  94. adjustment->_id = id;
  95. adjustment->_rgbBlackAdjustment = createRgbChannelAdjustment(adjustmentConfig, "black" , 0, 0, 0);
  96. adjustment->_rgbWhiteAdjustment = createRgbChannelAdjustment(adjustmentConfig, "white" , 255,255,255);
  97. adjustment->_rgbRedAdjustment = createRgbChannelAdjustment(adjustmentConfig, "red" , 255, 0, 0);
  98. adjustment->_rgbGreenAdjustment = createRgbChannelAdjustment(adjustmentConfig, "green" , 0,255, 0);
  99. adjustment->_rgbBlueAdjustment = createRgbChannelAdjustment(adjustmentConfig, "blue" , 0, 0,255);
  100. adjustment->_rgbCyanAdjustment = createRgbChannelAdjustment(adjustmentConfig, "cyan" , 0,255,255);
  101. adjustment->_rgbMagentaAdjustment = createRgbChannelAdjustment(adjustmentConfig, "magenta", 255, 0,255);
  102. adjustment->_rgbYellowAdjustment = createRgbChannelAdjustment(adjustmentConfig, "yellow" , 255,255, 0);
  103. adjustment->_rgbTransform = createRgbTransform(adjustmentConfig);
  104. adjustment->_okhsvTransform = createOkhsvTransform(adjustmentConfig);
  105. return adjustment;
  106. }
  107. static MultiColorAdjustment * createLedColorsAdjustment(int ledCnt, const QJsonObject & colorConfig)
  108. {
  109. // Create the result, the transforms are added to this
  110. MultiColorAdjustment * adjustment = new MultiColorAdjustment(ledCnt);
  111. const QJsonValue adjustmentConfig = colorConfig["channelAdjustment"];
  112. const QRegularExpression overallExp("([0-9]+(\\-[0-9]+)?)(,[ ]*([0-9]+(\\-[0-9]+)?))*");
  113. const QJsonArray & adjustmentConfigArray = adjustmentConfig.toArray();
  114. for (signed i = 0; i < adjustmentConfigArray.size(); ++i)
  115. {
  116. const QJsonObject & config = adjustmentConfigArray.at(i).toObject();
  117. ColorAdjustment * colorAdjustment = createColorAdjustment(config);
  118. adjustment->addAdjustment(colorAdjustment);
  119. const QString ledIndicesStr = config["leds"].toString("").trimmed();
  120. if (ledIndicesStr.compare("*") == 0)
  121. {
  122. // Special case for indices '*' => all leds
  123. adjustment->setAdjustmentForLed(colorAdjustment->_id, 0, ledCnt-1);
  124. continue;
  125. }
  126. if (!overallExp.match(ledIndicesStr).hasMatch())
  127. {
  128. // Given LED indices are not correctly formatted
  129. continue;
  130. }
  131. std::stringstream ss;
  132. const QStringList ledIndexList = ledIndicesStr.split(",");
  133. for (int i=0; i<ledIndexList.size(); ++i) {
  134. if (i > 0)
  135. {
  136. ss << ", ";
  137. }
  138. if (ledIndexList[i].contains("-"))
  139. {
  140. QStringList ledIndices = ledIndexList[i].split("-");
  141. int startInd = ledIndices[0].toInt();
  142. int endInd = ledIndices[1].toInt();
  143. adjustment->setAdjustmentForLed(colorAdjustment->_id, startInd, endInd);
  144. ss << startInd << "-" << endInd;
  145. }
  146. else
  147. {
  148. int index = ledIndexList[i].toInt();
  149. adjustment->setAdjustmentForLed(colorAdjustment->_id, index, index);
  150. ss << index;
  151. }
  152. }
  153. }
  154. return adjustment;
  155. }
  156. static QSize getLedLayoutGridSize(const QJsonArray& ledConfigArray)
  157. {
  158. std::vector<int> midPointsX;
  159. std::vector<int> midPointsY;
  160. for (signed i = 0; i < ledConfigArray.size(); ++i)
  161. {
  162. const QJsonObject& ledConfig = ledConfigArray[i].toObject();
  163. double minX_frac = qMax(0.0, qMin(1.0, ledConfig["hmin"].toDouble()));
  164. double maxX_frac = qMax(0.0, qMin(1.0, ledConfig["hmax"].toDouble()));
  165. double minY_frac = qMax(0.0, qMin(1.0, ledConfig["vmin"].toDouble()));
  166. double maxY_frac = qMax(0.0, qMin(1.0, ledConfig["vmax"].toDouble()));
  167. // Fix if the user swapped min and max
  168. if (minX_frac > maxX_frac)
  169. {
  170. std::swap(minX_frac, maxX_frac);
  171. }
  172. if (minY_frac > maxY_frac)
  173. {
  174. std::swap(minY_frac, maxY_frac);
  175. }
  176. // calculate mid point and make grid calculation
  177. midPointsX.push_back( int(1000.0*(minX_frac + maxX_frac) / 2.0) );
  178. midPointsY.push_back( int(1000.0*(minY_frac + maxY_frac) / 2.0) );
  179. }
  180. // remove duplicates
  181. std::sort(midPointsX.begin(), midPointsX.end());
  182. midPointsX.erase(std::unique(midPointsX.begin(), midPointsX.end()), midPointsX.end());
  183. std::sort(midPointsY.begin(), midPointsY.end());
  184. midPointsY.erase(std::unique(midPointsY.begin(), midPointsY.end()), midPointsY.end());
  185. QSize gridSize( static_cast<int>(midPointsX.size()), static_cast<int>(midPointsY.size()) );
  186. // Correct the grid in case it is malformed in width vs height
  187. // Expected is at least 50% of width <-> height
  188. if((gridSize.width() / gridSize.height()) > 2)
  189. gridSize.setHeight(qMax(1,gridSize.width()/2));
  190. else if((gridSize.width() / gridSize.height()) < 0.5)
  191. gridSize.setWidth(qMax(1,gridSize.height()/2));
  192. // Limit to 80px for performance reasons
  193. const int pl = 80;
  194. if(gridSize.width() > pl || gridSize.height() > pl)
  195. {
  196. gridSize.scale(pl, pl, Qt::KeepAspectRatio);
  197. }
  198. return gridSize;
  199. }
  200. };