// 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: jlDrawPixel + jlDrawLine (8-octant fan from cell center; pixel // row of all 16 colors along the cell's bottom edge). // TR: jlDrawRect + jlFillRect (concentric outlines + filled blocks at // deliberately odd x / odd width to catch nibble-edge bugs). // BL: jlDrawCircle + jlFillCircle (concentric outlines + a small filled // disk at center). // BR: jlTileCopy / jlTileCopyMasked / jlTileSnap+jlTilePaste / jlFloodFill. // // 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(jlSurfaceT *screen); static void drawCellBorder(jlSurfaceT *screen, int16_t cx, int16_t cy); static void drawAllCellBorders(jlSurfaceT *screen); static void drawPrimitivesPixelLine(jlSurfaceT *screen); static void drawPrimitivesRect(jlSurfaceT *screen); static void drawPrimitivesCircle(jlSurfaceT *screen); static void drawPrimitivesTileFlood(jlSurfaceT *screen); static void waitForKey(void); static void buildPalette(jlSurfaceT *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; jlPaletteSet(screen, 0, colors); jlScbSetRange(screen, 0, SURFACE_HEIGHT - 1, 0); } static void drawCellBorder(jlSurfaceT *screen, int16_t cx, int16_t cy) { jlDrawRect(screen, cx, cy, CELL_W, CELL_H, C_BORDER); } static void drawAllCellBorders(jlSurfaceT *screen) { drawCellBorder(screen, 0, 0); drawCellBorder(screen, CELL_W, 0); drawCellBorder(screen, 0, CELL_H); drawCellBorder(screen, CELL_W, CELL_H); } // Top-left cell: jlDrawPixel + jlDrawLine. // // 8 lines fan out from the cell center (80, 50). Four are diagonal // (the new ASM Bresenham path) and four are axis-aligned (jlDrawLine // routes those to jlFillRect). A horizontal row of 14 pixels along the // cell's bottom verifies jlDrawPixel: 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(jlSurfaceT *screen) { int16_t cx; int16_t cy; int16_t i; cx = CELL_W / 2; // 80 cy = CELL_H / 2; // 50 jlDrawLine(screen, cx, cy, cx + 70, cy, C_RED); // E (horizontal) jlDrawLine(screen, cx, cy, cx + 60, cy - 40, C_GREEN); // NE (diagonal) jlDrawLine(screen, cx, cy, cx, cy - 45, C_BLUE); // N (vertical) jlDrawLine(screen, cx, cy, cx - 60, cy - 40, C_YELLOW); // NW jlDrawLine(screen, cx, cy, cx - 70, cy, C_CYAN); // W jlDrawLine(screen, cx, cy, cx - 60, cy + 40, C_MAGENTA); // SW jlDrawLine(screen, cx, cy, cx, cy + 45, C_ORANGE); // S jlDrawLine(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++) { jlDrawPixel(screen, (int16_t)(10 + i * 10), (int16_t)(CELL_H - 6), (uint8_t)((i + 1) & 0x0F)); } } // Top-right cell: jlDrawRect + jlFillRect. // // 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 (jlDrawRect collapses to a // line via jlFillRect's 1-wide path). static void drawPrimitivesRect(jlSurfaceT *screen) { int16_t ox; ox = CELL_W; // cell origin x // Outer fill, even-aligned. jlFillRect(screen, ox + 8, 8, 144, 84, C_RED); // Inner outline, odd x to test partial-nibble edges. jlDrawRect(screen, ox + 17, 17, 124, 64, C_YELLOW); // Odd width fill, odd x. jlFillRect(screen, ox + 25, 25, 35, 48, C_GREEN); // 1-pixel vertical bar (degenerate rect through jlFillRect 1-wide path). jlFillRect(screen, ox + 100, 25, 1, 48, C_BORDER); // Odd-x odd-w narrow bar to specifically hit hasLeading + hasTrailing // in halFastFillRect. jlFillRect(screen, ox + 75, 25, 7, 48, C_CYAN); } // Bottom-left cell: jlDrawCircle + jlFillCircle. // // Concentric outlines at decreasing radii, alternating colors, plus a // small filled disk at the center. Center is at the cell midpoint. static void drawPrimitivesCircle(jlSurfaceT *screen) { int16_t cx; int16_t cy; cx = CELL_W / 2; cy = CELL_H + CELL_H / 2; jlDrawCircle(screen, cx, cy, 45, C_BORDER); jlDrawCircle(screen, cx, cy, 35, C_GREEN); jlDrawCircle(screen, cx, cy, 25, C_YELLOW); jlDrawCircle(screen, cx, cy, 15, C_CYAN); jlFillCircle(screen, cx, cy, 8, C_MAGENTA); } // Bottom-right cell: tile + flood fill. // // Top portion: a 16x16 colored block, then jlTileSnap one of its 8x8 // quadrants and jlTilePaste the captured tile to a neighbor block; // also jlTileCopy the same source quadrant to a third location to // exercise the full surface-to-surface path. Then a jlTileCopyMasked // 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: jlDrawRect outlines a closed region, jlFloodFillBounded // fills its interior with a different color, stopping at the outline. static void drawPrimitivesTileFlood(jlSurfaceT *screen) { int16_t ox; int16_t oy; int16_t bx; int16_t by; int16_t i; int16_t px; jlTileT snapBuf; ox = CELL_W; // 160 oy = CELL_H; // 100 // Source 16x16 block at (168, 108): a 4-quadrant pattern. jlFillRect(screen, ox + 8, oy + 8, 8, 8, C_RED); jlFillRect(screen, ox + 16, oy + 8, 8, 8, C_GREEN); jlFillRect(screen, ox + 8, oy + 16, 8, 8, C_BLUE); jlFillRect(screen, ox + 16, oy + 16, 8, 8, C_YELLOW); // jlTileSnap the top-left red quadrant (block bx=21, by=13) and // jlTilePaste it next to the 16x16 source as the 5th quadrant. bx = (int16_t)((ox + 8) / 8); by = (int16_t)((oy + 8) / 8); jlTileSnap(screen, (uint8_t)bx, (uint8_t)by, &snapBuf); jlTilePaste(screen, (uint8_t)(bx + 4), (uint8_t)by, &snapBuf); // jlTileCopy from the green quadrant onto a fresh location below. jlTileCopy(screen, (uint8_t)(bx + 4), (uint8_t)(by + 1), screen, (uint8_t)(bx + 1), (uint8_t)by); // jlTileCopyMasked 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. jlFillRect(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++) { jlDrawPixel(screen, (int16_t)(ox + 112 + px), (int16_t)(oy + 32 + i), (uint8_t)((px & 1) ? C_MAGENTA : 0)); } } // jlTileCopyMasked: source at block (ox+112)/8 = 34..35, by 16 // -> dst at backdrop block (ox+80)/8 = 30..31, by 16 jlTileCopyMasked(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; jlFloodFillBounded // from a point inside should fill with C_CYAN, stopping at the // border. jlDrawRect(screen, ox + 16, oy + 60, 64, 32, C_BORDER); jlFloodFillBounded(screen, (int16_t)(ox + 48), (int16_t)(oy + 76), C_CYAN, C_BORDER); // Plain jlFloodFill: solid block then re-fill to a new color. jlFillRect(screen, ox + 96, oy + 60, 48, 32, C_GREEN); jlFloodFill(screen, (int16_t)(ox + 120), (int16_t)(oy + 76), C_GRAY); } static void waitForKey(void) { jlWaitForAnyKey(); } int main(void) { jlConfigT config; jlSurfaceT *screen; config.codegenBytes = 8 * 1024; config.maxSurfaces = 4; config.audioBytes = 64UL * 1024; if (!jlInit(&config)) { fprintf(stderr, "jlInit failed: %s\n", jlLastError()); return 1; } screen = jlStageGet(); if (screen == NULL) { fprintf(stderr, "jlStageGet returned NULL\n"); jlShutdown(); return 1; } buildPalette(screen); jlSurfaceClear(screen, C_BG); drawAllCellBorders(screen); drawPrimitivesPixelLine(screen); drawPrimitivesRect(screen); drawPrimitivesCircle(screen); drawPrimitivesTileFlood(screen); jlStagePresent(); waitForKey(); jlShutdown(); return 0; }