TestTiled.h 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. #pragma once
  2. #include "test.h"
  3. // Bits on the far end of the 32-bit global tile ID are used for tile flags
  4. const unsigned FLIPPED_HORIZONTALLY_FLAG = 0x80000000;
  5. const unsigned FLIPPED_VERTICALLY_FLAG = 0x40000000;
  6. const unsigned FLIPPED_DIAGONALLY_FLAG = 0x20000000;
  7. DECLARE_SMART(Tiled, spTiled);
  8. class Tiled: public Sprite
  9. {
  10. public:
  11. struct layer
  12. {
  13. vector<unsigned int> tiles;
  14. };
  15. list< layer > layers;
  16. int width;
  17. int height;
  18. spNativeTexture nt;
  19. int tileWidth;
  20. int tileHeight;
  21. int cols;
  22. int rows;
  23. void createTileSetTexture(Image& src)
  24. {
  25. cols = src.getWidth() / tileWidth;
  26. rows = src.getHeight() / tileHeight;
  27. Image dest;
  28. dest.init(cols * (tileWidth + 2), rows * (tileHeight * 2), TF_R8G8B8A8);
  29. //http://stackoverflow.com/questions/19611745/opengl-black-lines-in-between-tiles
  30. for (int y = 0; y < rows; ++y)
  31. {
  32. for (int x = 0; x < cols; ++x)
  33. {
  34. Rect srcRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
  35. Rect destRect = srcRect;
  36. destRect.pos.x += 2 * x + 1;
  37. destRect.pos.y += 2 * y + 1;
  38. ImageData srcIm = src.lock(srcRect);
  39. ImageData destIm = dest.lock(destRect);
  40. operations::blit(srcIm, destIm);
  41. destRect.expand(Point(1, 1), Point(1, 1));
  42. operations::blit(
  43. dest.lock(destRect.pos.x + 1, destRect.pos.y + 1, tileWidth, 1),
  44. dest.lock(destRect.pos.x + 1, destRect.pos.y, tileWidth, 1));
  45. operations::blit(
  46. dest.lock(destRect.pos.x + 1, destRect.pos.y + tileHeight, tileWidth, 1),
  47. dest.lock(destRect.pos.x + 1, destRect.pos.y + tileHeight + 1, tileWidth, 1));
  48. operations::blit(
  49. dest.lock(destRect.pos.x + 1, destRect.pos.y, 1, tileHeight + 2),
  50. dest.lock(destRect.pos.x, destRect.pos.y, 1, tileHeight + 2));
  51. operations::blit(
  52. dest.lock(destRect.pos.x + tileWidth, destRect.pos.y, 1, tileHeight + 2),
  53. dest.lock(destRect.pos.x + tileWidth + 1, destRect.pos.y, 1, tileHeight + 2));
  54. }
  55. }
  56. nt = IVideoDriver::instance->createTexture();
  57. nt->init(dest.lock());
  58. nt->setClamp2Edge(true);
  59. nt->setLinearFilter(false);
  60. }
  61. Tiled(const std::string& tmx, const std::string& texture)
  62. {
  63. file::buffer fb;
  64. //read tmx into buffer
  65. file::read(tmx, fb);
  66. pugi::xml_document doc;
  67. //parse xml
  68. doc.load_buffer(fb.getData(), fb.getSize());
  69. pugi::xml_node map = doc.document_element();
  70. width = map.attribute("width").as_int();
  71. height = map.attribute("height").as_int();
  72. tileWidth = map.attribute("tilewidth").as_int();
  73. tileHeight = map.attribute("tileheight").as_int();
  74. //load layers
  75. pugi::xml_node layerNode = map.child("layer");
  76. while (!strcmp(layerNode.name(), "layer"))
  77. {
  78. pugi::xml_node data = layerNode.child("data");
  79. pugi::xml_node tile = data.first_child();
  80. layer l;
  81. for (int y = 0; y < height; ++y)
  82. {
  83. for (int x = 0; x < width; ++x)
  84. {
  85. l.tiles.push_back(tile.attribute("gid").as_uint());
  86. tile = tile.next_sibling();
  87. }
  88. }
  89. layers.push_back(l);
  90. layerNode = layerNode.next_sibling();
  91. }
  92. //load image from file
  93. Image src;
  94. file::read(texture, fb);
  95. src.init(fb, true);
  96. createTileSetTexture(src);
  97. //saveImage(dest.lock(), "test.tga");
  98. }
  99. void drawLayer(int startX, int startY, int endX, int endY, const layer& l)
  100. {
  101. const std::vector<unsigned int>& tiles = l.tiles;
  102. Color color(Color::White);
  103. STDRenderer* renderer = STDRenderer::getCurrent();
  104. float tw = 1.0f / nt->getWidth();
  105. float th = 1.0f / nt->getHeight();
  106. for (int y = startY; y < endY; ++y)
  107. {
  108. for (int x = startX; x < endX; ++x)
  109. {
  110. unsigned int tile = tiles[y * width + x];
  111. if (!tile)
  112. continue;
  113. tile = tile - 1;
  114. bool flipped_horizontally = (tile & FLIPPED_HORIZONTALLY_FLAG) ? true : false;
  115. bool flipped_vertically = (tile & FLIPPED_VERTICALLY_FLAG) ? true : false;
  116. bool flipped_diagonally = (tile & FLIPPED_DIAGONALLY_FLAG) ? true : false;
  117. // Clear the flags
  118. tile &= ~(FLIPPED_HORIZONTALLY_FLAG |
  119. FLIPPED_VERTICALLY_FLAG |
  120. FLIPPED_DIAGONALLY_FLAG);
  121. int col = tile % cols;
  122. int row = tile / cols;
  123. Rect src(col * (tileWidth + 2) + 1, row * (tileHeight + 2) + 1, tileWidth, tileHeight);
  124. if (flipped_horizontally)
  125. {
  126. src.pos.x += tileWidth;
  127. src.size.x *= -1;
  128. }
  129. if (flipped_vertically)
  130. {
  131. src.pos.y += tileHeight;
  132. src.size.y *= -1;
  133. }
  134. RectF srcUV = src.cast<RectF>();
  135. srcUV.pos.x *= tw;
  136. srcUV.pos.y *= th;
  137. srcUV.size.x *= tw;
  138. srcUV.size.y *= th;
  139. Rect dest(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
  140. RectF destF = dest.cast<RectF>();
  141. renderer->draw(color, srcUV, destF);
  142. }
  143. }
  144. }
  145. void doRender(const RenderState& rs)
  146. {
  147. Material::setCurrent(rs.material);
  148. STDRenderer* renderer = STDRenderer::getCurrent();
  149. renderer->setTexture(nt);
  150. renderer->setTransform(rs.transform);
  151. renderer->setBlendMode(blend_premultiplied_alpha);
  152. Transform world = rs.transform;
  153. world.invert();
  154. //find top left local position of TiledActor visible on display
  155. Vector2 topLeft = world.transform(Vector2(0, 0));
  156. //find bottom right local position of TiledActor visible on display
  157. Vector2 bottomRight = world.transform(getStage()->getSize());
  158. //we don't want to draw tiles outside of visible area
  159. int startX = std::max(0, int(topLeft.x / tileWidth));
  160. int startY = std::max(0, int(topLeft.y / tileHeight));
  161. int endX = std::min(width, int(bottomRight.x / tileWidth) + 1);
  162. int endY = std::min(height, int(bottomRight.y / tileHeight) + 1);
  163. for (std::list<layer>::const_iterator i = layers.begin(); i != layers.end(); ++i)
  164. drawLayer(startX, startY, endX, endY, *i);
  165. }
  166. };
  167. class TestTiled : public Test
  168. {
  169. public:
  170. TestTiled()
  171. {
  172. spTiled tiled = new Tiled("etc/orthogonal-outside.tmx", "etc/buch-outdoor.png");
  173. //use camera class from other test!
  174. spCamera cam = new Camera;
  175. cam->attachTo(content);
  176. cam->setContent(tiled);
  177. cam->setSize(content->getSize());
  178. }
  179. };