From 9d032314e9db794dc88889bc24bf50bbafc3ec8d Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Tue, 7 Feb 2017 04:31:53 -0800 Subject: plasma: add a plasma renderer --- src/modules/Makefile.am | 2 +- src/modules/plasma/Makefile.am | 4 ++ src/modules/plasma/plasma.c | 126 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 src/modules/plasma/Makefile.am create mode 100644 src/modules/plasma/plasma.c (limited to 'src/modules') diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am index a291174..2890308 100644 --- a/src/modules/Makefile.am +++ b/src/modules/Makefile.am @@ -1 +1 @@ -SUBDIRS = ray roto sparkler stars +SUBDIRS = plasma ray roto sparkler stars diff --git a/src/modules/plasma/Makefile.am b/src/modules/plasma/Makefile.am new file mode 100644 index 0000000..16efeb4 --- /dev/null +++ b/src/modules/plasma/Makefile.am @@ -0,0 +1,4 @@ +noinst_LIBRARIES = libplasma.a +libplasma_a_SOURCES = plasma.c +libplasma_a_CFLAGS = @ROTOTILLER_CFLAGS@ +libplasma_a_CPPFLAGS = @ROTOTILLER_CFLAGS@ -I@top_srcdir@/src diff --git a/src/modules/plasma/plasma.c b/src/modules/plasma/plasma.c new file mode 100644 index 0000000..59c394a --- /dev/null +++ b/src/modules/plasma/plasma.c @@ -0,0 +1,126 @@ +#include +#include +#include + +#include "fb.h" +#include "rototiller.h" + +/* Copyright (C) 2017 Vito Caputo */ + +#define FIXED_TRIG_LUT_SIZE 4096 /* size of the cos/sin look-up tables */ +#define FIXED_BITS 10 /* fractional bits */ +#define FIXED_EXP (1 << FIXED_BITS) /* 2^FIXED_BITS */ +#define FIXED_MASK (FIXED_EXP - 1) /* fractional part mask */ +#define FIXED_COS(_rad) costab[(_rad) & (FIXED_TRIG_LUT_SIZE-1)] +#define FIXED_SIN(_rad) sintab[(_rad) & (FIXED_TRIG_LUT_SIZE-1)] +#define FIXED_MULT(_a, _b) (((_a) * (_b)) >> FIXED_BITS) +#define FIXED_NEW(_i) ((_i) << FIXED_BITS) +#define FIXED_TO_INT(_f) ((_f) >> FIXED_BITS) + +typedef struct color_t { + int r, g, b; +} color_t; + + +static inline uint32_t color2pixel(color_t *color) +{ + return (FIXED_TO_INT(color->r) << 16) | (FIXED_TO_INT(color->g) << 8) | FIXED_TO_INT(color->b); +} + + +static void init_plasma(int32_t *costab, int32_t *sintab) +{ + int i; + + /* Generate fixed-point cos & sin LUTs. */ + for (i = 0; i < FIXED_TRIG_LUT_SIZE; i++) { + costab[i] = ((cos((double)2*M_PI*i/FIXED_TRIG_LUT_SIZE))*FIXED_EXP); + sintab[i] = ((sin((double)2*M_PI*i/FIXED_TRIG_LUT_SIZE))*FIXED_EXP); + } +} + + +/* Draw a plasma effect */ +static void plasma(fb_fragment_t *fragment) +{ + static int32_t costab[FIXED_TRIG_LUT_SIZE], sintab[FIXED_TRIG_LUT_SIZE]; + static int initialized; + static unsigned rr, rr2, rr6, rr8, rr16, rr20, rr12; + + unsigned stride = fragment->stride / 4, width = fragment->width, height = fragment->height; + int fw2 = FIXED_NEW(width / 2), fh2 = FIXED_NEW(height / 2); + int x, y, cx, cy, dx2, dy2; + uint32_t *buf = fragment->buf; + color_t c = { .r = 0, .g = 0, .b = 0 }, cscale; + + if (!initialized) { + initialized = 1; + + init_plasma(costab, sintab); + } + + rr2 = rr * 2; + rr6 = rr * 6; + rr8 = rr * 8; + rr16 = rr * 16; + rr20 = rr * 20; + rr12 = rr * 12; + + /* vary the color channel intensities */ + cscale.r = FIXED_MULT(FIXED_COS(rr / 2), FIXED_NEW(64)) + FIXED_NEW(64); + cscale.g = FIXED_MULT(FIXED_COS(rr / 5), FIXED_NEW(64)) + FIXED_NEW(64); + cscale.b = FIXED_MULT(FIXED_COS(rr / 7), FIXED_NEW(64)) + FIXED_NEW(64); + + cx = FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr), fw2) + fw2); + cy = FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr2), fh2) + fh2); + + for (y = 0; y < height; y++) { + int y2 = y << 1; + int y4 = y << 2; + + dy2 = cy - y; + dy2 *= dy2; + + for (x = 0; x < width; x++, buf++) { + int v; + int hyp; + + dx2 = cx - x; + dx2 *= dx2; + + hyp = (dx2 + dy2) >> 10; /* XXX: technically this should be a sqrt(), but >> 10 is a whole lot faster. */ + + v = FIXED_MULT( ((FIXED_COS(rr8 + hyp * 5)) + + (FIXED_SIN(-rr16 + (x << 2))) + + (FIXED_COS(rr20 + y4))), + FIXED_EXP / 3); /* XXX: note these '/ 3' get optimized out. */ + c.r = FIXED_MULT(v, cscale.r) + cscale.r; + + v = FIXED_MULT( ((FIXED_COS(rr12 + (hyp << 2))) + + (FIXED_COS(rr6 + (x << 1))) + + (FIXED_SIN(rr16 + y2))), + FIXED_EXP / 3); + c.g = FIXED_MULT(v, cscale.g) + cscale.g; + + v = FIXED_MULT( ((FIXED_SIN(rr6 + hyp * 6)) + + (FIXED_COS(-rr12 + x * 5)) + + (FIXED_SIN(-rr6 + y2))), + FIXED_EXP / 3); + c.b = FIXED_MULT(v, cscale.b) + cscale.b; + + *buf = color2pixel(&c); + } + + buf += stride; + } + + rr += 3; +} + +rototiller_renderer_t plasma_renderer = { + .render = plasma, + .name = "plasma", + .description = "Oldskool plasma effect", + .author = "Vito Caputo ", + .license = "GPLv2", +}; -- cgit v1.2.3