Advertisement
krzat

SFML TileRenderer

Jan 24th, 2013
2,666
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.74 KB | None | 0 0
  1. //MapRenderer.h
  2.  
  3. #pragma once
  4. #include <SFML\Graphics.hpp>
  5.  
  6. ///callback function that will provide data for each tile
  7. typedef void (*TileProvider)(int, int, int, sf::Color&, sf::IntRect&);
  8.  
  9. ///provides fast rendering of tilemaps
  10. class MapRenderer : public sf::Drawable
  11. {
  12. public:
  13.     MapRenderer(sf::Texture *texture, TileProvider provider, float tileSize=16, int layers=1);
  14.     ~MapRenderer(void);
  15.     float getTileSize() const;
  16.     int getLayers() const;
  17.  
  18.     void refresh();
  19.     void refresh(int x, int y);
  20.     void draw(sf::RenderTarget &rt, sf::RenderStates states) const;
  21.     void update(sf::RenderTarget &rt);
  22. private:
  23.     int width;
  24.     int height;
  25.     float tileSize;
  26.     int layers;
  27.     std::vector<sf::Vertex> vertices;
  28.     sf::Vector2i offset;
  29.     TileProvider provider;
  30.     sf::Texture *texture;
  31.  
  32.     void setSize(sf::Vector2f v);
  33.     void setCorner(sf::Vector2f v);
  34.     sf::Vector2i getTile(sf::Vector2f pos) const;
  35.     void draw(int index, sf::FloatRect rec, sf::IntRect src, sf::Color color);
  36.     void refreshLocal(int left, int top, int right, int bottom);
  37.  
  38. };
  39.  
  40. //MapRenderer.cpp
  41.  
  42. #include "MapRenderer.h"
  43.  
  44. MapRenderer::MapRenderer(sf::Texture *texture, TileProvider provider, float tileSize, int layers)
  45. {
  46.     if(provider == 0 || layers <= 0) throw "hey";
  47.     this->provider = provider;
  48.     this->texture = texture;
  49.     this->tileSize = tileSize;
  50.     this->layers = layers;
  51. }
  52. MapRenderer::~MapRenderer(void)
  53. {
  54. }
  55. float MapRenderer::getTileSize() const
  56. {
  57.     return tileSize;
  58. }
  59. int MapRenderer::getLayers() const
  60. {
  61.     return layers;
  62. }
  63.  
  64. ///redraw every tile on screen
  65. void MapRenderer::refresh()
  66. {
  67.     refreshLocal(0,0,width, height);
  68. }
  69.  
  70. ///redraw part of screen
  71. void MapRenderer::refreshLocal(int left, int top, int right, int bottom)
  72. {
  73.     for(int y= top; y < bottom; y++)
  74.         for(int x=left; x < right; x++)
  75.             refresh(x + offset.x, y + offset.y);
  76. }
  77.  
  78. ///adjust amount of vertices to size of the screen
  79. void MapRenderer::setSize(sf::Vector2f v)
  80. {
  81.     int w = static_cast<int>(v.x / tileSize) + 2;
  82.     int h = static_cast<int>(v.y / tileSize) + 2;
  83.     if(w == width && h == height) return;
  84.  
  85.     width = w;
  86.     height = h;
  87.  
  88.     int size = width*height*4*layers;
  89.     //allocate quad per tile per layer
  90.     if(vertices.size() < size)
  91.         vertices.resize(width*height*4*layers);
  92.     refresh();
  93. }
  94.  
  95. ///refresh parts of screen if player moved
  96. void MapRenderer::setCorner(sf::Vector2f v)
  97. {
  98.     auto tile = getTile(v);
  99.     auto dif = tile - offset;
  100.     if(dif.x == 0 && dif.y == 0)
  101.         return; //player didnt moved, no need to update anything
  102.     offset = tile; //offset is a tile position in the left top corner
  103.    
  104.     if(abs(dif.x) > width/ 4 || abs(dif.y) > height/4)
  105.     {
  106.         //if difference is too big, we simply redraw everyting
  107.         refresh();
  108.     }
  109.     else
  110.     {
  111.         //if player moved right, refresh colum on the right side of the screen
  112.         if (dif.x > 0) refreshLocal(width - dif.x, 0, width, height);
  113.         //and vice versa
  114.                 else refreshLocal(0, 0, -dif.x, height);
  115.  
  116.         //same if player moved top/ bottom
  117.         if (dif.y > 0) refreshLocal(0, height - dif.y, width, height);
  118.                 else refreshLocal(0, 0, width, -dif.y);
  119.     }
  120. }
  121. ///take world position and return tile indexes
  122. sf::Vector2i MapRenderer::getTile(sf::Vector2f pos) const
  123. {
  124.     int x = static_cast<int>(pos.x / tileSize);
  125.     int y = static_cast<int>(pos.y / tileSize);
  126.     if(pos.x < 0) x--;
  127.     if(pos.y < 0) y--;
  128.     return sf::Vector2i(x,y);
  129. }
  130. ///draw textured quad on given position
  131. void MapRenderer::draw(int index, sf::FloatRect rec, sf::IntRect src, sf::Color color)
  132. {
  133.     auto ptr = &vertices[index];
  134.     ptr->position.x = rec.left;
  135.     ptr->position.y = rec.top;
  136.     ptr->texCoords.x = src.left;
  137.     ptr->texCoords.y = src.top;
  138.     ptr->color = color;
  139.     ptr++;
  140.  
  141.     ptr->position.x = rec.left + rec.width;
  142.     ptr->position.y = rec.top;
  143.     ptr->texCoords.x = src.left + src.width;
  144.     ptr->texCoords.y = src.top;
  145.     ptr->color = color;
  146.     ptr++;
  147.  
  148.     ptr->position.x = rec.left + rec.width;
  149.     ptr->position.y = rec.top + rec.height;
  150.     ptr->texCoords.x = src.left + src.width;
  151.     ptr->texCoords.y = src.top + src.height;
  152.     ptr->color = color;
  153.     ptr++;
  154.  
  155.     ptr->position.x = rec.left;
  156.     ptr->position.y = rec.top + rec.height;
  157.     ptr->texCoords.x = src.left;
  158.     ptr->texCoords.y = src.top + src.height;
  159.     ptr->color = color;
  160. }
  161.  
  162. ///redraw quads that belong to given tile
  163. void MapRenderer::refresh(int x, int y)
  164. {
  165.     if(x < offset.x || x >= offset.x + width || y < offset.y || y >= offset.y + height)
  166.         return; //check if tile is visible
  167.  
  168.     //vertices works like 2d ring buffer
  169.     auto vx = x % width;      
  170.     auto vy = y % height;
  171.     if (vx < 0) vx += width;
  172.     if (vy < 0) vy += height;
  173.     //we can do this, because some tiles are never to be seen at once
  174.  
  175.     auto index = (vx+vy * width) * 4 * layers;
  176.     auto rec = sf::FloatRect(x * tileSize, y * tileSize, tileSize, tileSize);
  177.  
  178.     for (int i = 0; i < layers; i++)
  179.     {
  180.         sf::Color color;
  181.         sf::IntRect src;
  182.         provider(x, y, i, color, src);
  183.         //get color and texture rectangle from our providing function
  184.  
  185.         draw(index, rec, src, color);
  186.         //insert quad in vertex array
  187.         index += 4;
  188.     }
  189. }
  190. ///draw map on screen
  191. void MapRenderer::draw(sf::RenderTarget &rt, sf::RenderStates states) const
  192. {
  193.     states.texture = texture;
  194.     rt.draw(&vertices[0], vertices.size(), sf::PrimitiveType::Quads);
  195. }
  196.  
  197. ///update screen size and position of camera
  198. void MapRenderer::update(sf::RenderTarget &rt)
  199. {
  200.     auto view = rt.getView();
  201.     setSize(view.getSize());
  202.     setCorner(rt.mapPixelToCoords(sf::Vector2i()));
  203. }
  204.  
  205. //main.cpp
  206.  
  207. #pragma once
  208. #include <SFML\Graphics.hpp>
  209. #include "MapRenderer.h"
  210. using namespace sf;
  211.  
  212. ///we will simply autogenerate tiles
  213. ///you can read them from your tilemap class, etc.
  214. void provider(int x, int y, int layer, Color& color, IntRect &src)
  215. {
  216.     //color = Color::Yellow;
  217.     color = Color((x*5)%255, (y*5)%255,50);
  218.     src = IntRect(0,0,1,1);
  219. }
  220.  
  221. void main()
  222. {
  223.     RenderWindow window(VideoMode(800,600), "Game");
  224.     Clock clock;
  225.     View view = window.getDefaultView();
  226.     Texture texture;
  227.     texture.create(1,1);
  228.     MapRenderer map(&texture, provider);
  229.     Vector2f prev;
  230.     while(window.isOpen())
  231.     {
  232.         float dT = clock.getElapsedTime().asSeconds();
  233.         clock.restart();
  234.  
  235.         window.clear();
  236.         window.setView(view);
  237.  
  238.         map.update(window);
  239.         window.draw(map);
  240.  
  241.         window.display();
  242.  
  243.         Event event;
  244.         while(window.pollEvent(event))
  245.         {
  246.             Vector2f ms, delta;
  247.             switch(event.type)
  248.             {
  249.             case Event::Closed:
  250.                 window.close();
  251.                 break;
  252.             case Event::Resized:
  253.                 view.setSize(event.size.width, event.size.height);
  254.                 view.setCenter(view.getSize() * 0.5f );
  255.                 break;
  256.             case Event::MouseMoved:
  257.                 ms = Vector2f(event.mouseMove.x, event.mouseMove.y);
  258.                 delta = ms - prev;
  259.                 if(Mouse::isButtonPressed(Mouse::Button::Left))
  260.                     view.setCenter(view.getCenter() - delta);
  261.                 prev = ms;
  262.                 break;
  263.             case Event::KeyPressed:
  264.                 map.refresh();
  265.                 break;
  266.             }
  267.         }
  268.     }
  269. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement