// Tiles: 8x8 pixel blocks aligned on the 8-pixel grid of any surface. // // A "tile" in JoeyLib isn't a separate object -- it's just the 8x8 // region of a SurfaceT at block coordinates (bx, by), where bx is in // [0, 39] and by is in [0, 24] (40x25 blocks per 320x200 surface). // The tile API is a small set of operations that move 32-byte chunks // between surfaces or fill them with a solid color. // // Why this shape: anything you can do with a regular surface -- // drawPixel, drawLine, fillRect, blits -- also works on tile-aligned // regions, so authors can paint, edit, and procedurally generate tile // content using the same primitives they use for everything else. // "Fonts," "terrain tilesets," and "spritesheets" are just surfaces // you treat as tile sources at draw time. // // Snap / paste use a small TileT value type so callers don't need a // 32 KB scratch surface for save-under-style work. // // Block coords map to pixels by multiplying by 8 -- byte-aligned in // 4bpp packed (8 px = 4 bytes per row), so all the operations are // byte-shoveling memcpys with no shifting. #ifndef JOEYLIB_TILE_H #define JOEYLIB_TILE_H #include "platform.h" #include "surface.h" #include "types.h" // ----- Constants ----- #define TILE_PIXELS_PER_SIDE 8 #define TILE_BYTES_PER_ROW 4 #define TILE_BYTES (TILE_BYTES_PER_ROW * TILE_PIXELS_PER_SIDE) #define TILE_BLOCKS_PER_ROW (SURFACE_WIDTH / TILE_PIXELS_PER_SIDE) #define TILE_BLOCKS_PER_COL (SURFACE_HEIGHT / TILE_PIXELS_PER_SIDE) // Sentinel for asciiMap entries that should not draw. drawText // advances the cursor past TILE_NO_GLYPH chars without writing. #define TILE_NO_GLYPH ((uint16_t)0xFFFFu) // ----- Types ----- // Stack-allocated 32-byte snapshot buffer for tileSnap / tilePaste. typedef struct TileT { uint8_t pixels[TILE_BYTES]; } TileT; // ----- API ----- // Copy the 8x8 block at (srcBx, srcBy) on src to (dstBx, dstBy) on // dst, opaque. Out-of-range block coordinates on either side are // silent no-ops; src and dst can be the same surface. void tileCopy(SurfaceT *dst, uint8_t dstBx, uint8_t dstBy, const SurfaceT *src, uint8_t srcBx, uint8_t srcBy); // Like tileCopy but pixels equal to transparentIndex are skipped -- // the destination pixel keeps its original value. Use this for fonts // (transparentIndex = 0 leaves the page background showing through // glyph backgrounds) and for any tileset where some pixels are meant // to be see-through. void tileCopyMasked(SurfaceT *dst, uint8_t dstBx, uint8_t dstBy, const SurfaceT *src, uint8_t srcBx, uint8_t srcBy, uint8_t transparentIndex); // Fill the 8x8 block at (bx, by) with a solid color. Equivalent to // fillRect(s, bx*8, by*8, 8, 8, colorIndex) but skips the rect // clipping math since tile coords are already known to be in range. void tileFill(SurfaceT *s, uint8_t bx, uint8_t by, uint8_t colorIndex); // Capture the 8x8 block at (bx, by) into the caller's TileT. Used // for save-under style work where allocating a scratch surface would // be overkill. void tileSnap(const SurfaceT *src, uint8_t bx, uint8_t by, TileT *out); // Paste a TileT back onto a surface at block (bx, by). Always // opaque; use tileCopyMasked if you need transparency. void tilePaste(SurfaceT *dst, uint8_t bx, uint8_t by, const TileT *in); // Draw a NUL-terminated ASCII string at block (bx, by) using glyphs // pulled from fontSurface. // // asciiMap is a 256-entry table mapping ASCII code to glyph location // on fontSurface, encoded as a packed uint16_t: low byte = source // blockX, high byte = source blockY. asciiMap[c] == TILE_NO_GLYPH // causes that character to be skipped (cursor advances, nothing // drawn). Glyph color 0 is treated as transparent so the underlying // surface shows through glyph backgrounds. // // The cursor wraps to the next row at the right edge and truncates // at the bottom edge. void drawText(SurfaceT *dst, uint8_t bx, uint8_t by, const SurfaceT *fontSurface, const uint16_t *asciiMap, const char *str); #endif