== Drawing Primitives Declared in ``. All primitives clip to the surface rectangle. Out-of-bounds draws are silent no-ops, never errors, and there are no unclipped variants in the public API -- you cannot corrupt memory by drawing off the edge. Every primitive marks the rows it touched, so `jlStagePresent` knows what to copy. Primitives work in color indices, and use only the low 4 bits of one. Per-scanline palette resolution happens only at display time, so drawing does not care which palette a line uses. === jlSurfaceClear [source,c] ---- void jlSurfaceClear(jlSurfaceT *s, uint8_t colorIndex); ---- Fills the whole surface with one color index. Clearing to color 0 is a legitimate clear-to-black, not a skipped no-op. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlDrawPixel [source,c] ---- void jlDrawPixel(jlSurfaceT *s, int16_t x, int16_t y, uint8_t colorIndex); ---- Plots one pixel. Off-surface coordinates are no-ops. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Position. Valid range is 0..319 and 0..199. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlSamplePixel [source,c] ---- uint8_t jlSamplePixel(const jlSurfaceT *s, int16_t x, int16_t y); ---- Reads one pixel. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`const jlSurfaceT *` |Source surface. |`x`, `y` |`int16_t` |Position. |=== *Returns:* the color index at that position, or 0 for an off-surface read. === jlDrawLine [source,c] ---- void jlDrawLine(jlSurfaceT *s, int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint8_t colorIndex); ---- Draws a Bresenham line. Both endpoints are inclusive. Off-surface pixels are skipped individually, so a line that crosses the edge draws its visible part; a line entirely off-surface draws nothing. Horizontal and vertical runs take fast paths. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x0`, `y0` |`int16_t` |Start point, inclusive. |`x1`, `y1` |`int16_t` |End point, inclusive. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlDrawRect [source,c] ---- void jlDrawRect(jlSurfaceT *s, int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t colorIndex); ---- Draws a one-pixel-wide rectangle outline. A 1xN or Nx1 rectangle degenerates to a line, and 1x1 to a single pixel. Zero dimensions are no-ops. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Top-left corner. |`w`, `h` |`uint16_t` |Size in pixels. Zero is a no-op. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlFillRect [source,c] ---- void jlFillRect(jlSurfaceT *s, int16_t x, int16_t y, uint16_t w, uint16_t h, uint8_t colorIndex); ---- Fills a solid rectangle. Zero dimensions are no-ops. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Top-left corner. |`w`, `h` |`uint16_t` |Size in pixels. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlDrawCircle [source,c] ---- void jlDrawCircle(jlSurfaceT *s, int16_t cx, int16_t cy, uint16_t r, uint8_t colorIndex); ---- Draws a circle outline using the Bresenham midpoint algorithm. A radius of 0 plots a single pixel. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`cx`, `cy` |`int16_t` |Center. |`r` |`uint16_t` |Radius in pixels. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlFillCircle [source,c] ---- void jlFillCircle(jlSurfaceT *s, int16_t cx, int16_t cy, uint16_t r, uint8_t colorIndex); ---- Fills a disk, emitting one span per scanline using midpoint symmetry. A radius of 0 plots a single pixel. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`cx`, `cy` |`int16_t` |Center. |`r` |`uint16_t` |Radius in pixels. |`colorIndex` |`uint8_t` |Color index 0..15. |=== *Returns:* nothing. === jlFloodFill [source,c] ---- void jlFloodFill(jlSurfaceT *s, int16_t x, int16_t y, uint8_t newColor); ---- Flood-fills a 4-connected region, replacing every pixel of the original color reachable by north, south, east, and west steps. A no-op if the start point is off-surface or already `newColor`. The fill keeps a 512-entry stack of spans still to visit, and a region complex enough to need more is left partly filled, the same way on every port. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Seed point. |`newColor` |`uint8_t` |Replacement color index. |=== *Returns:* nothing. === jlFloodFillBounded [source,c] ---- void jlFloodFillBounded(jlSurfaceT *s, int16_t x, int16_t y, uint8_t newColor, uint8_t boundaryColor); ---- Flood-fills a 4-connected region, stopping at pixels of `boundaryColor` rather than at pixels differing from the seed color. Every reachable pixel that is not the boundary color becomes `newColor`. Pixels that are `newColor` already stop the fill too, so a region behind them is not reached, and a start on either color does nothing. The 512-entry span stack of `jlFloodFill` applies. This is the primitive for vector-art playback, such as Sierra-style picture drawing: outline a closed region with `jlDrawLine` in the boundary color, then fill it with this. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Seed point. |`newColor` |`uint8_t` |Replacement color index. |`boundaryColor` |`uint8_t` |Color that stops the fill. |=== *Returns:* nothing.