// Drawing primitive smoke test. Lays out a 2x2 grid of cells, each // exercising one family of primitives. On screen each cell should show // a clear visual signal that the underlying inner loops (C or ASM) // produced the expected pixel pattern. // // TL: drawPixel + drawLine (8-octant fan from cell center; pixel // row of all 16 colors along the cell's bottom edge). // TR: drawRect + fillRect (concentric outlines + filled blocks at // deliberately odd x / odd width to catch nibble-edge bugs). // BL: drawCircle + fillCircle (concentric outlines + a small filled // disk at center). // BR: tileCopy / tileCopyMasked / tileSnap+tilePaste / floodFill. // // Runs in HOST_MODE_TAKEOVER and holds the frame until the user // presses ESC / RETURN / SPACE. #include #include #define CELL_W 160 #define CELL_H 100 // Color slots (palette 0). Color 0 is the library-forced black. #define C_BG 0 #define C_BORDER 1 // white #define C_RED 2 #define C_GREEN 3 #define C_BLUE 4 #define C_YELLOW 5 #define C_CYAN 6 #define C_MAGENTA 7 #define C_ORANGE 8 #define C_GRAY 9 static void buildPalette(SurfaceT *screen); static void drawCellBorder(SurfaceT *screen, int16_t cx, int16_t cy); static void drawAllCellBorders(SurfaceT *screen); static void drawPrimitivesPixelLine(SurfaceT *screen); static void drawPrimitivesRect(SurfaceT *screen); static void drawPrimitivesCircle(SurfaceT *screen); static void drawPrimitivesTileFlood(SurfaceT *screen); static void waitForKey(void); static void buildPalette(SurfaceT *screen) { uint16_t colors[SURFACE_COLORS_PER_PALETTE]; // 16 distinct $0RGB entries. Index 0 is forced to black anyway. colors[0] = 0x000; colors[1] = 0xFFF; // white colors[2] = 0xF00; // red colors[3] = 0x0F0; // green colors[4] = 0x00F; // blue colors[5] = 0xFF0; // yellow colors[6] = 0x0FF; // cyan colors[7] = 0xF0F; // magenta colors[8] = 0xF80; // orange colors[9] = 0x888; // mid gray colors[10] = 0x800; colors[11] = 0x080; colors[12] = 0x008; colors[13] = 0x880; colors[14] = 0x088; colors[15] = 0x808; paletteSet(screen, 0, colors); scbSetRange(screen, 0, SURFACE_HEIGHT - 1, 0); } static void drawCellBorder(SurfaceT *screen, int16_t cx, int16_t cy) { drawRect(screen, cx, cy, CELL_W, CELL_H, C_BORDER); } static void drawAllCellBorders(SurfaceT *screen) { drawCellBorder(screen, 0, 0); drawCellBorder(screen, CELL_W, 0); drawCellBorder(screen, 0, CELL_H); drawCellBorder(screen, CELL_W, CELL_H); } // Top-left cell: drawPixel + drawLine. // // 8 lines fan out from the cell center (80, 50). Four are diagonal // (the new ASM Bresenham path) and four are axis-aligned (drawLine // routes those to fillRect). A horizontal row of 14 pixels along the // cell's bottom verifies drawPixel: each pixel uses a different color // index so the leftmost ones at color 0 are invisible (they are bg) // and 1..13 progress through the palette. static void drawPrimitivesPixelLine(SurfaceT *screen) { int16_t cx; int16_t cy; int16_t i; cx = CELL_W / 2; // 80 cy = CELL_H / 2; // 50 drawLine(screen, cx, cy, cx + 70, cy, C_RED); // E (horizontal) drawLine(screen, cx, cy, cx + 60, cy - 40, C_GREEN); // NE (diagonal) drawLine(screen, cx, cy, cx, cy - 45, C_BLUE); // N (vertical) drawLine(screen, cx, cy, cx - 60, cy - 40, C_YELLOW); // NW drawLine(screen, cx, cy, cx - 70, cy, C_CYAN); // W drawLine(screen, cx, cy, cx - 60, cy + 40, C_MAGENTA); // SW drawLine(screen, cx, cy, cx, cy + 45, C_ORANGE); // S drawLine(screen, cx, cy, cx + 60, cy + 40, C_GRAY); // SE // Pixel row: 14 single-pixel writes at consecutive x to exercise // both odd and even nibble paths. for (i = 0; i < 14; i++) { drawPixel(screen, (int16_t)(10 + i * 10), (int16_t)(CELL_H - 6), (uint8_t)((i + 1) & 0x0F)); } } // Top-right cell: drawRect + fillRect. // // Four nested rectangles with deliberately odd x/y/w/h to exercise // the partial-byte (nibble) edge handling in halFastFillRect. The // outermost is filled, the next outline-only, then filled with odd // width, then a 1-pixel-wide vertical bar (drawRect collapses to a // line via fillRect's 1-wide path). static void drawPrimitivesRect(SurfaceT *screen) { int16_t ox; ox = CELL_W; // cell origin x // Outer fill, even-aligned. fillRect(screen, ox + 8, 8, 144, 84, C_RED); // Inner outline, odd x to test partial-nibble edges. drawRect(screen, ox + 17, 17, 124, 64, C_YELLOW); // Odd width fill, odd x. fillRect(screen, ox + 25, 25, 35, 48, C_GREEN); // 1-pixel vertical bar (degenerate rect through fillRect 1-wide path). fillRect(screen, ox + 100, 25, 1, 48, C_BORDER); // Odd-x odd-w narrow bar to specifically hit hasLeading + hasTrailing // in halFastFillRect. fillRect(screen, ox + 75, 25, 7, 48, C_CYAN); } // Bottom-left cell: drawCircle + fillCircle. // // Concentric outlines at decreasing radii, alternating colors, plus a // small filled disk at the center. Center is at the cell midpoint. static void drawPrimitivesCircle(SurfaceT *screen) { int16_t cx; int16_t cy; cx = CELL_W / 2; cy = CELL_H + CELL_H / 2; drawCircle(screen, cx, cy, 45, C_BORDER); drawCircle(screen, cx, cy, 35, C_GREEN); drawCircle(screen, cx, cy, 25, C_YELLOW); drawCircle(screen, cx, cy, 15, C_CYAN); fillCircle(screen, cx, cy, 8, C_MAGENTA); } // Bottom-right cell: tile + flood fill. // // Top portion: a 16x16 colored block, then tileSnap one of its 8x8 // quadrants and tilePaste the captured tile to a neighbor block; // also tileCopy the same source quadrant to a third location to // exercise the full surface-to-surface path. Then a tileCopyMasked // case: paint a 2x1 (16x8) "stripe" containing a transparent color 0 // pattern interleaved with color, paste it over a solid backdrop with // transparent=0; the backdrop should show through the transparent // nibbles. // // Bottom portion: drawRect outlines a closed region, floodFillBounded // fills its interior with a different color, stopping at the outline. static void drawPrimitivesTileFlood(SurfaceT *screen) { int16_t ox; int16_t oy; int16_t bx; int16_t by; int16_t i; int16_t px; TileT snapBuf; ox = CELL_W; // 160 oy = CELL_H; // 100 // Source 16x16 block at (168, 108): a 4-quadrant pattern. fillRect(screen, ox + 8, oy + 8, 8, 8, C_RED); fillRect(screen, ox + 16, oy + 8, 8, 8, C_GREEN); fillRect(screen, ox + 8, oy + 16, 8, 8, C_BLUE); fillRect(screen, ox + 16, oy + 16, 8, 8, C_YELLOW); // tileSnap the top-left red quadrant (block bx=21, by=13) and // tilePaste it next to the 16x16 source as the 5th quadrant. bx = (int16_t)((ox + 8) / 8); by = (int16_t)((oy + 8) / 8); tileSnap(screen, (uint8_t)bx, (uint8_t)by, &snapBuf); tilePaste(screen, (uint8_t)(bx + 4), (uint8_t)by, &snapBuf); // tileCopy from the green quadrant onto a fresh location below. tileCopy(screen, (uint8_t)(bx + 4), (uint8_t)(by + 1), screen, (uint8_t)(bx + 1), (uint8_t)by); // tileCopyMasked test: build a "transparent" striped pattern at // (208, 132). The tile's source has color 0 in alternating // nibbles. Paste it onto a solid orange backdrop so transparent // nibbles let the orange show through. fillRect(screen, ox + 80, oy + 32, 16, 8, C_ORANGE); // backdrop // Build a vertical-stripe source at (240, 132): col-pixel = (px % 2 ? color : 0) for (i = 0; i < 8; i++) { for (px = 0; px < 16; px++) { drawPixel(screen, (int16_t)(ox + 112 + px), (int16_t)(oy + 32 + i), (uint8_t)((px & 1) ? C_MAGENTA : 0)); } } // tileCopyMasked: source at block (ox+112)/8 = 34..35, by 16 // -> dst at backdrop block (ox+80)/8 = 30..31, by 16 tileCopyMasked(screen, (uint8_t)((ox + 80) / 8), (uint8_t)((oy + 32) / 8), screen, (uint8_t)((ox + 112) / 8), (uint8_t)((oy + 32) / 8), 0); // Flood-fill region: a small bordered rectangle in the cell's // lower portion. Outline drawn in C_BORDER; floodFillBounded // from a point inside should fill with C_CYAN, stopping at the // border. drawRect(screen, ox + 16, oy + 60, 64, 32, C_BORDER); floodFillBounded(screen, (int16_t)(ox + 48), (int16_t)(oy + 76), C_CYAN, C_BORDER); // Plain floodFill: solid block then re-fill to a new color. fillRect(screen, ox + 96, oy + 60, 48, 32, C_GREEN); floodFill(screen, (int16_t)(ox + 120), (int16_t)(oy + 76), C_GRAY); } static void waitForKey(void) { joeyWaitForAnyKey(); } int main(void) { JoeyConfigT config; SurfaceT *screen; config.hostMode = HOST_MODE_TAKEOVER; config.codegenBytes = 8 * 1024; config.maxSurfaces = 4; config.audioBytes = 64UL * 1024; config.assetBytes = 128UL * 1024; if (!joeyInit(&config)) { fprintf(stderr, "joeyInit failed: %s\n", joeyLastError()); return 1; } screen = stageGet(); if (screen == NULL) { fprintf(stderr, "stageGet returned NULL\n"); joeyShutdown(); return 1; } buildPalette(screen); surfaceClear(screen, C_BG); drawAllCellBorders(screen); drawPrimitivesPixelLine(screen); drawPrimitivesRect(screen); drawPrimitivesCircle(screen); drawPrimitivesTileFlood(screen); stagePresent(); waitForKey(); joeyShutdown(); return 0; }