Effect.cpp 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. // Qt includes
  2. #include <QDateTime>
  3. #include <QFile>
  4. #include <QResource>
  5. // effect engin eincludes
  6. #include <effectengine/Effect.h>
  7. #include <effectengine/EffectModule.h>
  8. #include <utils/Logger.h>
  9. #include <hyperion/Hyperion.h>
  10. #include <hyperion/PriorityMuxer.h>
  11. // python utils
  12. #include <python/PythonProgram.h>
  13. Effect::Effect(Hyperion *hyperion, int priority, int timeout, const QString &script, const QString &name, const QJsonObject &args, const QString &imageData)
  14. : QThread()
  15. , _hyperion(hyperion)
  16. , _priority(priority)
  17. , _timeout(timeout)
  18. , _isEndless(timeout <= PriorityMuxer::ENDLESS)
  19. , _script(script)
  20. , _name(name)
  21. , _args(args)
  22. , _imageData(imageData)
  23. , _endTime(-1)
  24. , _interupt(false)
  25. , _imageSize(hyperion->getLedGridSize())
  26. , _image(_imageSize,QImage::Format_ARGB32_Premultiplied)
  27. {
  28. _colors.resize(_hyperion->getLedCount());
  29. _colors.fill(ColorRgb::BLACK);
  30. _log = Logger::getInstance("EFFECTENGINE");
  31. // init effect image for image based effects, size is based on led layout
  32. _image.fill(Qt::black);
  33. _painter = new QPainter(&_image);
  34. Q_INIT_RESOURCE(EffectEngine);
  35. }
  36. Effect::~Effect()
  37. {
  38. requestInterruption();
  39. wait();
  40. delete _painter;
  41. _imageStack.clear();
  42. }
  43. bool Effect::isInterruptionRequested()
  44. {
  45. return _interupt || (!_isEndless && getRemaining() <= 0);
  46. }
  47. int Effect::getRemaining() const
  48. {
  49. // determine the timeout
  50. int timeout = _timeout;
  51. if (timeout >= 0)
  52. {
  53. timeout = static_cast<int>( _endTime - QDateTime::currentMSecsSinceEpoch());
  54. }
  55. return timeout;
  56. }
  57. void Effect::setModuleParameters()
  58. {
  59. // import the buildtin Hyperion module
  60. PyObject * module = PyImport_ImportModule("hyperion");
  61. // add a capsule containing 'this' to the module to be able to retrieve the effect from the callback function
  62. PyModule_AddObject(module, "__effectObj", PyCapsule_New((void*)this, "hyperion.__effectObj", nullptr));
  63. // add ledCount variable to the interpreter
  64. int ledCount = 0;
  65. QMetaObject::invokeMethod(_hyperion, "getLedCount", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, ledCount));
  66. PyObject_SetAttrString(module, "ledCount", Py_BuildValue("i", ledCount));
  67. // add minimumWriteTime variable to the interpreter
  68. int latchTime = 0;
  69. QMetaObject::invokeMethod(_hyperion, "getLatchTime", Qt::BlockingQueuedConnection, Q_RETURN_ARG(int, latchTime));
  70. PyObject_SetAttrString(module, "latchTime", Py_BuildValue("i", latchTime));
  71. // add a args variable to the interpreter
  72. PyObject_SetAttrString(module, "args", EffectModule::json2python(_args));
  73. // decref the module
  74. Py_XDECREF(module);
  75. }
  76. void Effect::run()
  77. {
  78. PythonProgram program(_name, _log);
  79. setModuleParameters();
  80. // Set the end time if applicable
  81. if (_timeout > 0)
  82. {
  83. _endTime = QDateTime::currentMSecsSinceEpoch() + _timeout;
  84. }
  85. // Run the effect script
  86. QFile file (_script);
  87. if (file.open(QIODevice::ReadOnly))
  88. {
  89. program.execute(file.readAll());
  90. }
  91. else
  92. {
  93. Error(_log, "Unable to open script file %s.", QSTRING_CSTR(_script));
  94. }
  95. file.close();
  96. }