Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Appliquer un sf::Transform à un sf::Sprite et à un sf::shape dans un draw.  (Lu 10241 fois)

0 Membres et 1 Invité sur ce sujet

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok sinon je vois que tu fais toujours au moins une transformation pour les sprites car je n'ai pas vu de constructeur dans la classe sprite ou l'on peut passer la position du sprite.

Donc j'aurai du mal de faire un sprite sans transformation. :/

Je dois donc toujours faire au moins une transformation pour initialisé la position du sprite avec le constructeur de ma classe Tile. :/

Sinon pour les ConvesShape et VertexArray pas de soucis vu que la je peux passer directement la position des vertex grâce à la méthode addPoint ou append sans devoir faire de transformation.
PS : Et je ne peux pas modifier directement la position des Vertex des sprites car je n'y ai pas accès.
« Modifié: Août 28, 2013, 07:41:23 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Ok sinon je vois que tu fais toujours au moins une transformation pour les sprites car je n'ai pas vu de constructeur dans la classe sprite ou l'on peut passer la position du sprite.

Donc j'aurai du mal de faire un sprite sans transformation. :/

Je dois donc toujours faire au moins une transformation pour initialisé la position du sprite avec le constructeur de ma classe Tile. :/
??
Je ne comprends pas ce que tu veux dire là.

Citer
Sinon pour les ConvesShape et VertexArray pas de soucis vu que la je peux passer directement la position des vertex grâce à la méthode addPoint ou append sans devoir faire de transformation.
PS : Et je ne peux pas modifier directement la position des Vertex des sprites car je n'y ai pas accès.
Là non plus je ne vois vraiment pas ce que tu veux faire :-\
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bon j'ai trouvé mieux en faisant carrément une classe dérivée de sf::Transformable (TransformableEntity) qui se charge de faire des tranformations sur des entités quelconques, les méthodes de cette classe dérivée qui appliquent les transformation peuvent être redéfinie si pas exemple je dois transformer aussi des entités enfants dans la classe qui hérite de TransformableEntity, remettre à jour la physique ou encore faire mon propre sf::Transform.

Voici cette classe :
#ifndef TRANSF_ENTITY
#define TRANSF_ENTITY
class TransformableEntity : public virtual sf::Transformable {
public :
    void setLocalBounds (FloatRect localBounds) {
        this->localBounds = localBounds;
    }
    FloatRect getLocalBounds() {
        return localBounds;
    }
    virtual void setCenter(Vec2f center) {
        Transformable::setPosition(Vector2f(center.x, center.y));
    }
    Vec2f getCenter() {
        return Vec2f(Transformable::getPosition().x, Transformable::getPosition().y);
    }
    virtual void setPosition(Vec2f position) {
        Vec2f origin (Transformable::getOrigin().x, Transformable::getOrigin().y);
        Vec2f originalSize (getLocalBounds().width, getLocalBounds().height);
        Vec2f size = getSize();
        Vec2f scale (size.x / originalSize.x, size.y / originalSize.y);
        Vec2f sub (origin.x * scale.x, origin.y * scale.y);
        setCenter(position - sub);
    }
    Vec2f getPosition() {
        FloatRect globalBounds = getGlobalBounds();
        Vec2f position(globalBounds.left, globalBounds.top);
        return position;
    }

    Vec2f getSize() {
        FloatRect globalBounds = getGlobalBounds();
        Vec2f size(globalBounds.width, globalBounds.height);
        return size;
    }
    virtual void setRotation (float angle) {
        Transformable::setRotation(angle);
    }
    virtual void setScale(Vec2f scale) {
        Transformable::setScale(Vector2f(scale.x, scale.y));
    }
    virtual void move (Vec2f t) {
        Transformable::move(Vector2f(t.x, t.y));
    }
    virtual void setOrigin(Vec2f origin) {
        Transformable::setOrigin(Vector2f(origin.x, origin.y));
    }
    Vec2f getScale() {
        return Vec2f(Transformable::getScale().x, Transformable::getScale().y);
    }
    float getRotation() {
        return Transformable::getRotation();
    }
    Vec2f getOrigin() {
        return Vec2f(Transformable::getOrigin().x, Transformable::getOrigin().y);
    }
    virtual void setSize (Vec2f size) {
        Vec2f actualSize = this->getSize();
        Vec2f scale = size / actualSize;
        Transformable::setScale(scale.x, scale.y);
    }

    FloatRect getGlobalBounds() {
        FloatRect globalBounds = getTransform().transformRect(localBounds);
    }

private :
    FloatRect localBounds;
};
#endif // TRANSF_ENTITY
 

Ca m'évite de devoir réecrire du code et de devoir à chaque fois redéfinir toutes les méthodes de transformation pour mes entités transformable et je peux aussi utiliser le polymorphisme si je veux appliquer des transfomations sur toutes les entités sélectionnée qui peuvent être de type différents.
Je crois que je vis lui mettre un constructeur à cette classe en envoyant la position et la taille du localBounds. (Je ne fais pas de transformation au sprite je ne fait que les transformations avec ma classe TransormableEntity.)
Ce qui donne :
#include "tile.h"

#include "../world/gridMap.h"
#include "../Lighting/shadow.h"
#include "../Lighting/wall.h"

using namespace sf;
using namespace std;

/*Gère les différents tiles, cette classe hérite de Sprite.
*/

//Crée un tile, avec une image passée en paramètre.
Tile::Tile (sf::Texture &image, Vec2f position, Vec2f size, IntRect subRect, bool bToAnim) : Entity (E_TILE) {
    sprite.setTexture(image);
    sprite.setTextureRect(subRect);
    float factorX = size.x / subRect.width;
    float factorY = size.y / subRect.height;
    this->bToAnim = bToAnim;
    zOrder = 0;
    selected = false;
    TransformableEntity::setOrigin(subRect.width * 0.5f, subRect.height * 0.5f);
    TransformableEntity::setPosition(Vec2f(position.x + size.x * 0.5f, position.y + size.y * 0.5f));
    TransformableEntity::setScale(Vec2f(factorX, factorY));
    setLocalBounds(sprite.getLocalBounds());
}

IntRect Tile::getTextRect () {
    return sprite.getTextureRect();
}

const Texture& Tile::getTexture () {
    return *sprite.getTexture();
}

bool Tile::belongToAnim () {
    return bToAnim;
}
void Tile::popup () {
    if (zOrder + 1 <= DEFAULT_SHADOW_Z_ORDER)
        zOrder++;
}
void Tile::popback () {
    if (zOrder - 1 >= 0)
        zOrder--;
}

bool Tile::operator== (Tile &tile) {

    return sprite.getTexture() == tile.sprite.getTexture() &&
           sprite.getPosition().x == tile.sprite.getPosition().x &&
           sprite.getPosition().y == tile.sprite.getPosition().y &&
           getSize().x == tile.getSize().x &&
           getSize().y == tile.getSize().y &&
           getZOrder() == tile.getZOrder() &&
           getType() == tile.getType () &&
           sprite.getTextureRect().left == tile.sprite.getTextureRect().left &&
           sprite.getTextureRect().top == tile.sprite.getTextureRect().top &&
           sprite.getTextureRect().height == tile.sprite.getTextureRect().height &&
           sprite.getTextureRect().width == tile.sprite.getTextureRect().width;

}
bool Tile::operator!= (Tile &tile) {
    return !(*this == tile);
}

//Getter.
Sprite& Tile::getSprite () {
    return sprite;
}

//Renvoie le numéro de la couche du sprite.
int Tile::getZOrder() {
    return zOrder;
}

bool Tile::isSelected () {
    return selected;
}

void Tile::setZOrder(int zOrder) {

    this->zOrder = zOrder;
}

void Tile::setSelected (bool selected) {
    this->selected = selected;
}

void Tile::draw (RenderTarget &target, RenderStates states) const {
    states.transform = states.transform * getTransform();
    target.draw(sprite, states);
}


Tile::~Tile () {


}
 

J'avais pensé utiliser transfomable et faire hériter directement toutes les entités transformable de cette classe mais le problème c'est que les méthodes de la classe Transformable ne sont pas virtuelle donc je ne pourrai pas faire du polymorphisme. :/











Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
C'est très bancal tout ça.

Déjà, pourquoi est-ce que toutes les fonctions de ta classe sont virtuelles ? Ensuite, puisque tu redéfinis tout ce que sf::Transformable propose, pourquoi en hériter publiquement ? Là dans ta classe tu va tout avoir en double : tes fonctions + celles de sf::Transformable. Si tu hérites de sf::Transformable juste pour implémenter ta classe, alors fais un héritage prové pour ne pas polluer l'interface publique de ta classe.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
C'est très bancal tout ça.

Déjà, pourquoi est-ce que toutes les fonctions de ta classe sont virtuelles ?

Pour pouvoir utiliser le polymorphisme car ma grille contient des objets de type TransformableEntity et non pas de type Tile car je m'en fou de savoir si c'est une Tile ou bien un mur u ien n'importe quoi quand je veut redimentionner, faire tourner ou bien repositionner mes entités.
Et étant donné que les fonctions de Transformable ne sont pas virutelle comme la fonction draw de Drawable bah je peux pas utiliser des objets de type Transformable pour faire mes transformations car sinon, se seront les fonctions de Transformable qui seront appelée et pas les fonctions de ma classe qui hérite de Transformable, du coup certaines de mes entités de mon framework qui utilisent aussi de la physique et doivent redéfinir des méthodes de Transformable, et bah, ne remettront pas la physique à jour, comme par exemple, ma classe wall qui contient aussi les segments pour les intesections mur lumière ainsi que des points pour la projection des ombres en fonction des lumières :

#include "wall.h"
#include "lightManager.h"
Wall::Wall (Tile *t, int type) : Entity(Entity::E_WALL) , TransformableEntity(t->getPosition(), t->getSize(), t->getOrigin()) {
    this->type = type;
    this->t = t;
    shadow = new ShadowWall(LightManager::getSun(), t, this);
}
void Wall::setSize(Vec2f size) {
    TransformableEntity::setSize(size);
    scale(s);
}

void Wall:setCenter(Vec2f center) {
    Vec2f t = center - this->getCenter();
    TransformableEntity::setCenter(center);
    move(t);
}

void Wall::setPosition(Vec2f position) {
    TransformableEntity::setPosition(Vec2f (position.x, position.y));
    move(t);
}

void Wall::addSegment (Segment *seg) {
    segments.push_back(seg);
}
void Wall::addBottomPoint (Vec2f *point) {
    bottomPoints.push_back(point);
}
std::vector<Segment*> Wall::getSegment () {
    return segments;
}
std::vector<Vec2f*> Wall::getBottomPoints () {
    return bottomPoints;
}

void Wall::setType (int type) {
    this->type = type;
}
int Wall::getType () {
    return type;
}
void Wall::setRotation (float angle) {
   shadow->setRotation(angle);
   TransformMatrix tm;
   tm.setRotation(angle);
   for (int i = 0; i < segments.size(); i++) {
        segments[i]->rotate(angle, Vec2f(t->getOrigin().x, t->getOrigin().y));
   }
   for (int i = 0; i < bottomPoints.size(); i++) {
        *bottomPoints[i] = tm.transform(*bottomPoints[i]);
   }
   TransformableEntity::setRotation(angle);
}
void Wall::setScale (Vec2f s) {
   shadow->setScale(s.x, s.y);
   TransformMatrix tm;
   tm.setScale(s.x, s.y);
   for (int i = 0; i < segments.size(); i++) {
        segments[i]->scale(s.x, s.y);
   }
   for (int i = 0; i < bottomPoints.size(); i++) {
        *bottomPoints[i] = tm.transform(*bottomPoints[i]);
   }
   TransformableEntity::setScale(s.x, s.y);
}
void Wall::move (Vec2f t) {
   shadow->move(t.x, t.y);
   TransformMatrix tm;
   tm.setTranslation(t.x, t.y);
   for (int i = 0; i < segments.size(); i++) {
        segments[i]->translate(t.x, t.y);
   }
   for (int i = 0; i < bottomPoints.size(); i++) {
        *bottomPoints[i] = tm.transform(*bottomPoints[i]);
   }
   TransformableEntity::move(t.x, t.y);
}

void Wall::Draw (RenderTarget &target, RenderStates states) const {
    states.transform = states.transform * getTransform();
    target.draw(*t, states);
}
Shadow* Wall::getShadow() {
    return shadow;
}

Wall::~Wall () {
    for (unsigned int i = 0; i < segments.size(); i++)
        delete segments[i];
    segments.clear();
    for (unsigned int i = 0; i < bottomPoints.size(); i++)
        delete bottomPoints[i];
    bottomPoints.clear();
    delete shadow;
}
 
Donc voilà pourquoi j'ai déclarer mes méthodes virtuelles.

Ensuite, puisque tu redéfinis tout ce que sf::Transformable propose, pourquoi en hériter publiquement ?
 
Ha oui c'est vrai merci.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Bon j'ai fait un héritage privé, et j'ai fais mes propres interface qui sont implémentent les interfaces SFML mais avec des fonctions supplémentaires.

Et je peux aussi redéfinir ses fonctions si il y a lieux pour remettre à jour la physique du monde en cas de transformation sur mes entités.

Et enfin, j'en ai profité également pour faire une interface dont hériteront toutes les entités dynamique et statiques qui seront dessinable. ^^ (Les entités statique ayant aussi une position, un centre et une taille)






Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Sinon, une petite remarque, pour les entités statiques je préfère faire une seule transformation au chargement de la map puis afficher les entités plutôt que de faire la transformation à chaque rendu. :/ (Plus performant.)

Il n'y a que pour les entités dynamiques donc qu'il faut faire la transformation à chaque rendu.

Bref je vais réimplémenter tout ça.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Sinon une matrice 2*2 suffit amplement pour faire de la 2D si je ne me trompe pas :

x' = (x * cos(alpha) * sx + tx + ox) + (y * sin(alpha) * sy)
y' = (x * -sin(alpha) * sx) + (y * cos(alpha) * sy + ty + oy)

En espérant avoir bien recopier la formule que j'ai écrite sur papier ce matin.

tx et ty sont la translation de x et de y, sx et sy l'échelle, alpha l'angle de rotation, ox et oy les origines en x et y, x les coordonnées du point à transformer et ', y' les coordonnées du point transformé.

Hum..., j'ai du inverser les signes pour la matrice car l'axe y pointe vers le bas.

Ta matrice 4*4 ok elle marche mais je n'y comprend rien. :/
Bref moi je ne m'en sert que pour de la 3D. (Dans ma classe TransformMatrix j'ai 2 matrices, une 2*2 pour de la 2D et une 4*4 pour de la 3D.)

PS : de plus je combine les transformations dans ma classe TransformMatrix directement et si je veux pas combiner bah je fais loadIdentity avant chaque transformation je trouve ça plus pratique que de devoir réimplémenter une classe pour combiner les transformations.

Voici à quoi ressemble ma classe :
void TransformMatrix::setRotation (int angle) {
    float cosAlpha = Math::cosinus(Math::toRadians(angle));
    float sinAlpha = Math::sinus(Math::toRadians(angle));
    matrix2f.m11 += cosAlpha;
    matrix2f.m12 += sinAlpha;
    matrix2f.m21 += -sinAlpha;
    matrix2f.m22 += cosAlpha;
}
void TransformMatrix::setScale (float sx, float sy) {
    matrix2f.m11 *= sx;
    matrix2f.m12 *= sy;
    matrix2f.m21 *= sx;
    matrix2f.m22 *= sy;
}
void TransformMatrix::setTranslation (int dx, int dy) {
    matrix2f.m21 += dx;
    matrix2f.m22 += dy;
}
void TransformMatrix::reset () {
       matrix2f.identity ();
}
Vec2f TransformMatrix::transform (const Vec2f &vec2) {
    return matrix2f * vec2;
}
Vec3f TransformMatrix::inverseTransform (const Vec2f &vec2) {
    Matrix2f inv;  
    inv = matrix2f.inverse();
    return inv * vec2;
}
 

Bref ça m'ennuie beaucoup de devoir dériver de sf::Transformable ou bien de devoir réutiliser un sf::Transform en interne pour pouvoir faire ce genre de chose. :/

Je pense que je vais utiliser SFML que pour le fenêtrage finalement, les évènements, le son et le réseau.
Pour le reste j'ai besoin de code plus simple que de devoir dériver à chaque fois et utiliser mon propre sf::Transform pour gérer les transformations d'un parent et de ses noeuds. :/

Et ce qui m'énerve le plus c'est de devoir faire un setPosition pour un sprite si je veux lui mettre une position par défault hors que si mon sprite est statique et que je veux simplement lui donner 1 vertexarray avec 4 positions sans devoir passer par une transformation et devoir faire gaffe lorsque je combine cette transformation avec celle du noeud.
Je crois que je vais refaire une classe sprite ou je mets direct une position aux vertex pour les 4 coins et pas utiliser de tansformations si je n'en veut pas.
« Modifié: Août 31, 2013, 10:49:04 am par Lolilolight »

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Et un autre truc qui me chiffone c'est de devoir déplacer la vue d'une RenderTexture comme si c'était une seconde vue hors que ce n'est qu'une texture, au lieu de pouvoir l'utiliser comme un sprite ou n'importe quel autre entité dessinable. (De plus pas moyen de modifier l'origine d'une vue, l'origine de la vue c'est toujours le centre.)
Bref je n'ai jamais compris l'intérêt de faire une vue pour une texture de rendu hors que une texture de rendu ce n'est pas une vue. (Enfin pour moi ça ne l'est pas.)

PS : bref je vais pas continuer à chouiner comme je comprends pas mal opengl et la SFML j'ai trouvé une solution pour faire ça plus simplement en utilisant mes propres matrices, sprites et textures de rendu sans devoir modifier trop mon code.
« Modifié: Août 31, 2013, 11:07:57 am par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Citer
Sinon, une petite remarque, pour les entités statiques je préfère faire une seule transformation au chargement de la map puis afficher les entités plutôt que de faire la transformation à chaque rendu.
Dis toi bien que de toute façon OpenGL va appliquer une transformation à tous les points qu'il voit passer. Si tu ne transformes pas dynamiquement tes entités ce sera juste la matrice identité ; mais ça n'aura strictement aucun impact sur les performances.

Citer
Sinon une matrice 2*2 suffit amplement pour faire de la 2D si je ne me trompe pas
Pour les transformations linéaires oui. Mais la translation ne l'est pas, il faut donc une dimension supplémentaire pour la gérer.

Rappel : une transformation linéaire est du type y = a * x, or la translation est de type y = a + x.

Citer
Ta matrice 4*4 ok elle marche mais je n'y comprend rien.
SFML utilise une matrice 4x4 en interne de manière à pouvoir la refiler à OpenGL telle quelle, mais la 3ème dimension n'est pas utilisée.

Citer
de plus je combine les transformations dans ma classe TransformMatrix directement et si je veux pas combiner bah je fais loadIdentity avant chaque transformation je trouve ça plus pratique que de devoir réimplémenter une classe pour combiner les transformations.
Mais une fois que tu as combiné plusieurs composantes tu ne peux plus en changer une sans reconstruire toute la matrice. C'est ça que fait sf::Transformable : elle garde toutes ses composantes séparées, et les combine uniquement lorsqu'on a besoin d'avoir une représentation de la matrice.

Citer
Bref ça m'ennuie beaucoup de devoir dériver de sf::Transformable ou bien de devoir réutiliser un sf::Transform en interne pour pouvoir faire ce genre de chose. :/
Pourquoi utiliser un sf::Transform ne convient-il pas ?

Citer
Et ce qui m'énerve le plus c'est de devoir faire un setPosition pour un sprite si je veux lui mettre une position par défault hors que si mon sprite est statique et que je veux simplement lui donner 1 vertexarray avec 4 positions sans devoir passer par une transformation et devoir faire gaffe lorsque je combine cette transformation avec celle du noeud.
Je crois que je vais refaire une classe sprite ou je mets direct une position aux vertex pour les 4 coins et pas utiliser de tansformations si je n'en veut pas.
En effet tu peux faire ça ; sf::Sprite n'est qu'une couche très fine par dessus un sf::Vertex[4] + sf::Texture*. Mais je ne vois pas quel est l'inconvénient de faire un setPosition. Si tu penses aux performances, alors je vais te dire que ce n'est pas un argument tant que tu n'as pas prouvé que ça l'était. C'est assez minime comme impact.

Citer
Bref je n'ai jamais compris l'intérêt de faire une vue pour une texture de rendu hors que une texture de rendu ce n'est pas une vue. (Enfin pour moi ça ne l'est pas.)
Le fait que tu dessines sur une texture n'est pas pertinent ici. Que tu dessines sur une fenêtre, sur une texture, sur du papier ou n'importe quoi d'autre, c'est pareil : tu dessines. Et il faut bien définir quelle zone de la scène tu dessines.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
A ok je comprends mieux là, ok si ça n'a pas d'impact sur les performances alors je vais laisser ça comme ça.

En effet dans le code que j'ai mis j'ai besoin de reconstruire la matrice à chaque transformation.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok sinon, je pense que je vais faire ma propre classe transformable contenant un sf::Transform finalement et un ma propre classe sprite pour m'entrainer.

Sinon j'ai une question, ça :
float tx     = -m_origin.x * sxc - m_origin.y * sys + m_position.x;
float ty     =  m_origin.x * sxs - m_origin.y * syc + m_position.y;
 

Et ça :

float tx = m_origin.x + tx;
float ty = m_origin.y + ty;
 

Ce ne serait pas la même chose ???

Pour moi un changement d'origine n'a toujours été qu'une translation.

En tout cas sur papier ça me donne la même chose.
« Modifié: Août 31, 2013, 12:29:34 pm par Lolilolight »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Non, l'origine n'est pas qu'une translation. C'est l'origine de toute les autres transformations. Ce n'est pas équivalent.
Laurent Gomila - SFML developer

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Ok.

Lolilolight

  • Hero Member
  • *****
  • Messages: 1232
    • Voir le profil
Re : Appliquer un sf::Transform à un sf::Sprite et à un sf::shape dans un draw.
« Réponse #29 le: Septembre 02, 2013, 08:08:13 pm »
Bon finalement j'ai fait ma propre interface Transformable à laquelle j'ai rajouté des fonctions, et j'ai fait des méthodes que je redéfini si j'ai besoin de mettre à jour mon moteur physique quand je fais une transformation et que j'appelle dans ma propre interface Transformable.

Plutôt que de devoir ré-écrire tout le code dans toutes mes entités SFML-LIKE avec un sf::Transform pour chaque entité SFML-LIKE.

De plus j'ai besoin de connaitre la géométrie de mes entités avant de les dessiner afin de les mettre dans une grille, un quadtree ou bien un arbre binaire pour faire le furstrum culling. (Je n'utilise pas de graphe de scene.)

Je ne fais plus d'héritage à la place j'utilise une variable membre sf::Transform.

Et je fais hériter cette interface de toute les classes qui ont besoin de faire des transformations, je redéfini onRotation si par exemple j'ai besoin de mettre à jour la physique ou bien de faire une rotation sur des entités enfants d'un noeud.

Je trouve ça plus pratique.

PS : je posterai un exemple de code source plus loin.
« Modifié: Septembre 02, 2013, 08:13:48 pm par Lolilolight »