Une classe LightManager pour générer des lumières dynamiques en 2D

Je vais vous présenter un moteur de lumière dynamiques de ma création. Il permet de gérer des lumières dans un environnement en deux dimensions, avec des murs sans épaisseur. La version que je vous montre ici n'est pas optimisée pour la gestion des vues. Je part du principe que nous avons toujours un environnement fixe. Mais il est aisément faisable de rajouter des conditions pour éviter d'afficher des lumières en dehors de l'écran, en prenant par exemple des quadtree.

Vous trouverez des explications sur le moteur sur le blog d'Alpha-Arts : http://www.alpha-arts.net/blog/articles/view/18/moteur-de-lumieres.

Ou en encore plus détaillé sur Developpez : http://gregouar.developpez.com/tutoriels/jeux/moteur-lumieres-dynamiques-2d/.

Si vous voulez télécharger le projet de démonstration, c'est par ici.

Le code source d'exemple est réalisé pour la SFML2, que vous pourrez trouver sur la SVN.

ATTENTION : Ce moteur n'est pas encore à 100% optimisé. Il peut toujours avoir des problèmes. Vos remarques à ce propos sont les bienvenues sur ce sujet.

Le projet est découpé en 4 fichiers pour les lumières, plus un fichier main.cpp de démonstration et un fichier singleton.h pour la gestion des singletons.

LightManager.h

 
#include "Light.h"
 
#ifndef LIGHTMANAGERH
#define LIGHTMANAGERH
 
#include "Singleton.h"
 
 
class Light_Manager : public CSingleton<Light_Manager>
{
    protected :
 
    Light_Manager();
    ~Light_Manager();
 
     // Les tableaux de murs, lumières statiques et dynamiques
    std::vector <Wall> m_wall;
    std::vector <Light> m_StaticLight;
    std::vector <Light> m_DynamicLight;
 
    public :
    // Constructeur et destructeur
    friend Light_Manager* CSingleton<Light_Manager>::GetInstance();
    friend void CSingleton<Light_Manager>::Kill();
 
 
    //Différents moyen d'ajouter une lumière dynamique, soit on l'ajoute sans aucune valeur par défaut, soit on lui donne une lumière par défaut, soit on lui donne ses valeurs "à la main"
    Light_Entity Add_Dynamic_Light();
    Light_Entity Add_Dynamic_Light(Light);
    Light_Entity Add_Dynamic_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color);
 
    //Différents moyen d'ajouter une lumière dynamique, soit on lui donne une lumière par défaut, soit on lui donne ses valeurs "à la main"
    //On ne peut ajouter une lumière static sans rien, ça ne servirait à rien car elle ne peut être modifiée par la suite
    Light_Entity Add_Static_Light(Light);
    Light_Entity Add_Static_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color);
 
    // Ajouter un mur
    Wall_Entity Add_Wall(sf::Vector2f pt1,sf::Vector2f pt2);
 
    // Désactiver une lumière ou supprimer un mur
    void Delete_Light(Light_Entity);
    void Delete_Wall(Wall_Entity);
 
    void Delete_All_Wall();
    void Delete_All_Light();
 
    // Calculer toutes les lumières dynamiques
    void Generate();
    void Generate(Light_Entity);
 
    // Afficher toutes les lumières à l'écran
    void Draw(sf::RenderWindow *App);
 
    // Différentes méthodes pour modifier les attributs d'une lumière, ou les récupérer. Il faut à chaque fois envoyer une Light_Entity en paramètre pour
    // savoir de quelle lumière on parle/
 
    void SetPosition(Light_Entity, sf::Vector2f );
    void SetQuality(Light_Entity, int );
    void SetRadius(Light_Entity, int );
    void SetColor(Light_Entity, sf::Color );
    void SetIntensity(Light_Entity, int);
 
    float GetIntensity(Light_Entity);
    float GetRadius(Light_Entity);
    int GetQuality(Light_Entity);
    sf::Color GetColor(Light_Entity);
    sf::Vector2f GetPosition(Light_Entity);
 
    void SetPosition(Wall_Entity, sf::Vector2f );
 
    sf::Color m_basicLight;
    int m_lightSmooth;
 
    private:
 
    sf::Shader BlurEffect;
    std::vector<Light>::iterator Iter;
    sf::RenderImage m_renderImg;
 
};
#endif

LightManager.cpp

 
#include "LightManager.h"
 
Light_Manager::Light_Manager()
{
    m_lightSmooth=0;
 
    // Chargement du postFX pour adoucir les bords.
    BlurEffect.LoadFromFile("blur.sfx");
    BlurEffect.SetTexture("texture", sf::Shader::CurrentTexture);
 
    m_renderImg.Create(800,600);
 
}
Light_Manager::~Light_Manager()
{
    m_wall.clear();
    m_StaticLight.clear();
    m_DynamicLight.clear();
}
 
// Les différents moyens d'ajouter des lumières
 
Light_Entity Light_Manager::Add_Dynamic_Light()
{
    m_DynamicLight.push_back(Light ());
    return Light_Entity((int)m_DynamicLight.size()-1,true);
}
Light_Entity Light_Manager::Add_Dynamic_Light(Light light)
{
    m_DynamicLight.push_back(light);
    return Light_Entity((int)m_DynamicLight.size()-1,true);
}
Light_Entity Light_Manager::Add_Dynamic_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color)
{
    m_DynamicLight.push_back(Light (position,intensity,radius,quality,color));
    return Light_Entity((int)m_DynamicLight.size()-1,true);
}
 
 
// Notez bien qu'on calcule les lumières statiques lors de leur ajout.
 
Light_Entity Light_Manager::Add_Static_Light(Light light)
{
    m_StaticLight.push_back(light);
    m_StaticLight.back().Generate(m_wall);
    return Light_Entity((int)m_StaticLight.size()-1,false);
}
Light_Entity Light_Manager::Add_Static_Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color)
{
    m_StaticLight.push_back(Light (position,intensity,radius,quality,color));
    m_StaticLight.back().Generate(m_wall);
    return Light_Entity((int)m_StaticLight.size()-1,false);
}
 
// Ajouter un mur
 
Wall_Entity Light_Manager::Add_Wall(sf::Vector2f pt1,sf::Vector2f pt2)
{
    bool Add_Wall = true;
    for(int i=0;i<(int)m_wall.size();i++)
        if((pt1.y-pt2.y)/(pt1.x-pt2.y)==(m_wall[i].pt1.y-m_wall[i].pt2.y)/(m_wall[i].pt1.x-m_wall[i].pt2.y))
            if(pt1==m_wall[i].pt1 || pt2==m_wall[i].pt1 || pt1==m_wall[i].pt2 || pt2==m_wall[i].pt2)
            {
                sf::Vector2f min=pt1,max=pt2;
 
                if(pt2.x<min.x)
                    min.x=pt2.x;
                if(pt1.x>max.x)
                    max.x=pt2.x;
 
                if(m_wall[i].pt1.x<min.x)
                    min.x=m_wall[i].pt1.x;
                if(m_wall[i].pt2.x<min.x)
                    min.x=m_wall[i].pt2.x;
 
                if(m_wall[i].pt1.x>max.x)
                    max.x=m_wall[i].pt1.x;
                if(m_wall[i].pt2.x>max.x)
                    max.x=m_wall[i].pt2.x;
 
 
                if(pt2.y<min.y)
                    min.y=pt2.y;
                if(pt1.y>max.y)
                    max.y=pt2.y;
 
                if(m_wall[i].pt1.y<min.y)
                    min.y=m_wall[i].pt1.y;
                if(m_wall[i].pt2.y<min.y)
                    min.y=m_wall[i].pt2.y;
 
                if(m_wall[i].pt1.y>max.y)
                    max.y=m_wall[i].pt1.y;
                if(m_wall[i].pt2.y>max.y)
                    max.y=m_wall[i].pt2.y;
 
                m_wall[i].pt1=min;
                m_wall[i].pt2=max;
 
                return Wall_Entity(i);
 
            }
 
    m_wall.push_back(Wall (pt1,pt2));
    return Wall_Entity(m_wall.size()-1);
}
 
// On désactive une lumière
void Light_Manager::Delete_Light(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].m_actif=false;
    else
        if(e.ID()>=0&&e.ID()<(int)m_StaticLight.size())
            m_StaticLight[e.ID()].m_actif=false;
}
 
// On supprime un mur
void Light_Manager::Delete_Wall(Wall_Entity e)
{
    m_wall.erase(m_wall.begin()+e.ID());
}
 
void Light_Manager::Delete_All_Wall()
{
    m_wall.clear();
}
void Light_Manager::Delete_All_Light()
{
    m_StaticLight.clear();
    m_DynamicLight.clear();
}
 
// On calcule toutes les lumières dynamiques actives
void Light_Manager::Generate()
{
    m_renderImg.Clear(m_basicLight);
    BlurEffect.SetParameter("offset",0.005 * m_lightSmooth);
 
    for(Iter=m_DynamicLight.begin();Iter!=m_DynamicLight.end();++Iter)
        if(Iter->m_actif)
            Iter->Generate(m_wall), Iter->Draw(&m_renderImg);
 
    for(Iter=m_StaticLight.begin();Iter!=m_StaticLight.end();++Iter)
        if(Iter->m_actif)
            Iter->Draw(&m_renderImg);
 
 
    m_renderImg.Display();
}
 
 
void Light_Manager::Generate(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].Generate(m_wall);
}
 
// On crée une image avec toutes les lumières actives
void Light_Manager::Draw(sf::RenderWindow *App)
{
    sf::Sprite sprite;
    sprite.SetImage(m_renderImg.GetImage());
    sprite.SetBlendMode(sf::Blend::Multiply);
    App->Draw(sprite,BlurEffect);
}
 
// On modifie ou récupère les attributs de lumières dynamiques
 
void Light_Manager::SetPosition(Light_Entity e, sf::Vector2f p)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].SetPosition(p);
}
void Light_Manager::SetQuality(Light_Entity e, int q)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].SetQuality(q);
}
void Light_Manager::SetRadius(Light_Entity e, int r)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].SetRadius(r);
}
void Light_Manager::SetColor(Light_Entity e, sf::Color c)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].SetColor(c);
}
void Light_Manager::SetIntensity(Light_Entity e, int i)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            m_DynamicLight[e.ID()].SetIntensity(i);
}
 
 
float Light_Manager::GetIntensity(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            return m_DynamicLight[e.ID()].GetIntensity();
    return 0;
}
float Light_Manager::GetRadius(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            return m_DynamicLight[e.ID()].GetRadius();
    return 0;
}
int Light_Manager::GetQuality(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            return m_DynamicLight[e.ID()].GetQuality();
 
    return 0;
}
sf::Color Light_Manager::GetColor(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            return m_DynamicLight[e.ID()].GetColor();
 
    return sf::Color (0,0,0);
}
sf::Vector2f Light_Manager::GetPosition(Light_Entity e)
{
    if(e.Dynamic())
        if(e.ID()>=0&&e.ID()<(int)m_DynamicLight.size())
            return m_DynamicLight[e.ID()].GetPosition();
 
    return sf::Vector2f (0,0);
}
 
 
 
// On modifie ou récupère différents attributs des murs
 
void Light_Manager::SetPosition(Wall_Entity e, sf::Vector2f p)
{
    if(e.ID()>=0&&e.ID()<(int)m_wall.size())
    {
        sf::Vector2f buffer=m_wall[e.ID()].pt1;
        m_wall[e.ID()].pt1=p;
        m_wall[e.ID()].pt2.x= m_wall[e.ID()].pt2.x + (p.x-buffer.x);
        m_wall[e.ID()].pt2.y= m_wall[e.ID()].pt2.y + (p.y-buffer.y);
    }
}

Light.h

#include <SFML/System.hpp>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>
 
#ifndef LIGHTH
#define LIGHTH
 
struct Wall
{
    Wall (sf::Vector2f p1,sf::Vector2f p2)
    {
        pt1=p1;
        pt2=p2;
    }
 
    // Pt1 et Pt2 sont les deux extrémités du mur
    sf::Vector2f pt1;
    sf::Vector2f pt2;
 
    // Position du mur
    sf::Vector2f position;
};
 
// Wall_Entity est une variable qui permet de représenter dans le programme un mur
struct Wall_Entity
{
    Wall_Entity (int id)
    {
        m_ID=id;
    }
 
    int ID() { return m_ID; }
 
    private:
 
    int m_ID;
};
 
 
// Light_Entity est une variable qui permet de représenter dans le programme une lumière
struct Light_Entity
{
    Light_Entity (){m_Dynamic=false,m_ID=0;}
    Light_Entity (int id,bool d)
    {
        m_ID=id;
        m_Dynamic=d;
    }
 
    int ID() { return m_ID; }
    bool Dynamic() { return m_Dynamic; }
 
    private:
 
    int m_ID;
    bool m_Dynamic;
};
 
class Light
{
    public :
 
    // Constructeur et destructeur
    Light();
    Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color);
    ~Light();
 
    // Afficher la lumière
    void Draw(sf::RenderTarget *App);
 
    // Calculer la lumière
    void Generate(std::vector <Wall> &m_wall);
 
    // Ajouter un triangle à la lumière, en effet, les lumières sont composée de triangles
    void AddTriangle(sf::Vector2f pt1,sf::Vector2f pt2, int minimum_wall,std::vector <Wall> &m_wall);
 
    // Changer différents attributs de la lumière
    void SetIntensity(float);
    void SetRadius(float);
    void SetQuality(int);
    void SetColor(sf::Color);
    void SetPosition(sf::Vector2f);
 
 
    // Retourner différents attributs de la lumière
    float GetIntensity();
    float GetRadius();
    int GetQuality();
    sf::Color GetColor();
    sf::Vector2f GetPosition();
 
    // Une petite bool pour savoir si la lumière est allumée ou éteinte
    bool m_actif;
 
    private :
    //Position à l'écran
    sf::Vector2f m_position;
    //Intensité, gère la transparence ( entre 0 et 255 )
    float m_intensity;
    //Rayon de la lumière
    float m_radius;
    //Couleur de la lumière
    sf::Color m_color;
    //Qualité de la lumière, c'est à dire le nombre de triangles par défaut qui la compose.
    int m_quality;
 
    //Tableau dynamique de Shape, ce sont ces shapes de type triangle qui compose la lumière
    std::vector <sf::Shape> m_shape;
};
 
#endif

Light.cpp

 
#include <iostream>
#include <math.h>
#include "light.h"
 
Light::Light()
{
    m_intensity=0;
    m_radius=0;
    m_quality=0;
    m_actif=true;
}
 
Light::Light(sf::Vector2f position, float intensity, float radius, int quality, sf::Color color)
{
    m_position=position;
    m_intensity=intensity;
    m_radius=radius;
    m_color=color;
    m_quality=quality;
}
 
Light::~Light()
{
    m_shape.clear();
}
 
 
void Light::Draw(sf::RenderTarget *App)
{
    // On boucle sur m_shape pour afficher tous les triangles.
    for(int i=0;i<(int)m_shape.size();i++)
        App->Draw(m_shape[i]);
}
 
sf::Vector2f Intersect(sf::Vector2f p1, sf::Vector2f p2, sf::Vector2f q1, sf::Vector2f q2)
{
    sf::Vector2f i;
 
    if((p2.x - p1.x) == 0 && (q2.x - q1.x) == 0)
        i.x = 0, i.y = 0;
    else if((p2.x - p1.x) == 0)
    {
        i.x = p1.x;
 
        float c = (q2.y - q1.y) / (q2.x - q1.x);
        float d = q1.y - q1.x * c;
 
        i.y = c * i.x + d;
    }
 
    else if((q2.x - q1.x) == 0)
    {
        i.x = q1.x;
 
        float a = (p2.y - p1.y) / (p2.x - p1.x);
        float b = p1.y - p1.x * a;
 
        i.y = a * i.x + b;
    }
    else
    {
        float a = (p2.y - p1.y) / (p2.x - p1.x);
        float b = p1.y - p1.x * a;
 
        float c = (q2.y - q1.y) / (q2.x - q1.x);
        float d = q1.y - q1.x * c;
 
        i.x = (d-b)/(a-c);
        i.y = a * i.x + b;
    }
 
    return i;
}
 
sf::Vector2f Collision(sf::Vector2f p1, sf::Vector2f p2, sf::Vector2f q1, sf::Vector2f q2)
{
    sf::Vector2f i;
    i = Intersect(p1, p2, q1, q2);
 
    if(((i.x >= p1.x - 0.1 && i.x <= p2.x + 0.1)
        || (i.x >= p2.x - 0.1 && i.x <= p1.x + 0.1))
    && ((i.x >= q1.x - 0.1 && i.x <= q2.x + 0.1)
        || (i.x >= q2.x - 0.1 && i.x <= q1.x + 0.1))
    && ((i.y >= p1.y - 0.1 && i.y <= p2.y + 0.1)
        || (i.y >= p2.y - 0.1 && i.y <= p1.y + 0.1))
    && ((i.y >= q1.y - 0.1 && i.y <= q2.y + 0.1)
        || (i.y >= q2.y - 0.1 && i.y <= q1.y + 0.1)))
        return i;
    else
        return sf::Vector2f (0,0);
 
}
 
void Light::AddTriangle(sf::Vector2f pt1,sf::Vector2f pt2, int minimum_wall,std::vector <Wall> &m_wall)
{
    int w = minimum_wall;
    // On boucle sur tous les murs
    for(std::vector<Wall>::iterator IterWall=m_wall.begin()+minimum_wall;IterWall!=m_wall.end();++IterWall,++w)
    {
        // l1 et l2 sont les positions relatives au centre de la lumière des deux extrémités du mur
        sf::Vector2f l1(IterWall->pt1.x-m_position.x, IterWall->pt1.y-m_position.y);
        sf::Vector2f l2(IterWall->pt2.x-m_position.x, IterWall->pt2.y-m_position.y);
 
        if(l1.x * l1.x + l1.y * l1.y < m_radius * m_radius)
        {
            sf::Vector2f i = Intersect(pt1,pt2,sf::Vector2f (0,0),l1);
 
            if((pt1.x > i.x && pt2.x < i.x) || (pt1.x < i.x && pt2.x > i.x))
            if((pt1.y > i.y && pt2.y < i.y) || (pt1.y < i.y && pt2.y > i.y))
                if(l1.y > 0 && i.y > 0 || l1.y < 0 && i.y < 0)
                if(l1.x > 0 && i.x > 0 || l1.x < 0 && i.x < 0)
                AddTriangle(i, pt2, w, m_wall), pt2 = i;
        }
        if(l2.x * l2.x + l2.y * l2.y < m_radius * m_radius)
        {
            sf::Vector2f i = Intersect(pt1,pt2,sf::Vector2f (0,0),l2);
 
            if((pt1.x > i.x && pt2.x < i.x) || (pt1.x < i.x && pt2.x > i.x))
            if((pt1.y > i.y && pt2.y < i.y) || (pt1.y < i.y && pt2.y > i.y))
                if(l2.y > 0 && i.y > 0 || l2.y < 0 && i.y < 0)
                if(l2.x > 0 && i.x > 0 || l2.x < 0 && i.x < 0)
                AddTriangle(pt1, i, w, m_wall), pt1 = i;
        }
 
        sf::Vector2f m = Collision(l1, l2, sf::Vector2f(0,0), pt1);
        sf::Vector2f n = Collision(l1, l2, sf::Vector2f(0,0), pt2);
        sf::Vector2f o = Collision(l1, l2, pt1, pt2);
 
        if((m.x != 0 || m.y != 0) && (n.x != 0 || n.y != 0))
            pt1 = m, pt2 = n;
        else
        {
            if((m.x != 0 || m.y != 0) && (o.x != 0 || o.y != 0))
                AddTriangle(m ,o , w, m_wall), pt1 = o;
 
            if((n.x != 0 || n.y != 0) && (o.x != 0 || o.y != 0))
                AddTriangle(o ,n , w, m_wall), pt2 = o;
        }
    }
 
    // Variable qui contiendra l'intensité calculée, pour le dégradé
    float intensity;
 
    // On ajoute un shape
    m_shape.push_back(sf::Shape ());
 
    // On lui donne comme point de départ (0,0), le centre de la lumière, avec la couleur et intensité maximal
    m_shape.back().AddPoint(0, 0,  sf::Color((int)(m_intensity*m_color.r/255),
                                             (int)(m_intensity*m_color.g/255),
                                             (int)(m_intensity*m_color.b/255)),sf::Color(255,255,255));
 
    // On calcul ou l'on se trouve par rapport au centre, pour savoir à quel intensité on est
    intensity=m_intensity-sqrt(pt1.x*pt1.x + pt1.y*pt1.y)*m_intensity/m_radius;
    // Et on ajoute un  point au shape
    m_shape.back().AddPoint(pt1.x, pt1.y,  sf::Color((int)(intensity*m_color.r/255),
                                                     (int)(intensity*m_color.g/255),
                                                     (int)(intensity*m_color.b/255)),sf::Color(255,255,255));
 
    // Idem
    intensity=m_intensity-sqrt(pt2.x*pt2.x + pt2.y*pt2.y)*m_intensity/m_radius;
    m_shape.back().AddPoint(pt2.x, pt2.y,  sf::Color((int)(intensity*m_color.r/255),
                                                     (int)(intensity*m_color.g/255),
                                                     (int)(intensity*m_color.b/255)),sf::Color(255,255,255));
 
    // On met que le shape soit en Add et on lui donne sa position
    m_shape.back().SetBlendMode(sf::Blend::Add);
    m_shape.back().SetPosition(m_position);
}
 
void Light::Generate(std::vector <Wall> &m_wall)
{
    // On vide la mémoire
    m_shape.clear();
 
    // buf est l'angle de chaque triangle, c'est donc 2pi divisé par le nombre de triangles
    float buf=(M_PI*2)/(float)m_quality;
 
    // On ajoute tous les triangles qui composent la lumière
    for(int i=0;i<m_quality;i++)
    {
        AddTriangle(sf::Vector2f((float)((float)m_radius*cos((float)i*buf))
                                ,(float)((float)m_radius*sin((float)i*buf))) ,
                    sf::Vector2f((float)((float)m_radius*cos((float)(i+1)*buf))
                                ,(float)((float)m_radius*sin((float)(i+1)*buf))),0,m_wall);
    }
}
 
 
// Différentes fonctions pour modifier les attributs de la lumière, et pour les récupérer
 
void Light::SetIntensity(float intensity) { m_intensity=intensity; }
void Light::SetRadius(float radius) { m_radius=radius; }
void Light::SetQuality(int quality) { m_quality=quality; }
void Light::SetColor(sf::Color color) { m_color=color; }
void Light::SetPosition(sf::Vector2f position)
{
    m_position=position;
}
 
 
 
float Light::GetIntensity(){ return m_intensity; }
float Light::GetRadius(){ return m_radius; }
int Light::GetQuality(){ return m_quality; }
sf::Vector2f Light::GetPosition(){ return m_position;}
sf::Color Light::GetColor(){ return m_color; }

Le code d'exemple :

Main.cpp

 
#include "LightManager.h"
 
int main()
{
    // Création de la fenêtre de rendu.
    sf::RenderWindow App(sf::VideoMode(800, 600, 32), "Holyspirit Light Test");
 
    // Création de l'horloge pour gérer le temps.
    sf::Clock Clock;
 
    // Création d'un tableau dynamique qui contient les images des murs.
    std::vector <sf::Shape> Wall;
 
    // On ajoute des lignes à "Wall" pour représenter les murs de facon graphique.
    Wall.push_back(sf::Shape::Line(450,  325, 300,  200, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(250, 240, 400, 365, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(125, 125, 100, 100, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(500, 200, 600, 300, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(500, 300, 600, 200, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(125, 425, 125, 475, 5, sf::Color(255,255,255)));
    Wall.push_back(sf::Shape::Line(125, 475, 175, 475, 5, sf::Color(255,255,255)));
 
    // Création du Light_Manager, c'est lui qui va s'occupper de gérer les lumières.
    Light_Manager *Manager;
    Manager=Light_Manager::GetInstance();
 
    Manager->m_lightSmooth=2;
    Manager->m_basicLight=sf::Color(32,32,32);
 
    // On ajoute des murs au Light_Manager, ce sont ces murs qui sont pris en compte lors du calcul des lumières
    // (Position du point 1, Position du point 2).
 
    Manager->Add_Wall(sf::Vector2f(450,325),sf::Vector2f(300,200));
    Manager->Add_Wall(sf::Vector2f(250,240),sf::Vector2f(400,365));
    Manager->Add_Wall(sf::Vector2f(100,100),sf::Vector2f(125,125));
    Manager->Add_Wall(sf::Vector2f(500,200),sf::Vector2f(600,300));
    Manager->Add_Wall(sf::Vector2f(500,300),sf::Vector2f(600,200));
    Manager->Add_Wall(sf::Vector2f(125,425),sf::Vector2f(125,475));
    Manager->Add_Wall(sf::Vector2f(125,475),sf::Vector2f(175,475));
 
 
    // Création des Light_Entity, ce sont elles qui permettent de modifier les lumières par après, comme changer de position, de couleur, etc
    Light_Entity light,light2,light3;
 
    // On ajoute une lumière dynamique au Light_Manager et on dit que c'est "light" qui la représente.
    light=Manager->Add_Dynamic_Light();
    light2=Manager->Add_Dynamic_Light();
    // On ajoute une lumière dynamique à la position (600,600), d'intensité 255, de rayon 160, de qualité 16 et de couleur verte.
    light3=Manager->Add_Dynamic_Light(sf::Vector2f(600,200),255,160,16,sf::Color(0,255,0));
 
    // On ajoute une lumière statique à la position (110,490), d'intensité 160, de rayon 96, de qualité 8 et de couleur blanche. On ne la raccorde pas à une
    // Light_Entity car c'est une lumière statique et qui n'est donc pas modifiable.
    Manager->Add_Static_Light(sf::Vector2f(110,490),160,96,32,sf::Color(255,255,255));
 
    // On donne la position (375,275) à la lumière raccordée à "light".
    Manager->SetPosition(light,sf::Vector2f(375,275));
 
    // On donne une intensité de 255 à la lumière raccordée à "light".
    Manager->SetIntensity(light,255);
 
    // On donne un rayon de 128 à la lumière raccordée à "light".
    Manager->SetRadius(light,128);
 
    // On donne une qualité de 16 à la lumière raccordée à "light".
    Manager->SetQuality(light,16);
 
    // On donne une couleur rouge à la lumière raccordée à "light".
    Manager->SetColor(light,sf::Color(255,0,0));
 
 
    // Même chose que juste au dessus, mais avec "light2"
    Manager->SetPosition(light2,sf::Vector2f(175,50));
    Manager->SetIntensity(light2,255);
    Manager->SetRadius(light2,128);
    Manager->SetQuality(light2,16);
    Manager->SetColor(light2,sf::Color(0,0,255));
 
 
    // Création d'une image qui servira d'image de fond, on charge donc l'image "test.png".
    sf::Image Image;
    Image.LoadFromFile("test.png");
    sf::Sprite background;
    background.SetImage(Image);
    background.Resize(800,600);
 
    // Création d'une sf::String pour afficher les FPS
    sf::Text FPS;
    // Création d'un buffer pour préparer le texte des FPS
    char buffer[255];
 
    // Création de variables pour la gestion du temps.
    float AfficherFPS=0,LightRefresh=0;
 
    //Création de bool pour faire rebondir les lumières
    bool allerX=true,allerY=true;
    bool allerX2=true,allerY2=true;
 
 
    // Exécution de la boucle principale
    while (App.IsOpened())
    {
        // Traitement des évènements
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            // Fenêtre fermée : on quitte
            if (Event.Type == sf::Event::Closed)
                App.Close();
        }
 
        // On ajoute le temps écoulé
        AfficherFPS+=Clock.GetElapsedTime();
        LightRefresh+=Clock.GetElapsedTime();
 
 
        //On déplace la "light" en fonction du temps, avec allerX et allerY pour savoir si on monte ou on descend.
        if(allerX)
            Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x+100*Clock.GetElapsedTime(),Manager->GetPosition(light).y));
        else
            Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x-100*Clock.GetElapsedTime(),Manager->GetPosition(light).y));
 
        if(allerY)
            Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x,Manager->GetPosition(light).y+100*Clock.GetElapsedTime()));
        else
            Manager->SetPosition(light,sf::Vector2f(Manager->GetPosition(light).x,Manager->GetPosition(light).y-100*Clock.GetElapsedTime()));
 
        //Si la "light" sort d'une certaine zone, on modifie allerX et/ou allerY pour faire rebondir.
        if(Manager->GetPosition(light).x>800)
            allerX=false;
        if(Manager->GetPosition(light).x<0)
            allerX=true;
 
        if(Manager->GetPosition(light).y>600)
            allerY=false;
        if(Manager->GetPosition(light).y<0)
            allerY=true;
 
        // Ce ne sert que pour la démo technique et n'intervient pas dans l'utilisation du moteur de lumières
 
 
        // Idem mais avec light2
        if(allerX2)
            Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x+125*Clock.GetElapsedTime(),Manager->GetPosition(light2).y));
        else
            Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x-125*Clock.GetElapsedTime(),Manager->GetPosition(light2).y));
 
        if(allerY2)
            Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x,Manager->GetPosition(light2).y+125*Clock.GetElapsedTime()));
        else
            Manager->SetPosition(light2,sf::Vector2f(Manager->GetPosition(light2).x,Manager->GetPosition(light2).y-125*Clock.GetElapsedTime()));
 
        if(Manager->GetPosition(light2).x>800)
            allerX2=false;
        if(Manager->GetPosition(light2).x<0)
            allerX2=true;
 
        if(Manager->GetPosition(light2).y>600)
            allerY2=false;
        if(Manager->GetPosition(light2).y<0)
            allerY2=true;
 
 
        // On récupère la position de la souris
        const sf::Input& Input = App.GetInput();
        // On place light 3 à cette position, avec un tout petit décalage, pour éviter d'avoir une lumière pile sur l'axe d'un mur, ça peut engendrer des problèmes pour le moment.
        Manager->SetPosition(light3,sf::Vector2f(Input.GetMouseX(),Input.GetMouseY()));
 
        Clock.Reset();
 
        //Vous pouvez changer le 0.025 par une autre valeur si vous voulez que les lumières ne se rafraichissent que toutes les x secondes, au lieu de le faire à chaque tour de boucle.
        if(LightRefresh>0.025)
        {
            // On re-calcule les lumières
            Manager->Generate();
            LightRefresh=0;
        }
 
        // Efface l'écran (remplissage avec du noir)
        App.Clear();
 
        // On affiche le fond
        App.Draw(background);
 
        // On affiches les murs
        for(int w=0;w<(int)Wall.size();w++)
            App.Draw(Wall[w]);
 
        // On affiche les lumières
        Manager->Draw(&App);
 
        // On affiche les FPS
        if(AfficherFPS>0.2)
        {
            float Framerate = 1.f / App.GetFrameTime();
            sprintf(buffer,"%i",(int)Framerate);
            FPS.SetString(buffer);
            AfficherFPS=0;
        }
        App.Draw(FPS);
 
 
 
        // Affichage du contenu de la fenêtre à l'écran
        App.Display();
    }
 
     Manager->Kill();
 
    return EXIT_SUCCESS;
}

Singleton.h

#include <iostream>
 
/// Script repris de : http://www.siteduzero.com/tutoriel-3-32923-la-classe-singleton.html
/// Ecrit par : Davidbrcz
 
 
template<typename T> class CSingleton
{
public:
 
    /*
      Cette fonction retourne l'unique instance de l'objet
    */
    static T* GetInstance(void)
    {
        if(singleton==0)
	    {
		singleton = new T;
	    }
        return singleton;
    }
 
    /*
      Cette fonction tue l'unique instance de l'objet
    */
    static void Kill()
    {
        if(singleton!=0)
	    {
		delete singleton ;
		singleton=0;
	    }
    }
 
 
    //un couple d'accesseur / mutateur
    int GetValue()
    {
        return  value;
    }
 
    void SetValue(int val)
    {
	value=val;
    }
 
protected:
 
    int value;
 
    CSingleton() : value(0)
    {
        std::cout<<"Singleton crée"<<std::endl;
    }
 
    virtual ~CSingleton()
    {
        std::cout<<"Singleton détruit"<<std::endl;
    }
 
    static T *singleton;
};
 
template <typename T> T* CSingleton<T>::singleton = 0;
 
fr/sources/lightmanager.txt · Last modified: 2010/09/07 10:41 by gregouar
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki