Set up an animation framework and a pleasing Flame animation

i2c
Savanni D'Gerinel 2022-06-17 01:31:38 -04:00
parent 762ba275b6
commit c9e0775b4b
9 changed files with 213 additions and 51 deletions

43
animation/animation.c Normal file
View File

@ -0,0 +1,43 @@
#include "animation.h"
line_t line_new(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1) {
uint8_t dx = x1 - x0;
int8_t dy = y1 - y0;
int8_t inc = dy > 0 ? 1 : dy == 0 ? 0 : -1;
int8_t m = 2 * dy;
int8_t error = 0;
if (m > 0) {
error = m - dx;
} else {
error = m + dx;
}
return (line_t){ .y = y0, .m = m, .error = error, .inc = inc, .dx = dx };
}
uint8_t line_next(line_t *slope) {
slope->error += slope->m;
if (slope->m > 0) {
if (slope->error >= 0) {
slope->y += slope->inc;
slope->error -= 2 * slope->dx;
}
} else {
if (slope->error <= 0) {
slope->y += slope->inc;
slope->error += 2 * slope->dx;
}
}
return slope->y;
}
/*
void line_print(line_t *line) {
printf("y: %d\tm: %d\terror: %d\tinc: %d\t:dx: %d\n", line->y, line->m, line->error, line->inc, line->dx);
}
*/

27
animation/animation.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef __ANIMATION_H__
#define __ANIMATION_H__
#include <avr/io.h>
// line_t provides a simplified implementation of Bresenham's line drawing
// technique. At this time, it assumes a transition of x = 0 -> 60, and a dy
// between -59 and 59. I am not sure I understand Bresenham's algorithm yet,
// but I'll need to revisit all of this if I want to expand the boundaries.
typedef struct line_s {
uint8_t y;
int8_t m;
int8_t error;
int8_t inc;
uint8_t dx;
} line_t;
// Construct a new line object. x1 must be greater than x0, and dy must be less than dx.
line_t line_new(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1);
// Calculate the next y value of the line.
uint8_t line_next(line_t *line);
// Diagnostic printout of the current state of line_t.
// void line_print(line_t *line);
#endif

32
animation/bresenham.c Normal file
View File

@ -0,0 +1,32 @@
#include <stdlib.h>
void bresenham(int x1, int y1, int x2, int y2) {
int dx = x2 - x1;
int dy = y2 - y1;
int m = 2 * dy;
int err = 0;
if (m > 0) {
err = m - dx;
} else if (m < 0) {
err = m + dx;
}
for (int x = x1, y = y1; x <= x2; x++) {
printf("(%d, %d) [%d]\n", x, y, err);
err += m;
if (m > 0) {
if (err >= 0) {
y++;
err -= 2 * dx;
}
} else if (m < 0) {
if (err <= 0) {
y--;
err += 2 * dx;
}
}
}
}

21
animation/main.c Normal file
View File

@ -0,0 +1,21 @@
#include <stdlib.h>
#include <base.h>
#include <rng.h>
typedef struct RGB_s {
uint8_t brightness;
uint8_t r;
uint8_t g;
uint8_t b;
} rgb_t;
int main (void) {
rng_t rng = rng_new(0);
animation_t animation = animation_new();
for (int i = 0; i < 120; i++) {
animation_step(&animation, &rng);
printf("[%d] %d %d %d\n", animation.frame, animation.lamp.r, animation.lamp.g, animation.lamp.b);
}
}

View File

@ -55,15 +55,4 @@ inline int dio_read(dio_t *line) {
return (*(line->pin) & _BV(line->addr)) > 0;
}
typedef struct RNG {
uint8_t mod;
int8_t a;
int8_t c;
uint8_t seed;
} rng_t;
rng_t rng_new(uint8_t seed);
uint8_t rng_sample(rng_t *state);
#endif

View File

@ -41,12 +41,57 @@
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
buildPhase = ''
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o base.o -c ${src}/base/base.c
'';
installPhase = ''
mkdir $out
cp base/base.h base.o $out/
cp base/base.h $out/
'';
};
packages."x86_64-linux"."rng" =
{ mcu, chip_select, f_cpu }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
avr = pkgs.pkgsCross.avr.buildPackages;
in pkgs.stdenv.mkDerivation rec {
name = "rng";
src = ./.;
buildInputs = [
(packages."x86_64-linux"."base" { inherit mcu chip_select f_cpu; })
];
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
INCLUDE_DIRS = pkgs.lib.concatStringsSep " " (map (dir: "-I${dir}") buildInputs);
OBJECT_FILES = pkgs.lib.concatStringsSep " " (map (dir: "${dir}/*.o") buildInputs);
buildPhase = ''
${avr.gcc}/bin/avr-gcc ${CFLAGS} ${INCLUDE_DIRS} -o rng.o -c ${src}/rng/rng.c
'';
installPhase = ''
mkdir $out
cp rng/rng.h rng.o $out/
'';
};
packages."x86_64-linux"."animation" =
{ mcu, chip_select, f_cpu }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
avr = pkgs.pkgsCross.avr.buildPackages;
in pkgs.stdenv.mkDerivation rec {
name = "animation";
src = ./.;
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
buildPhase = ''
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o animation.o -c ${src}/animation/animation.c
'';
installPhase = ''
mkdir $out
cp animation/animation.h animation.o $out/
'';
};
@ -186,6 +231,7 @@
{ mcu, chip_select, f_cpu }:
let
pkgs = import nixpkgs { system = "x86_64-linux"; };
lib = pkgs.lib;
avr = pkgs.pkgsCross.avr.buildPackages;
in pkgs.stdenv.mkDerivation rec {
name = "flame";
@ -194,6 +240,8 @@
buildInputs = [
(packages."x86_64-linux"."base" { inherit mcu chip_select f_cpu; })
(packages."x86_64-linux"."sk9822" { inherit mcu chip_select f_cpu; })
(packages."x86_64-linux"."rng" { inherit mcu chip_select f_cpu; })
(packages."x86_64-linux"."animation" { inherit mcu chip_select f_cpu; })
];
CFLAGS = cflags { inherit mcu chip_select f_cpu; };
@ -239,6 +287,7 @@
${avr.gcc}/bin/avr-gcc ${CFLAGS} -o prime-tx.elf main.o ${OBJECT_FILES}
$OBJCOPY -O ihex prime-tx.elf prime-tx.hex
'';
installPhase = ''
mkdir $out
cp prime-tx.elf prime-tx.hex $out

View File

@ -3,13 +3,15 @@
#include <base.h>
#include <sk9822.h>
#include <rng.h>
#include <animation.h>
#define FPS 60
#define FRAME_DELAY_MS 1000 / FPS
uint8_t random_step(uint8_t value, uint8_t min, uint8_t max, rng_t *rng) {
int8_t step = (rng_sample(rng) % 32) - 16;
uint16_t new_value = value + step;
int8_t step = (rng_sample(rng) % 20) - 10;
int new_value = value + step;
if (new_value > max) {
return max;
} else if (new_value < min) {
@ -28,9 +30,9 @@ typedef struct {
rgb_t lamp;
color_scheme_e color_scheme;
int8_t red_step;
int8_t green_step;
int8_t blue_step;
line_t red_line;
line_t green_line;
line_t blue_line;
uint8_t frame;
uint8_t duration;
@ -38,11 +40,11 @@ typedef struct {
animation_t animation_new(void) {
return (animation_t){
.lamp = (rgb_t){ .brightness = 9, .r = 212, .g = 50, .b = 0 },
.lamp = (rgb_t){ .brightness = 1, .r = 200, .g = 30, .b = 0 },
.color_scheme = normal,
.red_step = 0,
.green_step = 0,
.blue_step = 0,
.red_line = line_new(0, 0, 0, 0),
.green_line = line_new(0, 0, 0, 0),
.blue_line = line_new(0, 0, 0, 0),
.frame = 0,
.duration = 0,
@ -55,10 +57,10 @@ void animation_flicker(animation_t *animation, rng_t *rng) {
switch (animation->color_scheme) {
case normal:
rdest = random_step(animation->lamp.r, 180, 255, rng);
gdest = random_step(animation->lamp.g, 10, 40, rng);
animation->red_step = 60 / (rdest - animation->lamp.r);
animation->green_step = 60 / (gdest - animation->lamp.g);
animation->duration = 60;
gdest = random_step(animation->lamp.g, 20, 50, rng);
animation->red_line = line_new(0, animation->lamp.r, 30, rdest);
animation->green_line = line_new(0, animation->lamp.g, 30, gdest);
animation->duration = 30;
break;
case creepy:
break;
@ -72,25 +74,15 @@ void animation_step(animation_t *animation, rng_t *rng) {
if (animation->frame == animation->duration) {
animation->frame = 0;
animation->duration = 0;
animation->red_step = 0;
animation->green_step = 0;
animation->blue_step = 0;
} else {
animation->frame++;
animation->lamp.r += animation->red_step;
animation->lamp.g += animation->green_step;
animation->lamp.b += animation->blue_step;
animation->lamp.r = line_next(&animation->red_line);
animation->lamp.g = line_next(&animation->green_line);
animation->lamp.b = line_next(&animation->blue_line);
}
}
}
/*
void flicker(rgb_t *pixel, rng_t *rng) {
pixel->r = random_step(pixel->r, 180, 255, rng);
pixel->g = random_step(pixel->g, 10, 40, rng);
}
*/
int main (void) {
DDRB = _BV(2) | _BV(1) | _BV(0);
PORTB = 0;

View File

@ -10,7 +10,7 @@ Lumeto is distributed in the hope that it will be useful, but WITHOUT ANY WARRAN
You should have received a copy of the GNU General Public License along with Lumeto. If not, see <https://www.gnu.org/licenses/>.
*/
#include "base.h"
#include "rng.h"
rng_t rng_new(uint8_t seed) {
rng_t rng = { .mod = 255, .a = 253, .c = 41, .seed = seed };
@ -22,12 +22,3 @@ uint8_t rng_sample(rng_t *state) {
return state->seed;
}
/*
void strobe_line(gpio_t *line, uint32_t us) {
set_line(line);
_delay_us(us);
clear_line(line);
_delay_us(us);
}
*/

18
rng/rng.h Normal file
View File

@ -0,0 +1,18 @@
#include <base.h>
#include <stdlib.h>
#ifndef __RNG_H__
#define __RNG_H__
typedef struct RNG {
uint8_t mod;
int8_t a;
int8_t c;
uint8_t seed;
} rng_t;
rng_t rng_new(uint8_t seed);
uint8_t rng_sample(rng_t *state);
#endif