diff --git a/config.yml b/config.yml index c206987..f67edb5 100644 --- a/config.yml +++ b/config.yml @@ -51,6 +51,11 @@ operations: params: enabled: false duration: 5000 + knightrider: + type: knightrider + params: + duration: 5000 + width: 0.2 rotate: type: rotate params: diff --git a/src/config_sequence.cpp b/src/config_sequence.cpp index 5e8fc9b..f58e235 100644 --- a/src/config_sequence.cpp +++ b/src/config_sequence.cpp @@ -8,6 +8,7 @@ #include "operations/FlashOperation.h" #include "operations/GameOfLifeOperation.h" #include "operations/HSVUDPInputOperation.h" +#include "operations/KnightRider.h" #include "operations/RainbowOperation.h" #include "operations/RaindropOperation.h" #include "operations/RotateOperation.h" @@ -45,6 +46,7 @@ std::unique_ptr generateSequenceStep( {"gameoflife", &generator}, {"hsvudpinput", &generator}, {"lua", &generator}, + {"knightrider", &generator}, {"rainbow", &generator}, {"raindrop", &generator}, {"rotate", &generator}, diff --git a/src/operations/KnightRider.cpp b/src/operations/KnightRider.cpp new file mode 100644 index 0000000..48299fe --- /dev/null +++ b/src/operations/KnightRider.cpp @@ -0,0 +1,82 @@ +#include "KnightRider.h" + +#include +#include +#include + +#include +#include + +KnightRiderOperation::KnightRiderOperation(const std::string& name, + std::shared_ptr store, + YAML::const_iterator begin, + YAML::const_iterator end) + : Operation(name, store, begin, end), + state(State::IDLE), + value(name + "/value", + Operation::HSV_VALUE, + store, + getValueByKey("value", begin, end, 1.0f)), + duration_milliseconds(name + "/duration", + Operation::INT, + store, + getValueByKey("duration", begin, end, 1000)), + width(name + "/width", + Operation::FLOAT, + store, + getValueByKey("width", begin, end, 0.1f)) {} + +Operation::BufferType KnightRiderOperation::operator()( + Operation::BufferType& buffer) { + if (!isEnabled()) + return buffer; + + int size = (*buffer).size(); + + for (int i = 0; i < size; i++) { + if (direction == Direction::ASCENDING && i > currentCenter) { + (*buffer).at(i) = HSV{0, 0, 0}; + continue; + } + + if (direction == Direction::DESCENDING && i < currentCenter) { + (*buffer).at(i) = HSV{0, 0, 0}; + continue; + } + + int distance = std::abs(i - currentCenter); + float relValue = value - pow(float(distance) / float(size), width); + auto& p = (*buffer).at(i); + (*buffer).at(i) = HSV{p.hue, p.saturation, std::clamp(relValue, 0.f, 1.f)}; + } + + return buffer; +} + +void KnightRiderOperation::update(const size_t width, const size_t fps) { + if (!isEnabled()) { + return; + } + + auto stepWitdh = width / fps / float(duration_milliseconds / 1000); + + if (direction == Direction::ASCENDING) { + if (currentCenter >= width - 1) { + direction = Direction::DESCENDING; + return; + } else { + currentCenter += stepWitdh; + } + } + + if (direction == Direction::DESCENDING) { + if (currentCenter <= 0) { + direction = Direction::ASCENDING; + return; + } else { + currentCenter -= stepWitdh; + } + } + + currentCenter = std::clamp(currentCenter, 0, int(width - 1)); +} diff --git a/src/operations/KnightRider.h b/src/operations/KnightRider.h new file mode 100644 index 0000000..f0d1d07 --- /dev/null +++ b/src/operations/KnightRider.h @@ -0,0 +1,36 @@ +#pragma once + +#include "Operation.h" + +class KnightRiderOperation : public Operation { + enum State { + IDLE, + RUNNING, + } state; + + enum Direction { + ASCENDING, + DESCENDING, + } direction; + + int currentCenter = 0; + + BoundConcreteValue value; + + BoundConcreteValue duration_milliseconds; + BoundConcreteValue width; + + float getShade() const; + + public: + KnightRiderOperation(const std::string& name, + std::shared_ptr store, + YAML::const_iterator begin, + YAML::const_iterator end); + + virtual ~KnightRiderOperation() {} + + virtual Operation::BufferType operator()(Operation::BufferType& buffer); + + virtual void update(const size_t width, const size_t fps); +};