tilemap_layer.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. // Flexlay - A Generic 2D Game Editor
  2. // Copyright (C) 2002 Ingo Ruhnke <grumbel@gmx.de>
  3. //
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. #include "tilemap_layer.hpp"
  17. #include <ClanLib/Display/display.h>
  18. #include <ClanLib/Display/pixel_format.h>
  19. #include <ClanLib/Display/sprite.h>
  20. #include "gui/editor_map_component.hpp"
  21. #include "tile.hpp"
  22. #include "tileset.hpp"
  23. #include "tile_brush.hpp"
  24. #include "blitter.hpp"
  25. #include "layer_impl.hpp"
  26. TilemapLayer TilemapLayer::current_;
  27. class TilemapLayerImpl : public LayerImpl
  28. {
  29. public:
  30. Tileset tileset;
  31. CL_Color background_color;
  32. CL_Color foreground_color;
  33. Field<int> field;
  34. bool draw_grid;
  35. bool draw_attribute;
  36. MetaData metadata;
  37. TilemapLayerImpl() {}
  38. virtual ~TilemapLayerImpl() {}
  39. bool has_bounding_rect() const;
  40. CL_Rect get_bounding_rect();
  41. void draw(const GraphicContextState& state, CL_GraphicContext* gc);
  42. };
  43. TilemapLayer::TilemapLayer()
  44. {
  45. }
  46. /*TilemapLayer::TilemapLayer(const std::shared_ptr<TilemapLayerImpl>& i)
  47. : impl(i)
  48. {
  49. }*/
  50. TilemapLayer::TilemapLayer(Tileset tileset_, int w, int h)
  51. : impl(new TilemapLayerImpl())
  52. {
  53. impl->field = Field<int>(w, h);
  54. // FIXME: Move this to the widget or to some more generic
  55. // map-properties thingy
  56. impl->draw_grid = false;
  57. impl->draw_attribute = false;
  58. for (int y = 0; y < impl->field.get_height(); ++y)
  59. for (int x = 0; x < impl->field.get_width(); ++x)
  60. impl->field.at(x, y) = 0;
  61. impl->background_color = CL_Color(0, 0, 0, 0);
  62. impl->foreground_color = CL_Color(255, 255, 255, 255);
  63. impl->tileset = tileset_;
  64. }
  65. TilemapLayer::~TilemapLayer()
  66. {
  67. }
  68. void
  69. TilemapLayer::draw(const GraphicContextState& state, CL_GraphicContext* gc)
  70. {
  71. impl->draw(state, gc);
  72. }
  73. void
  74. TilemapLayerImpl::draw(const GraphicContextState& state, CL_GraphicContext* gc)
  75. {
  76. int tile_size = this->tileset.get_tile_size();
  77. if (this->background_color.get_alpha() != 0)
  78. CL_Display::fill_rect(CL_Rect(CL_Point(0,0),
  79. CL_Size(this->field.get_width() * tile_size,
  80. this->field.get_height() * tile_size)),
  81. this->background_color);
  82. CL_Display::flush();
  83. CL_Rect rect(state.get_clip_rect());
  84. int start_x = std::max(0, rect.left / tile_size);
  85. int start_y = std::max(0, rect.top / tile_size);
  86. int end_x = std::min(this->field.get_width(), rect.right / tile_size + 1);
  87. int end_y = std::min(this->field.get_height(), rect.bottom / tile_size + 1);
  88. if (foreground_color != CL_Color(255, 255, 255, 255))
  89. {
  90. for (int y = start_y; y < end_y; ++y)
  91. for (int x = start_x; x < end_x; ++x)
  92. {
  93. int tile_id = this->field.at(x, y);
  94. if (tile_id)
  95. {
  96. Tile* tile = tileset.create(tile_id);
  97. if (tile) // skip transparent tile for faster draw
  98. {
  99. CL_Sprite sprite = tile->get_sprite();
  100. sprite.set_color(foreground_color);
  101. sprite.draw(x * tile_size, y * tile_size, gc);
  102. if (draw_attribute)
  103. CL_Display::fill_rect(CL_Rect(CL_Point(x, y), CL_Size(tileset.get_tile_size(),
  104. tileset.get_tile_size())),
  105. tile->get_attribute_color());
  106. }
  107. }
  108. }
  109. }
  110. else
  111. {
  112. for (int y = start_y; y < end_y; ++y)
  113. for (int x = start_x; x < end_x; ++x)
  114. {
  115. int tile_id = this->field.at(x, y);
  116. if (tile_id) // skip transparent tile for faster draw
  117. {
  118. Tile* tile = tileset.create(this->field.at(x, y));
  119. if (tile)
  120. {
  121. tile->get_sprite().draw(x * tile_size, y * tile_size, gc);
  122. if (draw_attribute)
  123. CL_Display::fill_rect(CL_Rect(CL_Point(x, y), CL_Size(tileset.get_tile_size(),
  124. tileset.get_tile_size())),
  125. tile->get_attribute_color());
  126. }
  127. }
  128. }
  129. }
  130. if (this->draw_grid)
  131. {
  132. for (int y = start_y; y <= end_y; ++y)
  133. CL_Display::draw_line(start_x * tile_size,
  134. y * tile_size,
  135. end_x * tile_size,
  136. y * tile_size,
  137. y % 2 ? CL_Color(150, 150, 150) : CL_Color(255, 255, 255));
  138. for (int x = start_x; x <= end_x; ++x)
  139. CL_Display::draw_line(x * tile_size,
  140. start_y * tile_size,
  141. x * tile_size,
  142. end_y * tile_size,
  143. x % 2 ? CL_Color(150, 150, 150) : CL_Color(255, 255, 255));
  144. }
  145. CL_Display::flush();
  146. }
  147. int
  148. TilemapLayer::get_tile (int x, int y)
  149. {
  150. if (x >= 0 && x < (int)impl->field.get_width() &&
  151. y >= 0 && y < (int)impl->field.get_height())
  152. return impl->field.at(x, y);
  153. else
  154. return 0;
  155. }
  156. void
  157. TilemapLayer::resize(const CL_Size& size, const CL_Point& point)
  158. {
  159. impl->field.resize(size.width, size.height, point.x, point.y);
  160. }
  161. void
  162. TilemapLayer::draw_tile(int id, const CL_Point& pos)
  163. {
  164. if (pos.x >= 0 && pos.x < impl->field.get_width()
  165. && pos.y >= 0 && pos.y < impl->field.get_height())
  166. {
  167. impl->field.at(pos.x, pos.y) = id;
  168. }
  169. }
  170. void
  171. TilemapLayer::draw_tile(const TileBrush& brush, const CL_Point& pos)
  172. {
  173. draw_tiles(&impl->field, brush, pos);
  174. }
  175. void
  176. TilemapLayer::draw_tiles(Field<int>* field, const TileBrush& brush, const CL_Point& pos)
  177. {
  178. int start_x = std::max(0, -pos.x);
  179. int start_y = std::max(0, -pos.y);
  180. int end_x = std::min(brush.get_width(), field->get_width() - pos.x);
  181. int end_y = std::min(brush.get_height(), field->get_height() - pos.y);
  182. for (int y = start_y; y < end_y; ++y)
  183. for (int x = start_x; x < end_x; ++x)
  184. {
  185. if (brush.is_opaque() || brush.at(x, y) != 0)
  186. {
  187. field->at(pos.x + x, pos.y + y) = brush.at(x, y);
  188. }
  189. }
  190. }
  191. void
  192. TilemapLayer::set_draw_attribute(bool t)
  193. {
  194. impl->draw_attribute = t;
  195. }
  196. bool
  197. TilemapLayer::get_draw_attribute() const
  198. {
  199. return impl->draw_attribute;
  200. }
  201. void
  202. TilemapLayer::set_draw_grid(bool t)
  203. {
  204. impl->draw_grid = t;
  205. }
  206. bool
  207. TilemapLayer::get_draw_grid() const
  208. {
  209. return impl->draw_grid;
  210. }
  211. CL_PixelBuffer
  212. TilemapLayer::create_pixelbuffer()
  213. {
  214. int tile_size = impl->tileset.get_tile_size();
  215. CL_PixelBuffer pixelbuffer(get_width() * tile_size,
  216. get_height() * tile_size,
  217. get_width() * tile_size * 4,
  218. CL_PixelFormat::rgba8888);
  219. {
  220. pixelbuffer.lock();
  221. unsigned char* buf = static_cast<unsigned char*>(pixelbuffer.get_data());
  222. int width = pixelbuffer.get_width();
  223. int height = pixelbuffer.get_height();
  224. // Draw a nice gradient
  225. for(int y = 0; y < height; ++y)
  226. {
  227. for (int x = 0; x < width; ++x)
  228. {
  229. buf[4*(y*width + x) + 0] = 255;
  230. buf[4*(y*width + x) + 1] = 255;
  231. buf[4*(y*width + x) + 2] = 255*y/height;
  232. buf[4*(y*width + x) + 3] = 255*y/height;
  233. }
  234. }
  235. pixelbuffer.unlock();
  236. }
  237. for (int y = 0; y < get_height(); ++y)
  238. for (int x = 0; x < get_width(); ++x)
  239. {
  240. Tile* tile = impl->tileset.create(impl->field.at(x, y));
  241. if (tile)
  242. {
  243. CL_PixelBuffer buf = tile->get_pixelbuffer();
  244. if (buf)
  245. {
  246. blit(pixelbuffer, buf, x*tile_size, y*tile_size);
  247. }
  248. }
  249. }
  250. return pixelbuffer;
  251. }
  252. CL_Rect
  253. TilemapLayer::get_bounding_rect()
  254. {
  255. return impl->get_bounding_rect();
  256. }
  257. CL_Rect
  258. TilemapLayerImpl::get_bounding_rect()
  259. {
  260. return CL_Rect(CL_Point(0, 0),
  261. CL_Size(field.get_width() * tileset.get_tile_size(),
  262. field.get_height() * tileset.get_tile_size()));
  263. }
  264. CL_Point
  265. TilemapLayer::world2tile(const CL_Pointf& pos) const
  266. {
  267. int x = static_cast<int>(pos.x / impl->tileset.get_tile_size());
  268. int y = static_cast<int>(pos.y / impl->tileset.get_tile_size());
  269. return CL_Point(pos.x < 0 ? x-1 : x,
  270. pos.y < 0 ? y-1 : y);
  271. }
  272. Field<int>*
  273. TilemapLayer::get_field()
  274. {
  275. return &impl->field;
  276. }
  277. TilemapLayer
  278. TilemapLayer::current()
  279. {
  280. return current_;
  281. }
  282. void
  283. TilemapLayer::set_current(TilemapLayer t)
  284. {
  285. current_ = t;
  286. }
  287. Tileset
  288. TilemapLayer::get_tileset()
  289. {
  290. return impl->tileset;
  291. }
  292. const std::vector<int>&
  293. TilemapLayer::get_data()
  294. {
  295. return impl->field.get_data();
  296. }
  297. void
  298. TilemapLayer::set_data(std::vector<int> d)
  299. {
  300. impl->field.set_data(d);
  301. }
  302. void
  303. TilemapLayer::set_background_color(const CL_Color& color)
  304. {
  305. impl->background_color = color;
  306. }
  307. void
  308. TilemapLayer::set_foreground_color(const CL_Color& color)
  309. {
  310. impl->foreground_color = color;
  311. }
  312. int
  313. TilemapLayer::get_width() const
  314. {
  315. return impl->field.get_width();
  316. }
  317. int
  318. TilemapLayer::get_height() const
  319. {
  320. return impl->field.get_height();
  321. }
  322. bool
  323. TilemapLayer::has_bounding_rect() const
  324. {
  325. return impl->has_bounding_rect();
  326. }
  327. bool
  328. TilemapLayerImpl::has_bounding_rect() const
  329. {
  330. return true;
  331. }
  332. Layer
  333. TilemapLayer::to_layer()
  334. {
  335. return Layer(impl);
  336. }
  337. void
  338. TilemapLayer::set_metadata(const MetaData& metadata)
  339. {
  340. impl->metadata = metadata;
  341. }
  342. MetaData
  343. TilemapLayer::get_metadata() const
  344. {
  345. return impl->metadata;
  346. }
  347. /* EOF */