diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-08 06:15:41 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-08 06:15:41 +0800 |
| commit | e5f8e13580959e24b80073a04e1c66da27bfc1ec (patch) | |
| tree | bab9c5ea28e74fcd329acb56b0ba0d69abe73e01 /kon | |
| parent | b784a525bfa07bd2da20ae51a1987b2e7c3cb74f (diff) | |
Add kontile: tilemap data, collision and drawing as a module
Diffstat (limited to 'kon')
| -rw-r--r-- | kon/kontile.h | 138 |
1 files changed, 138 insertions, 0 deletions
diff --git a/kon/kontile.h b/kon/kontile.h new file mode 100644 index 0000000..d416d34 --- /dev/null +++ b/kon/kontile.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: MIT */ +/* + * kontile.h + * + * Copyright (c) 2026 KonAki + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef KONTILE_H +#define KONTILE_H + +#include "konsofren.h" + +/*** definition ***/ + +/* tiles holds columns * rows ids, 0 is empty and n draws tile n - 1 of the sheet, counted left to right then top to bottom */ +typedef struct kon_tilemap { + int columns, rows; + int tileWidth, tileHeight; + uint16_t *tiles; + const kon_image *sheet; + int sheetColumns; /* 0 works it out from the sheet width */ +} kon_tilemap_t; + +/* 0 outside the map */ +uint16_t kon_tilemapAt(const kon_tilemap_t *map, int column, int row); + +/* does nothing outside the map */ +void kon_tilemapSet(kon_tilemap_t *map, int column, int row, uint16_t tile); + +/* works for negative positions too, returns 0 if the position is outside the map */ +int kon_tilemapPixelToTile(const kon_tilemap_t *map, int x, int y, int *column, int *row); + +/* solid is indexed by tile id, non-zero means solid, ids past solidCount are not solid. solid[0] decides what the empty tile + and everything outside the map counts as. returns 1 if any tile touching the box x, y, width, height (in map pixels) is solid */ +int kon_tilemapBoxHits(const kon_tilemap_t *map, int x, int y, int width, int height, const uint8_t *solid, int solidCount); + +/* cameraX, cameraY is the map pixel shown at the top left of fb */ +void kon_drawTilemap(kon_framebuffer_t *fb, const kon_tilemap_t *map, int cameraX, int cameraY); + +/*** implementation ***/ + +#ifdef KONTILE_IMPLEMENTATION + +static int kon_floorDiv_(int a, int b) { + int q = a / b; + return (a % b != 0 && (a < 0) != (b < 0)) ? q - 1 : q; +} + +uint16_t kon_tilemapAt(const kon_tilemap_t *map, int column, int row) { + if (!map || !map->tiles) return 0; + if (column < 0 || row < 0 || column >= map->columns || row >= map->rows) return 0; + return map->tiles[(size_t)row * (size_t)map->columns + (size_t)column]; +} + +void kon_tilemapSet(kon_tilemap_t *map, int column, int row, uint16_t tile) { + if (!map || !map->tiles) return; + if (column < 0 || row < 0 || column >= map->columns || row >= map->rows) return; + map->tiles[(size_t)row * (size_t)map->columns + (size_t)column] = tile; +} + +int kon_tilemapPixelToTile(const kon_tilemap_t *map, int x, int y, int *column, int *row) { + if (!map || map->tileWidth <= 0 || map->tileHeight <= 0) return 0; + + int c = kon_floorDiv_(x, map->tileWidth); + int r = kon_floorDiv_(y, map->tileHeight); + if (column) *column = c; + if (row) *row = r; + + return c >= 0 && r >= 0 && c < map->columns && r < map->rows; +} + +int kon_tilemapBoxHits(const kon_tilemap_t *map, int x, int y, int width, int height, const uint8_t *solid, int solidCount) { + if (!map || !solid || solidCount <= 0 || map->tileWidth <= 0 || map->tileHeight <= 0 || width <= 0 || height <= 0) return 0; + + int firstColumn = kon_floorDiv_(x, map->tileWidth); + int firstRow = kon_floorDiv_(y, map->tileHeight); + int lastColumn = kon_floorDiv_(x + width - 1, map->tileWidth); + int lastRow = kon_floorDiv_(y + height - 1, map->tileHeight); + + for (int row = firstRow; row <= lastRow; row++) { + for (int column = firstColumn; column <= lastColumn; column++) { + int tile = kon_tilemapAt(map, column, row); + if (tile < solidCount && solid[tile]) return 1; + } + } + return 0; +} + +void kon_drawTilemap(kon_framebuffer_t *fb, const kon_tilemap_t *map, int cameraX, int cameraY) { + if (!fb || !map || !map->sheet || !map->tiles) return; + if (map->tileWidth <= 0 || map->tileHeight <= 0) return; + + int sheetColumns = map->sheetColumns > 0 ? map->sheetColumns : map->sheet->width / map->tileWidth; + if (sheetColumns <= 0) return; + + int firstColumn = kon_floorDiv_(cameraX, map->tileWidth); + int firstRow = kon_floorDiv_(cameraY, map->tileHeight); + int lastColumn = kon_floorDiv_(cameraX + fb->width - 1, map->tileWidth); + int lastRow = kon_floorDiv_(cameraY + fb->height - 1, map->tileHeight); + + if (firstColumn < 0) firstColumn = 0; + if (firstRow < 0) firstRow = 0; + if (lastColumn > map->columns - 1) lastColumn = map->columns - 1; + if (lastRow > map->rows - 1) lastRow = map->rows - 1; + + for (int row = firstRow; row <= lastRow; row++) { + for (int column = firstColumn; column <= lastColumn; column++) { + int tile = map->tiles[(size_t)row * (size_t)map->columns + (size_t)column]; + if (tile == 0) continue; + tile--; + + kon_rect_t src = KON_RECT((tile % sheetColumns) * map->tileWidth, (tile / sheetColumns) * map->tileHeight, map->tileWidth, map->tileHeight); + kon_drawImageRegion(fb, column * map->tileWidth - cameraX, row * map->tileHeight - cameraY, map->sheet, src); + } + } +} + +#endif /* KONTILE_IMPLEMENTATION */ + +#endif |
