drawing routine improved (faster + eliminated 38 bytes), double buffering now mandatory

This commit is contained in:
Christian Kroll 2012-08-22 23:34:55 +00:00
parent f97edbfa34
commit df83dbb8ac
2 changed files with 51 additions and 57 deletions

View File

@ -59,8 +59,6 @@ comment "Animations"
mainmenu_option next_comment mainmenu_option next_comment
comment "Fixed-point math patterns" comment "Fixed-point math patterns"
bool "Double Buffering" FP_DOUBLE_BUFFERING 1
bool "Plasma" ANIMATION_PLASMA $ANIMATION_FIXEDPOINT bool "Plasma" ANIMATION_PLASMA $ANIMATION_FIXEDPOINT
int "Additional Frame Delay (in ms) For Plasma" FP_PLASMA_DELAY 1 int "Additional Frame Delay (in ms) For Plasma" FP_PLASMA_DELAY 1

View File

@ -11,7 +11,6 @@
#include <assert.h> #include <assert.h>
#include <stdint.h> #include <stdint.h>
#include <string.h>
#include "../config.h" #include "../config.h"
#include "../pixel.h" #include "../pixel.h"
#include "../util.h" #include "../util.h"
@ -19,24 +18,6 @@
#ifdef DOXYGEN #ifdef DOXYGEN
/**
* 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 if you prefer speed over beauty.
*/
#define FP_DOUBLE_BUFFERING
#endif DOXYGEN
#ifdef FP_LOW_PRECISION
#undef FP_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 * Low precision means that we use Q10.5 values and 16 bit types for almost
* every calculation (with multiplication and division as notable exceptions * every calculation (with multiplication and division as notable exceptions
@ -52,8 +33,20 @@
* square root, sine, cosine, multiplication etc. utilize 32 bit types. * square root, sine, cosine, multiplication etc. utilize 32 bit types.
*/ */
#define FP_LOW_PRECISION #define FP_LOW_PRECISION
#endif /* DOXYGEN */
#ifdef FP_LOW_PRECISION
#undef FP_LOW_PRECISION
#endif #endif
// low precision for displays where each dimension is less than or equal to 16
#if NUM_COLS <= 16 && NUM_ROWS <= 16
#define FP_LOW_PRECISION
#endif
#ifdef FP_LOW_PRECISION #ifdef FP_LOW_PRECISION
/** This is the type we expect ordinary integers to be. */ /** This is the type we expect ordinary integers to be. */
typedef int16_t ordinary_int_t; typedef int16_t ordinary_int_t;
@ -330,12 +323,6 @@ typedef unsigned char (*fpmath_pattern_func_t)(unsigned char const x,
fixp_t const t, fixp_t const t,
void *const r); void *const r);
#ifdef FP_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). * Draws an animated two dimensional graph for a given function f(x, y, t).
@ -346,42 +333,51 @@ typedef unsigned char (*fpmath_pattern_func_t)(unsigned char const x,
* @param fpPattern Function which generates a pattern depending on x, y and t. * @param fpPattern Function which generates a pattern depending on x, y and t.
* @param r A pointer to persistent data required by the fpPattern function. * @param r A pointer to persistent data required by the fpPattern function.
*/ */
static void fixPattern(fixp_t const t_start, static void fixDrawPattern(fixp_t const t_start,
fixp_t const t_stop, fixp_t const t_stop,
fixp_t const t_delta, fixp_t const t_delta,
int const frame_delay, int const frame_delay,
fpmath_pattern_func_t fpPattern, fpmath_pattern_func_t fpPattern,
void *r) void *r)
{ {
#ifdef FP_DOUBLE_BUFFERING
// double buffering to reduce half painted pictures
unsigned char pixmap_buffer[NUMPLANE][NUM_ROWS][LINEBYTES];
#endif
for (fixp_t t = t_start; t < t_stop; t += t_delta) for (fixp_t t = t_start; t < t_stop; t += t_delta)
{ {
// For performance reasons we draw the pattern to an off-screen buffer
// without distributing bits of higher planes down to lower ones. This
// is done afterwards when the off-screen contents are copied to the
// actual frame buffer.
unsigned char pOffScreen[NUMPLANE + 1][NUM_ROWS][LINEBYTES] = {{{0}}};
for (unsigned char y = 0; y < NUM_ROWS; ++y) for (unsigned char y = 0; y < NUM_ROWS; ++y)
{ {
unsigned char nChunk[NUMPLANE + 1][LINEBYTES] = {{0}}; for (unsigned char x = 0; x < (LINEBYTES * 8u); ++x)
for (unsigned char x = 0; x < (LINEBYTES * 8); ++x)
{ {
assert (y < 16); pOffScreen[fpPattern(x, y, t, r)][y][x / 8] |= shl_table[x % 8];
nChunk[fpPattern(x, y, t, r) - 1][x / 8u] |= shl_table[x % 8u];
}
for (unsigned char p = NUMPLANE; p--;)
{
for (unsigned char col = LINEBYTES; col--;)
{
nChunk[p][col] |= nChunk[p + 1][col];
BUFFER[p][y][col] = nChunk[p][col];
}
} }
} }
#ifdef FP_DOUBLE_BUFFERING // better safe than sorry
memcpy(pixmap, pixmap_buffer, sizeof(pixmap)); #if ((NUM_ROWS * LINEBYTES) < 256)
typedef unsigned char bitmap_offset_t;
#else
typedef unsigned int bitmap_offset_t;
#endif #endif
// Here we transcribe the off-screen contents to the actual frame buffer
// by distributing down 8 bits in parallel (per iteration).
for (bitmap_offset_t nOffset = sizeof(pixmap[0]); nOffset--;)
{
// for whatever reason, gcc produces leaner code if "p" is of type
// "unsigned int" as opposed to "unsigned char"
for (unsigned int p = NUMPLANE; p--;)
{
(&pixmap[p][0][0])[nOffset] =
(&pOffScreen[p + 1][0][0])[nOffset];
(&pOffScreen[p][0][0])[nOffset] |=
(&pOffScreen[p + 1][0][0])[nOffset];
}
}
// wait a moment to ensure that the current frame is visible
wait(frame_delay); wait(frame_delay);
} }
} }
@ -471,12 +467,12 @@ void plasma(void)
{ {
fixp_plasma_t r; fixp_plasma_t r;
#ifndef __AVR__ #ifndef __AVR__
fixPattern(0, fixScaleUp(75), 0.1 * FIX, 80, fixAnimPlasma, &r); fixDrawPattern(0, fixScaleUp(75), 0.1 * FIX, 15, fixAnimPlasma, &r);
#else #else
#ifndef FP_PLASMA_DELAY #ifndef FP_PLASMA_DELAY
#define FP_PLASMA_DELAY 1 #define FP_PLASMA_DELAY 1
#endif #endif
fixPattern(0, fixScaleUp(60), 0.1 * FIX, fixDrawPattern(0, fixScaleUp(60), 0.1 * FIX,
FP_PLASMA_DELAY, fixAnimPlasma, &r); FP_PLASMA_DELAY, fixAnimPlasma, &r);
#endif /* __AVR__ */ #endif /* __AVR__ */
} }
@ -539,12 +535,12 @@ void psychedelic(void)
{ {
fixp_psychedelic_t r; fixp_psychedelic_t r;
#ifndef __AVR__ #ifndef __AVR__
fixPattern(0, fixScaleUp(75), 0.1 * FIX, 80, fixAnimPsychedelic, &r); fixDrawPattern(0, fixScaleUp(75), 0.1 * FIX, 30, fixAnimPsychedelic, &r);
#else #else
#ifndef FP_PSYCHO_DELAY #ifndef FP_PSYCHO_DELAY
#define FP_PSYCHO_DELAY 15 #define FP_PSYCHO_DELAY 15
#endif #endif
fixPattern(0, fixScaleUp(60), 0.1 * FIX, FP_PSYCHO_DELAY, fixDrawPattern(0, fixScaleUp(60), 0.1 * FIX, FP_PSYCHO_DELAY,
fixAnimPsychedelic, &r); fixAnimPsychedelic, &r);
#endif /* __AVR__ */ #endif /* __AVR__ */
} }