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

Author Topic: SFML simple shader experiment  (Read 14962 times)

0 Members and 1 Guest are viewing this topic.

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
SFML simple shader experiment
« on: April 01, 2015, 01:03:04 pm »
Hey guys,

This is my first post here.

I'm fairly new to SFML, C++ and graphics programming in general.
I would like to share my latest experiment with you. It's based on the various tutorials I found here and also on youtube.

What it does:
- Generate small squares which follow the mouse
- If the mouse is out of the window they move randomly
- On click change the strenght of the attraction towards the mouse
- Each square shines light (using inline GLSL shader code)

The effect looks kinda like colorful fireflies :-)

Please let me know what you think about the code.
I'm new to C++ so if you see something that is not good practice / wrong / buggy, please let me know.

#include <SFML/Graphics.hpp>
#include <iostream>
#include <chrono>

#ifndef _NOEXCEPT
#define _NOEXCEPT noexcept
#endif

using namespace std;
using namespace sf;

using FrameTime = float;

static const string shaderCode = \
"uniform vec2 frag_LightOrigin;"\
"uniform vec3 frag_LightColor;"\
"uniform float frag_LightAttenuation;"\
"uniform vec2 frag_ScreenResolution;"\
"void main(){"\
"       vec2 baseDistance =  gl_FragCoord.xy;"\
"       baseDistance.y = frag_ScreenResolution.y-baseDistance.y;"\
"       vec2 distance=frag_LightOrigin - baseDistance;"\
"       float linear_distance = length(distance);"\
"       float attenuation=1.0/( frag_LightAttenuation*linear_distance + frag_LightAttenuation*linear_distance);"\
"       vec4 lightColor = vec4(frag_LightColor, 1.0);"\
"       vec4 color = vec4(attenuation, attenuation, attenuation, 1.0) * lightColor; gl_FragColor=color;}";


static const unsigned int windowWidth{ 800 }, windowHeight{ 600 };

static const float walkerWidth{ 8.f }, walkerHeight{ 8.f };
static const float walkerVelocity{ 1.f };

static const float ftStep{ 1.f }, ftSlice{ 1.f };

static const int walkerCount{ 15 };

static const float directionMultiplier1{ 0.008f }, directionMultiplier2{ 0.002f };

static float directionMultiplier{ 0.008f };

/* UTILITY FUNCTIONS */

void normalize(Vector2f& source){
        float length = sqrt((source.x * source.x) + (source.y * source.y));
        if (length != 0){
                source.x = source.x / length;
                source.y = source.y / length;
        }
}

/* GAME CLASSES */

struct Rectangle {
        RectangleShape shape;
        float x()      const _NOEXCEPT{ return shape.getPosition().x; }
        float y()      const _NOEXCEPT{ return shape.getPosition().y; }
        float left()   const _NOEXCEPT{ return x() - shape.getSize().x / 2.0f; }
        float right()  const _NOEXCEPT{ return x() + shape.getSize().x / 2.0f; }
        float top()    const _NOEXCEPT{ return y() - shape.getSize().y / 2.0f; }
        float bottom() const _NOEXCEPT{ return y() + shape.getSize().y / 2.0f; }
};


struct Walker : public Rectangle{

        Vector2f velocity;
        Vector3f color;

        Walker(float mX, float mY){
                shape.setPosition(mX, mY);
                shape.setSize({ walkerWidth, walkerHeight });
                color = Vector3f(rand() % 255, rand() % 255, rand() % 255);
                shape.setFillColor(Color(color.x, color.y, color.z));
                shape.setOrigin(walkerWidth / 2.0f, walkerHeight / 2.0f);
        }

        void update(FrameTime ft, RenderWindow& window){
               
                Vector2f mousePosition = (Vector2f)Mouse::getPosition(window);

                //follow mouse if it is inside of the window           
                if (mousePosition.x > 0.f && mousePosition.y > 0.f &&
                        mousePosition.x < windowWidth && mousePosition.y < windowHeight){

                        Vector2f direction = mousePosition - shape.getPosition();

                        normalize(direction);

                        direction *= directionMultiplier;
                        direction.x += generateVelocityFloat() * 0.05;
                        direction.y += generateVelocityFloat() * 0.05;

                        velocity += direction;

                        //limit velocity
                        if(velocity.x > walkerVelocity) velocity.x = walkerVelocity;
                        if(velocity.y > walkerVelocity) velocity.y = walkerVelocity;
                        if(velocity.x < -walkerVelocity) velocity.x = -walkerVelocity;
                        if(velocity.y < -walkerVelocity) velocity.y = -walkerVelocity;

                } else {
                        if (( 1 + rand() % 100) == 1){
                                velocity.x = generateVelocityFloat();
                                velocity.y = generateVelocityFloat();
                        }
                }
                       
                //guard edges of screen
                if ((right() >= windowWidth && velocity.x > 0) || (left() <= 0 && velocity.x < 0)){
                        velocity.x = 0;
                }
                if ((top() <= 0 && velocity.y < 0) || (bottom() >= windowHeight && velocity.y > 0)){
                        velocity.y = 0;
                }

                shape.move(velocity * ft);
        }
       
        float generateVelocityFloat(){
                return (-walkerVelocity) +static_cast <float> (rand()) / (static_cast <float> (RAND_MAX / (walkerVelocity - (-walkerVelocity))));
        }
};

struct Game {

        RenderWindow window{ VideoMode(windowWidth, windowHeight) , "Followers!" };
        FrameTime lastFt{ 0.f }, currentSlice{ 0.f };
        bool running{ false };

        RenderTexture myRenderTexture;
    Sprite spriteWorld;
        Shader shader;    

        vector<Walker> walkers;

        void initializeWalkers(){
                walkers.clear();
                for (int a{ 0 }; a < walkerCount; ++a){
                        walkers.emplace_back(windowWidth / 2.f,
                                windowHeight/2.f);
                }
        }

        void checkInput(){
                Event event;
                while (window.pollEvent(event)) {
                        if (event.type == Event::Closed){
                                window.close();
                                break;
                        }
                        if (event.type == Event::MouseButtonPressed){
                                if (directionMultiplier == directionMultiplier1){
                                        directionMultiplier = directionMultiplier2;
                                }
                                else {
                                        directionMultiplier = directionMultiplier1;
                                }
                        }
                }

                if (Keyboard::isKeyPressed(Keyboard::Escape)) running = false;
               
        }
       
        void update(){
                        currentSlice += lastFt;

                        //update multiple times based on fps
                        for (; currentSlice >= ftSlice; currentSlice -= ftSlice){

                                for (auto& walker : walkers){
                                        walker.update(ftStep, window);
                                }

                        }
        }

        void draw(){
                for (auto& walker : walkers){

                        myRenderTexture.draw(walker.shape);

                        shader.setParameter("frag_LightOrigin", walker.shape.getPosition());
                shader.setParameter("frag_LightColor", walker.color);
                shader.setParameter("frag_LightAttenuation", 50);

                sf::RenderStates states;
                states.shader = &shader;
                states.blendMode = sf::BlendAdd;

                myRenderTexture.draw(spriteWorld, states);

                }

                myRenderTexture.display();
        window.draw(spriteWorld);
                window.display();
        }


        void run(){

                myRenderTexture.create(windowWidth, windowHeight);
            spriteWorld.setTexture(myRenderTexture.getTexture());
        spriteWorld.setOrigin(spriteWorld.getTextureRect().width/2, spriteWorld.getTextureRect().height/2);
        spriteWorld.setPosition(windowWidth / 2, windowHeight / 2);

        shader.loadFromMemory(shaderCode, sf::Shader::Fragment);
        shader.setParameter("frag_ScreenResolution",sf::Vector2f(windowWidth, windowHeight));

                running = true;

                while (running) {

                        auto time1(chrono::high_resolution_clock::now());

                        window.clear(Color::Black);
                        myRenderTexture.clear();

                        checkInput();
                        update();
                        draw();

                        auto time2(chrono::high_resolution_clock::now());
                        auto elapsedTime(time2 - time1);
                        FrameTime ft{ chrono::duration_cast<chrono::duration<float, milli>>(elapsedTime).count() };

                        lastFt = ft;

                        auto ftSeconds(ft / 1000.f);
                        if (ftSeconds > 0.f){
                                auto fps(1.f / ftSeconds);
                                window.setTitle("FT: " + to_string(ft) + "\tFPS: " + to_string(fps));
                        }
                }
        }


        Game(){

                //framerate now handled by chrono library
                //to test with low framerate:
                //window.setFramerateLimit(15);
                window.setFramerateLimit(500);
                initializeWalkers();

        }
};


int main() {
        Game{}.run();
        return 0;
}
 

« Last Edit: April 01, 2015, 01:05:16 pm by Miretz »

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: SFML simple shader experiment
« Reply #1 on: April 01, 2015, 01:48:46 pm »
Are you just from Java? =)
Quote
I'm new to C++ so if you see something that is not good practice / wrong / buggy, please let me know.
Sorry, but almost all is wrong. You have to read C++ books.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10800
    • View Profile
    • development blog
    • Email
Re: SFML simple shader experiment
« Reply #2 on: April 01, 2015, 01:53:26 pm »
Sorry, but almost all is wrong. You have to read C++ books.
???
Sure it's not the best code design etc. but "almost all is wrong" is quite an overstatement.

Anyways here's a video for the curious people:

http://www.youtube.com/watch?v=YJX_KyXR0Y0

The lag is due to my bad GPU!
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #3 on: April 01, 2015, 02:05:58 pm »
Are you just from Java? =)

Yes =) The curly brace position gives it away. I do Java for work. But I like C++ for it's power.   

Sorry, but almost all is wrong. You have to read C++ books.

I agree. I'm currently reading C++ Succinctly but not sure if this is the best book to start with.

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #4 on: April 01, 2015, 02:07:27 pm »
Sorry, but almost all is wrong. You have to read C++ books.
???
Sure it's not the best code design etc. but "almost all is wrong" is quite an overstatement.

Anyways here's a video for the curious people:

http://www.youtube.com/watch?v=YJX_KyXR0Y0

The lag is due to my bad GPU!

Thanks for the upload :)

Mario

  • SFML Team
  • Hero Member
  • *****
  • Posts: 879
    • View Profile
Re: SFML simple shader experiment
« Reply #5 on: April 01, 2015, 02:20:36 pm »
Sorry, but almost all is wrong. You have to read C++ books.

Doesn't matter, there are lights, lights everywhere, just look the lights,... whoooooo!

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #6 on: April 01, 2015, 02:37:52 pm »
Sorry, but almost all is wrong. You have to read C++ books.

Doesn't matter, there are lights, lights everywhere, just look the lights,... whoooooo!

 ;D ;D ;D

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: SFML simple shader experiment
« Reply #7 on: April 01, 2015, 03:35:58 pm »
Are you just from Java? =)
Quote
I'm new to C++ so if you see something that is not good practice / wrong / buggy, please let me know.
Sorry, but almost all is wrong. You have to read C++ books.

Imho what you said
Are you just from Java? =)

For me all the static const variables gave it away. Nice effect nonetheless :D

Yes =) The curly brace position gives it away. I do Java for work. But I like C++ for it's power.   

Sorry, but almost all is wrong. You have to read C++ books.

I agree. I'm currently reading C++ Succinctly but not sure if this is the best book to start with.
is neither fair nor useful. I admit that it's not the nicest code to look at, but it is not wrong.

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: SFML simple shader experiment
« Reply #8 on: April 01, 2015, 03:44:54 pm »
Why not all wrong? Who think that it has several minor mistakes - try to expand this app by adding several classes in their own files. It won't even compile. =)
I mean, if you will continue do it that way.
Well, giving advices it is not for my english level. =)
« Last Edit: April 01, 2015, 04:11:31 pm by ChronicRat »

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: SFML simple shader experiment
« Reply #9 on: April 01, 2015, 04:11:18 pm »
Why not all wrong? Who think that it has several minor mistakes - try to expand this app by adding several classes in their own files. It won't even compile. =)

Just because it isn't extensible or nice to read doesn't make it wrong. I agree with you that it won't work in the long run(which would have been more constructive criticism).
But "wrong" is the wrong ;) word here.

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #10 on: April 01, 2015, 04:27:38 pm »
Why not all wrong? Who think that it has several minor mistakes - try to expand this app by adding several classes in their own files. It won't even compile. =)

I know that the design is wrong. Looks more like a script not a correct OOP solution.
But It can be refactored into a clean OOP solution.

What I would like to know are some specific errors for C++ & SFML.
For example if the program is not leaking memory or if I'm calling the SFML methods correctly & effectively.







« Last Edit: April 01, 2015, 04:44:59 pm by Miretz »

ChronicRat

  • Sr. Member
  • ****
  • Posts: 327
  • C++ programmer
    • View Profile
    • My blog
Re: SFML simple shader experiment
« Reply #11 on: April 01, 2015, 06:27:14 pm »
You are not using "new" operator so there is only one easy way to get memleak - it is non-virtual destructor in some base class which you are not using too. You are not copying big objects in function calls because of using references, it is also good.
Well, it is noticeable that you are new in C++ but not in programming. =)

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Re: SFML simple shader experiment
« Reply #12 on: April 01, 2015, 06:50:27 pm »
What I would like to know are some specific errors for C++ & SFML.
For example if the program is not leaking memory or if I'm calling the SFML methods correctly & effectively.

If you want specific feedback, I will go ahead - otherwise ignore this post.

using namespace std;
using namespace sf;

Bad idea, always use full qualifying namespaces - don't believe me? Just google around and you will find plenty of reasons.

if(velocity.x > walkerVelocity) velocity.x = walkerVelocity;
            if(velocity.y > walkerVelocity) velocity.y = walkerVelocity;
            if(velocity.x < -walkerVelocity) velocity.x = -walkerVelocity;
            if(velocity.y < -walkerVelocity) velocity.y = -walkerVelocity;

Use std::min and std::max functions instead, it will be easier to read.

if (( 1 + rand() % 100) == 1)

You are already using c++11, so why not make use of the <random> header?

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

Game{}.run();

This just looks weird using curly braces instead of parenthesis.

struct Rectangle {
    RectangleShape shape;
    float x()      const _NOEXCEPT{ return shape.getPosition().x; }
    float y()      const _NOEXCEPT{ return shape.getPosition().y; }
    float left()   const _NOEXCEPT{ return x() - shape.getSize().x / 2.0f; }
    float right()  const _NOEXCEPT{ return x() + shape.getSize().x / 2.0f; }
    float top()    const _NOEXCEPT{ return y() - shape.getSize().y / 2.0f; }
    float bottom() const _NOEXCEPT{ return y() + shape.getSize().y / 2.0f; }
};

I really don't see how this utility class helps at all, to me it seems like more typing and another layer for no real benefit.

#ifndef _NOEXCEPT
#define _NOEXCEPT noexcept
#endif

What exactly is this supposed to accomplish?

There is more stuff to mention, but this is the major stuff I see.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #13 on: April 01, 2015, 07:44:09 pm »
What I would like to know are some specific errors for C++ & SFML.
For example if the program is not leaking memory or if I'm calling the SFML methods correctly & effectively.

If you want specific feedback, I will go ahead - otherwise ignore this post.

using namespace std;
using namespace sf;

Bad idea, always use full qualifying namespaces - don't believe me? Just google around and you will find plenty of reasons.

if(velocity.x > walkerVelocity) velocity.x = walkerVelocity;
            if(velocity.y > walkerVelocity) velocity.y = walkerVelocity;
            if(velocity.x < -walkerVelocity) velocity.x = -walkerVelocity;
            if(velocity.y < -walkerVelocity) velocity.y = -walkerVelocity;

Use std::min and std::max functions instead, it will be easier to read.

if (( 1 + rand() % 100) == 1)

You are already using c++11, so why not make use of the <random> header?

https://channel9.msdn.com/Events/GoingNative/2013/rand-Considered-Harmful

Game{}.run();

This just looks weird using curly braces instead of parenthesis.

struct Rectangle {
    RectangleShape shape;
    float x()      const _NOEXCEPT{ return shape.getPosition().x; }
    float y()      const _NOEXCEPT{ return shape.getPosition().y; }
    float left()   const _NOEXCEPT{ return x() - shape.getSize().x / 2.0f; }
    float right()  const _NOEXCEPT{ return x() + shape.getSize().x / 2.0f; }
    float top()    const _NOEXCEPT{ return y() - shape.getSize().y / 2.0f; }
    float bottom() const _NOEXCEPT{ return y() + shape.getSize().y / 2.0f; }
};

I really don't see how this utility class helps at all, to me it seems like more typing and another layer for no real benefit.

did not know about the <random> and std::min / std::max.
Also the Game{}.run() was probably copied from a tutorial or my mistake. I'm not sure.
You are right about the utility class. There is no reason to keep it there.
This is really good advice.
Thanks :)

#ifndef _NOEXCEPT
#define _NOEXCEPT noexcept
#endif

What exactly is this supposed to accomplish?

I have read somewhere that it is effective to mark methods that never throw an exception with the 'noexcept' C++11 operator for optimization.
I work in Visual Studio on my Windows PC and with Code::Blocks on my Ubuntu laptop and to get the same code working on both computers I'm using the #define.
VS2013 does not support noexcept but it has _NOEXCEPT which should be the same.
« Last Edit: April 01, 2015, 07:51:58 pm by Miretz »

Miretz

  • Newbie
  • *
  • Posts: 12
    • View Profile
    • Miretz Github
    • Email
Re: SFML simple shader experiment
« Reply #14 on: April 02, 2015, 12:53:14 am »
Updated version. I hope I'm on the right path and did not introduce any more errors :-\

Also used the Code::Block source formatter  8)

#include <SFML/Graphics.hpp>
#include <iostream>
#include <random>
#include <chrono>

#ifndef _NOEXCEPT
#define _NOEXCEPT noexcept
#endif

typedef float FrameTime;
const float ftStep
{
    1.f
};
const float ftSlice
{
    1.f
};

static const std::string shaderCode = \
                                      "uniform vec2 frag_LightOrigin;"\
                                      "uniform vec3 frag_LightColor;"\
                                      "uniform float frag_LightAttenuation;"\
                                      "uniform vec2 frag_ScreenResolution;"\
                                      "void main(){"\
                                      " vec2 baseDistance =  gl_FragCoord.xy;"\
                                      " baseDistance.y = frag_ScreenResolution.y-baseDistance.y;"\
                                      " vec2 distance=frag_LightOrigin - baseDistance;"\
                                      " float linear_distance = length(distance);"\
                                      " float attenuation=1.0/( frag_LightAttenuation*linear_distance + frag_LightAttenuation*linear_distance);"\
                                      " vec4 lightColor = vec4(frag_LightColor, 1.0);"\
                                      " vec4 color = vec4(attenuation, attenuation, attenuation, 1.0) * lightColor; gl_FragColor=color;}";

class Walker
{
private:
    const float walkerWidth
    {
        8.f
    };
    const float walkerHeight
    {
        8.f
    };
    const float walkerVelocity
    {
        1.f
    };
    const float strenghts[2] = { 0.008f, 0.002f };

    sf::RectangleShape shape;
    sf::Vector2f velocity;
    sf::Vector3f color;

    std::mt19937 gen {std::random_device{}()};
    std::uniform_int_distribution<int> randomColor {0, 255};
    std::bernoulli_distribution randomChance {0.02};
    std::uniform_real_distribution<float> randomVelocity {0, walkerVelocity * 2};

    void generateRandomColor()
    {
        color = sf::Vector3f(randomColor(gen), randomColor(gen), randomColor(gen));
    }

    int generateRandomChance()
    {
        return randomChance(gen);
    }

    float generateVelocityFloat()
    {
        return randomVelocity(gen) - walkerVelocity;
    }

    void normalize(sf::Vector2f& source)
    {
        float length = sqrt((source.x * source.x) + (source.y * source.y));
        if (length != 0)
        {
            source.x = source.x / length;
            source.y = source.y / length;
        }
    }

public:

    static int sSelected;

    Walker(float mX, float mY)
    {
        generateRandomColor();

        shape.setPosition(mX, mY);
        shape.setSize({ walkerWidth, walkerHeight });
        shape.setFillColor(sf::Color(color.x, color.y, color.z));
        shape.setOrigin(walkerWidth / 2.0f, walkerHeight / 2.0f);
    }

    virtual ~Walker() {}

    static void changeStrenght()
    {
        sSelected = (sSelected == 0) ? 1 : 0;
    }

    void update(FrameTime ft, sf::RenderWindow& window)
    {

        sf::Vector2f mousePosition = (sf::Vector2f) sf::Mouse::getPosition(window);
        sf::Vector2u winSize = window.getSize();

        //follow mouse if it is inside of the window
        if (mousePosition.x > 0.f && mousePosition.y > 0.f &&
                mousePosition.x < winSize.x && mousePosition.y < winSize.y)
        {

            sf::Vector2f direction = mousePosition - shape.getPosition();
            normalize(direction);

            direction *= Walker::strenghts[sSelected];
            direction.x += generateVelocityFloat() * 0.05;
            direction.y += generateVelocityFloat() * 0.05;

            velocity += direction;

            //limit velocity
            velocity.x = std::min(walkerVelocity, velocity.x);
            velocity.y = std::min(walkerVelocity, velocity.y);
            velocity.x = std::max(-walkerVelocity, velocity.x);
            velocity.y = std::max(-walkerVelocity, velocity.y);

        }
        else
        {
            if (generateRandomChance())
            {
                velocity.x = generateVelocityFloat();
                velocity.y = generateVelocityFloat();
            }
        }

        //guard edges of screen
        if ((right() >= winSize.x && velocity.x > 0) || (left() <= 0 && velocity.x < 0))
        {
            velocity.x = 0;
        }
        if ((top() <= 0 && velocity.y < 0) || (bottom() >= winSize.y && velocity.y > 0))
        {
            velocity.y = 0;
        }

        shape.move(velocity * ft);
    }

    void draw(sf::RenderTarget& target)
    {
        target.draw(shape);
    }

    sf::Vector2f getPosition() const _NOEXCEPT
    {
        return shape.getPosition();
    }
    sf::Vector3f getColor() const _NOEXCEPT
    {
        return color;
    }
    float x()      const _NOEXCEPT
    {
        return shape.getPosition().x;
    }
    float y()      const _NOEXCEPT
    {
        return shape.getPosition().y;
    }
    float left()   const _NOEXCEPT
    {
        return x() - shape.getSize().x / 2.0f;
    }
    float right()  const _NOEXCEPT
    {
        return x() + shape.getSize().x / 2.0f;
    }
    float top()    const _NOEXCEPT
    {
        return y() - shape.getSize().y / 2.0f;
    }
    float bottom() const _NOEXCEPT
    {
        return y() + shape.getSize().y / 2.0f;
    }

};

int Walker::sSelected = 0;

class Game
{
private:
    unsigned int windowWidth = 800;
    unsigned int windowHeight = 600;
    int walkerCount = 15;

    sf::RenderWindow window { sf::VideoMode(windowWidth, windowHeight), "Followers!" };
    FrameTime lastFt { 0.f }, currentSlice { 0.f };
    bool running { false };

    sf::RenderTexture myRenderTexture;
    sf::Sprite spriteWorld;
    sf::Shader shader;

    std::vector<Walker> walkers;

    void initializeWalkers()
    {
        walkers.clear();
        for (int a { 0 }; a < walkerCount; ++a)
        {
            walkers.emplace_back(window.getSize().x / 2.f,
                                 window.getSize().y / 2.f);
        }
    }

    void checkInput()
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                running = false;
            }
            else if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
            {
                running = false;
            }
            else if (event.type == sf::Event::MouseButtonPressed)
            {
                Walker::changeStrenght();
            }
        }

    }

    void update()
    {
        currentSlice += lastFt;

        //update multiple times based on fps
        for (; currentSlice >= ftSlice; currentSlice -= ftSlice)
        {
            for (auto& walker : walkers)
            {
                walker.update(ftStep, window);
            }
        }
    }

    void draw()
    {
        for (auto& walker : walkers)
        {

            walker.draw(myRenderTexture);

            shader.setParameter("frag_LightOrigin", walker.getPosition());
            shader.setParameter("frag_LightColor", walker.getColor());
            shader.setParameter("frag_LightAttenuation", 50);

            sf::RenderStates states;
            states.shader = &shader;
            states.blendMode = sf::BlendAdd;

            myRenderTexture.draw(spriteWorld, states);

        }

        myRenderTexture.display();
        window.draw(spriteWorld);
        window.display();
    }

public:

    void run()
    {
        myRenderTexture.create(windowWidth, windowHeight);
        spriteWorld.setTexture(myRenderTexture.getTexture());
        spriteWorld.setOrigin(spriteWorld.getTextureRect().width / 2, spriteWorld.getTextureRect().height / 2);
        spriteWorld.setPosition(windowWidth / 2.f, windowHeight / 2.f);

        shader.loadFromMemory(shaderCode, sf::Shader::Fragment);
        shader.setParameter("frag_ScreenResolution", sf::Vector2f(windowWidth, windowHeight));

        running = true;

        while (running)
        {

            auto time1(std::chrono::high_resolution_clock::now());

            window.clear(sf::Color::Black);
            myRenderTexture.clear();

            checkInput();
            update();
            draw();

            auto time2(std::chrono::high_resolution_clock::now());
            auto elapsedTime(time2 - time1);
            FrameTime ft { std::chrono::duration_cast<std::chrono::duration<float, std::milli>>(elapsedTime).count() };

            lastFt = ft;

            auto ftSeconds(ft / 1000.f);
            if (ftSeconds > 0.f)
            {
                auto fps(1.f / ftSeconds);
                window.setTitle("FT: " + std::to_string(ft) + "\tFPS: " + std::to_string(fps));
            }
        }
    }


    Game()
    {
        window.setFramerateLimit(500);
        initializeWalkers();
    }

    virtual ~Game() {}
};

int main()
{
    Game().run();
    return EXIT_SUCCESS;
}
 
« Last Edit: April 02, 2015, 01:15:21 am by Miretz »