SFML community forums

Help => Graphics => Topic started by: Sakman on July 17, 2018, 03:53:53 pm

Title: Do I really have to use std::vector<sf::CircleShape> ?
Post by: Sakman on July 17, 2018, 03:53:53 pm
(https://i.imgur.com/VMKFzbd.png)

Hello! Lets say I have collection of circles that I want to draw. They are identical in color, outline etc. Like shown in the picture above.

Let's say I store the positions and radiuses in vectors. I don't want to store every sf::CircleShape individually since that takes too much memory and makes the program slow.

Is there a way to make a single sf::CircleShape and use (tranform?) something to move and scale the circle with the vectors mentioned above? And is there a way to draw them with a single RenderTarget::draw() like with sf::VertexArray?

Responses are greatly appreciated.
Title: Re: Do I really have to use std::vector<sf::CircleShape> ?
Post by: tomvidm on July 17, 2018, 04:00:06 pm
You can make a vector std::vector<sf::Transformable>. Instead of iterating through a vector of circle shapes, iterate through the transforms. For each transform T, you call draw on the circle shape, pass a sf::RenderStates with T.getTransform() as the transform parameter. (Look at the declaration of sf::RenderStates structure)

This way, the vertices defining the circle itself does not change. The CircleShape itself is logically in the same place all the time, but the vertices are transformed and sent for rendering in turns.
Title: Re: Do I really have to use std::vector<sf::CircleShape> ?
Post by: Hapax on July 17, 2018, 04:03:53 pm
See my response to your duplicate post (https://en.sfml-dev.org/forums/index.php?topic=24263).
(click to show/hide)
Title: Re: Do I really have to use std::vector<sf::CircleShape> ?
Post by: Sakman on July 17, 2018, 04:44:20 pm
Thank you for your response!

I'm a bit confused. So what I need to do is make an empty texture and draw the circles on it?

Could you link a tutorial or an example, please. Thank you.
Title: Re: Do I really have to use std::vector<sf::CircleShape> ?
Post by: verdog on July 17, 2018, 07:18:41 pm
I'd probably wrap the group of circles into a class/struct:

struct CirclePosition {
  sf::Vector2f position;
  float radius;
}

struct CircleGroup {
  mutable sf::CircleShape base; // mutable so its radius can be changed within the draw function
  std::vector<CirclePosition> positions; // filled with a CirclePosition for each sf::CircleShape

  void draw(sf::RenderTarget& target, sf::RenderStates states) const {
    for (CirclePosition &cPosition : positions) {
      // apply the radius
      base.setRadius(cPosition.radius);

      // move the circle
      sf::Transform circleTransform;
      transform.translate(cPosition.position);
      states.transform = circleTransform;
      target.draw(base, states);
    }
  }
}
 

Pretty sloppy solution, and it might give you issues when you try to compile it (wrote it quickly at work  :P), but maybe this can give you an idea to get started?
Title: Re: Do I really have to use std::vector<sf::CircleShape> ?
Post by: Hapax on July 18, 2018, 01:55:27 am
I'm a bit confused. So what I need to do is make an empty texture and draw the circles on it?

Could you link a tutorial or an example, please. Thank you.
Again, if your circles do not move, yes, you can draw them to a kind of texture and then draw that texture in one draw call. However, if your circles are moving/changing, you'll still need at least as many draw calls (to draw them to the texture).

Basically, set up an sf::RenderTexture to match the window size and draw the circles to that in the same way you draw to a window (and prepare the sprite that draws the render texture):
std::vector<sf::CircleShape> circles;
sf::RenderTexture renderTexture;
// set up render texture and circles
renderTexture.clear();
for (auto& circle : circles)
    renderTexture.draw(circle);
renderTexture.display();
sf::Sprite renderSprite(renderTexture.getTexture());
This can be done before the main loop since they are not changing.
Also, you no longer need the vector of circle shapes...

Then, in the main loop where you are drawing to a window, just draw the render sprite:
while (window.isOpen())
{
    // event loop
    // updates
    window.clear();
    window.draw(renderSprite);
    window.display();
}