/* Copyright (c) 2021 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __TileMap_H__ #define __TileMap_H__ #ifdef __cplusplus extern "C" { #endif #include "tileset/TilesetEditData.h" #include #include #define TILE_ID_INVALID ((TileID) UINT32_MAX) typedef struct TileMap { unsigned int width; unsigned int height; TileID * tiles; } TileMap; typedef struct TileMapStringKeyEntry { char character; TileID tileID; } TileMapStringKeyEntry; typedef struct TileMapColorKeyEntry { uint8_t red; uint8_t green; uint8_t blue; TileID tileID; } TileMapColorKeyEntry; typedef struct TileAdjacency4 { unsigned int left : 8; unsigned int right : 8; unsigned int top : 8; unsigned int bottom : 8; } TileAdjacency4; typedef struct TileAdjacency8 { unsigned int topLeft : 8; unsigned int top : 8; unsigned int topRight : 8; unsigned int left : 8; unsigned int right : 8; unsigned int bottomLeft : 8; unsigned int bottom : 8; unsigned int bottomRight : 8; } TileAdjacency8; typedef struct TileAdjacencyKeyEntry { TileID originTileID; TileID adjacentTileID; // value defaults to 0 for no adjacency; set to 1 or greater for all provided entries uint8_t value; // If true, adjacency of tiles of type originTileID will be assigned as if adjacentTileID extends // beyond the edges of TileMap. If multiple matches with assignAtEdges set to true exist in the // specified keys, the latest one in the list will be used. bool assignAtEdges; } TileAdjacencyKeyEntry; // Treat edges and corners as matches when considering them. #define AUTO_TILE_OPTION_EDGE_IS_MATCH 0x1 // Treat zero tiles as matches when considering them. #define AUTO_TILE_OPTION_ZERO_IS_MATCH 0x2 // For the rule to pass, a match in a specified direction is considered a failure, and a mismatch is considered a success. Edges and zeroes are still ignored if the options for them are specified. #define AUTO_TILE_OPTION_NEGATIVE 0x4 enum AutoTileAdjacentDirection { ADJACENT_NORTHWEST, ADJACENT_NORTH, ADJACENT_NORTHEAST, ADJACENT_WEST, ADJACENT_EAST, ADJACENT_SOUTHWEST, ADJACENT_SOUTH, ADJACENT_SOUTHEAST, ADJACENT_DIRECTION_COUNT }; typedef struct AutoTileRule { TileID baseTileID; TileID adjustedTileID; // If a direction is set to TILE_ID_INVALID, that direction won't be considered while matching TileID adjacentDirections[ADJACENT_DIRECTION_COUNT]; uint8_t options; } AutoTileRule; typedef struct AutoTileRuleset { unsigned int ruleCount; AutoTileRule * rules; } AutoTileRuleset; // Initializes all tiles to TileID 0 TileMap * TileMap_create(unsigned int width, unsigned int height); // Copies the contents of tiles and does not take ownership of it TileMap * TileMap_createWithTiles(unsigned int width, unsigned int height, TileID * tiles); // Returns true if both tile maps have the same width, height, and tile data bool TileMap_isEqual(TileMap * self, TileMap * tileMap); TileMap * TileMap_copy(TileMap * tileMap); void TileMap_dispose(TileMap * tileMap); // Unrecognized or undefined tiles are set to ID 0 TileMap * TileMap_loadString(const char * string, unsigned int forceWidth, unsigned int forceHeight, TileMapStringKeyEntry * key, unsigned int entryCount); TileMap * TileMap_loadRGB(const uint8_t * pixels, unsigned int width, unsigned int height, TileMapColorKeyEntry * key, unsigned int entryCount); // outString must be large enough to store (width + 1) * height bytes, and will be null terminated on return. // Rows are separated by newline (\n) characters. void TileMap_writeString(TileMap * tileMap, char * outString, TileMapStringKeyEntry * key, unsigned int entryCount, char unknownTileCharacter); // outPixels must be large enough to store width * 3 * height bytes void TileMap_writeRGB(TileMap * tileMap, uint8_t * outPixels, TileMapColorKeyEntry * key, unsigned int entryCount, uint8_t unknownTileRed, uint8_t unknownTileGreen, uint8_t unknownTileBlue); void TileMap_calculateAdjacency4(TileMap * tileMap, TileAdjacency4 * outAdjacency, TileAdjacencyKeyEntry * key, unsigned int entryCount); void TileMap_calculateAdjacency8(TileMap * tileMap, TileAdjacency8 * outAdjacency, TileAdjacencyKeyEntry * key, unsigned int entryCount); // Evalutes tile adjacency as specified in ruleset and assigns adjustedTileID to each position in toTileMap where a match is found // in fromTileMap. If fromTileMap and toTileMap are the same pointer, the remapping will be done in-place. // For each tile, the surrounding 8 tiles are examined and evaluated, and if a matching rule is found in ruleset for the tile's // adjacency, that tile is replaced by the adjustedTileID in the passing rule. // Evaluation for each tile stops at the first match, so more specific rules should be listed in ruleset before more general ones. void TileMap_applyAutoTile(TileMap * toTileMap, TileMap * fromTileMap, AutoTileRuleset * ruleset); // Evaluates a single tile in tileMap for auto-tiling, returning the resulting TileID for that position. TileID TileMap_autoTileSingle(TileMap * tileMap, unsigned int columnIndex, unsigned int rowIndex, AutoTileRuleset * ruleset); // Sets all tiles in tileMap to tileID void TileMap_clear(TileMap * tileMap, TileID tileID); // Copies a region of source to target, of a size specified by width and height, from an offset specified by sourceX and sourceY, to // an offset specified by targetX and targetY. The copied region is clipped if it would go outside either source or target's bounds. void TileMap_copyTiles(TileMap * target, TileMap * source, int sourceX, int sourceY, int targetX, int targetY, unsigned int width, unsigned int height); // Similar to TileMap_copyTiles(), but doesn't overwrite target where source's tileID is 0 void TileMap_composite(TileMap * target, TileMap * source, int sourceX, int sourceY, int targetX, int targetY, unsigned int width, unsigned int height); void TileMap_flipHorizontal(TileMap * tileMap); void TileMap_flipVertical(TileMap * tileMap); void TileMap_rotate180(TileMap * tileMap); void TileMap_rotate90CW(TileMap * tileMap); void TileMap_rotate90CCW(TileMap * tileMap); #ifdef __cplusplus } #endif #endif