diff options
| author | KonAki <konaki@anokonaki.org> | 2026-10-15 14:57:24 +0800 |
|---|---|---|
| committer | KonAki <konaki@anokonaki.org> | 2026-10-15 14:57:24 +0800 |
| commit | a971a6688ebdfc5fb4a21f2795546fd1cae8cc92 (patch) | |
| tree | ef3ca3d414f041645b6493eaafc0ceb522d8653e | |
| parent | eef87380a41357bc3bb52149ec33f1787ebd2b40 (diff) | |
add rmtile: rpg maker tile geometry
| -rw-r--r-- | kon/konrmtile.c | 216 | ||||
| -rw-r--r-- | kon/konrmtile.h | 67 |
2 files changed, 283 insertions, 0 deletions
diff --git a/kon/konrmtile.c b/kon/konrmtile.c new file mode 100644 index 0000000..48a0eb3 --- /dev/null +++ b/kon/konrmtile.c @@ -0,0 +1,216 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konrmtile.c + * + * 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. + */ + +#include "konrmtile.h" + +#define TILE_B 0 +#define TILE_C 256 +#define TILE_D 512 +#define TILE_E 768 +#define TILE_A5 1536 +#define TILE_A1 2048 +#define TILE_A2 2816 +#define TILE_A3 4352 +#define TILE_A4 5888 +#define TILE_MAX 8192 + +/*** the shapes ***/ + +/* the four quarters of each of the 48 shapes of an autotile that is a floor or a water edge. every entry is the column and row + in the picture of the autotile's 4 by 6 quarters, for the top left, top right, bottom left and bottom right of the tile. + the order is the one the editor writes into the tile id */ +static const signed char floorTable[48][4][2] = { + {{2,4},{1,4},{2,3},{1,3}}, {{2,0},{1,4},{2,3},{1,3}}, {{2,4},{3,0},{2,3},{1,3}}, {{2,0},{3,0},{2,3},{1,3}}, + {{2,4},{1,4},{2,3},{3,1}}, {{2,0},{1,4},{2,3},{3,1}}, {{2,4},{3,0},{2,3},{3,1}}, {{2,0},{3,0},{2,3},{3,1}}, + {{2,4},{1,4},{2,1},{1,3}}, {{2,0},{1,4},{2,1},{1,3}}, {{2,4},{3,0},{2,1},{1,3}}, {{2,0},{3,0},{2,1},{1,3}}, + {{2,4},{1,4},{2,1},{3,1}}, {{2,0},{1,4},{2,1},{3,1}}, {{2,4},{3,0},{2,1},{3,1}}, {{2,0},{3,0},{2,1},{3,1}}, + {{0,4},{1,4},{0,3},{1,3}}, {{0,4},{3,0},{0,3},{1,3}}, {{0,4},{1,4},{0,3},{3,1}}, {{0,4},{3,0},{0,3},{3,1}}, + {{2,2},{1,2},{2,3},{1,3}}, {{2,2},{1,2},{2,3},{3,1}}, {{2,2},{1,2},{2,1},{1,3}}, {{2,2},{1,2},{2,1},{3,1}}, + {{2,4},{3,4},{2,3},{3,3}}, {{2,4},{3,4},{2,1},{3,3}}, {{2,0},{3,4},{2,3},{3,3}}, {{2,0},{3,4},{2,1},{3,3}}, + {{2,4},{1,4},{2,5},{1,5}}, {{2,0},{1,4},{2,5},{1,5}}, {{2,4},{3,0},{2,5},{1,5}}, {{2,0},{3,0},{2,5},{1,5}}, + {{0,4},{3,4},{0,3},{3,3}}, {{2,2},{1,2},{2,5},{1,5}}, {{0,2},{1,2},{0,3},{1,3}}, {{0,2},{1,2},{0,3},{3,1}}, + {{2,2},{3,2},{2,3},{3,3}}, {{2,2},{3,2},{2,1},{3,3}}, {{2,4},{3,4},{2,5},{3,5}}, {{2,0},{3,4},{2,5},{3,5}}, + {{0,4},{1,4},{0,5},{1,5}}, {{0,4},{3,0},{0,5},{1,5}}, {{0,2},{3,2},{0,3},{3,3}}, {{0,2},{1,2},{0,5},{1,5}}, + {{0,4},{3,4},{0,5},{3,5}}, {{2,2},{3,2},{2,5},{3,5}}, {{0,2},{3,2},{0,5},{3,5}}, {{0,0},{1,0},{0,1},{1,1}} +}; + +/* walls have four on or off edges, the shape is those as bits: 1 left, 2 up, 4 right, 8 down. a set bit means that side is the border */ +static void wallQuarter(int shape, int corner, signed char out[2]) +{ + int left = shape & 1, up = shape >> 1 & 1, right = shape >> 2 & 1, down = shape >> 3 & 1; + + switch (corner) { + case 0: out[0] = left ? 0 : 2; out[1] = up ? 0 : 2; break; + case 1: out[0] = right ? 3 : 1; out[1] = up ? 0 : 2; break; + case 2: out[0] = left ? 0 : 2; out[1] = down ? 3 : 1; break; + default: out[0] = right ? 3 : 1; out[1] = down ? 3 : 1; break; + } +} + +/* a waterfall only has the left and right: 1 left, 2 right, and it is always the top two rows of its picture */ +static void waterfallQuarter(int shape, int corner, signed char out[2]) +{ + int left = shape & 1, right = shape >> 1 & 1; + + out[0] = corner % 2 == 0 ? (left ? 0 : 2) : (right ? 3 : 1); + out[1] = corner < 2 ? 0 : 1; +} + +/*** tiles ***/ + +int kon_rmTileIsAutotile(int tileId) +{ + return tileId >= TILE_A1 && tileId < TILE_MAX; +} + +int kon_rmTileIsAnimated(int tileId) +{ + int kind; + + if (tileId < TILE_A1 || tileId >= TILE_A2) return 0; + kind = (tileId - TILE_A1) / 48; + return kind < 16; +} + +int kon_rmTileIsHigher(int flags) +{ + return (flags & 0x10) != 0; +} + +int kon_rmSheetSize(int sheet, int *columns, int *rows) +{ + int c, r; + + switch (sheet) { + case 0: case 1: c = 32; r = 24; break; + case 2: c = 32; r = 16; break; + case 3: c = 32; r = 30; break; + case 4: c = 16; r = 32; break; + case 5: case 6: case 7: case 8: c = 32; r = 32; break; + default: return 0; + } + if (columns) *columns = c; + if (rows) *rows = r; + return 1; +} + +static int plainTile(int tileId, kon_rmQuad_t quads[4]) +{ + int sheet, column, row; + + if (tileId >= TILE_A5 && tileId < TILE_A1) { + if (tileId >= TILE_A5 + 128) return 0; + sheet = 4; + column = tileId % 8; + row = (tileId / 8) % 16; + } else if (tileId < TILE_A5) { + if (tileId >= TILE_E + 256) return 0; + sheet = 5 + tileId / 256; + column = (tileId / 128 % 2) * 8 + tileId % 8; + row = (tileId % 256 / 8) % 16; + } else { + return 0; + } + quads[0].sheet = sheet; + quads[0].sx = column * 2; + quads[0].sy = row * 2; + quads[0].dx = quads[0].dy = 0; + quads[0].w = quads[0].h = 2; + return 1; +} + +int kon_rmTileQuads(int tileId, int frame, kon_rmQuad_t quads[4]) +{ + int kind, shape, tx, ty, bx = 0, by = 0, sheet = 0, i; + int table = 0; /* 0 floor, 1 wall, 2 waterfall */ + int surface; + + if (!quads || tileId <= 0 || tileId >= TILE_MAX) return 0; + if (!kon_rmTileIsAutotile(tileId)) return plainTile(tileId, quads); + if (frame < 0) frame = 0; + + kind = (tileId - TILE_A1) / 48; + shape = (tileId - TILE_A1) % 48; + tx = kind % 8; + ty = kind / 8; + surface = (int[]){0, 1, 2, 1}[frame % 4]; + + if (tileId < TILE_A2) { + sheet = 0; + if (kind == 0) { bx = surface * 2; by = 0; } + else if (kind == 1) { bx = surface * 2; by = 3; } + else if (kind == 2) { bx = 6; by = 0; } + else if (kind == 3) { bx = 6; by = 3; } + else { + bx = tx / 4 * 8; + by = ty * 6 + tx / 2 % 2 * 3; + if (kind % 2 == 0) { + bx += surface * 2; + } else { + bx += 6; + table = 2; + by += frame % 3; + } + } + } else if (tileId < TILE_A3) { + sheet = 1; + bx = tx * 2; + by = (ty - 2) * 3; + } else if (tileId < TILE_A4) { + sheet = 2; + bx = tx * 2; + by = (ty - 6) * 2; + table = 1; + } else { + sheet = 3; + bx = tx * 2; + by = ((ty - 10) * 5 + (ty % 2 == 1 ? 1 : 0)) / 2; + if (ty % 2 == 1) table = 1; + } + + if (table == 0 && shape >= 48) return 0; + if (table == 1 && shape >= 16) return 0; + if (table == 2 && shape >= 4) return 0; + + for (i = 0; i < 4; i++) { + signed char q[2]; + + if (table == 0) { + q[0] = floorTable[shape][i][0]; + q[1] = floorTable[shape][i][1]; + } else if (table == 1) { + wallQuarter(shape, i, q); + } else { + waterfallQuarter(shape, i, q); + } + quads[i].sheet = sheet; + quads[i].sx = bx * 2 + q[0]; + quads[i].sy = by * 2 + q[1]; + quads[i].dx = i % 2; + quads[i].dy = i / 2; + quads[i].w = quads[i].h = 1; + } + return 4; +} diff --git a/kon/konrmtile.h b/kon/konrmtile.h new file mode 100644 index 0000000..bae2ada --- /dev/null +++ b/kon/konrmtile.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: MIT */ +/* + * konrmtile.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 KONRMTILE_H +#define KONRMTILE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/*** definition ***/ + +/* where the pieces of one RPG Maker map tile come from in the tileset pictures, with nothing drawn. a tile is one whole piece + from a picture, or for an autotile four quarters that fit together with their neighbours. everything is counted in half tiles, + so for a picture made of 48 pixel tiles a half tile is 24 pixels. mzmap writes the tileset's picture names in order: + sheet 0 is A1, 1 A2, 2 A3, 3 A4, 4 A5, 5 B, 6 C, 7 D and 8 E */ + +#define KON_RM_SHEETS 9 + +typedef struct kon_rmQuad { + int sheet; + int sx, sy; /* where the piece starts in the picture */ + int dx, dy; /* where it goes inside the tile, 0 or 1 for a quarter */ + int w, h; /* 2 and 2 for a whole tile, 1 and 1 for a quarter */ +} kon_rmQuad_t; + +/* fills quads (room for 4) and returns how many there are: 0 for an empty tile or one that is not drawn, 1 for a whole tile, + 4 for an autotile. frame is the animation count, water and waterfalls move with it and it is 0 for a still picture */ +int kon_rmTileQuads(int tileId, int frame, kon_rmQuad_t quads[4]); + +/* how many half tiles wide and tall a picture of that sheet has to be to hold every piece of it, for checking a loaded picture. + returns 0 for a sheet number that does not exist */ +int kon_rmSheetSize(int sheet, int *columns, int *rows); + +/* 1 for the tiles that are drawn above the characters: the ones marked with a star, flags is the tile's flags from its tileset */ +int kon_rmTileIsHigher(int flags); + +/* 1 for a tile that is an autotile, 1 for one that moves */ +int kon_rmTileIsAutotile(int tileId); +int kon_rmTileIsAnimated(int tileId); + +#ifdef __cplusplus +} +#endif +#endif |
