// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License. // See LICENSE.md for license information. // SPDX-License-Identifier: MIT // // JoeyLib lifecycle: configuration, initialization, shutdown. #ifndef JOEYLIB_CORE_H #define JOEYLIB_CORE_H #include "platform.h" #include "types.h" typedef struct { // Runtime compiled-sprite cache size. 0 selects a per-platform // default: 8 KB on the IIgs, 64 KB on the Amiga and ST, and 32 KB // everywhere else (the 68k/x86 emitters are ~4-8x less code-dense // than the 65816's, so a 32x32 sprite can need 8-16 KB there). The // ports that interpret every sprite still allocate it. Size against // jlSpriteCompiledSize() when tuning. Elsewhere the cache is one // block, and jlInit fails if it cannot be had. On the IIgs it is up // to four Memory Manager blocks of at most 64 KB, each inside one // bank (a compiled sprite cannot cross a bank), so at most 256 KB; // a bank that is refused is retried at 60 KB, and jlInit takes // whatever part of the request it was granted. uint32_t codegenBytes; // True: leave audio off. Every audio call is then silent, as on a // machine without sound, and the program pays nothing for audio: // on the IIgs no replayer read from disk, on DOS and the Amiga no // interrupt hooked. jlInit starts audio otherwise, and jlShutdown // stops it. bool noAudio; } jlConfigT; // Initialize the library, audio too (unless config->noAudio). Returns true // on success; sound that does not start is not a failure (modules and // effects are then silent, and the log says so). On failure, jlLastError() // returns a human-readable description; where the port's own start-up // fails without saying why, that is just "jlpInit failed". bool jlInit(const jlConfigT *config); // Shut down the library, audio first, releasing the library's own // resources. Surfaces and sprites the program created are not freed: // destroy them first. void jlShutdown(void); // Returns the most recent error message, or NULL if none. const char *jlLastError(void); // Returns the platform identifier string (e.g., "Apple IIgs", "MS-DOS"). const char *jlPlatformName(void); // Returns the library version string (e.g., "1.0.0"). const char *jlVersionString(void); // Allocate a large or persistent buffer, backed by the platform's // native allocator rather than the small C heap. Use this (not malloc) // for anything that exceeds the per-allocation or total ceiling of the // stock C heap -- on the IIgs the whole C heap is one Memory Manager // block of 32 KB to 48 KB (or, if that block cannot be had, what the // link left in the program's bank, which can be tiny), so multi-KB // caches and frame buffers must come from the IIgs Memory Manager // instead. Returns NULL on failure. The returned pointer is NOT // zero-filled. void *jlAlloc(uint32_t bytes); // Release a buffer returned by jlAlloc. NULL is accepted and ignored. // Never mix jlFree and free: on the IIgs a jlAlloc block is a Memory // Manager handle, and either one given the other's block corrupts memory. void jlFree(void *p); // memcpy with a 32-bit count. Same contract as memcpy (no overlap); every // port runs its libc memcpy (on the IIgs MVN block moves at 7 cycles a // byte, split at bank boundaries). void jlMemCopy(void *dst, const void *src, uint32_t bytes); // Block the calling thread until the next display vertical blank, to // pace a game loop to the display's refresh. On the machine ports it // waits for the display's own vertical blank. The hosted ports, and DVX // in a window, have none to wait for: there it waits for the next tick // of a virtual frame clock (60 Hz hosted, 70 Hz DVX), and nothing keeps // a present from tearing. void jlWaitVBL(void); // Monotonic 16-bit frame counter, kept by an interrupt or derived from a // clock, so it does not miss frames however seldom it is read (except on // an X68000 whose system refused JoeyLib's frame interrupt: there it // counts only while jlWaitVBL, jlFrameCount, or jlStagePresent is // called). It wraps about every 18 minutes at 60 Hz, so compare two // readings by subtraction. Used by benchmarks and frame-rate-independent // animation. uint16_t jlFrameCount(void); // Display frame rate in Hz: 60 on the IIgs (50 on a PAL machine), 50 on // the Amiga (60 on an NTSC machine that cannot show PAL), 50 or 60 on // the ST as the machine is set, 70 on DOS and DVX, 55 on the X68000 (56 // under MAME), and 60 on every hosted port. The actual VBL cadence may // drift slightly; the value reported here is what benchmarks divide // by to convert iters-per-N-frames to ops/sec. uint16_t jlFrameHz(void); // Monotonic wall-clock millisecond counter since jlInit. It may // advance a frame at a time. Call it at least once every 15 minutes, or // the time between two calls can be lost. Two consecutive calls // separated by a long render report the true elapsed time, not the // number of VBLs that fired. uint32_t jlMillisElapsed(void); // Deterministic, seedable pseudo-random generator. Bit-identical // output across every JoeyLib port for a given seed, since stdlib // rand() varies wildly between platforms and C libraries. // The underlying algorithm is xorshift32 (Marsaglia): period 2^32-1, // no multiply, suitable for games but not for cryptography. uint32_t jlRandom(void); // Return a value in [0, bound). bound == 0 returns 0. uint16_t jlRandomRange(uint16_t bound); // Seed the generator. Any 32-bit value is accepted; a seed of 0 is // remapped to 1 since xorshift cannot escape the all-zero state. void jlRandomSeed(uint32_t seed); #endif