65816-llvm-mos/runtime/include/iigs/sprite.h
Scott Duensing da095402ec Updated
2026-06-02 23:17:57 -05:00

130 lines
5 KiB
C

// iigs/sprite.h - 16x16 fixed-shape 4bpp packed sprite primitives for
// SHR 320 mode.
//
// Phase 4.2 / Phase 0.6 standalone path: sprite.c brings up SHR 320
// mode itself (NEWVIDEO bit 7 via $C029, SCBs at $E1:9D00, palette 0
// at $E1:9E00) so callers don't have to drag startdesk()'s full 16-
// tool chain in. 640 mode deferred per Phase 0.6.
//
// Pixel format (4bpp packed, SHR 320 mode native):
// - 128 bytes per sprite image: 16 lines x 8 bytes per line.
// - Byte layout: high nibble = LEFT pixel, low nibble = RIGHT pixel.
// - Pixel value 0 is TRANSPARENT (no plot, background shows through).
// Pixel values 1..15 plot the corresponding palette-0 color.
//
// ----- $C035 SHADOW GOTCHA (CRITICAL) -----
// Bank 0 $2000..$9FFF mirrors to $E1:2000..$E1:9FFF via the IIgs SHR
// shadow register at $C035. This means a background save buffer
// allocated in bank-0 $2000..$9FFF would alias the very SHR pixels it
// is trying to preserve. The built-in save area lives in bank 0
// $A000..$AFFF (16 sprites x 128 bytes = 2 KB), which is OUTSIDE the
// shadowed range and safe. If you need more than 16 sprites or want
// to relocate the save area, call iigsSpriteAttachBuffer() with a
// caller-supplied buffer that lives EITHER above $A000 in bank 0 OR in
// a non-zero bank. Buffers inside bank-0 $2000..$9FFF will silently
// scribble on the screen.
//
// Coordinate system: (x, y) is the top-left corner of the sprite.
// - x in pixels (0..303 for full sprite visibility at right edge).
// Currently MUST be even (no sub-byte horizontal alignment in this
// first cut). Odd x is clamped down 1 pixel.
// - y in scan lines (0..183 for full sprite visibility at bottom).
//
// Off-screen clipping is NOT implemented in this first cut. Callers
// must place sprites entirely on-screen (x <= 304 even, y <= 184).
#ifndef IIGS_SPRITE_H
#define IIGS_SPRITE_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stddef.h>
// Maximum sprites tracked by the built-in list. Bumped past this only
// by calling iigsSpriteAttachBuffer() with a larger caller buffer.
#define IIGS_SPRITE_MAX_DEFAULT 16
// Each sprite is (position, pointer-to-128-bytes). pixels points to
// the 4bpp packed image (16 lines x 8 bytes). Pixel value 0 in the
// source is transparent.
typedef struct IigsSpriteT {
uint16_t x; // top-left x, even pixel
uint16_t y; // top-left scan line
const uint8_t * pixels; // 128 bytes, 4bpp packed
} IigsSpriteT;
// Bring up SHR 320 mode (NEWVIDEO bit 7 = 1, all SCBs = 0x00 for
// palette 0 in 320 mode, palette 0 loaded with a default 16-color
// ramp). Idempotent: subsequent calls reset the screen state.
//
// After this returns, callers can write SHR pixel bytes directly to
// $E1:2000..$E1:9CFF, or use the sprite list API below.
void iigsSpriteInit(void);
// Set palette 0 to a caller-supplied 16-entry table. Each entry is a
// 12-bit RGB value (0x0RGB). Pass NULL to reset to the default ramp
// iigsSpriteInit() installed.
void iigsSpriteSetPalette(const uint16_t *palette16);
// Replace the built-in save buffer with caller-supplied storage. buf
// MUST live OUTSIDE bank-0 $2000..$9FFF (see $C035 shadow gotcha at
// top of this header). size must be at least sprites * 128 bytes.
// Returns the maximum number of sprites the new buffer supports
// (size / 128, capped). Pass buf=NULL,size=0 to revert to the built-in
// 16-sprite buffer.
uint16_t iigsSpriteAttachBuffer(void *buf, size_t size);
// ----- sprite list API -----------------------------------------------
// Typical frame:
// iigsSpriteBegin();
// for (each sprite) iigsSpriteAdd(&s);
// iigsSpriteRenderAll(); // save background + blit each sprite
// // ... game logic, animation update ...
// iigsSpriteEraseAll(); // restore saved background in reverse
//
// Render/erase pair preserves the framebuffer outside the sprite
// rectangles. EraseAll MUST be called before the next Begin if the
// background should not accumulate prior frames.
// ---------------------------------------------------------------------
// Clear the sprite list. Call once at the start of each frame.
void iigsSpriteBegin(void);
// Append one sprite to the current frame's list. Copies the sprite
// descriptor by value (caller may modify or free *s after return).
// Silently no-ops if the list is full. Returns the slot index, or
// 0xFFFF if full.
uint16_t iigsSpriteAdd(const IigsSpriteT *s);
// Save the 16x16 background under each sprite into the save buffer,
// then blit each sprite (with pixel 0 = transparent). Walk order:
// list order (sprite 0 first, last drawn on top).
void iigsSpriteRenderAll(void);
// Restore each saved background in REVERSE order (last sprite first)
// so overlapping sprites de-occlude correctly. Pair with the most
// recent iigsSpriteRenderAll().
void iigsSpriteEraseAll(void);
// Count of sprites currently in the list. Useful for tests + debug.
uint16_t iigsSpriteCount(void);
#ifdef __cplusplus
}
#endif
#endif // IIGS_SPRITE_H