SFML community forums

Help => Graphics => Topic started by: Switchboy on August 23, 2021, 11:45:12 am

Title: VertexArray Quads not rendering in the right color or place
Post by: Switchboy on August 23, 2021, 11:45:12 am
I am currently working on a RTS game with a minimap. Since drawing this minimap is eating around 20% of my CPU time. I thought of reducing the amount of draw calls. So instead of using a rectangleShape for every map tile I might try using a vertex array of quads instead. And only draw the vertex array going from 62500 (for a 250*250 tiles map) draw calls per miniMap layer update to one!

So I came up with the following code:

        static const sf::Color colors[] =
        {
            {0, 0, 0},
            {152, 205, 115},
            {200, 160, 80},
            {200, 160, 80},
            {200, 160, 80},
            {200, 160, 80},
            {200, 160, 80},
            {69, 164, 208},
            {69, 164, 208},
            {69, 164, 208},
            {69, 164, 208},
            {69, 164, 208}
        };


sf::VertexArray miniMapPoints(sf::Quads, MAP_HEIGHT*MAP_WIDTH);
            minimapTexture.clear(sf::Color(0, 0, 0, 0));
            for (int j = 0; j < MAP_HEIGHT; j++)
            {
                for (int i = 0; i < MAP_WIDTH; i++)
                {
                    sf::Vertex* currentMiniMapQuad = &miniMapPoints[(i * MAP_HEIGHT) + j];

                    currentMiniMapQuad[0].color = colors[currentGame.currentMap[i][j]];
                    currentMiniMapQuad[1].color = colors[currentGame.currentMap[i][j]];
                    currentMiniMapQuad[2].color = colors[currentGame.currentMap[i][j]];
                    currentMiniMapQuad[3].color = colors[currentGame.currentMap[i][j]];

                    //cords miniMapSpace(cords location)
                    //{
                    //    int wX = mapOffsetX * 20 + (location.x - location.y) * (20 / 2);
                    //    int wY = mapOffsetY * 10 + (location.x + location.y) * (10 / 2);
                    //    return { wX, wY };
                    //}
                   
                    //Each quad should be 20px wide and 10px high. We define them clockwise from the top left (x + 0 and y + 0)
                    currentMiniMapQuad[0].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y)); //0,0
                    currentMiniMapQuad[1].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y)); //1,0
                    currentMiniMapQuad[2].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y) + 10.f); //1,1
                    currentMiniMapQuad[3].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y)+10.f); //0,1
                   
                   
                    //miniMapPixel.setFillColor(colors[currentGame.currentMap[i][j]]);
                    //miniMapPixel.setPosition(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y));
                    //minimapTexture.draw(miniMapPixel);
                }

            }
            minimapTexture.draw(miniMapPoints);
            minimapTexture.display();

I left the old working code for drawing the miniMapPixels in there for reference. And also added the commented out function miniMapSpace() to make clear what is happening.

I attached the result of the miniMap draw and the expected result.

                        currentMiniMapQuad[0].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y) + 10.f); //0,1
                        currentMiniMapQuad[1].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y)); //0,0
                        currentMiniMapQuad[2].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y)); //1,0
                        currentMiniMapQuad[3].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y) + 10.f); //1,1

I tried different orders of the currentQuad corner coordinates. Like starting on the bottom left. While this somewhat fixed the colors the map drawn is not correct. Eg water tiles are drawn where grass tiles need to go. And there is distortion the lower Y goes and the higher X goes. So last attachment.

I think the error lies in the order of assigning the four corners of the quad. But I cant figure out the right order.

And doing this:
currentMiniMapQuad->color = colors[currentGame.currentMap[i][j]];
 
Also does not get the correct result.

Title: Re: VertexArray Quads not rendering in the right color or place
Post by: Switchboy on August 23, 2021, 01:41:17 pm
I think something is going wrong here: sf::Vertex* currentMiniMapQuad = &miniMapPoints[(i * MAP_HEIGHT) + j]; Could it be that I am actually the memory adress of another Quad corner?

                        sf::Vertex* currentMiniMapQuad = &miniMapPoints[(i * MAP_HEIGHT) + j];
                        if (i % 2 == 0 && j % 2 == 0) {
                           
                            //Each quad should be 20px wide and 10px high. We define them clockwise from the top left (x + 0 and y + 0)
                            currentMiniMapQuad[0].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y));                  // 0 , 0 = 0 , 0
                            currentMiniMapQuad[1].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y));           // 1 , 0 = 20 , 0
                            currentMiniMapQuad[2].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x) + 20.f, static_cast<float>(miniMapSpace({ i, j }).y) + 10.f);    // 1 , 1 = 20 , 10
                            currentMiniMapQuad[3].position = sf::Vector2f(static_cast<float>(miniMapSpace({ i, j }).x), static_cast<float>(miniMapSpace({ i, j }).y) + 10.f);           // 0 , 1 = 0 , 10

                            currentMiniMapQuad[0].color = colors[currentGame.currentMap[i][j]];
                            currentMiniMapQuad[1].color = colors[currentGame.currentMap[i][j]];
                            currentMiniMapQuad[2].color = colors[currentGame.currentMap[i][j]];
                            currentMiniMapQuad[3].color = colors[currentGame.currentMap[i][j]];
                        }
                        else {
                            currentMiniMapQuad[0].position = sf::Vector2f(0, 0);
                            currentMiniMapQuad[1].position = sf::Vector2f(0, 0);
                            currentMiniMapQuad[2].position = sf::Vector2f(0, 0);
                            currentMiniMapQuad[3].position = sf::Vector2f(0, 0);
                            currentMiniMapQuad[0].color = colors[0];
                            currentMiniMapQuad[1].color = colors[0];
                            currentMiniMapQuad[2].color = colors[0];
                            currentMiniMapQuad[3].color = colors[0];
                        }

See result of my attempt to only draw even coordinates and move the other vertexes to 0,0 with a size of 0 and color black


Fixed it! It was indeed a memory adress issue!
Should have used: sf::Vertex* currentMiniMapQuad = &miniMapPoints[((i * MAP_HEIGHT) + j) *4];

Title: Re: VertexArray Quads not rendering in the right color or place
Post by: Paul on August 25, 2021, 02:24:52 am
You don't need render whole minimap each frame, especially terrain or another elements which never changes. Render it once to texture.
Title: Re: VertexArray Quads not rendering in the right color or place
Post by: Switchboy on August 25, 2021, 03:28:33 pm
Already did those optimazations. Actors and fog of war are more dynamic so they need a lot of redraws. While I was at it I decided to make the background a vertex array ass well. (Started with that because it was easy for prototyping) and ran into the above problem.