You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

299 line
7.1 KiB

  1. //
  2. // Lol Engine
  3. //
  4. // Copyright © 2010—2019 Sam Hocevar <sam@hocevar.net>
  5. //
  6. // Lol Engine is free software. It comes without any warranty, to
  7. // the extent permitted by applicable law. You can redistribute it
  8. // and/or modify it under the terms of the Do What the Fuck You Want
  9. // to Public License, Version 2, as published by the WTFPL Task Force.
  10. // See http://www.wtfpl.net/ for more details.
  11. //
  12. #include <lol/engine-internal.h>
  13. #include <map>
  14. #include <cstdlib>
  15. #include <cstdio>
  16. #include <cstring>
  17. #if defined _WIN32
  18. # define WIN32_LEAN_AND_MEAN
  19. # include <windows.h>
  20. # undef WIN32_LEAN_AND_MEAN
  21. #endif
  22. #include "textureimage-private.h"
  23. namespace lol
  24. {
  25. /* The tileset cache */
  26. static entity_dict<TileSet> tileset_cache;
  27. /*
  28. * TileSet implementation class
  29. */
  30. class TileSetData
  31. {
  32. friend class TileSet;
  33. protected:
  34. /* Pixels, then texture coordinates */
  35. array<ibox2, box2> m_tiles;
  36. ivec2 m_tile_size;
  37. };
  38. /*
  39. * Public TileSet class
  40. */
  41. TileSet *TileSet::create(std::string const &path)
  42. {
  43. auto ret = tileset_cache.get(path);
  44. return ret ? ret : tileset_cache.set(path, new TileSet(path));
  45. }
  46. TileSet *TileSet::create(std::string const &path, image* img)
  47. {
  48. auto ret = tileset_cache.get(path);
  49. return ret ? ret : tileset_cache.set(path, new TileSet(path, img));
  50. }
  51. TileSet *TileSet::create(std::string const &path, image* img, array<ivec2, ivec2>& tiles)
  52. {
  53. auto ret = tileset_cache.get(path);
  54. if (!ret)
  55. {
  56. ret = tileset_cache.set(path, new TileSet(path, img));
  57. ret->define_tile(tiles);
  58. }
  59. return ret;
  60. }
  61. TileSet *TileSet::create(std::string const &path, ivec2 size, ivec2 count)
  62. {
  63. auto ret = tileset_cache.get(path);
  64. if (!ret)
  65. {
  66. ret = tileset_cache.set(path, new TileSet(path));
  67. /* If count is valid, fix size; otherwise, fix count. */
  68. if (count.x > 0 && count.y > 0)
  69. {
  70. size = ret->m_data->m_image_size / count;
  71. }
  72. else
  73. {
  74. if (size.x <= 0 || size.y <= 0)
  75. size = ivec2(32, 32);
  76. count = max(ivec2(1, 1), ret->m_data->m_image_size / size);
  77. }
  78. for (int j = 0; j < count.y; ++j)
  79. for (int i = 0; i < count.x; ++i)
  80. {
  81. ret->define_tile(ibox2(size * ivec2(i, j),
  82. size * ivec2(i + 1, j + 1)));
  83. }
  84. }
  85. return ret;
  86. }
  87. TileSet *TileSet::create(std::string const &path, image* img, ivec2 size, ivec2 count)
  88. {
  89. auto ret = tileset_cache.get(path);
  90. if (!ret)
  91. {
  92. ret = tileset_cache.set(path, new TileSet(path, img));
  93. /* If count is valid, fix size; otherwise, fix count. */
  94. if (count.x > 0 && count.y > 0)
  95. {
  96. size = ret->m_data->m_image_size / count;
  97. }
  98. else
  99. {
  100. if (size.x <= 0 || size.y <= 0)
  101. size = ivec2(32, 32);
  102. count = max(ivec2(1, 1), ret->m_data->m_image_size / size);
  103. }
  104. for (int j = 0; j < count.y; ++j)
  105. for (int i = 0; i < count.x; ++i)
  106. {
  107. ret->define_tile(ibox2(size * ivec2(i, j),
  108. size * ivec2(i + 1, j + 1)));
  109. }
  110. }
  111. return ret;
  112. }
  113. void TileSet::destroy(TileSet *tileset)
  114. {
  115. // FIXME: decrement!
  116. tileset_cache.erase(tileset);
  117. }
  118. TileSet::TileSet(std::string const &path)
  119. : TextureImage(path),
  120. m_tileset_data(new TileSetData()),
  121. m_palette(nullptr)
  122. {
  123. }
  124. TileSet::TileSet(std::string const &path, image *img)
  125. : TextureImage(path, img),
  126. m_tileset_data(new TileSetData()),
  127. m_palette(nullptr)
  128. {
  129. }
  130. TileSet::~TileSet()
  131. {
  132. delete m_tileset_data;
  133. }
  134. void TileSet::Init(std::string const &path, ResourceCodecData* loaded_data)
  135. {
  136. //Load tileset if available
  137. auto tileset_data = dynamic_cast<ResourceTilesetData*>(loaded_data);
  138. if (tileset_data != nullptr)
  139. {
  140. define_tile(tileset_data->m_tiles);
  141. }
  142. m_data->m_name = "<tileset> " + path;
  143. super::Init(path, loaded_data);
  144. }
  145. void TileSet::Init(std::string const &path, Image* image)
  146. {
  147. super::Init(path, image);
  148. m_data->m_name = "<tileset> " + path;
  149. }
  150. //Inherited from Entity -------------------------------------------------------
  151. std::string TileSet::GetName() const
  152. {
  153. return m_data->m_name;
  154. }
  155. //New methods -----------------------------------------------------------------
  156. void TileSet::clear_all()
  157. {
  158. m_tileset_data->m_tiles.clear();
  159. }
  160. int TileSet::define_tile(ibox2 rect)
  161. {
  162. m_tileset_data->m_tiles.push(rect,
  163. box2((vec2)rect.aa / (vec2)m_data->m_texture_size,
  164. (vec2)rect.bb / (vec2)m_data->m_texture_size));
  165. return m_tileset_data->m_tiles.count() - 1;
  166. }
  167. void TileSet::define_tile(ivec2 count)
  168. {
  169. ivec2 size = m_data->m_image_size / count;
  170. for (int j = 0; j < count.y; ++j)
  171. for (int i = 0; i < count.x; ++i)
  172. {
  173. define_tile(ibox2(size * ivec2(i, j),
  174. size * ivec2(i + 1, j + 1)));
  175. }
  176. }
  177. void TileSet::define_tile(array<ibox2>& tiles)
  178. {
  179. for (int i = 0; i < tiles.count(); i++)
  180. define_tile(tiles[i]);
  181. }
  182. void TileSet::define_tile(array<ivec2, ivec2>& tiles)
  183. {
  184. for (int i = 0; i < tiles.count(); i++)
  185. define_tile(ibox2(tiles[i].m1, tiles[i].m1 + tiles[i].m2));
  186. }
  187. int TileSet::GetTileCount() const
  188. {
  189. return m_tileset_data->m_tiles.count();
  190. }
  191. ivec2 TileSet::GetTileSize(int tileid) const
  192. {
  193. return m_tileset_data->m_tiles[tileid].m1.extent();
  194. }
  195. ibox2 TileSet::GetTilePixel(int tileid) const
  196. {
  197. return m_tileset_data->m_tiles[tileid].m1;
  198. }
  199. box2 TileSet::GetTileTexel(int tileid) const
  200. {
  201. return m_tileset_data->m_tiles[tileid].m2;
  202. }
  203. //Palette ---------------------------------------------------------------------
  204. void TileSet::SetPalette(TileSet* palette)
  205. {
  206. m_palette = palette;
  207. }
  208. TileSet* TileSet::GetPalette()
  209. {
  210. return m_palette;
  211. }
  212. TileSet const* TileSet::GetPalette() const
  213. {
  214. return m_palette;
  215. }
  216. void TileSet::BlitTile(uint32_t id, mat4 model, vec3 *vertex, vec2 *texture)
  217. {
  218. ibox2 pixels = m_tileset_data->m_tiles[id].m1;
  219. box2 texels = m_tileset_data->m_tiles[id].m2;
  220. float dtx = texels.extent().x;
  221. float dty = texels.extent().y;
  222. float tx = texels.aa.x;
  223. float ty = texels.aa.y;
  224. vec3 pos = (model * vec4(0.f, 0.f, 0.f, 1.f)).xyz;
  225. vec3 extent_x = 0.5f * pixels.extent().x * (model * vec4::axis_x).xyz;
  226. vec3 extent_y = 0.5f * pixels.extent().y * (model * vec4::axis_y).xyz;
  227. if (!m_data->m_image && m_data->m_texture)
  228. {
  229. *vertex++ = pos + extent_x + extent_y;
  230. *vertex++ = pos - extent_x + extent_y;
  231. *vertex++ = pos + extent_x - extent_y;
  232. *vertex++ = pos + extent_x - extent_y;
  233. *vertex++ = pos - extent_x + extent_y;
  234. *vertex++ = pos - extent_x - extent_y;
  235. *texture++ = vec2(tx + dtx, ty);
  236. *texture++ = vec2(tx, ty);
  237. *texture++ = vec2(tx + dtx, ty + dty);
  238. *texture++ = vec2(tx + dtx, ty + dty);
  239. *texture++ = vec2(tx, ty);
  240. *texture++ = vec2(tx, ty + dty);
  241. }
  242. else
  243. {
  244. memset((void *)vertex, 0, 6 * sizeof(vec3));
  245. memset((void *)texture, 0, 6 * sizeof(vec2));
  246. }
  247. }
  248. } /* namespace lol */