Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Vertexes are slow  (Read 2734 times)

0 Members and 1 Guest are viewing this topic.

lrx

  • Newbie
  • *
  • Posts: 29
    • View Profile
Vertexes are slow
« on: August 04, 2012, 06:54:56 am »
Hello again

I was advised to use vertexes and views in my Tile Map engine(bleh again I know). Reading this forum I got impression that they are supposed to be fast. So I've written sample code to test this and I can not get decent fps and using View causes horizontal lines disorder on image. Possibly I don't understand how to use Vertexes. I am trying to get 300fps+ on 1680x1050 resolution which means I have to display around 360 tiles each frame + possible other objects later one.
 Here is what I'm doing:
1. setup 2d vector of VertexArrays as sf::Quads
2. ONCE for each Tilemap[][] setup 4 vertexes(position and texture coords)
3. in main loop go though all Tilemap[][] and call draw(Tilemap
  • [y], &texture);


Resulting in around 30 fps, which is by far not enough, especially if I wanted to add more sprites on top of that later on.

Am I doing it wrong or It just has to be this way? Maybe using this method would be faster?

#include <SFML/Graphics.hpp>

#define TILE_IMG_W 64
#define TILE_IMG_H 64

//function declarations
//Getting rect defining part of texture to use
sf::Rect<int> GetSourceRectangle(int tileIndex);
//converting index numbers to Draw position
sf::Vector2i IndxToIso(int x, int y);

void Draw();
//Preparing Map
void init();

sf::RenderWindow window;
sf::Texture tileTexture;
sf::View* Cam;

std::vector< std::vector< sf::VertexArray > > Tilemap;

//MapSize = size*size
int size = 50;

int main()
{      
        Cam = new sf::View(sf::FloatRect(0, 0, 1680, 1050));
       
        //Load Texture
        tileTexture.loadFromFile("part4_tileset.png");
       
        //Initialize window
        window.create(sf::VideoMode(1680, 1050),"");
        window.setActive(false);

        //Setup map,
        init();

        //thread for draw function
        sf::Thread RenderThread(&Draw);
        RenderThread.launch();

        //GameLoop
        while(window.isOpen())
        {
                //Event Handling
                sf::Event event;
                while(window.pollEvent(event))
                {
                        if(event.type == sf::Event::Closed)
                                window.close();
                        if(event.type == sf::Event::KeyPressed)
                        {
                                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
                                        window.close();
                        }
                       
                }

        }
        return 0;
}

void Draw()
{
        int counter = 0;
        int fps = 0;
        sf::Text fpsText;
        sf::Clock clk;

        window.setActive(true);
        window.setVerticalSyncEnabled(false);

        while(window.isOpen())
        {
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
                        Cam->move(-10, 0);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
                        Cam->move(10, 0);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
                        Cam->move(0, -10);
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
                        Cam->move(0, 10);

                window.setView(*Cam);
                window.clear();

                //Drawing loops
                for(int y=0; y<size; y++)
                {
                        for(int x=0; x<size; x++)
                        {
                                window.draw(Tilemap[x][y], &tileTexture);
                        }
                }

                //fps
                counter++;
                if(clk.getElapsedTime().asSeconds()>=1)
                {
                        fps = counter/clk.getElapsedTime().asSeconds();
                        counter=0;
                        clk.restart();
                        std::string sss;
                        char tempB[20];
                        sprintf(tempB, "%d", fps);
                        sss = tempB;
                        fpsText.setString(sss);
                }
               
                window.setView(window.getDefaultView());
                window.draw(fpsText);
                window.display();
        }
};

void init()
{
        //Temp Quad
        sf::Vertex vertices[4];
       
        //preparing vectors
        Tilemap.resize(size);
        for(int i=0; i<size; i++)
                Tilemap[i].resize(size);
       
        //setting VertexArrays for each tle
        for(int y=0; y<size; y++)
        {
                for(int x=0; x<size; x++)
                {
                        sf::Vector2i position = IndxToIso(x, y);
                        sf::Rect<int> TexPos = GetSourceRectangle(0);

                        Tilemap[x][y].setPrimitiveType(sf::Quads);

                        Tilemap[x][y].append(sf::Vertex(sf::Vector2f(position.x, position.y), sf::Vector2f(TexPos.left, TexPos.top)));
                        Tilemap[x][y].append(sf::Vertex(sf::Vector2f(position.x + TILE_IMG_W, position.y), sf::Vector2f(TexPos.left + TexPos.width, TexPos.top)));
                        Tilemap[x][y].append(sf::Vertex(sf::Vector2f(position.x + TILE_IMG_W, position.y + TILE_IMG_H), sf::Vector2f(TexPos.left + TexPos.width, TexPos.top + TexPos.height)));
                        Tilemap[x][y].append(sf::Vertex(sf::Vector2f(position.x, position.y + TILE_IMG_H), sf::Vector2f(TexPos.left, TexPos.top + TexPos.height)));
                }
        }                                      
};

sf::Rect<int> GetSourceRectangle(int tileIndex)
{
        sf::Vector2u TileSetSize = tileTexture.getSize();
        int tileY = tileIndex / (TileSetSize.x / TILE_IMG_W);
        int tileX = tileIndex % (TileSetSize.x / TILE_IMG_W);

        sf::Rect<int> tempR(tileX * TILE_IMG_W, tileY * TILE_IMG_H, TILE_IMG_W, TILE_IMG_H);
        return tempR;
};

sf::Vector2i IndxToIso(int x, int y)
{
        sf::Vector2i temp;

        temp.x = (x-y) * 33;
        temp.y = (x+y) * 17;

        return temp;
};
 

binary1248

  • SFML Team
  • Hero Member
  • *****
  • Posts: 1405
  • I am awesome.
    • View Profile
    • The server that really shouldn't be running
Re: Vertexes are slow
« Reply #1 on: August 04, 2012, 07:32:52 am »
I think you misunderstood the hints on the forum regarding usage of sf::VertexArray. They are only faster because they result in less OpenGL calls (among other calls) being made in total for the same amount of vertices (if used correctly). Having a 2d vector of sf::VertexArrays won't improve performance much over using standard SFML geometry because you are still drawing x*y distinct objects. What you need to do is combine all tiles into one sf::VertexArray and draw just that one thing. How you do this I leave to you as an exercise :).

And as a tip: You need to be careful how you iterate through vectors. They are the fastest STL container regarding sequential access but iterating through a 2d vector in the wrong order will destroy performance. You might want to look at this.
SFGUI # SFNUL # GLS # Wyrm <- Why do I waste my time on such a useless project? Because I am awesome (first meaning).

lrx

  • Newbie
  • *
  • Posts: 29
    • View Profile
Re: Vertexes are slow
« Reply #2 on: August 04, 2012, 08:13:00 am »
I thought that might be the case :F

Regarding iterating order - it's going to be huge problem for me. Algorithm I've to "pick tiles to display" requires to go though x first, but I'll look into other solutions.

I will work on these stuff and report back should I encounter more troubles
« Last Edit: August 05, 2012, 01:17:03 am by lrx »

lrx

  • Newbie
  • *
  • Posts: 29
    • View Profile
Re: Vertexes are slow
« Reply #3 on: August 05, 2012, 01:17:12 am »
OK! I can't do it ;/ now I'm just pumping Vertexes representing each corner of each Tile into single VertexArray then drawing them, it boosted my fps a bit, but still is far cry from what I expected and need :F
This is still bad way of doing things right?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: Vertexes are slow
« Reply #4 on: August 05, 2012, 01:23:08 am »
This is still bad way of doing things right?
Depends on your code change which my magic ball unfortunatly refuses to show... ;)

If you join the tiles every iteration into the vertex array then yes this is still bad.
The idea is to have one big VertexArray that contains all the tiles and if you change anything you make the changes on the vertex array and not on any other structurs of yours and you don't update the vertex array with any structurs of yours.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

lrx

  • Newbie
  • *
  • Posts: 29
    • View Profile
Re: Vertexes are slow
« Reply #5 on: August 05, 2012, 01:29:31 am »
This is still bad way of doing things right?
If you join the tiles every iteration into the vertex array then yes this is still bad.

If I was not to do that I would have to keep whole map stored in vertex array at all times, which sounds like bad idea considering size of it.
But I guess that's why guy in different topic was supposed to divide map into smaller chunks.
Would that work? Like divide whole map into chunks of approximately 1/4 of display and just keep track of which chunk to display?
that would mean ~9 calls in worst case.