/** * @file tilemap.h * @brief Declares the public tilemap API. */ #ifndef _TILEMAP_H_ #define _TILEMAP_H_ #include #include #include #include #include #define AKGL_TILEMAP_MAX_WIDTH 512 #define AKGL_TILEMAP_MAX_HEIGHT 512 #define AKGL_TILEMAP_MAX_LAYERS 16 #define AKGL_TILEMAP_MAX_TILESETS 16 #define AKGL_TILEMAP_MAX_TILES_PER_IMAGE 65536 #define AKGL_TILEMAP_MAX_TILESET_NAME_SIZE 512 #define AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE PATH_MAX #define AKGL_TILEMAP_MAX_OBJECT_NAME_SIZE 512 #define AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER 128 #define AKGL_TILEMAP_OBJECT_TYPE_ACTOR 1 #define AKGL_TILEMAP_LAYER_TYPE_TILES 1 #define AKGL_TILEMAP_LAYER_TYPE_OBJECTS 2 #define AKGL_TILEMAP_LAYER_TYPE_IMAGE 3 /** @brief Stores tileset metadata, texture, and frame offsets. */ typedef struct { float x; float y; int gid; int id; int height; int width; int rotation; int type; bool visible; akgl_Actor *actorptr; char name[AKGL_TILEMAP_MAX_OBJECT_NAME_SIZE]; } akgl_TilemapObject; /** @brief Represents an object embedded in a tilemap layer. */ typedef struct { short type; float opacity; bool visible; int height; int width; int x; int y; int id; SDL_Texture *texture; int data[AKGL_TILEMAP_MAX_WIDTH * AKGL_TILEMAP_MAX_HEIGHT]; akgl_TilemapObject objects[AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER]; } akgl_TilemapLayer; /** @brief Stores tile, image, or object data for one map layer. */ typedef struct { int columns; int firstgid; char imagefilename[AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE]; int imageheight; int imagewidth; char name[AKGL_TILEMAP_MAX_TILESET_NAME_SIZE]; SDL_Texture *texture; // Use this as a lookup table instead of storing tiles // in individual textures to blit them from a single // texture at runtime // FIXME: This is probably not very efficient. For a map // with a single tileset it makes sense. For a map with // multiple tilesets you may have set A start at firstgid 1 // and have 1728 tiles. Set B may start at firstgid 1729 and // have 1728 more tiles. This means Set B has 1728 empty // tile_offsets[] entries before firstgid 1729 because of the // way akgl_tilemap_load_tilesets() works. This is really inefficient // and should be improved in the future, and will eventually // lead to premature exhaustion of AKGL_TILEMAP_MAX_TILES_PER_IMAGE // because set D or E may only have 64 tiles but they may be // at the upper end of the array bound already because of this. int tile_offsets[AKGL_TILEMAP_MAX_TILES_PER_IMAGE][2]; int tilecount; int tileheight; int tilewidth; int spacing; int margin; } akgl_Tileset; /** @brief Represents a complete tilemap and its optional physics backend. */ typedef struct { int tilewidth; int tileheight; int width; int height; int numlayers; int orientation; // 0 = orthogonal, 1 = isometric int numtilesets; int p_foreground_y; int p_vanishing_y; int p_foreground_h; int p_vanishing_h; float p_foreground_scale; float p_vanishing_scale; float p_scale; float p_rate; akgl_Tileset tilesets[AKGL_TILEMAP_MAX_TILESETS]; akgl_TilemapLayer layers[AKGL_TILEMAP_MAX_LAYERS]; // Different levels may have different physics. bool use_own_physics; akgl_PhysicsBackend physics; } akgl_Tilemap; /** * @brief Tilemap load. * @param fname Path to the input or output file. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load(char *fname, akgl_Tilemap *dest); /** * @brief Tilemap draw. * @param dest Output destination populated by the function. * @param viewport World-space rectangle visible to the renderer. * @param layeridx Zero-based tilemap layer index. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw(akgl_Tilemap *dest, SDL_FRect *viewport, int layeridx); /** * @brief Tilemap draw tileset. * @param dest Output destination populated by the function. * @param tilesetidx Zero-based tileset index. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_draw_tileset(akgl_Tilemap *dest, int tilesetidx); /* * These functions are part of the internal API and should not be called by the user. * They are only exposed here for unit testing. */ /** * @brief Get json tilemap property. * @param obj Object to initialize, inspect, or modify. * @param key JSON object key or property name to locate. * @param type Expected JSON property type or backend type name. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_KEY When the corresponding validation or operation fails. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_TYPE When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_tilemap_property(json_t *obj, char *key, char *type, json_t **dest); /** * @brief Get json properties string. * @param obj Object to initialize, inspect, or modify. * @param key JSON object key or property name to locate. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_* Propagates an error reported by a delegated operation. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_string(json_t *obj, char *key, akgl_String **dest); /** * @brief Get json properties integer. * @param obj Object to initialize, inspect, or modify. * @param key JSON object key or property name to locate. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_* Propagates an error reported by a delegated operation. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_get_json_properties_integer(json_t *obj, char *key, int *dest); /** * @brief Tilemap compute tileset offsets. * @param dest Output destination populated by the function. * @param tilesetidx Zero-based tileset index. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_* Propagates an error reported by a delegated operation. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_compute_tileset_offsets(akgl_Tilemap *dest, int tilesetidx); /** * @brief Tilemap load layer objects. * @param dest Output destination populated by the function. * @param root Base directory used to resolve the path. * @param layerid Zero-based tilemap layer index. * @param dirname Directory containing paths referenced by the document. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layer_objects(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname); /** * @brief Tilemap load layer tile. * @param dest Output destination populated by the function. * @param root Base directory used to resolve the path. * @param layerid Zero-based tilemap layer index. * @param dirname Directory containing paths referenced by the document. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layer_tile(akgl_Tilemap *dest, json_t *root, int layerid, akgl_String *dirname); /** * @brief Tilemap load layers. * @param dest Output destination populated by the function. * @param root Base directory used to resolve the path. * @param dirname Directory containing paths referenced by the document. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. * @throws AKERR_OUTOFBOUNDS When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_layers(akgl_Tilemap *dest, json_t *root, akgl_String *dirname); /** * @brief Tilemap load tilesets each. * @param tileset JSON tileset object to load. * @param dest Output destination populated by the function. * @param tsidx Zero-based destination tileset index. * @param dirname Directory containing paths referenced by the document. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets_each(json_t *tileset, akgl_Tilemap *dest, int tsidx, akgl_String *dirname); /** * @brief Tilemap load tilesets. * @param dest Output destination populated by the function. * @param root Base directory used to resolve the path. * @param dirname Directory containing paths referenced by the document. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_load_tilesets(akgl_Tilemap *dest, json_t *root, akgl_String *dirname); /** * @brief Tilemap release. * @param dest Output destination populated by the function. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_release(akgl_Tilemap *dest); /** * @brief Tilemap scale actor. * @param map Tilemap to inspect, draw, or modify. * @param actor Actor to inspect or modify. * @return `NULL` on success, otherwise an error context owned by the caller. * @throws AKERR_NULLPOINTER When the corresponding validation or operation fails. */ akerr_ErrorContext AKERR_NOIGNORE *akgl_tilemap_scale_actor(akgl_Tilemap *map, akgl_Actor *actor); #endif //_TILEMAP_H_