joeylib2/docs/ApiDraw.adoc
2026-09-26 21:02:41 -05:00

226 lines
5.6 KiB
Text

== Drawing Primitives
Declared in `<joey/draw.h>`.
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.