|
|
@ -1,30 +1,277 @@ |
|
|
|
#include <math.h> // Floating point math is dog slow on AVR, but I don't care. |
|
|
|
#include <string.h> |
|
|
|
/**
|
|
|
|
* Routines for drawing patterns generated by fixed point math functions. |
|
|
|
*/ |
|
|
|
|
|
|
|
#include <assert.h> |
|
|
|
#include <stdint.h> |
|
|
|
#include <string.h> |
|
|
|
#include "../config.h" |
|
|
|
#include "../pixel.h" |
|
|
|
#include "../util.h" |
|
|
|
#include "fpmath_patterns.h" |
|
|
|
|
|
|
|
/**
|
|
|
|
* \defgroup fixedpoint Fixed-point based animated plasma patterns. |
|
|
|
*/ |
|
|
|
/*@{*/ |
|
|
|
|
|
|
|
/**
|
|
|
|
* Double buffering helps in reducing the effect of visibly redrawing every |
|
|
|
* frame. With this option turned on, a frame is rendered into an off-screen |
|
|
|
* buffer first and then copied to the actual frame buffer in one piece. |
|
|
|
* However, given the borg's graphics architecture, half painted frames may |
|
|
|
* still occur, but they are barely noticeable with this option enabled. |
|
|
|
* |
|
|
|
* Turn this off (#undef DOUBLE_BUFFERING) if you prefer speed over beauty. |
|
|
|
*/ |
|
|
|
#define DOUBLE_BUFFERING |
|
|
|
#ifdef DOUBLE_BUFFERING |
|
|
|
#define BUFFER pixmap_buffer |
|
|
|
|
|
|
|
|
|
|
|
#ifdef LOW_PRECISION |
|
|
|
#undef LOW_PRECISION |
|
|
|
#endif |
|
|
|
|
|
|
|
#if NUM_COLS <= 16 && NUM_ROWS <= 16 |
|
|
|
/**
|
|
|
|
* Low precision means that we use Q10.5 values and 16 bit types for almost |
|
|
|
* every calculation (with multiplication and division as notable exceptions |
|
|
|
* as they and their interim results utilize 32 bit). |
|
|
|
* |
|
|
|
* Use this precision mode with care as image quality will suffer |
|
|
|
* noticeably. It produces leaner and faster code, though. This mode should |
|
|
|
* not be used with resolutions higher than 16x16 as overflows are likely to |
|
|
|
* occur in interim calculations. |
|
|
|
* |
|
|
|
* Normal precision (i.e. #undef LOW_PRECISION) conforms to Q7.8 with the |
|
|
|
* ability to store every interim result as Q23.8. Most operations like |
|
|
|
* square root, sine, cosine, multiplication etc. utilize 32 bit types. |
|
|
|
*/ |
|
|
|
#define LOW_PRECISION |
|
|
|
#endif |
|
|
|
|
|
|
|
#ifdef LOW_PRECISION |
|
|
|
/** This is the type we expect ordinary integers to be. */ |
|
|
|
typedef int16_t ordinary_int_t; |
|
|
|
/** This is the type which we use for fixed point values. */ |
|
|
|
typedef int16_t fixp_t; |
|
|
|
/** This type covers arguments of fixSin() and fixCos(). */ |
|
|
|
typedef int16_t fixp_trig_t; |
|
|
|
/** This type covers interim results of fixed point operations. */ |
|
|
|
typedef uint32_t fixp_interim_t; |
|
|
|
/** This type covers interim results of the fixed point sqrt() function. */ |
|
|
|
typedef uint16_t ufixp_interim_t; |
|
|
|
/** Amount of bits the fixed point sqrt() function can handle. */ |
|
|
|
#define SQRT_BITS 16 |
|
|
|
|
|
|
|
// NOTE: If you change the following values, don't forget to adapt the sine
|
|
|
|
// lookup table as well!
|
|
|
|
|
|
|
|
/** Multiply a number by this factor to convert it to a fixed point value.*/ |
|
|
|
#define FIX 32 |
|
|
|
/** Amount of fractional bits of a value (i.e. ceil(log_2(FIX))). */ |
|
|
|
#define FIX_FRACBITS 5 |
|
|
|
/**
|
|
|
|
* The amount of temporal quantization steps of the sine lookup table. It |
|
|
|
* must be a divisor of (FIX * 2 * pi) and this divisor must be divisable by |
|
|
|
* 4 itself. Approximate this value as close as possible to keep rounding |
|
|
|
* errors at a minimum. |
|
|
|
*/ |
|
|
|
#define FIX_SIN_COUNT 200 |
|
|
|
/** The rounded down quotient of (FIX * 2 * pi) and FIX_SIN_COUNT */ |
|
|
|
#define FIX_SIN_DIVIDER 1 |
|
|
|
|
|
|
|
/** Type of the lookup table elements. */ |
|
|
|
typedef uint8_t lut_t; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup table of fractional parts which model the first quarter of a |
|
|
|
* sine period. The rest of that period is calculated by mirroring those |
|
|
|
* values. These values are intended for Q5 types. |
|
|
|
*/ |
|
|
|
static lut_t const fix_sine_lut[FIX_SIN_COUNT / 4] = |
|
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7, |
|
|
|
8, 9, 10, 11, 12, 13, 14, 15, |
|
|
|
15, 16, 17, 18, 19, 20, 20, 21, |
|
|
|
22, 22, 23, 24, 24, 25, 26, 26, |
|
|
|
27, 27, 28, 28, 29, 29, 29, 30, |
|
|
|
30, 30, 31, 31, 31, 31, 31, 31, |
|
|
|
31, 31}; |
|
|
|
#else |
|
|
|
#define BUFFER pixmap |
|
|
|
/** This is the type we expect ordinary integers to be. */ |
|
|
|
typedef int16_t ordinary_int_t; |
|
|
|
/** This is the type which we use for fixed point values. */ |
|
|
|
typedef int16_t fixp_t; |
|
|
|
/** This type covers arguments of fixSin() and fixCos(). */ |
|
|
|
typedef int32_t fixp_trig_t; |
|
|
|
/** This type covers interim results of fixed point operations. */ |
|
|
|
typedef int32_t fixp_interim_t; |
|
|
|
/** This type covers interim results of the fixed point sqrt() function. */ |
|
|
|
typedef uint32_t ufixp_interim_t; |
|
|
|
/** Amount of bits the fixed point sqrt() function can handle. */ |
|
|
|
#define SQRT_BITS 32 |
|
|
|
|
|
|
|
// NOTE: If you change the following values, don't forget to adapt the sine
|
|
|
|
// lookup table as well!
|
|
|
|
|
|
|
|
/** Multiply a number by this factor to convert it to a fixed point value.*/ |
|
|
|
#define FIX 256 |
|
|
|
/** Amount of fractional bits of a value (i.e. ceil(log_2(FIX))). */ |
|
|
|
#define FIX_FRACBITS 8 |
|
|
|
/**
|
|
|
|
* The amount of temporal quantization steps of the sine lookup table. It |
|
|
|
* must be a divisor of (FIX * 2 * pi) and this divisor must be divisable by |
|
|
|
* 4 itself. Approximate this value as close as possible to keep rounding |
|
|
|
* errors at a minimum. |
|
|
|
*/ |
|
|
|
#define FIX_SIN_COUNT 200 |
|
|
|
/** The rounded down quotient of (FIX * 2 * pi) and FIX_SIN_COUNT */ |
|
|
|
#define FIX_SIN_DIVIDER 8 |
|
|
|
|
|
|
|
/** Type of the lookup table elements. */ |
|
|
|
typedef uint8_t lut_t; |
|
|
|
|
|
|
|
/**
|
|
|
|
* Lookup table of fractional parts which model the first quarter of a |
|
|
|
* sine period. The rest of that period is calculated by mirroring those |
|
|
|
* values. These values are intended for Q8 types. |
|
|
|
*/ |
|
|
|
static lut_t const fix_sine_lut[FIX_SIN_COUNT / 4] = |
|
|
|
{ 0, 9, 17, 24, 32, 40, 48, 56, |
|
|
|
64, 72, 79, 87, 94, 102, 109, 116, |
|
|
|
123, 130, 137, 144, 150, 157, 163, 169, |
|
|
|
175, 181, 186, 192, 197, 202, 207, 211, |
|
|
|
216, 220, 224, 228, 231, 235, 238, 240, |
|
|
|
243, 245, 247, 249, 251, 252, 253, 254, |
|
|
|
255, 255}; |
|
|
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/** The ordinary pi constant. */ |
|
|
|
#define PI 3.14159265358979323846 |
|
|
|
/** Fixed point version of (pi / 2). */ |
|
|
|
#define FIX_PI_2 ((fixp_t)(PI * FIX / 2)) |
|
|
|
/** Fixed point version of pi. */ |
|
|
|
#define FIX_PI ((fixp_t)(PI * FIX)) |
|
|
|
/** Fixed point version of (2 * pi). */ |
|
|
|
#define FIX_2PI ((fixp_t)(2 * PI * FIX)) |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Pointer to a function which return a value depending on two-dimensional |
|
|
|
* coordinates and a "step" value. |
|
|
|
* @param x x-coordinate |
|
|
|
* @param y y-coordinate |
|
|
|
* @param t a step value which changes for each frame, allowing for animations |
|
|
|
* @return |
|
|
|
* Scales an ordinary integer up to its fixed point format. |
|
|
|
* @param a an ordinary integer to be scaled up |
|
|
|
* @return The given value in fixed point format. |
|
|
|
*/ |
|
|
|
typedef unsigned char (*fpmath_pattern_func_t)(unsigned char const x, |
|
|
|
unsigned char const y, |
|
|
|
double t); |
|
|
|
inline static fixp_t fixScaleUp(ordinary_int_t a) |
|
|
|
{ |
|
|
|
return (fixp_t)a * FIX; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Scales a fixed point value down to an ordinary integer (omitting the |
|
|
|
* fractional part). |
|
|
|
* @param a fixed point value to be scaled down |
|
|
|
* @return The given value in fixed point format. |
|
|
|
*/ |
|
|
|
inline static ordinary_int_t fixScaleDown(fixp_t const a) |
|
|
|
{ |
|
|
|
return a / FIX; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Multiplies two fixed point values. |
|
|
|
* @param a operand a |
|
|
|
* @param b operand b |
|
|
|
* @return Product of a and b. |
|
|
|
*/ |
|
|
|
inline static fixp_interim_t fixMul(fixp_t const a, fixp_t const b) |
|
|
|
{ |
|
|
|
return ((fixp_interim_t)a * (fixp_interim_t)b) / FIX; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Divides two fixed point values. |
|
|
|
* @param a operand a |
|
|
|
* @param b operand b |
|
|
|
* @return Quotient of a and b. |
|
|
|
*/ |
|
|
|
inline static fixp_t fixDiv(fixp_interim_t const a, fixp_interim_t const b) |
|
|
|
{ |
|
|
|
return (a * FIX) / b; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fixed point variant of the sine function which receives a fixed point angle |
|
|
|
* (radian). It uses a lookup table which models the first quarter of a full |
|
|
|
* sine period and calculates the rest from that quarter. |
|
|
|
* @param angle fixed point radian value |
|
|
|
* @return Result of the sine function normalized to a range from -FIX to FIX. |
|
|
|
*/ |
|
|
|
static fixp_t fixSin(fixp_t const fAngle) |
|
|
|
{ |
|
|
|
// convert given angle to its corresponding lookup table quantization step
|
|
|
|
ordinary_int_t nNormAng = fAngle / FIX_SIN_DIVIDER; |
|
|
|
// trim that value so that it fits into a range between [0, FIX_SIN_COUNT]
|
|
|
|
nNormAng = (nNormAng - (nNormAng / FIX_SIN_COUNT * FIX_SIN_COUNT) + |
|
|
|
FIX_SIN_COUNT) % FIX_SIN_COUNT; |
|
|
|
|
|
|
|
uint8_t nIndex = nNormAng % (FIX_SIN_COUNT / 2); |
|
|
|
if (nIndex >= (FIX_SIN_COUNT / 4)) |
|
|
|
{ |
|
|
|
nIndex = (FIX_SIN_COUNT / 2 - 1) - nIndex; |
|
|
|
} |
|
|
|
assert(nIndex < (FIX_SIN_COUNT / 4)); |
|
|
|
|
|
|
|
return ((fixp_t)fix_sine_lut[nIndex]) * |
|
|
|
(nNormAng < (FIX_SIN_COUNT / 2) ? 1 : -1); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fixed point variant of the cosine function which takes a fixed point angle |
|
|
|
* (radian). It adds FIX_PI_2 to the given angle and consults the fixSin() |
|
|
|
* function for the final result. |
|
|
|
* @param angle fixed point radian value |
|
|
|
* @return Result of the cosine function normalized to a range from -FIX to FIX. |
|
|
|
*/ |
|
|
|
static fixp_t fixCos(fixp_t const angle) |
|
|
|
{ |
|
|
|
return fixSin(angle + FIX_PI_2); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Fixed point square root algorithm as proposed by Ken Turkowski: |
|
|
|
* http://www.realitypixels.com/turk/computergraphics/FixedSqrt.pdf
|
|
|
|
* @param radicant we want the square root of |
|
|
|
* @return The square root of the given value. |
|
|
|
*/ |
|
|
|
static fixp_t fixSqrt(ufixp_interim_t const a) |
|
|
|
{ |
|
|
|
ufixp_interim_t nRoot, nRemainingHigh, nRemainingLow, nTestDiv, nCount; |
|
|
|
nRoot = 0; // clear root
|
|
|
|
nRemainingHigh = 0; // clear high part of partial remainder
|
|
|
|
nRemainingLow = a; // get argument into low part of partial remainder
|
|
|
|
nCount = (SQRT_BITS / 2 - 1) + (FIX_FRACBITS >> 1); // load loop counter
|
|
|
|
do |
|
|
|
{ |
|
|
|
nRemainingHigh = |
|
|
|
(nRemainingHigh << 2) | (nRemainingLow >> (SQRT_BITS - 2)); |
|
|
|
nRemainingLow <<= 2; // get 2 bits of the argument
|
|
|
|
nRoot <<= 1; // get ready for the next bit in the root
|
|
|
|
nTestDiv = (nRoot << 1) + 1; // test radical
|
|
|
|
if (nRemainingHigh >= nTestDiv) |
|
|
|
{ |
|
|
|
nRemainingHigh -= nTestDiv; |
|
|
|
nRoot++; |
|
|
|
} |
|
|
|
} while (nCount-- != 0); |
|
|
|
return (nRoot); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
@ -33,41 +280,69 @@ typedef unsigned char (*fpmath_pattern_func_t)(unsigned char const x, |
|
|
|
* @param y1 y coordinate of the first point |
|
|
|
* @param x2 x coordinate of the second point |
|
|
|
* @param y2 y coordinate of the second point |
|
|
|
* @return distance between the points |
|
|
|
* @return The distance between the given coordinates. |
|
|
|
*/ |
|
|
|
static double dist(double x1, double y1, double x2, double y2) |
|
|
|
static fixp_t fixDist(fixp_t const x1, |
|
|
|
fixp_t const y1, |
|
|
|
fixp_t const x2, |
|
|
|
fixp_t const y2) |
|
|
|
{ |
|
|
|
return sqrt(((x1 - x2) * (x1 - x2)) + ((y1 - y2) * (y1 - y2))); |
|
|
|
return fixSqrt(fixMul((x1 - x2), (x1 - x2)) + fixMul((y1 - y2), (y1 - y2))); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws an animated two dimensional graph for a given function f(x,y,t). |
|
|
|
* @param t_start start value for the function's time variable |
|
|
|
* @param t_stop stop value for the function's time variable |
|
|
|
* @param t_delta value by which the function's timing variable gets incremented |
|
|
|
* @param frame_delay frame delay in ms |
|
|
|
* @param fpPattern function which generates a pattern depending on x, y, t |
|
|
|
* This pointer type covers functions which return a brightness value for the |
|
|
|
* given coordinates and a "step" value. This actually results in a more or less |
|
|
|
* "beautiful" pattern. |
|
|
|
* @param x x-coordinate |
|
|
|
* @param y y-coordinate |
|
|
|
* @param t step value which changes for each frame, allowing for animations |
|
|
|
* @param r pointer to persistent data required by the pattern function |
|
|
|
* @return The brightness value (0 < n <= NUM_PLANES) of the given coordinate. |
|
|
|
*/ |
|
|
|
typedef unsigned char (*fpmath_pattern_func_t)(unsigned char const x, |
|
|
|
unsigned char const y, |
|
|
|
fixp_t const t, |
|
|
|
void *const r); |
|
|
|
|
|
|
|
#ifdef DOUBLE_BUFFERING |
|
|
|
# define BUFFER pixmap_buffer |
|
|
|
#else |
|
|
|
# define BUFFER pixmap |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws an animated two dimensional graph for a given function f(x, y, t). |
|
|
|
* @param t_start start value for the function's step variable |
|
|
|
* @param t_stop stop value for the function's step variable |
|
|
|
* @param t_delta value by which the function's step variable gets incremented |
|
|
|
* @param frame_delay frame delay in milliseconds |
|
|
|
* @param fpPattern function which generates a pattern depending on x, y and t |
|
|
|
* @param r pointer to persistent data required by the fpPattern function |
|
|
|
*/ |
|
|
|
static void fpmath_pattern(double const t_start, |
|
|
|
double const t_stop, |
|
|
|
double const t_delta, |
|
|
|
unsigned int const frame_delay, |
|
|
|
fpmath_pattern_func_t fpPattern) |
|
|
|
static void fixPattern(fixp_t const t_start, |
|
|
|
fixp_t const t_stop, |
|
|
|
fixp_t const t_delta, |
|
|
|
int const frame_delay, |
|
|
|
fpmath_pattern_func_t fpPattern, |
|
|
|
void *r) |
|
|
|
{ |
|
|
|
#ifdef DOUBLE_BUFFERING |
|
|
|
// double buffering to reduce half painted pictures
|
|
|
|
unsigned char pixmap_buffer[NUMPLANE][NUM_ROWS][LINEBYTES]; |
|
|
|
#endif |
|
|
|
|
|
|
|
for (double t = t_start; t < t_stop; t += t_delta) |
|
|
|
for (fixp_t t = t_start; t < t_stop; t += t_delta) |
|
|
|
{ |
|
|
|
for (unsigned char y = 0; y < NUM_ROWS; ++y) |
|
|
|
{ |
|
|
|
unsigned char nChunk[NUMPLANE + 1][LINEBYTES] = {{0}}; |
|
|
|
for (unsigned char x = 0; x < (LINEBYTES * 8); ++x) |
|
|
|
{ |
|
|
|
nChunk[fpPattern(x, y, t) - 1][x / 8u] |= shl_table[x % 8u]; |
|
|
|
assert (y < 16); |
|
|
|
nChunk[fpPattern(x, y, t, r) - 1][x / 8u] |= shl_table[x % 8u]; |
|
|
|
} |
|
|
|
for (unsigned char p = NUMPLANE; p--;) |
|
|
|
{ |
|
|
@ -89,71 +364,133 @@ static void fpmath_pattern(double const t_start, |
|
|
|
|
|
|
|
|
|
|
|
#ifdef ANIMATION_PLASMA |
|
|
|
#define PLASMA_X (1.0 / (NUM_COLS / (2.0 * M_PI))) |
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws a simple plasma like pattern. |
|
|
|
* This type maintains values relevant for the Plasma animation which need to be |
|
|
|
* persistent over consecutive invocations. |
|
|
|
*/ |
|
|
|
static unsigned char fpmath_plasma(unsigned char x, unsigned char y, double t) |
|
|
|
typedef struct fixp_plasma_s |
|
|
|
{ |
|
|
|
fixp_t fFunc1[NUM_COLS]; /**< Result of 1st trig. func. depending on x. */ |
|
|
|
fixp_t fFunc2CosArg; /**< Arg. of 2st trig. func. depending on the frame. */ |
|
|
|
fixp_t fFunc2SinArg; /**< Arg. of 2st trig. func. depending on the frame. */ |
|
|
|
} fixp_plasma_t; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws a plasma like pattern (sort of... four shades of grey are pretty |
|
|
|
* scarce for a neat plasma animation). |
|
|
|
* @param x x-coordinate |
|
|
|
* @param y y-coordinate |
|
|
|
* @param t step value which changes for each frame, allowing for animations |
|
|
|
* @param r pointer to persistent interim results |
|
|
|
* @return The brightness value (0 < n <= NUM_PLANES) of the given coordinate. |
|
|
|
*/ |
|
|
|
static unsigned char fixAnimPlasma(unsigned char const x, |
|
|
|
unsigned char const y, |
|
|
|
fixp_t const t, |
|
|
|
void *const r) |
|
|
|
{ |
|
|
|
assert(x < NUM_COLS); |
|
|
|
assert(y < NUM_ROWS); |
|
|
|
|
|
|
|
static double fFunc1[NUM_COLS]; |
|
|
|
static double fFunc2CosArg; |
|
|
|
static double fFunc2SinArg; |
|
|
|
// scaling factor
|
|
|
|
static fixp_t const fPlasmaX = (2 * PI * FIX) / NUM_COLS; |
|
|
|
|
|
|
|
// reentrant data
|
|
|
|
fixp_plasma_t *const p = (fixp_plasma_t *)r; |
|
|
|
|
|
|
|
if (x == 0 && y == 0) |
|
|
|
{ |
|
|
|
fFunc2CosArg = NUM_ROWS * cos(t) + NUM_ROWS; |
|
|
|
fFunc2SinArg = NUM_COLS * sin(t) + NUM_COLS; |
|
|
|
p->fFunc2CosArg = NUM_ROWS * fixCos(t) + fixScaleUp(NUM_ROWS); |
|
|
|
p->fFunc2SinArg = NUM_COLS * fixSin(t) + fixScaleUp(NUM_COLS); |
|
|
|
} |
|
|
|
if (y == 0) |
|
|
|
{ |
|
|
|
fFunc1[x] = sin(x * PLASMA_X + t); |
|
|
|
p->fFunc1[x] = fixSin(fixMul(fixScaleUp(x), fPlasmaX) + t); |
|
|
|
} |
|
|
|
|
|
|
|
return (fFunc1[x] + sin(dist(x, y, fFunc2SinArg, fFunc2CosArg) * PLASMA_X) |
|
|
|
+ 2) * (NUMPLANE - 1) / 2; |
|
|
|
fixp_t const fFunc2 = fixSin(fixMul(fixDist(fixScaleUp(x), fixScaleUp(y), |
|
|
|
p->fFunc2SinArg, p->fFunc2CosArg), fPlasmaX)); |
|
|
|
|
|
|
|
uint8_t const nRes = fixScaleDown(fixDiv(fixMul(p->fFunc1[x] + fFunc2 + |
|
|
|
fixScaleUp(2), fixScaleUp(NUMPLANE - 1)), fixScaleUp(2))); |
|
|
|
assert (nRes <= 3); |
|
|
|
|
|
|
|
return nRes; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void plasma(void) |
|
|
|
{ |
|
|
|
fixp_plasma_t r; |
|
|
|
#ifndef __AVR__ |
|
|
|
fpmath_pattern(0.0, 75, 0.1, 80, fpmath_plasma); |
|
|
|
fixPattern(0, fixScaleUp(75), 0.1 * FIX, 80, fixAnimPlasma, &r); |
|
|
|
#else |
|
|
|
fpmath_pattern(0.0, 60.0, 0.1, 1, fpmath_plasma); |
|
|
|
#endif |
|
|
|
fixPattern(0, fixScaleUp(60), 0.1 * FIX, 1, fixAnimPlasma, &r); |
|
|
|
#endif /* __AVR__ */ |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
#endif /* ANIMATION_PLASMA */ |
|
|
|
|
|
|
|
|
|
|
|
#ifdef ANIMATION_PSYCHEDELIC |
|
|
|
|
|
|
|
/**
|
|
|
|
* This type maintains values relevant for the Psychedelic animation which need |
|
|
|
* to be persistent over consecutive invocations. |
|
|
|
*/ |
|
|
|
typedef struct fixp_psychedelic_s |
|
|
|
{ |
|
|
|
fixp_t fCos; /** column factor for the circle calculation */ |
|
|
|
fixp_t fSin; /** row factor for the circle calculation */ |
|
|
|
fixp_interim_t ft10; /** value involved in rotating the animation's center*/ |
|
|
|
} fixp_psychedelic_t; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Draws flowing circular waves with a rotating center. |
|
|
|
* @param x x-coordinate |
|
|
|
* @param y y-coordinate |
|
|
|
* @param t step value which changes for each frame, allowing for animations |
|
|
|
* @param r pointer to persistent interim results |
|
|
|
* @return The brightness value (0 < n <= NUM_PLANES) of the given coordinate. |
|
|
|
*/ |
|
|
|
static unsigned char fpmath_psycho(unsigned char x, unsigned char y, double t) |
|
|
|
static unsigned char fixAnimPsychedelic(unsigned char const x, |
|
|
|
unsigned char const y, |
|
|
|
fixp_t const t, |
|
|
|
void *const r) |
|
|
|
{ |
|
|
|
assert(x < NUM_COLS); |
|
|
|
assert(y < NUM_ROWS); |
|
|
|
fixp_psychedelic_t *p = (fixp_psychedelic_t *)r; |
|
|
|
|
|
|
|
static double fCosinus; |
|
|
|
static double fSinus; |
|
|
|
static double t10; |
|
|
|
if (x == 0 && y == 0) |
|
|
|
{ |
|
|
|
fCosinus = NUM_COLS * cos(t); |
|
|
|
fSinus = NUM_ROWS * sin(t); |
|
|
|
t10 = t * 10; |
|
|
|
p->fCos = NUM_COLS/2 * fixCos(t); |
|
|
|
p->fSin = NUM_ROWS/2 * fixSin(t); |
|
|
|
p->ft10 = fixMul(t, fixScaleUp(10)); |
|
|
|
} |
|
|
|
return (sin(dist(x, y, fCosinus, fSinus) - t10) + 1) * (NUMPLANE - 1); |
|
|
|
|
|
|
|
uint8_t const nResult = |
|
|
|
fixScaleDown(fixMul(fixSin((fixp_interim_t)fixDist(fixScaleUp(x), |
|
|
|
fixScaleUp(y), p->fCos, p->fSin) - p->ft10) + fixScaleUp(1), |
|
|
|
fixScaleUp(NUMPLANE - 1))); |
|
|
|
assert(nResult <= NUMPLANE); |
|
|
|
|
|
|
|
return nResult; |
|
|
|
} |
|
|
|
|
|
|
|
void psychedelic(void) |
|
|
|
{ |
|
|
|
fixp_psychedelic_t r; |
|
|
|
#ifndef __AVR__ |
|
|
|
fpmath_pattern(0.0, 75, 0.1, 80, fpmath_psycho); |
|
|
|
fixPattern(0, fixScaleUp(75), 0.1 * FIX, 80, fixAnimPsychedelic, &r); |
|
|
|
#else |
|
|
|
fpmath_pattern(0.0, 60.0, 0.1, 1, fpmath_psycho); |
|
|
|
#endif |
|
|
|
fixPattern(0, fixScaleUp(60), 0.1 * FIX, 15, fixAnimPsychedelic, &r); |
|
|
|
#endif /* __AVR__ */ |
|
|
|
} |
|
|
|
#endif |
|
|
|
|
|
|
|
#endif /* ANIMATION_PSYCHEDELIC */ |
|
|
|
|
|
|
|
/*@}*/ |
|
|
|