/src/Tilemap.c

https://github.com/megamarc/Tilengine · C · 363 lines · 176 code · 26 blank · 161 comment · 26 complexity · 77cd1d2cb00ef15d8bef86148bc481f8 MD5 · raw file

  1. /*
  2. * Tilengine - The 2D retro graphics engine with raster effects
  3. * Copyright (C) 2015-2019 Marc Palacios Domenech <mailto:megamarc@hotmail.com>
  4. * All rights reserved
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. * */
  10. #ifdef __STRICT_ANSI__
  11. #undef __STRICT_ANSI__
  12. #endif
  13. #include <string.h>
  14. #include <stdio.h>
  15. #include "Tilengine.h"
  16. #include "Tilemap.h"
  17. typedef struct
  18. {
  19. int x,y,w,h;
  20. }
  21. Rect;
  22. /*!
  23. * \brief
  24. * Creates a new tilemap
  25. *
  26. * \param rows
  27. * Number of rows (vertical dimension)
  28. *
  29. * \param cols
  30. * Number of cols (horizontal dimension)
  31. *
  32. * \param tiles
  33. * Array of tiles with data (see struct Tile)
  34. *
  35. * \param bgcolor
  36. * Background color value (RGB32 packed)
  37. *
  38. * \param tileset
  39. * Optional reference to associated tileset, can be NULL
  40. *
  41. * \returns
  42. * Reference to the created tilemap, or NULL if error
  43. *
  44. * \remarks
  45. * Make sure that the tiles[] array is has at least rows*cols items or application may crash
  46. *
  47. * \see
  48. * TLN_DeleteTilemap(), struct Tile
  49. */
  50. TLN_Tilemap TLN_CreateTilemap (int rows, int cols, TLN_Tile tiles, uint32_t bgcolor, TLN_Tileset tileset)
  51. {
  52. TLN_Tilemap tilemap = NULL;
  53. int size = sizeof(struct Tilemap) + (rows * cols * sizeof(Tile));
  54. tilemap = (TLN_Tilemap)CreateBaseObject (OT_TILEMAP, size);
  55. if (!tilemap)
  56. return NULL;
  57. tilemap->rows = rows;
  58. tilemap->cols = cols;
  59. tilemap->bgcolor = bgcolor;
  60. tilemap->tileset = tileset;
  61. tilemap->visible = true;
  62. if (tiles)
  63. memcpy (tilemap->tiles, tiles, tilemap->size - sizeof(struct Tilemap));
  64. TLN_SetLastError (TLN_ERR_OK);
  65. return tilemap;
  66. }
  67. /*!
  68. * \brief
  69. * Creates a duplicate of the specified tilemap
  70. *
  71. * \param src
  72. * Reference to the tilemap to clone
  73. *
  74. * \returns
  75. * A reference to the newly cloned tilemap, or NULL if error
  76. *
  77. * \see
  78. * TLN_LoadTilemap()
  79. */
  80. TLN_Tilemap TLN_CloneTilemap (TLN_Tilemap src)
  81. {
  82. TLN_Tilemap tilemap;
  83. if (!CheckBaseObject (src, OT_TILEMAP))
  84. return NULL;
  85. tilemap = (TLN_Tilemap)CloneBaseObject (src);
  86. if (tilemap)
  87. {
  88. TLN_SetLastError (TLN_ERR_OK);
  89. return tilemap;
  90. }
  91. else
  92. return NULL;
  93. }
  94. /*!
  95. * \brief
  96. * Returns the number of vertical tiles in the tilemap
  97. *
  98. * \param tilemap
  99. * Reference of the tilemap to get info
  100. *
  101. * \see
  102. * TLN_GetTilemapCols()
  103. */
  104. int TLN_GetTilemapRows (TLN_Tilemap tilemap)
  105. {
  106. if (CheckBaseObject (tilemap, OT_TILEMAP))
  107. {
  108. TLN_SetLastError (TLN_ERR_OK);
  109. return tilemap->rows;
  110. }
  111. else
  112. return 0;
  113. }
  114. /*!
  115. * \brief
  116. * Returns the number of horizontal tiles in the tilemap
  117. *
  118. * \param tilemap
  119. * Reference of the tilemap to get info
  120. *
  121. * \see
  122. * TLN_GetTilemapCols()
  123. */
  124. int TLN_GetTilemapCols (TLN_Tilemap tilemap)
  125. {
  126. if (CheckBaseObject (tilemap, OT_TILEMAP))
  127. {
  128. TLN_SetLastError (TLN_ERR_OK);
  129. return tilemap->cols;
  130. }
  131. else
  132. return 0;
  133. }
  134. /*!
  135. * \brief
  136. * Returns the optional associated tileset to the specified tilemap
  137. *
  138. * \param tilemap
  139. * Reference of the tilemap to get info
  140. *
  141. * \see
  142. * TLN_CreateTilemap(), TLN_LoadTilemap()
  143. */
  144. TLN_Tileset TLN_GetTilemapTileset (TLN_Tilemap tilemap)
  145. {
  146. if (CheckBaseObject (tilemap, OT_TILEMAP))
  147. {
  148. TLN_SetLastError (TLN_ERR_OK);
  149. return tilemap->tileset;
  150. }
  151. else
  152. return NULL;
  153. }
  154. static TLN_Tile GetTilemapPtr (TLN_Tilemap tilemap, int row, int col)
  155. {
  156. if (row<tilemap->rows && col<tilemap->cols)
  157. return &tilemap->tiles[row*tilemap->cols + col];
  158. else
  159. return NULL;
  160. }
  161. /*!
  162. * \brief
  163. * Gets data of a single tile inside a tilemap
  164. *
  165. * \param tilemap
  166. * Reference of the tilemap to get the tile
  167. *
  168. * \param row
  169. * Vertical location of the tile (0 <= row < rows)
  170. *
  171. * \param col
  172. * Horizontal location of the tile (0 <= col < cols)
  173. *
  174. * \param tile
  175. * Reference to an application-allocated struct Tile that will get the data
  176. */
  177. bool TLN_GetTilemapTile (TLN_Tilemap tilemap, int row, int col, TLN_Tile tile)
  178. {
  179. if (CheckBaseObject (tilemap, OT_TILEMAP) && tile)
  180. {
  181. TLN_Tile srctile = GetTilemapPtr (tilemap, row, col);
  182. if (srctile)
  183. {
  184. tile->flags = srctile->flags;
  185. tile->index = srctile->index;
  186. TLN_SetLastError (TLN_ERR_OK);
  187. return true;
  188. }
  189. else
  190. {
  191. TLN_SetLastError (TLN_ERR_WRONG_SIZE);
  192. return false;
  193. }
  194. }
  195. else
  196. return false;
  197. }
  198. /*!
  199. * \brief
  200. * Sets a tile of a tilemap
  201. *
  202. * \param tilemap
  203. * Reference to the tilemap
  204. *
  205. * \param row
  206. * Row (vertical position) of the tile [0 - num_rows - 1]
  207. *
  208. * \param col
  209. * Column (horizontal position) of the tile [0 - num_cols - 1]
  210. *
  211. * \param tile
  212. * Reference to the tile to set, or NULL to set an empty tile
  213. *
  214. * \returns
  215. * true (success) or false (error)
  216. */
  217. bool TLN_SetTilemapTile (TLN_Tilemap tilemap, int row, int col, TLN_Tile tile)
  218. {
  219. if (CheckBaseObject (tilemap, OT_TILEMAP) && tile)
  220. {
  221. TLN_Tile dsttile = GetTilemapPtr (tilemap, row, col);
  222. if (dsttile)
  223. {
  224. if (tile)
  225. {
  226. dsttile->value = tile->value;
  227. if (tilemap->maxindex < tile->index)
  228. tilemap->maxindex = tile->index;
  229. }
  230. else
  231. dsttile->value = 0;
  232. TLN_SetLastError (TLN_ERR_OK);
  233. return true;
  234. }
  235. else
  236. {
  237. TLN_SetLastError (TLN_ERR_WRONG_SIZE);
  238. return false;
  239. }
  240. }
  241. else
  242. return false;
  243. }
  244. /*!
  245. * \brief
  246. * Deletes the specified tilemap and frees memory
  247. *
  248. * \param tilemap
  249. * Reference to the tilemap to delete
  250. *
  251. * \remarks
  252. * Don't delete a tilemap currently attached to a layer!
  253. *
  254. * \see
  255. * TLN_LoadTilemap(), TLN_CloneTilemap()
  256. */
  257. bool TLN_DeleteTilemap (TLN_Tilemap tilemap)
  258. {
  259. if (CheckBaseObject (tilemap, OT_TILEMAP))
  260. {
  261. if (ObjectOwner (tilemap))
  262. TLN_DeleteTileset (tilemap->tileset);
  263. DeleteBaseObject (tilemap);
  264. TLN_SetLastError (TLN_ERR_OK);
  265. return true;
  266. }
  267. else
  268. return false;
  269. }
  270. static void ClipRect (Rect* src, Rect* dst)
  271. {
  272. if (src->x + src->w >= dst->w)
  273. src->w = dst->w - src->x;
  274. if (src->y + src->h >= dst->h)
  275. src->h = dst->h - src->y;
  276. }
  277. /*!
  278. * \brief
  279. * Copies blocks of tiles between two tilemaps
  280. *
  281. * \param src
  282. * Reference to the source tilemap
  283. *
  284. * \param srcrow
  285. * Starting row (vertical position) inside the source tilemap
  286. *
  287. * \param srccol
  288. * Starting column (horizontal position) inside the source tilemap
  289. *
  290. * \param rows
  291. * Number of rows to copy
  292. *
  293. * \param cols
  294. * Number of columns to copy
  295. *
  296. * \param dst
  297. * Reference to the target tilemap
  298. *
  299. * \param dstrow
  300. * Starting row (vertical position) inside the target tilemap
  301. *
  302. * \param dstcol
  303. * Starting column (horizontal position) inside the target tilemap
  304. *
  305. * \remarks
  306. * Use this function to implement tile streaming
  307. */
  308. bool TLN_CopyTiles (TLN_Tilemap src, int srcrow, int srccol, int rows, int cols, TLN_Tilemap dst, int dstrow, int dstcol)
  309. {
  310. int y, size;
  311. if (!CheckBaseObject (src, OT_TILEMAP) || !CheckBaseObject (dst, OT_TILEMAP))
  312. return false;
  313. /* setup rects */
  314. {
  315. Rect tgtrect = {srccol,srcrow, cols,rows}; /* area a copiar */
  316. Rect srcrect = {0,0, src->rows,src->cols}; /* tilemap de origen */
  317. Rect dstrect = {0,0, dst->rows,dst->cols}; /* tilemap de destino */
  318. /* clipping */
  319. ClipRect (&tgtrect, &srcrect);
  320. ClipRect (&tgtrect, &dstrect);
  321. size = tgtrect.w * sizeof(Tile);
  322. for (y=0; y<tgtrect.h; y++)
  323. {
  324. Tile* srctile = GetTilemapPtr (src, y + srcrow, srccol);
  325. Tile* dsttile = GetTilemapPtr (dst, y + dstrow, dstcol);
  326. if (srctile && dsttile)
  327. memcpy (dsttile, srctile, size);
  328. else
  329. {
  330. TLN_SetLastError (TLN_ERR_WRONG_SIZE);
  331. return false;
  332. }
  333. }
  334. }
  335. TLN_SetLastError (TLN_ERR_OK);
  336. return true;
  337. }