summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonAki <konaki@anokonaki.org>2026-10-08 06:15:41 +0800
committerKonAki <konaki@anokonaki.org>2026-10-08 06:15:41 +0800
commite5f8e13580959e24b80073a04e1c66da27bfc1ec (patch)
treebab9c5ea28e74fcd329acb56b0ba0d69abe73e01
parentb784a525bfa07bd2da20ae51a1987b2e7c3cb74f (diff)
Add kontile: tilemap data, collision and drawing as a module
-rw-r--r--kon/kontile.h138
-rw-r--r--src/impl/kontile.c2
2 files changed, 140 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
diff --git a/src/impl/kontile.c b/src/impl/kontile.c
new file mode 100644
index 0000000..8f57579
--- /dev/null
+++ b/src/impl/kontile.c
@@ -0,0 +1,2 @@
+#define KONTILE_IMPLEMENTATION
+#include "kontile.h"