joeylib2/docs/ApiCore.adoc
2026-10-13 14:01:46 -05:00

271 lines
6.2 KiB
Text

== Core and Lifecycle
Declared in `<joey/core.h>`, included by `<joey/joey.h>`.
=== jlConfigT
[source,c]
----
typedef struct {
uint32_t codegenBytes;
} jlConfigT;
----
[cols="1,1,4", options="header"]
|===
|Field |Type |Description
|`codegenBytes`
|`uint32_t`
|Size of the runtime compiled-sprite cache. `0` selects a per-platform
default: 8 KB on IIgs, 32 KB on Amiga, ST, DOS and DVX (SDL3 interprets every
sprite and leaves the cache unused). On the IIgs the cache is
one Memory Manager block that may not span a 64 KB bank boundary, so values
above 65536 are clamped to 65536, and even a clamped request can fail if no
free bank exists. Size it against `jlSpriteCompiledSize()`.
|===
=== jlInit
[source,c]
----
bool jlInit(const jlConfigT *config);
----
Initialises the library: takes over the display, allocates the stage and the
codegen arena, and brings up input. Must be called before any other JoeyLib
function.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`config` |`const jlConfigT *` |Configuration. Must not be `NULL`.
|===
*Returns:* `true` on success. On failure returns `false` and `jlLastError()`
describes the reason.
=== jlShutdown
[source,c]
----
void jlShutdown(void);
----
Shuts the library down, restoring the display mode, releasing all library
resources and un-hooking any interrupt vectors the port installed. Call it on
every exit path; skipping it can leave the machine unusable.
*Parameters:* none. *Returns:* nothing.
=== jlLastError
[source,c]
----
const char *jlLastError(void);
----
*Parameters:* none.
*Returns:* the most recent error message, or `NULL` if there has been none. The
string is library-owned; do not free it.
=== jlPlatformName
[source,c]
----
const char *jlPlatformName(void);
----
*Parameters:* none.
*Returns:* a human-readable platform identifier, for example `"Apple IIgs"`,
`"MS-DOS"`, `"DVX"`, `"SDL3"` (the web port is the SDL3 port in a browser) or
`"Windows"`.
Library-owned.
=== jlVersionString
[source,c]
----
const char *jlVersionString(void);
----
*Parameters:* none.
*Returns:* the library version, for example `"1.0.0"`. Library-owned.
=== jlAlloc
[source,c]
----
void *jlAlloc(uint32_t bytes);
----
Allocates a large or persistent buffer from the platform's native allocator
rather than the small C heap. *Use this instead of `malloc` for anything
substantial.* On the IIgs the C heap lives in bank 0 and is tiny, with a single
`malloc` capped around 32 KB, so multi-kilobyte caches and frame buffers must
come from the Memory Manager instead.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`bytes` |`uint32_t` |Number of bytes required.
|===
*Returns:* a pointer to the block, or `NULL` on failure. The memory is *not*
zero-filled.
=== jlFree
[source,c]
----
void jlFree(void *p);
----
Releases a buffer from `jlAlloc`.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`p` |`void *` |Block to release. `NULL` is accepted and ignored.
|===
*Returns:* nothing.
=== jlMemCopy
[source,c]
----
void jlMemCopy(void *dst, const void *src, uint32_t bytes);
----
Copies a block. Same contract as `memcpy`, including that the regions must not
overlap, with a 32-bit byte count on every port. It is the port's libc
`memcpy`; on the IIgs that is `MVN` block moves at 7 cycles per byte, split
correctly at bank boundaries.
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`dst` |`void *` |Destination.
|`src` |`const void *` |Source. Must not overlap `dst`.
|`bytes` |`uint32_t` |Byte count.
|===
*Returns:* nothing.
=== jlWaitVBL
[source,c]
----
void jlWaitVBL(void);
----
Blocks until the next display vertical blank, pacing a game loop to the
display's native refresh rate. Cheap on every port, because the underlying
mechanism is always a hardware-level wait rather than a software timer.
*Parameters:* none. *Returns:* nothing.
=== jlFrameCount
[source,c]
----
uint16_t jlFrameCount(void);
----
*Parameters:* none.
*Returns:* a monotonic 16-bit frame counter.
[WARNING]
====
You must poll faster than twice `jlFrameHz()` or edges are missed, and the
counter wraps roughly every 18 minutes at 60 Hz. For elapsed-time work prefer
`jlMillisElapsed`.
====
=== jlFrameHz
[source,c]
----
uint16_t jlFrameHz(void);
----
*Parameters:* none.
*Returns:* the nominal display frame rate in Hz -- 50 on Amiga PAL, 60 on IIgs
and ST NTSC, 55 on the X68000, 70 on VGA mode 13h and on DVX, whose window has
a virtual 70 Hz (and whose full screen is mode 13h's, or a VBE mode's, with the
same frame count), and 60 under SDL3, whose window has a virtual 60 Hz. The X68000 times its display at `jlInit` and rounds to the
nearest whole number: 55.46 Hz on the machine, 56.07 Hz under MAME, which
therefore reports 56. The real cadence may drift slightly; this is the figure
to divide by when converting frames to seconds.
=== jlMillisElapsed
[source,c]
----
uint32_t jlMillisElapsed(void);
----
Monotonic millisecond counter since `jlInit`. DOS, ST, X68000, DVX and SDL3 read a
real timer; IIgs and Amiga derive it from the frame counter, so the
value steps at frame granularity there. Two calls separated by a long render report the true
elapsed time, not the number of vertical blanks that fired.
*Parameters:* none.
*Returns:* milliseconds since `jlInit`.
[NOTE]
====
On the frame-derived ports you must poll at least once every 65535 frames --
about 18 minutes at 60 Hz -- or wrapped frames are lost.
====
=== jlRandom
[source,c]
----
uint32_t jlRandom(void);
----
Deterministic pseudo-random generator, xorshift32. Produces *bit-identical*
output on every JoeyLib port for a given seed, which `rand()` does not.
Period 2^32^-1. Suitable for games, not for cryptography.
*Parameters:* none. *Returns:* the next 32-bit value.
=== jlRandomRange
[source,c]
----
uint16_t jlRandomRange(uint16_t bound);
----
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`bound` |`uint16_t` |Exclusive upper bound.
|===
*Returns:* a value in `[0, bound)`. A `bound` of 0 returns 0.
=== jlRandomSeed
[source,c]
----
void jlRandomSeed(uint32_t seed);
----
[cols="1,1,4", options="header"]
|===
|Parameter |Type |Description
|`seed` |`uint32_t` |Any 32-bit value. A seed of 0 is remapped to 1, because
xorshift cannot escape the all-zero state.
|===
*Returns:* nothing.