// Internal sprite definitions shared between sprite.c and the // per-platform codegen emitters. Public API users include // joey/sprite.h instead. #ifndef JOEYLIB_SPRITE_INTERNAL_H #define JOEYLIB_SPRITE_INTERNAL_H #include "codegenArenaInternal.h" #include "joey/sprite.h" #define SPRITE_OP_DRAW 0 #define SPRITE_OP_SAVE 1 #define SPRITE_OP_RESTORE 2 #define SPRITE_OP_COUNT 3 // Sentinel stored in routineOffsets[shift][op] when that op's emitter // returned 0 bytes (i.e., the platform doesn't implement compiled // codegen for that op yet). Distinct from a real offset of 0, which // is valid for the first emitted op (typically DRAW shift 0). #define SPRITE_NOT_COMPILED 0xFFFFu struct SpriteT { const uint8_t *tileData; // wTiles * hTiles * 32 bytes; NULL for loaded sprites uint8_t widthTiles; uint8_t heightTiles; bool ownsTileData; // true if spriteDestroy must free tileData // Compiled-path state. slot==NULL means not yet compiled (or // compile failed); spriteDraw falls back to the interpreter. // The fn-call address for (shift, op) is computed at draw time: // (codegenArenaBase() + slot->offset + routineOffsets[shift][op]) // so a codegenArenaCompact that moves the slot's bytes is // transparent to the caller. ArenaSlotT *slot; uint16_t routineOffsets[JOEY_SPRITE_SHIFT_COUNT][SPRITE_OP_COUNT]; SpriteFlagsE flags; // Per-shift, per-op MVN bank-patch cache for IIgs save/restore. // patchMvnBanks rewrites 16+ MVN bank operands every call, but the // banks themselves rarely change frame-to-frame (screen surface // is fixed; backup buffer is allocated once). After the first // patch, subsequent calls compare requested banks to the cache // and skip the re-stamp loop. 0xFF means "never patched yet". // 12 bytes per sprite. Unused on non-IIgs. uint8_t cachedDstBank[JOEY_SPRITE_SHIFT_COUNT][SPRITE_OP_COUNT]; uint8_t cachedSrcBank[JOEY_SPRITE_SHIFT_COUNT][SPRITE_OP_COUNT]; // Cached `copyBytes * heightPx` per shift for spriteCompiledSaveUnder's // `backup->sizeBytes` field. uint16_t * uint16_t goes through ORCA-C // 2.2.1's ~CUMUL2 helper (~30-50 cyc); cache hit dodges it. Filled // lazily on first call (0 sentinel = uncached). uint16_t cachedSizeBytes[JOEY_SPRITE_SHIFT_COUNT]; }; // Compiled entry points. Implemented alongside spriteCompile in // src/codegen/spriteCompile.c. Each handles the per-platform calling // convention the emitted bytes use (cdecl on x86, stack args on 68k, // inline asm + self-modifying stub on IIgs). The dispatchers in // src/core/sprite.c call these when sp->slot is non-NULL, the // matching routineOffsets entry is not SPRITE_NOT_COMPILED, and the // draw/save/restore is fully on-surface. void spriteCompiledDraw (SurfaceT *dst, const SpriteT *sp, int16_t x, int16_t y); void spriteCompiledSaveUnder (const SurfaceT *src, SpriteT *sp, int16_t x, int16_t y, SpriteBackupT *backup); void spriteCompiledRestoreUnder (SurfaceT *dst, const SpriteBackupT *backup); #endif