Set up an animation framework and a pleasing Flame animation
This commit is contained in:
parent
762ba275b6
commit
c9e0775b4b
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
11
base/base.h
11
base/base.h
|
@ -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
|
||||
|
|
57
flake.nix
57
flake.nix
|
@ -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
|
||||
|
|
44
flame/main.c
44
flame/main.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
*/
|
||||
|
Loading…
Reference in New Issue