== 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 colour indices. 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 colour index. Clearing to colour 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` |Colour 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` |Colour 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 colour 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` |Colour 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` |Colour 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` |Colour 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` |Centre. |`r` |`uint16_t` |Radius in pixels. |`colorIndex` |`uint8_t` |Colour 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` |Centre. |`r` |`uint16_t` |Radius in pixels. |`colorIndex` |`uint8_t` |Colour 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 colour reachable by north, south, east and west steps. A no-op if the start point is off-surface or already `newColor`. [cols="1,1,4", options="header"] |=== |Parameter |Type |Description |`s` |`jlSurfaceT *` |Target surface. |`x`, `y` |`int16_t` |Seed point. |`newColor` |`uint8_t` |Replacement colour 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 colour. Every reachable pixel that is not the boundary colour becomes `newColor`. This is the primitive for vector-art playback, such as Sierra-style picture drawing: outline a closed region with `jlDrawLine` in the boundary colour, 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 colour index. |`boundaryColor` |`uint8_t` |Colour that stops the fill. |=== *Returns:* nothing.