/* * gfx_dbuf — double-buffering demo. * * Renders a moving rectangle by alternating between page 0 and page 1: * - Each frame: draw to the HIDDEN page, then flip visible to it. * - The page currently being displayed is never written to, so the * user only sees fully-rendered frames (no half-drawn artefacts, * no flicker from the per-frame clear). * * Indicators help verify the swap is actually happening: * - A small colour swatch in the top-right alternates each frame: * one shade when page 0 is shown, another when page 1. If the * box motion looks smooth and the swatch flickers between the two * shades at the animation rate, the swap is working. * * NOTE: each graphics screen has its OWN palette page (screen 0 → * palette 0, screen 1 → palette 1). We load the same palette into * both so the colours look identical regardless of which page is * currently visible. See memory/sprinter_graphics.md. * * Press any key to exit. */ #include #include #include #include static uint8_t palette[256 * 4]; #define COL_BLACK 0x00 #define COL_BG 0x20 #define COL_STRIPE 0x60 #define COL_TEXT 0xC0 #define COL_BOX 0xFF #define COL_PAGE0 0x40 #define COL_PAGE1 0xE0 static void make_palette(void) { for (int i = 0; i < 256; i++) { palette[i*4+0] = (uint8_t)i; palette[i*4+1] = (uint8_t)i; palette[i*4+2] = (uint8_t)i; palette[i*4+3] = 0; } } static void draw_frame(int box_x, int box_y, uint8_t page_indicator) { gfx_clear256(COL_BG); /* Static decoration — identical on both pages so the swap doesn't * flicker the chrome. */ gfx_fill_rect256(0, 0, GFX_WIDTH, 8, COL_STRIPE); gfx_fill_rect256(0, GFX_HEIGHT - 8, GFX_WIDTH, 8, COL_STRIPE); gfx_text256(8, 16, "double-buffering demo", COL_TEXT, COL_BG); gfx_text256(8, GFX_HEIGHT - 24, "press a key to exit", COL_TEXT, COL_BG); /* Page indicator — different shade for each page so a flickering * box here proves the swap is happening. */ gfx_fill_rect256(GFX_WIDTH - 24, 16, 12, 12, page_indicator ? COL_PAGE1 : COL_PAGE0); /* The animated box. */ gfx_fill_rect256(box_x, box_y, 40, 30, COL_BOX); gfx_rect256 (box_x, box_y, 40, 30, COL_BLACK); } int main(void) { make_palette(); uint8_t prev = gfx_init(GFX_MODE_320x256x256, 0); /* Each graphics screen has its own palette page (0→pal 0, 1→pal 1). * Load the same data into both so the visual swap is seamless. */ gfx_pal_load(0, 0, 0, palette); gfx_pal_load(1, 0, 0, palette); /* Clear both pages so the very first flip doesn't reveal garbage. */ gfx_set_draw_page(0); gfx_clear256(COL_BG); gfx_set_draw_page(1); gfx_clear256(COL_BG); /* Bouncing rect state. */ int box_x = 10; int box_y = 100; int dx = 3; int dy = 2; const int box_w = 40, box_h = 30; while (!kbhit()) { uint8_t hidden = 1 - gfx_get_visible_page(); gfx_set_draw_page(hidden); draw_frame(box_x, box_y, hidden); /* Wait for the next frame interrupt before flipping, so the * page swap lands during vertical retrace and the user never * sees a half-drawn frame. */ gfx_wait_vsync(); gfx_set_visible_page(hidden); /* Step the box; bounce off all four walls. */ box_x += dx; if (box_x < 0) { box_x = 0; dx = -dx; } if (box_x + box_w > GFX_WIDTH) { box_x = GFX_WIDTH - box_w; dx = -dx; } box_y += dy; if (box_y < 8) { box_y = 8; dy = -dy; } if (box_y + box_h > GFX_HEIGHT-8) { box_y = GFX_HEIGHT-8 - box_h; dy = -dy; } } (void)getch(); gfx_done(prev); puts("done"); return 0; }