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

Author Topic: Factoryfunction pointer  (Read 4519 times)

0 Members and 1 Guest are viewing this topic.

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Factoryfunction pointer
« on: October 31, 2013, 07:57:22 pm »
Hello everybody!
I have a design question for C++11. It's not directly SFML related, but more to graphics programming in general.
I have a program that makes extensive use of particles. Here is my current design: I programmed a particle system, that consists out of a super class Particle. The subclasses (like StarParticle) inherate from it. Because the type of particle changes at runtime I created a "factory function" for each particle type, which looks like this:
std::unique_ptr<Particle> createStarParticle (sf::Vector2f position)
{
    return std::unique_ptr<StarParticle> (new StarParticle(position));
}
I then have a std::vector<std::unique_ptr<Particle> (* pointerToFactoryFunction) (sf::Vector2f)> which holdes pointers to all the factory functions. For the insertion I use:
particles.push_back((*factoryFunctionVector[index])(sf::Vector2f(x, y)));

Now, the code works perfectly fine, like I expected it, but it looks to like C style to me. So I my question is, is there a C++11 way of doing this. I read a little bit about std::function and lambdas, but I'm not a 100% if I can acchive what I want with those.
Could somebody with more C++11 knowledge help me on that one?

Thanks in advance,
Foaly

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Factoryfunction pointer
« Reply #1 on: October 31, 2013, 10:31:31 pm »
Yes, you're looking for std::function, which is a generalization of the function pointer concept. The advantage over function pointers is that the function objects assigned to std::function can carry state with them.

However, there are several things to consider. Using dynamic allocation and runtime polymorphism for every single particle introduces a lot of overhead, both in execution time and memory usage. I would not do it if it can be avoided, especially if you make extensive use of particles.

You could have a look at the design of the particle system implementation in Thor (API documentation, tutorial). I implemented particles as a structure with direct access to public members, without inheritance. I initially used get/set method encapsulation, but found it would complicate everything without real advantages. As factories, I use emitters that are based on std::function, because they allow maximum flexibility, requiring far less code than an inheritance approach would.

Of course, you can also directly use Thor if you don't want to reinvent the wheel ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10827
    • View Profile
    • development blog
    • Email
Re: Factoryfunction pointer
« Reply #2 on: October 31, 2013, 11:47:19 pm »
I'm not very familiar with std::function, thus I can't really answer your question, however I just wanted to point out, that afaik you could make your factory function use a template, thus removing the need to implement a function for each type.
For example you could just call
auto my_star = ParticleSystem::create<StarParticle>({20.f, 30.f});

Not sure how that would then translate for function pointers or std::function. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #3 on: November 05, 2013, 11:59:12 pm »
Thanks for the tips! I never thought about using Thor. But now that I take a look at it, it seems like a good idea. Like the design of emitters and affectors. I might have to write an emitter myself (because I want to spawn the particles differently), but that shouldn't be to hard.
But I have one thing that I don't understand: How is your system more efficent? From what I understand from the source code, you also use a base class Particle. And then particle object are dynamically created, pushed in a vector and deleted. Were is the diffence?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Factoryfunction pointer
« Reply #4 on: November 06, 2013, 07:30:02 am »
From what I understand from the source code, you also use a base class Particle. And then particle object are dynamically created, pushed in a vector and deleted.
No, totally not ;)

As mentioned, thor::Particle is a class with direct member access and no inheritance. Have a look at the file Thor/Particles/Particle.hpp.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #5 on: November 09, 2013, 05:03:12 pm »
I did some tests with Thor today and I really like it! I came across an issue though. I want every Particle to have a random color. I couldn't find a distribution function for sf::Color, so I wrote one myself. Looks like this:
thor::Distribution<sf::Color> randomColor()
{
    return sf::Color(thor::random(0, 255), thor::random(0, 255), thor::random(0, 255), thor::random(0, 255));
}
The problem is that all the particles have to same color. The color is random, but it's the same for all particles. How can I change this to every particle having its own random color.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Factoryfunction pointer
« Reply #6 on: November 09, 2013, 06:34:56 pm »
You're assigning a constant and not a function to thor::Distribution<sf::Color>.

Here's one example with a function pointer:
sf::Color randomColor()
{
    return sf::Color(thor::random(0, 255), thor::random(0, 255), thor::random(0, 255));
}

thor::UniversalEmitter emitter;
emitter.setParticleColor(&randomColor);

Note that the color will not be as random as you expect, it contains a lot of gray. A colorful random distribution will be simpler once I implement HSV colors.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #7 on: November 10, 2013, 02:58:43 am »
Thanks! It works now! Are the grays due to the randomizer?

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: Factoryfunction pointer
« Reply #8 on: November 10, 2013, 10:46:21 am »
If you randomize red, green and blue part independently its happens often that they are about the same or the point gets drawn near another point of a complementary color that cancels it out visually, making you see it as grey.
I thought of a better method some time ago, that should help with the first part of the problem:
sf::Color randomColor()
{
    unsigned char color=thor::random(0, 255);
    switch(thor::random(0, 5)) {
    case 0:
        return sf::Color(255, color, 0);
    case 1:
        return sf::Color(255, 0, color);
    case 2:
        return sf::Color(0, 255, color);
    case 3:
        return sf::Color(color, 255, 0);
    case 4:
        return sf::Color(color, 0, 255);
    case 5:
        return sf::Color(0, color, 255);
    }
}
 

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #9 on: November 12, 2013, 02:50:14 pm »
Thanks I got it working now.
Also thanks for the alternative implementation of getRandomColor, but I found that for my purpose the function with the gray in it looks better. The other colors look to "bright". I'm still having trouble understanding why my random function produces colors with more gray in it though. From my understanding each of the components gets chosen randomly resulting in a random color. I searched the web, but couldn't find anything. Could somebody explain it to me again?

@Nexus: I am looking through the source of Thor's particle system to understand how it works and I have a question about the deletion of particles. I see that the deletion of dead particles happens in line 179. Which means that all dead particles are at the end of the vector. But new particles are also pushed to the end and I can't see any kind of swapping. Could you explain the magic that happens with writer?

P.s: I hope nobody minds if I ask all these topic unrelated/Thor questions in this thread. If somebody does I'll switch to something else.

wintertime

  • Sr. Member
  • ****
  • Posts: 255
    • View Profile
Re: Factoryfunction pointer
« Reply #10 on: November 12, 2013, 03:42:11 pm »
The thing with the grey colors is a quirk of the RGB color system.
This should help you a bit to imagine how a color would be seen:
void SplitColor(sf::Color color) {
  unsigned char minIntensity(min(min(color.r,color.g),color.b));
  sf::Color whiteness(minIntensity,minIntensity,minIntensity);
  sf::Color colorfulness(color-whiteness);
}
 

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Factoryfunction pointer
« Reply #11 on: November 12, 2013, 05:28:18 pm »
I'm still having trouble understanding why my random function produces colors with more gray in it though. From my understanding each of the components gets chosen randomly resulting in a random color.
What does "random" mean? This term doesn't make sense if not used together with a distribution. Usually, uniform distribution is assumed. But since color is a 3-dimensional space (not taking alpha into account), the easiest approach is to distribute each of the three components uniformly. This is what we do, and it results in a random color.

The fact that this color differs from your expectations is a different thing. Gray scale in RGB can be expressed as a vector (c, c, c), that is, all three components have the same value. If all three components have similar values, the color looks gray-ish. The more they differ, the more colorful (or saturated) the result tends to look.

However, the "colorfulness" cannot be easily expressed with RGB. That's why different color spaces exist, I already mentioned HSV (hue, saturation, value). They allow a representation which is more intuitive to human vision, but has to be converted for graphics hardware.


@Nexus: I am looking through the source of Thor's particle system to understand how it works and I have a question about the deletion of particles. I see that the deletion of dead particles happens in line 179. Which means that all dead particles are at the end of the vector. But new particles are also pushed to the end and I can't see any kind of swapping. Could you explain the magic that happens with writer?
The dead particles are removed from the vector by the call to the erase() overload taking an iterator range:
mParticles.erase(writer, mParticles.end());

The reader/writer loop is basically an extended std::remove_if() that both updates particles and moves the dead ones to the end, in order to avoid a needless second iteration.
« Last Edit: November 12, 2013, 05:31:19 pm by Nexus »
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #12 on: November 12, 2013, 07:37:13 pm »
Thanks for the clear explanation! That is just what I needed! I understand the problem now. Of course I was thinking of a uniform distribution :P I once wrote a function for shifting a hue. It can easily be modified to produce random colors. Maybe you or someone else might find it usefull.

Quote
The dead particles are removed from the vector by the call to the erase() overload taking an iterator range
Of course I understood, that particles are being removed using erase :D I also understood that the loop moves dead particles to the end and removes them all at once. What I don't understand is where does the swapping happen? Particularlly I am a little confused about the line:
// Go ahead
*writer++ = *reader;
Sorry if I didn't make that clear in my previous question.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: Factoryfunction pointer
« Reply #13 on: November 12, 2013, 08:07:55 pm »
As stated, it is an extended std::remove_if(). I suggest you understand how it is implemented, e.g. here.

The line you mentioned assigns the element referenced by the iterator reader to the element referenced by writer, and then increments writer. writer is the iterator that creates the new (possibly compacted) range of alive particles, that's why all the elements between writer and end() -- i.e. the dead particles -- are eventually erased.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Factoryfunction pointer
« Reply #14 on: November 13, 2013, 10:54:02 pm »
Thanks for the explanation. It works like I thought it would, but I didn't understand the implementation. I do now :D
But I decided to not use Thor for now, because after a couple small test I found that Thor's particle system does not outperform mine (the framerate drops for both at around 80.000 particles), but I really like the modularity of the emitters and affectors. This seems very useful if one wants to add more particle types without repeating code. Maybe I'll switch later, if I decide to add more types  :D
« Last Edit: November 13, 2013, 10:57:16 pm by Foaly »