// 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 #include // 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