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

229 lines
6 KiB
Text

== Surfaces and Presenting
Declared in `<joey/surface.h>` and `<joey/present.h>`.
A surface is a 320x200 16-colour image with its own 200-entry SCB table and its
own 16x16 palette set. Storage is target-native -- chunky 4bpp on IIgs and DOS,
planar on Amiga, ST and X68000 -- but every entry point speaks in colour
indices, so your code never sees the difference.
=== Constants
[cols="3,1,4", options="header"]
|===
|Name |Value |Meaning
|`SURFACE_WIDTH` |320 |Surface width in pixels.
|`SURFACE_HEIGHT` |200 |Surface height in pixels.
|`SURFACE_BYTES_PER_ROW` |160 |Bytes per row in chunky 4bpp form.
|`SURFACE_PIXELS_SIZE` |32000 |Total pixel bytes.
|`SURFACE_PALETTE_COUNT` |16 |Palettes per surface.
|`SURFACE_COLORS_PER_PALETTE` |16 |Colours per palette.
|`SURFACE_PALETTE_ENTRIES` |256 |Total palette entries per surface.
|===
=== jlSurfaceT
[source,c]
----
typedef struct jlSurfaceT jlSurfaceT;
----
Opaque. Obtain one from `jlSurfaceCreate`, `jlStageGet` or a loader.
=== jlSurfaceCreate
[source,c]
----
jlSurfaceT *jlSurfaceCreate(void);
----
Allocates a new offscreen surface.
*Parameters:* none.
*Returns:* the surface, or `NULL` on failure (`jlLastError()` explains why).
=== jlSurfaceDestroy
[source,c]
----
void jlSurfaceDestroy(jlSurfaceT *s);
----
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`s` |`jlSurfaceT *` |Surface to release. `NULL` is a no-op, and passing the
stage is also a no-op -- the library owns it.
|===
*Returns:* nothing.
=== jlStageGet
[source,c]
----
jlSurfaceT *jlStageGet(void);
----
Returns the library-owned stage: the back buffer that `jlStagePresent` flips to
the display. Always valid between `jlInit` and `jlShutdown`.
On the IIgs the stage's pixel buffer is pinned to bank `$01` Super Hi-Res space
with shadowing inhibited, so writes run at full speed and stay isolated from
the displayed framebuffer until the next present.
*Parameters:* none. *Returns:* the stage surface.
=== jlSurfaceCopy
[source,c]
----
void jlSurfaceCopy(jlSurfaceT *dst, const jlSurfaceT *src);
----
Copies pixels, SCBs and palettes from `src` into `dst`.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`dst` |`jlSurfaceT *` |Destination. Must be valid.
|`src` |`const jlSurfaceT *` |Source. Must be valid.
|===
*Returns:* nothing.
=== jlSurfaceCopyRect
[source,c]
----
void jlSurfaceCopyRect(jlSurfaceT *dst, const jlSurfaceT *src,
int16_t x, int16_t y, uint16_t w, uint16_t h);
----
Copies a pixel rectangle from `src` to `dst` *at the same position* -- there is
no repositioning, so the planar ports never have to shift bits. This is the
erase half of the clean-buffer pattern: keep a pristine copy of the scene, and
restore rectangles from it before redrawing sprites.
Copies pixels only. SCBs and palettes are untouched.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`dst` |`jlSurfaceT *` |Destination surface.
|`src` |`const jlSurfaceT *` |Source surface.
|`x`, `y` |`int16_t` |Top-left of the rectangle, clipped to the surface.
|`w`, `h` |`uint16_t` |Size in pixels.
|===
*Returns:* nothing.
[WARNING]
====
The rectangle is clipped to the surface and then *widened outward to the
16-pixel group grid on every port*: `x` rounds down and `x + w` rounds up to
multiples of 16. Two consequences you own:
* up to 15 extra pixels each side are copied, so a snapped erase can clobber
on-screen content outside the rectangle you asked for;
* it silently invalidates any live `jlSpriteBackupT` whose recorded window it
touches.
Erase *all* windows, then draw *all* sprites. Never mix this with per-sprite
save and restore in the same region.
====
=== jlSurfaceSaveFile
[source,c]
----
bool jlSurfaceSaveFile(const jlSurfaceT *src, const char *path);
----
Writes a surface to disk in target-native form: 32000 pixel bytes, then 200 SCB
bytes, then 512 bytes of `$0RGB` palette data.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`src` |`const jlSurfaceT *` |Surface to write.
|`path` |`const char *` |Destination path.
|===
*Returns:* `true` on success; `false` if the file could not be opened or the
write failed.
[IMPORTANT]
====
The format is *not portable*. No endianness or layout conversion is performed,
so the same platform that wrote a file must be the one that reads it. Use this
for runtime caches, not for shipped assets.
====
=== jlSurfaceLoadFile
[source,c]
----
bool jlSurfaceLoadFile(jlSurfaceT *dst, const char *path);
----
Reads a surface from disk, overwriting `dst`. The surface keeps its identity --
nothing is reallocated.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`dst` |`jlSurfaceT *` |Surface to overwrite.
|`path` |`const char *` |Source path.
|===
*Returns:* `true` on success; `false` if the file is missing, the wrong size,
or unreadable.
=== jlSurfaceHash
[source,c]
----
uint32_t jlSurfaceHash(const jlSurfaceT *s);
----
Computes a 32-bit content hash over the surface: the packed chunky pixel byte
stream, then the 200 SCB bytes, then the 256 palette entries.
The important property is that *the same logical pixels hash the same on every
port*, whatever the internal storage format. That makes it the tool for proving
two platforms render identically -- which is exactly how the library's own
cross-port validation works.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`s` |`const jlSurfaceT *` |Surface to hash.
|===
*Returns:* the hash value.
=== jlStagePresent
[source,c]
----
void jlStagePresent(void);
----
Flips the dirty regions of the stage to the display and clears the dirty state.
On chunky platforms this is a direct copy; on planar platforms it is a
chunky-to-planar conversion.
Drawing primitives mark per-row dirty ranges as a side effect, so you only need
to call this at the end of a frame and everything you drew appears. Rows
nothing touched since the last present are skipped.
*Parameters:* none. *Returns:* nothing.
[NOTE]
====
If you modify pixels by a route other than the library's primitives, the dirty
tracking does not know, and those rows will not be presented.
====