ESP32 Native version of Blinky, featureful controller code for WS2811/WS2812/NeoPixels
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

139 行
4.0KB

  1. static const char *TAG = "gradient";
  2. #include <esp_log.h>
  3. #include "presets.hpp"
  4. #include "utils.hpp"
  5. struct Gradient {
  6. Color at(Fixed x) const;
  7. static Gradient* make(int n) {
  8. Gradient *gradient = (Gradient*)malloc(
  9. sizeof(Gradient) + n * sizeof(*colors)
  10. );
  11. gradient->n_colors = n;
  12. return gradient;
  13. }
  14. unsigned int n_colors;
  15. Color colors[];
  16. };
  17. class GradientPattern : public Pattern {
  18. public:
  19. GradientPattern(
  20. Gradient *_gradient,
  21. int _cycle_length=20, int _cycle_time_ms=-1,
  22. bool _reverse=false, bool _march=false
  23. ) : cycle_length(_cycle_length),
  24. cycle_time_ms( _cycle_time_ms < 0 ?
  25. _cycle_length * 500 : _cycle_time_ms
  26. ),
  27. reverse(_reverse), march(_march), gradient(_gradient)
  28. {}
  29. ~GradientPattern() { free(gradient); }
  30. State* start(int) const { return new State(); }
  31. void step(Color[], int, State*) const;
  32. private:
  33. struct State : Pattern::State {
  34. State() : last_us(0), offset(0) {}
  35. int64_t last_us;
  36. Fixed offset;
  37. };
  38. int cycle_length;
  39. int cycle_time_ms;
  40. bool reverse;
  41. bool march;
  42. Gradient *gradient;
  43. };
  44. static inline uint8_t mix(int l, int r, Fixed x) {
  45. return ((l << shift) + (x * (r - l))) >> shift;
  46. }
  47. Color Gradient::at(Fixed x) const {
  48. int i_left = (x * n_colors) >> shift;
  49. int i_right = i_left < n_colors - 1 ? i_left + 1 : 0;
  50. Fixed ratio = (x * n_colors) - (i_left << shift);
  51. //ESP_LOGI(TAG, "at(%d) = %d between %d and %d", x, ratio, i_left, i_right);
  52. Color cl = colors[i_left];
  53. Color cr = colors[i_right];
  54. Color color = {
  55. mix(cl.r, cr.r, ratio),
  56. mix(cl.g, cr.g, ratio),
  57. mix(cl.b, cr.b, ratio)
  58. };
  59. /*ESP_LOGI(TAG, "(%d, %d, %d) %f (%d, %d, %d) -> (%d, %d, %d)",
  60. cl.r, cl.g, cl.b,
  61. ratio / (float)factor,
  62. cr.r, cr.g, cr.b,
  63. color.r, color.g, color.b
  64. );*/
  65. return color;
  66. }
  67. void GradientPattern::step(Color pixels[], int len, Pattern::State *_state) const {
  68. GradientPattern::State *state = (GradientPattern::State*)_state;
  69. int64_t now_us = time_us();
  70. int64_t duration_us = state->last_us == 0 ? 0 : now_us - state->last_us;
  71. state->last_us = now_us;
  72. //ESP_LOGI(TAG, "duration %d", duration_us);
  73. /*
  74. int period_us = 1000000 / 60;
  75. int n_skipped = (duration_us - period_us / 2) / period_us;
  76. if (n_skipped) {
  77. ESP_LOGW(TAG, "Skipped %d frames", n_skipped);
  78. }
  79. */
  80. // Don't make a major animation jump if it's been terribly long
  81. if (duration_us > 100000) duration_us = 100000;
  82. int offset_delta = (duration_us << shift) / (cycle_time_ms * 1000);
  83. if (reverse) state->offset += offset_delta; else state->offset -= offset_delta;
  84. Fixed off = march ?
  85. (((int)state->offset * cycle_length) & ~((1 << shift) - 1)) / cycle_length :
  86. state->offset;
  87. //ESP_LOGI(TAG, "cycle time %d, delta %d, offset %d, off %d", cycle_time_ms, offset_delta, offset, off);
  88. for (int i = 0; i < len; ++i) {
  89. pixels[i] = gradient->at(off + ((i << shift) / cycle_length));
  90. }
  91. }
  92. Pattern* json_gradient_pattern(cJSON *pattern, const Presets::ColorMap &colors) {
  93. if (pattern->type != cJSON_Object) {
  94. ESP_LOGE(TAG, "Not an object: %s", pattern->string);
  95. return NULL;
  96. }
  97. cJSON *jcolors = cJSON_GetObjectItem(pattern, "colors");
  98. if (!jcolors) {
  99. ESP_LOGE(TAG, "No colors in %s", pattern->string);
  100. return NULL;
  101. }
  102. if (jcolors->type != cJSON_Array) {
  103. ESP_LOGE(TAG, "Not an array: %s", jcolors->string);
  104. return NULL;
  105. }
  106. Gradient *gradient = Gradient::make(cJSON_GetArraySize(jcolors));
  107. int i = 0;
  108. cJSON *jcolor;
  109. cJSON_ArrayForEach(jcolor, jcolors) {
  110. Color color = Presets::json_color(jcolor, colors);
  111. gradient->colors[i++] = color;
  112. }
  113. return new GradientPattern(gradient);
  114. }