diff options
-rw-r--r-- | modules/roto/roto.c | 231 | ||||
-rw-r--r-- | modules/roto/roto.h | 9 |
2 files changed, 240 insertions, 0 deletions
diff --git a/modules/roto/roto.c b/modules/roto/roto.c new file mode 100644 index 0000000..21e68b7 --- /dev/null +++ b/modules/roto/roto.c @@ -0,0 +1,231 @@ +#include <stdint.h> +#include <inttypes.h> +#include <math.h> + +#include "fb.h" +#include "rototiller.h" + +/* Copyright (C) 2016 Vito Caputo <vcaputo@pengaru.com> */ + +/* Some defines for the fixed-point stuff in render(). */ +#define FIXED_TRIG_LUT_SIZE 4096 /* size of the cos/sin look-up tables */ +#define FIXED_BITS 12 /* fractional bits */ +#define FIXED_EXP 4096 /* 2^FIXED_BITS */ +#define FIXED_COS(_rad) costab[_rad % FIXED_TRIG_LUT_SIZE] +#define FIXED_SIN(_rad) sintab[_rad % FIXED_TRIG_LUT_SIZE] +#define FIXED_MULT(_a, _b) ((_a * _b) >> FIXED_BITS) +#define FIXED_NEW(_i) (_i << FIXED_BITS) +#define FIXED_TO_INT(_f) ((_f) >> FIXED_BITS) + + +/* Draw a rotating checkered 256x256 texture into fragment. (32-bit version) */ +static void roto32(fb_fragment_t *fragment) +{ + static int32_t costab[FIXED_TRIG_LUT_SIZE], sintab[FIXED_TRIG_LUT_SIZE]; + static uint8_t texture[256][256]; + static int initialized; + static uint32_t colors[2]; + static unsigned r, rr; + + int y_cos_r, y_sin_r, x_cos_r, x_sin_r, x_cos_r_init, x_sin_r_init, cos_r, sin_r; + int x, y, stride = fragment->stride / 4, width = fragment->width, height = fragment->height; + uint8_t tx, ty; /* 256x256 texture; 8 bit texture indices to modulo via overflow. */ + uint32_t *buf = fragment->buf; + + if (!initialized) { + int i; + + initialized = 1; + + /* Generate simple checker pattern texture, nothing clever, feel free to play! */ + /* If you modify texture on every frame instead of only @ initialization you can + * produce some neat output. These values are indexed into colors[] below. */ + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) + texture[y][x] = 1; + for (; x < 256; x++) + texture[y][x] = 0; + } + for (; y < 256; y++) { + for (x = 0; x < 128; x++) + texture[y][x] = 0; + for (; x < 256; x++) + texture[y][x] = 1; + } + + /* 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); + } + } + + /* This is all done using fixed-point in the hopes of being faster, and yes assumptions + * are being made WRT the overflow of tx/ty as well, only tested on x86_64. */ + cos_r = FIXED_COS(r); + sin_r = FIXED_SIN(r); + + /* Vary the colors, this is just a mashup of sinusoidal rgb values. */ + colors[0] = ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr), FIXED_NEW(127))) + 128) << 16) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr / 2), FIXED_NEW(127))) + 128) << 8) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr / 3), FIXED_NEW(127))) + 128)); + + colors[1] = ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr / 2), FIXED_NEW(127))) + 128) << 16) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr / 2), FIXED_NEW(127))) + 128)) << 8 | + ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr), FIXED_NEW(127))) + 128) ); + + /* The dimensions are cut in half and negated to center the rotation. */ + /* The [xy]_{sin,cos}_r variables are accumulators to replace multiplication with addition. */ + x_cos_r_init = FIXED_MULT(-FIXED_NEW((width / 2)), cos_r); + x_sin_r_init = FIXED_MULT(-FIXED_NEW((width / 2)), sin_r); + + y_cos_r = FIXED_MULT(-FIXED_NEW((height / 2)), cos_r); + y_sin_r = FIXED_MULT(-FIXED_NEW((height / 2)), sin_r); + + for (y = 0; y < height; y++) { + + x_cos_r = x_cos_r_init; + x_sin_r = x_sin_r_init; + + for (x = 0; x < width; x++, buf++) { + + tx = FIXED_TO_INT(x_sin_r - y_cos_r); + ty = FIXED_TO_INT(y_sin_r + x_cos_r); + + *buf = colors[texture[ty][tx]]; + + x_cos_r += cos_r; + x_sin_r += sin_r; + } + + buf += stride; + y_cos_r += cos_r; + y_sin_r += sin_r; + } + + // This governs the rotation and color cycle. + r += FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr), FIXED_NEW(16))); + rr += 2; +} + + +/* Draw a rotating checkered 256x256 texture into fragment. (64-bit version) */ +static void roto64(fb_fragment_t *fragment) +{ + static int32_t costab[FIXED_TRIG_LUT_SIZE], sintab[FIXED_TRIG_LUT_SIZE]; + static uint8_t texture[256][256]; + static int initialized; + static uint32_t colors[2]; + static unsigned r, rr; + + int y_cos_r, y_sin_r, x_cos_r, x_sin_r, x_cos_r_init, x_sin_r_init, cos_r, sin_r; + int x, y, stride = fragment->stride / 8, width = fragment->width, height = fragment->height; + uint8_t tx, ty; /* 256x256 texture; 8 bit texture indices to modulo via overflow. */ + uint64_t *buf = (uint64_t *)fragment->buf; + + if (!initialized) { + int i; + + initialized = 1; + + /* Generate simple checker pattern texture, nothing clever, feel free to play! */ + /* If you modify texture on every frame instead of only @ initialization you can + * produce some neat output. These values are indexed into colors[] below. */ + for (y = 0; y < 128; y++) { + for (x = 0; x < 128; x++) + texture[y][x] = 1; + for (; x < 256; x++) + texture[y][x] = 0; + } + for (; y < 256; y++) { + for (x = 0; x < 128; x++) + texture[y][x] = 0; + for (; x < 256; x++) + texture[y][x] = 1; + } + + /* 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); + } + } + + /* This is all done using fixed-point in the hopes of being faster, and yes assumptions + * are being made WRT the overflow of tx/ty as well, only tested on x86_64. */ + cos_r = FIXED_COS(r); + sin_r = FIXED_SIN(r); + + /* Vary the colors, this is just a mashup of sinusoidal rgb values. */ + colors[0] = ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr), FIXED_NEW(127))) + 128) << 16) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr / 2), FIXED_NEW(127))) + 128) << 8) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr / 3), FIXED_NEW(127))) + 128)); + + colors[1] = ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr / 2), FIXED_NEW(127))) + 128) << 16) | + ((FIXED_TO_INT(FIXED_MULT(FIXED_COS(rr / 2), FIXED_NEW(127))) + 128)) << 8 | + ((FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr), FIXED_NEW(127))) + 128) ); + + /* The dimensions are cut in half and negated to center the rotation. */ + /* The [xy]_{sin,cos}_r variables are accumulators to replace multiplication with addition. */ + x_cos_r_init = FIXED_MULT(-FIXED_NEW((width / 2)), cos_r); + x_sin_r_init = FIXED_MULT(-FIXED_NEW((width / 2)), sin_r); + + y_cos_r = FIXED_MULT(-FIXED_NEW((height / 2)), cos_r); + y_sin_r = FIXED_MULT(-FIXED_NEW((height / 2)), sin_r); + + width /= 2; /* Since we're processing 64-bit words (2 pixels) at a time */ + + for (y = 0; y < height; y++) { + + x_cos_r = x_cos_r_init; + x_sin_r = x_sin_r_init; + + for (x = 0; x < width; x++, buf++) { + uint64_t p; + + tx = FIXED_TO_INT(x_sin_r - y_cos_r); + ty = FIXED_TO_INT(y_sin_r + x_cos_r); + + p = colors[texture[ty][tx]]; + + x_cos_r += cos_r; + x_sin_r += sin_r; + + tx = FIXED_TO_INT(x_sin_r - y_cos_r); + ty = FIXED_TO_INT(y_sin_r + x_cos_r); + + p |= (uint64_t)colors[texture[ty][tx]] << 32; + + *buf = p; + + x_cos_r += cos_r; + x_sin_r += sin_r; + } + + buf += stride; + y_cos_r += cos_r; + y_sin_r += sin_r; + } + + // This governs the rotation and color cycle. + r += FIXED_TO_INT(FIXED_MULT(FIXED_SIN(rr), FIXED_NEW(16))); + rr += 2; +} + + +rototiller_renderer_t roto32_renderer = { + .render = roto32, + .name = "roto32", + .description = "Tiled texture rotation (32-bit)", + .author = "Vito Caputo <vcaputo@pengaru.com>", + .license = "GPLv2", +}; + + +rototiller_renderer_t roto64_renderer = { + .render = roto64, + .name = "roto64", + .description = "Tiled texture rotation (64-bit)", + .author = "Vito Caputo <vcaputo@pengaru.com>", + .license = "GPLv2", +}; diff --git a/modules/roto/roto.h b/modules/roto/roto.h new file mode 100644 index 0000000..84a66a9 --- /dev/null +++ b/modules/roto/roto.h @@ -0,0 +1,9 @@ +#ifndef _ROTO_H +#define _ROTO_H + +#include "fb.h" + +void roto64(fb_fragment_t *fragment); +void roto32(fb_fragment_t *fragment); + +#endif |