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

Auteur Sujet: [Résolu]Problème de positionnement avec sf::VertexArray  (Lu 3322 fois)

0 Membres et 2 Invités sur ce sujet

Black Templar

  • Newbie
  • *
  • Messages: 45
    • Live Messenger (MSN) - ferdipiette@hotmail.com
    • Voir le profil
    • E-mail
[Résolu]Problème de positionnement avec sf::VertexArray
« le: Avril 24, 2013, 11:09:31 am »
Bonjour,

Je viens vous soumettre un problème (ou bug potentiel ?) avec sf::VertexArray
J'essaye de quadriller ma fenêtre avec des carrés blancs de 16pixels par 16.
Pour ça, j'utilise un sf::VertexArray(sf::Lines,2) pour dessiner des lignes horizontales et verticales.

Ma fenêtre fais 673 pixels (=16px*42+1)
Je devrais donc réussir à caser 43 lignes horizontales et 43 verticales.

Pas de problème pour les lignes horizontales. Par contre, pour les lignes verticales, tout est décalé de 1 pixel : la ligne verticale à x=0 ne s'affiche pas et la dernière ligne à s'afficher à pour coordonnée x = 671 au lieu de 672.

Voir le problème sur cet image (j'ai mis un fond rouge uniforme pour bien voir) :


J'ai refait un code minimal pour illustrer le problème.
Le style de la fenêtre est sf::Style::None pour qu'on puisse bien voir le problème.
La touche Echap quitte l'appli.

J'utilise SFML2 (RC) compilé avec MinGW 7.4
J'utilise la norme C++11

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

int main(int argc, char** argv) {
    //673 = 16*42+1
    sf::RenderWindow mapWindow(sf::VideoMode(673, 673, 32), "Map", sf::Style::None);
    mapWindow.setFramerateLimit(10);

    while (mapWindow.isOpen())
    {
        sf::Event event;
        while(mapWindow.pollEvent(event))
        {
            // Close Window (press escape)
            if (event.type == sf::Event::Closed || ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)))
                mapWindow.close();

            // Mouse Debug
            // Coin haut gauche : (0,0)
            // Coin bas droite  : (672,672)
            if(event.type == sf::Event::MouseMoved)
                std::cout << "x=" << sf::Mouse::getPosition(mapWindow).x << " ; y=" << sf::Mouse::getPosition(mapWindow).y << std::endl;
        }
       
        // Draw vertical lines
        for(unsigned int i = 0; i <= mapWindow.getSize().x / 16; i++) {
            sf::VertexArray vArray(sf::Lines, 2);
            vArray[0].position = sf::Vector2f(i*16,0);
            vArray[1].position = sf::Vector2f(i*16,mapWindow.getSize().y);
            vArray[0].color = sf::Color::White;
            vArray[1].color = sf::Color::White;  
            mapWindow.draw(vArray);
        }

        // Draw horizontal lines
        for(unsigned int i = 0; i <= mapWindow.getSize().y / 16; i++) {
            sf::VertexArray vArray(sf::Lines, 2);
            vArray[0].position = sf::Vector2f(0,i*16);
            vArray[1].position = sf::Vector2f(mapWindow.getSize().x,i*16);
            vArray[0].color = sf::Color::White;
            vArray[1].color = sf::Color::White;  
            mapWindow.draw(vArray);
        }
       
        // Display Window
        mapWindow.display();
        mapWindow.clear();
    }
   
    return 0;
}
 

C'est peut-être moi qui utilise mal le sf::vertexArray, il suffit que je rajoute un +1 lorsque je dessine mes lignes verticales, mais je ne trouve pas ça très logique.

++
Black Templar
« Modifié: Avril 24, 2013, 02:34:08 pm par Black Templar »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème de positionnement avec sf::VertexArray
« Réponse #1 le: Avril 24, 2013, 11:23:45 am »
En fait, comme les lignes font un pixel d'épaisseur et que leurs coordonnées représentent la ligne médiane (i.e. quand tu dessines il y a 0.5 pixels d'un côté de ta coordonnée, et 0.5 de l'autre), tu peux en déduire que pour remplir une ligne/colonne de pixels, il faut placer la ligne au centre des pixels, donc utiliser des demi-coordonnées.

Par exemple, pour remplir la colonne Y = 0 :
vArray[0].position = sf::Vector2f(0.5f, 0);
vArray[1].position = sf::Vector2f(0.5f, height);

Pour en revenir à ton code, au lieu de "i*16" il faut écrire "i*16+0.5f".

Normalement il faut le faire pour les deux axes, mais vu que tes lignes horizontales fonctionnent déjà bien, si ça les choucroutent alors ne le fais que pour les lignes verticales ;D

Citer
sf::VertexArray vArray(sf::Lines, 2);
Arg! sf::VertexArray est un std::vector<sf::Vertex>. Ca ne te viendrait pas à l'idée de faire plein de new/delete juste pour allouer 2 sf::Vertex, n'est-ce pas ?

Remplace par ça, ce sera beaucoup plus léger :
sf::Vertex vArray[2];
...
mapWindow.draw(vArray, 2, sf::Lines);

Et sinon, pourquoi plein de petits vertex arrays plutôt qu'un gros avec tout dedans ?
« Modifié: Avril 24, 2013, 11:25:50 am par Laurent »
Laurent Gomila - SFML developer

Black Templar

  • Newbie
  • *
  • Messages: 45
    • Live Messenger (MSN) - ferdipiette@hotmail.com
    • Voir le profil
    • E-mail
Re : Re : Problème de positionnement avec sf::VertexArray
« Réponse #2 le: Avril 24, 2013, 11:36:14 am »
En fait, comme les lignes font un pixel d'épaisseur et que leurs coordonnées représentent la ligne médiane (i.e. quand tu dessines il y a 0.5 pixels d'un côté de ta coordonnée, et 0.5 de l'autre), tu peux en déduire que pour remplir une ligne/colonne de pixels, il faut placer la ligne au centre des pixels, donc utiliser des demi-coordonnées.

Ahhh merci :)
ça explique donc le pourquoi du comment XD


Citer
sf::VertexArray vArray(sf::Lines, 2);
Arg! sf::VertexArray est un std::vector<sf::Vertex>. Ca ne te viendrait pas à l'idée de faire plein de new/delete juste pour allouer 2 sf::Vertex, n'est-ce pas ?

Remplace par ça, ce sera beaucoup plus léger :
sf::Vertex vArray[2];
...
mapWindow.draw(vArray, 2, sf::Lines);
oops :p
En effet, c'est pas top.
Pour le moment, j'essaye juste de comprendre comment marche les Vertex. (jamais fais d'opengl moi)

Et sinon, pourquoi plein de petits vertex arrays plutôt qu'un gros avec tout dedans ?
Hum... C'est à dire ?
Un vertexArray avec plein de Vectex à chaque intersection ?
Je trouvais plus économique de tracer des droites (2*43*2 points) plutôt que de spécifier toutes les intersections (43^2 points)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32498
    • Voir le profil
    • SFML's website
    • E-mail
Re : Problème de positionnement avec sf::VertexArray
« Réponse #3 le: Avril 24, 2013, 11:47:34 am »
Citer
Hum... C'est à dire ?
Un vertexArray avec plein de Vectex à chaque intersection ?
Je trouvais plus économique de tracer des droites (2*43*2 points) plutôt que de spécifier toutes les intersections (43^2 points)
Non, tu gardes exactement la même définition avec les mêmes lignes, mais au lieu de les regrouper 1 par 1 tu les mets toutes dans le même vertex array et tu les dessines d'un coup. C'est un peu ça le but du vertex array à la base ;)
Laurent Gomila - SFML developer

Black Templar

  • Newbie
  • *
  • Messages: 45
    • Live Messenger (MSN) - ferdipiette@hotmail.com
    • Voir le profil
    • E-mail
Re : Re : Problème de positionnement avec sf::VertexArray
« Réponse #4 le: Avril 24, 2013, 12:01:43 pm »
Citer
Hum... C'est à dire ?
Un vertexArray avec plein de Vectex à chaque intersection ?
Je trouvais plus économique de tracer des droites (2*43*2 points) plutôt que de spécifier toutes les intersections (43^2 points)
Non, tu gardes exactement la même définition avec les mêmes lignes, mais au lieu de les regrouper 1 par 1 tu les mets toutes dans le même vertex array et tu les dessines d'un coup. C'est un peu ça le but du vertex array à la base ;)

Ahhh, oki, je comprend mieux.
En effet, ça marche très bien :)
void MapView::draw(sf::RenderTarget& target, sf::RenderStates states) const {
    for(auto tileIt = this->mapLvl0.begin(); tileIt != this->mapLvl0.end(); ++tileIt) {
        target.draw(**tileIt, states);
    }
   
    for(auto tileIt = this->mapLvl1.begin(); tileIt != this->mapLvl1.end(); ++tileIt) {
        target.draw(**tileIt, states);
    }
   
    sf::VertexArray vArray(sf::Lines, (target.getSize().x / 16 + 1)*4);
    for(unsigned int i = 0; i <= target.getSize().x / 16; i++) {
        vArray[2*i].position = sf::Vector2f(i*16+0.5f,0);
        vArray[2*i+1].position = sf::Vector2f(i*16+0.5f,target.getSize().y);
        vArray[2*i].color = sf::Color::White;
        vArray[2*i+1].color = sf::Color::White;  
        //Debug::info << NEW_ENTRY << 2*i << ":" << 2*i+1 << std::endl;
    }
    unsigned int offset = 2 * (target.getSize().x / 16 + 1);
    for(unsigned int i = 0; i <= target.getSize().y / 16; i++) {
        vArray[offset+2*i].position = sf::Vector2f(0,i*16+0.5f);
        vArray[offset+2*i+1].position = sf::Vector2f(target.getSize().x,i*16+0.5f);
        vArray[offset+2*i].color = sf::Color::White;
        vArray[offset+2*i+1].color = sf::Color::White;
        //Debug::info << NEW_ENTRY << offset+2*i << ":" << offset+2*i+1 << std::endl;
    }
    target.draw(vArray, states);
}

Merci Laurent !
Tout marche nickel