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

Author Topic: Batch Drawing  (Read 11238 times)

0 Members and 1 Guest are viewing this topic.

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« on: February 27, 2012, 01:50:17 pm »
As a way of making the drawing much faster would it be possible to use batch drawing to draw everything at once?
Not sure if this is already planned for the new graphics API but it would make things much faster.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #1 on: February 27, 2012, 01:57:44 pm »
What the new graphics API provides is not really batching, it's more an access to the low-level stuff (vertex array) that allows you to create your own geometric entities.

Have you tried it first?
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #2 on: February 27, 2012, 03:14:06 pm »
Im using the newest API but still relying on sf::Sprite, the problem is that because of driver issues or something, drawing around 2000 sprites (for the background tiles) makes it go less than a frame a second, and as im using intell graphics card I cant really use a renderTexture to draw onto and then just draw that.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #3 on: February 27, 2012, 03:15:47 pm »
So you should definitely use sf::VertexArray.
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #4 on: February 27, 2012, 03:25:30 pm »
From what I see on the documentation, would I just use a vertex array instead of a sprite?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #5 on: February 27, 2012, 03:32:09 pm »
You would use a single vertex array instead of many sprites that compose the same entity (same texture, same transform). The most typical use case is a tiled map.
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #6 on: February 27, 2012, 03:37:56 pm »
I see, however how would I assign the images?
Do you know if there are any tutorials on how to use a vertex array? or same code in any of the examples?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #7 on: February 27, 2012, 03:45:27 pm »
There is an examlpe here:
http://www.sfml-dev.org/forum/viewtopic.php?t=7060

If you need more specific help you can describe what you want, and I'll try to write an example for you.
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #8 on: February 27, 2012, 07:01:05 pm »
Quote from: "Laurent"
There is an examlpe here:
http://www.sfml-dev.org/forum/viewtopic.php?t=7060

If you need more specific help you can describe what you want, and I'll try to write an example for you.


That should work fine, however im trying to implement it with SFML.Net with this code:

Code: [Select]
class Map
{

SFML.Graphics.VertexArray map;
SFML.Graphics.RenderStates state;

public Map ()
{
}

public Map (string filename)
{
System.Drawing.Bitmap mapText = new System.Drawing.Bitmap ("./Resources/Maps/Level1.png");

//Console.WriteLine(mapText.Width + ":" + mapText.Height);

state = new SFML.Graphics.RenderStates (TextureManager.GetFile ("./Resources/Images/Tiles.png"));

map = new SFML.Graphics.VertexArray (SFML.Graphics.PrimitiveType.Quads, (uint)(mapText.Width * mapText.Height * 4));


for (int x = 0; x < mapText.Width; x++) {
for (int y = 0; y < mapText.Height; y++) {

int size = 16;
int width = 16;
uint current = (uint)((x + y *  mapText.Width) * 4);

// define the position of the 4 points of the current tile
map [current ].Position = new SFML.Window.Vector2f ((x + 0) * size, (y + 0) * size);
map [current + 1].Position = new SFML.Window.Vector2f ((x + 0) * size, (y + 1) * size);
map [current + 2].Position = new SFML.Window.Vector2f ((x + 1) * size, (y + 1) * size);
map [current + 3].Position = new SFML.Window.Vector2f ((x + 1) * size, (y + 0) * size);

int tx = 0;
int ty = 0;

if (mapText.GetPixel (x, y) == System.Drawing.Color.Black) {
tx = 1;
ty = 1;
} else {
tx = 0;
ty = 0;
}

map [current + 0].TexCoords = new SFML.Window.Vector2i ((tx + 0) * size, (ty + 0) * size);
map [current + 1].TexCoords = new SFML.Window.Vector2i ((tx + 0) * size, (ty + 1) * size);
map [current + 2].TexCoords = new SFML.Window.Vector2i ((tx + 1) * size, (ty + 1) * size);
map [current + 3].TexCoords = new SFML.Window.Vector2i ((tx + 1) * size, (ty + 0) * size);
}
}


}

public void Draw (SFML.Graphics.RenderWindow target)
{
target.Draw (map, state);
}
}


But I am getting these errors:
Quote

/home/richy/Projects/DotGame/DotGunner/src/Map.cs(37,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(38,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(39,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(40,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(53,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(54,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(55,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)
/home/richy/Projects/DotGame/DotGunner/src/Map.cs(56,45): error CS1612: Cannot modify a value type return value of `SFML.Graphics.VertexArray.this[uint]'. Consider storing the value in a temporary variable
/home/richy/Projects/DotGame/DotGunner/extlibs/linSFML/sfml net debug/sfmlnet-graphics-2.dll (Location of the symbol related to previous error)


Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #9 on: February 27, 2012, 07:36:48 pm »
Got it working, however because of the method I currently use to store the map, it isnt loading them.
Not sure if you know of anyway to get these to compare correctly?

Code: [Select]
int tx = 0;
int ty = 0;

if (mapText.GetPixel(x, y) == System.Drawing.Color.Black ) {
Console.WriteLine(mapText.GetPixel (x, y));
tx = 1;
ty = 1;
}

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #10 on: February 27, 2012, 07:40:29 pm »
Try to compare with SFML.Graphics.Color.Black.
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #11 on: February 27, 2012, 07:57:38 pm »
Quote from: "Laurent"
Try to compare with SFML.Graphics.Color.Black.


MapText is a System.Drawing.Bitmap tho.
I have got it working using:
Code: [Select]
if (mapText.GetPixel(x, y).ToArgb() == System.Drawing.Color.Black.ToArgb() ) {
Console.WriteLine(mapText.GetPixel (x, y));
tx = 1;
ty = 1;
}


Not ideal as I have to use an extra 2 functions just to compare but it does the job.

Anyway now that it has been ported I have noticed some tremendous gains in performance however its still very slow compared to the C++ version, dont get me wrong i know the C# version wont be as fast as teh C++ one but I was hoping better performance than this :S

The image on the left is C++ drawing an 800x600 image using a sprite.
The one on the right is the C# version drawing an 800x600 pixel map with vertex arrays

I should mention the C# version is normally at 190ms, there must have been a small spke due to the screenshot

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Batch Drawing
« Reply #12 on: February 27, 2012, 08:25:24 pm »
Quote
The image on the left is C++ drawing an 800x600 image using a sprite.
The one on the right is the C# version drawing an 800x600 pixel map with vertex arrays

Is there really only one image in the C++ program? And it takes 117 ms to be drawn?
How many vertices are there in the vertex array of the C# program?
Laurent Gomila - SFML developer

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #13 on: February 27, 2012, 08:57:59 pm »
Yea, the current C++ code is:
Code: [Select]
IntroState::IntroState(Game *eGame):
IGameState(eGame)
{
    IntroSprite = sf::Sprite(*(game->textureManager.getFile("./Resources/Images/blah.png", true)));
    if(IntroSprite.GetTexture()->GetWidth() == 8)
        IntroSprite.Scale(800/8.0f, 600/8.0f);
    IntroSprite.SetPosition(sf::Vector2f(0.0f, 0.0f));

    delay = 100.0f;
    alpha = 0.0f;
    disapearing = false;
    appearing = true;
}

IntroState::~IntroState()
{

}

void IntroState::Init()
{

}

void IntroState::Cleanup(){}

void IntroState::Pause(){}
void IntroState::Resume(){}

void IntroState::HandleEvents(sf::Event &Event)
{

}

void IntroState::Update()
{
    sf::Int32 delta = game->getDelta()/100;
    if(appearing && !disapearing)
        alpha += delta * 10.0f;
    else if(!appearing && !disapearing && (alpha > 254.0f))
        delay -= delta* 10.0f;
    else if(!appearing && disapearing)
        alpha -= delta * 10.0f;

    if(alpha > 254.0f && delay > 0.0f)
    {
        disapearing = false;
        appearing = false;
    }

    else if(alpha > 254.0f && delay < 0.0f)
    {
        disapearing = true;
    }

    else if(alpha < -10.0f && delay < 0.0f)
        game->gameStateManager.PopState();

    IntroSprite.SetColor(sf::Color(255,255,255,clamp(0.0f, 255.0f,alpha) ));
}

float IntroState::clamp(float min, float max, float num)
{
    if(num > max) return max;
    if(num < min) return min;
    return num;
}

void IntroState::Draw()
{
    game->App.Draw(IntroSprite);
}


and then this to draw the time:
Code: [Select]

void Game::drawDebug()
{

     std::stringstream ss;
   ss << Game::delta << " ms" << std::endl;

   sf::Text text( ss.str() );
   text.SetPosition(5,5);
   text.SetCharacterSize(10);
   text.SetColor(sf::Color::White);
    App.Draw(text);
}


As for the C#, the map image is 54x42 (whith each tile being 16x16 so the overall size of the VertexArray is just over 800x600) and each point has 4 verteces

Richy19

  • Full Member
  • ***
  • Posts: 190
    • View Profile
Batch Drawing
« Reply #14 on: February 27, 2012, 09:34:09 pm »
Just made a benchmark to test it out.

The C# code is:
Code: [Select]
public static void Main (string[] args)
{
RenderWindow window = new RenderWindow(new SFML.Window.VideoMode(800,600), "SFML TEST");
Sprite spr = new Sprite(new Texture("img.png") );
int startTime = 0;
int delta = 0;
int i = 111; //have an int to turn it into a string as the delta would be
for(int a = 0; a < 10; a++)
{
startTime = Environment.TickCount;
window.SetActive();

                window.Clear(SFML.Graphics.Color.White);
   
window.Draw(spr);
window.Draw(new SFML.Graphics.Text( i + " ms", SFML.Graphics.Font.DefaultFont, 12));
                // Finally, display the rendered frame on screen
                window.Display();
delta += (Environment.TickCount - startTime);
}

window.Close();
Console.WriteLine("Average in 10 runs is: " + (delta/10.0f) );
//Average output is around 79-80
}

With an average frame taking 79 to 80 ms to clear, draw an 800x600 image, draw the time & display it.

And C++ takes around the same to do the same... (well around 76 ms) So I guess my program is just because of the vertex array then.
Oh well Im ok with that I guess :)
On any decent computer it should run pretty fast.

The C++ code btw is:

Code: [Select]
#include <SFML/Graphics.hpp>
#include <iostream>
#include <sstream>

int main()
{
    sf::Clock clock;
    sf::Int32 delta = 0;
    sf::RenderWindow App;

    App.Create( sf::VideoMode(800,600,32), "Window");
    sf::Sprite spr;
    sf::Texture tex;
    tex.LoadFromFile("img.png");
    spr.SetTexture(tex);


    for(int i = 0; i < 10; i++)
    {
        clock.Restart().AsMilliseconds();

        App.SetActive();

        App.Clear(sf::Color::Black);

        App.Draw(spr);

        std::stringstream ss;
        ss << delta << " ms" << std::endl;
        sf::Text text( ss.str() );
        App.Draw(text);

        App.Display();
        delta += clock.Restart().AsMilliseconds();
    }
    std::cout << (delta/10.0f) << std::endl;
}


And the image I used is: http://i.imgur.com/UW5pm.jpg