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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#include <stdint.h>
#include <inttypes.h>
#include <math.h>
#include "fb.h"
#include "rototiller.h"
/* Copyright (C) 2017 Vito Caputo <vcaputo@pengaru.com> */
#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 <vcaputo@pengaru.com>",
.license = "GPLv2",
};
|