joeylib2/include/joey/core.h

124 lines
5.7 KiB
C

// 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, ST, and X68000, and
// 32 KB on DOS, DVX, and Win16 (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 have no cache and
// allocate none. Size against jlSpriteCompiledSize() when tuning.
// Every port takes as much of the request as the machine has, and
// jlInit fails only if it can have none (jlSpriteCodegenBytesTotal
// says what it got): on the IIgs 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; elsewhere one block, halved until the
// heap has room, down to 4 KB.
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 of why, on every port.
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. A program that returns from main or calls exit
// without it has it run then (jlInit registers it with atexit).
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, to the
// millisecond (a frame at a time only where the machine's timer is
// taken: docs/ApiCore.adoc). 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