aboutsummaryrefslogtreecommitdiff
path: root/main/pattern/twinkle.c
blob: 450cda63e288233a3a0faa81c469249804b2876d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#include "pattern/twinkle.h"

#include <stdint.h>
#include <stdlib.h>

// The shape of a "spike"
uint8_t w_arr[91] = {1,   2,   4,   7,   11,  17,  24,  33,  44,  56,  70,  85,
                     101, 117, 134, 151, 167, 183, 197, 210, 222, 232, 240, 247,
                     251, 254, 255, 255, 253, 250, 246, 240, 234, 227, 219, 211,
                     202, 194, 185, 176, 167, 158, 149, 140, 132, 123, 116, 108,
                     101, 94,  87,  81,  75,  69,  64,  59,  54,  50,  46,  42,
                     39,  35,  32,  30,  27,  25,  22,  20,  18,  17,  15,  14,
                     12,  11,  10,  9,   8,   7,   6,   6,   5,   4,   4,   3,
                     3,   3,   2,   2,   2,   1,   1};

static inline uint8_t byte_scale(uint8_t n, uint8_t sc)
{
  return n * sc / 255;
}

static uint8_t calc_w(uint8_t n, uint8_t shift)
{
  uint8_t s = byte_scale(shift, 164);
  uint8_t n_p = byte_scale(n, 255 - s) + s;
  if (n_p < 164) {
    return 0;
  }

  return w_arr[n_p - 164];
}

/* Produces a "pseudo-random" number given seed 'x' */
static uint8_t pseudo_random(uint8_t x)
{
  return (1103515245 * x + 12345) & 0xFF;  // & 0xFF ensures the result is 0-255
}

/* Produces a randomize "twinkle" effect. */
static uint8_t twinkle_raw(uint32_t time, size_t x, uint8_t amt)
{
  uint8_t time_offset = pseudo_random(x);

  uint32_t adj_time = time - time_offset;
  uint32_t time8 = adj_time & 0xff;
  uint32_t speed = pseudo_random((adj_time >> 8) + x) & 0x3;

  time8 *= speed;
  if (time8 <= 255) {
    return calc_w(time8, amt);
  } else {
    return 0;
  }
}

uint8_t twinkle(uint32_t time, size_t x, uint8_t amt)
{
  if (time % 2 == 0) {
    return twinkle_raw(time / 2, x, amt);
  } else {
    return (twinkle_raw(time / 2, x, amt) + twinkle_raw(time / 2 + 1, x, amt)) /
           2;
  }
}