Forum de la communauté SFML

Aide => Général => Discussion démarrée par: MadMaXx le Mai 26, 2013, 02:44:45 pm

Titre: Chemin d'une image et .qrc
Posté par: MadMaXx le Mai 26, 2013, 02:44:45 pm
Bonjour,

Un moyen efficace de lier des images à un .exe sans éviter de toute se les trimballer est d'utiliser un fichier ressource .rc . Dans mon cas j'utilise un fichier ressource à la sauce Qt soit un .qrc (http://qt.developpez.com/doc/4.6/resources/ ).

Concrètement, sa s'utilise comme ça avec la librairie Qt:

QIcon(":/images/img.png")

Le :/ permet de dire directement que l'image est dans le .qrc
Mais ça ne marche pas dans ce cas:

if (!image.loadFromFile(":/images/img.jpg"))
        return EXIT_FAILURE;

Avec les objets SFML ça ne marche pas. Je suppose que ce n'est pas exclusif a SFML, mais au fond j'en sais trop rien (c'est pour ça que je poste ici d'ailleurs). Pourtant ces .qrc sont très pratiques.

Auriez-vous une idée de comment faire pour pouvoir utiliser les .qrc avec SFML ? J'ai déjà cherché sur le web sans succès. Merci de m'aider, sinon tant pis je rangerais mes images de façon "classique" (dossiers à coté du .exe).
Titre: Re : Chemin d'une image et .qrc
Posté par: Laurent le Mai 26, 2013, 05:57:01 pm
SFML ne peut bien sûr pas utiliser le système de ressources spécifique à Qt, il n'y a que Qt qui sait interpréter un chemin du type ":/la_ressource".

Du coup tu as deux solutions :

1. Tu copies ta ressource dans un tableau de char (je ne pense pas que Qt puisse te fournir un pointeur direct sur celle-ci), et tu utilises image.loadFromMemory.

2. Tu crées un sf::InputStream qui sait lire la ressource avec les classes Qt, et tu utilises image.loadFromStream.

Que tu choisisses l'une ou l'autre solution, tu auras besoin de QFile, et peut-être de QDataStream.
Titre: Re : Chemin d'une image et .qrc
Posté par: MadMaXx le Mai 31, 2013, 03:40:07 pm
Alors j'ai tenté quelque chose mais j'ai comme erreur: 'Int64' does not name a type. J'ai vu sur Internet qu'avec cette erreur il fallait inclure  <inttypes.h> et tester uint64_t ou int64_t à la place de Int64, mais ça donne toujours des erreurs. Il y aussi un truc dont je ne suis pas sûr... La méthode de la classe QFile pos() renvoie un qint32 et la méthode seek prend un int32. Est-ce bien compatible ? Voici le code:

main.cpp:

#include <SFML/Graphics.hpp>
#include "stream.h"

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 800), "SFML works!");
    sf::Texture image;
    Stream stream(":/img/uuu.jpg");
    if (!image.loadFromStream(stream))
        return EXIT_FAILURE;
    sf::Sprite sprite;
    sprite.setTexture(image);
    sprite.setPosition(0,0);
    sprite.setScale(0.5,0.5);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(sprite);
        window.display();
    }

    return 0;
}
 

stream.cpp:

#include "stream.h"

Stream::Stream(QString & name)
{
    QFile file(name);
    seek(file.pos());
}

stream.h:

#ifndef STREAM_H
#define STREAM_H

#include <QTemporaryFile>
#include <QFile>
#include <stdint.h>
#include <inttypes.h>

class Stream : public sf::InputStream
{
public:
    Stream(QString & name);
    Int64 read(void* data, Int64 size);
    Int64 seek(Int64 position);
    Int64 tell();
    Int64 getSize();
};

#endif // STREAM_H
 

Titre: Re : Chemin d'une image et .qrc
Posté par: Laurent le Mai 31, 2013, 04:17:23 pm
Int64 est un type SFML, donc sf::Int64. Sinon, commence à implémenter le truc et puis tu verras bien ;)
Titre: Re : Chemin d'une image et .qrc
Posté par: MadMaXx le Mai 31, 2013, 06:20:59 pm
Ah oui c'était pourtant évident !  ::) Bon j'ai mis maintenant l'IDE  me met:

erreur : undefined reference to `vtable for Stream'
erreur : undefined reference to `Stream::seek(long long)'

Un problème d'héritage je crois. J'ai pourtant bien remis les méthodes virtuelles pures de la classe parente non? :S

main.cpp

#include <SFML/Graphics.hpp>
#include "stream.h"

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 800), "SFML works!");
    sf::Texture image;
    Stream stream(":/img/uuu.jpg");
    if (!image.loadFromStream(stream))
        return EXIT_FAILURE;
    sf::Sprite sprite;
    sprite.setTexture(image);
    sprite.setPosition(0,0);
    sprite.setScale(0.5,0.5);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(sprite);
        window.display();
    }

    return 0;
}
 

stream.cpp

#include "stream.h"

Stream::Stream(const char name[])
{
    QFile file(name);
    seek(file.pos());
}

 

stream.h

#ifndef STREAM_H
#define STREAM_H

#include <SFML/System.hpp>
#include <QTemporaryFile>
#include <QFile>

class Stream : public sf::InputStream
{
public:
    Stream(const char name[]);
    sf::Int64 read(void* data, sf::Int64 size);
    sf::Int64 seek(sf::Int64 position);
    sf::Int64 tell();
    sf::Int64 getSize();
};

#endif // STREAM_H

 

Titre: Re : Chemin d'une image et .qrc
Posté par: Laurent le Mai 31, 2013, 07:14:53 pm
Et où sont définies toutes les fonctions que tu déclares dans la classe Stream ?
Titre: Re : Chemin d'une image et .qrc
Posté par: MadMaXx le Mai 31, 2013, 10:33:11 pm
Je mettais les prototypes en pensant que les fonctions étaient déjà définies et que ça "annulerait" le fait qu'elles soient virtuelles enfin bref n'importe quoi puisqu'elles ne sont pas du tout définies en amont...

Je crois que je m'embête pour rien et qu'il y a bien plus simple avec loadFromMemory. Ça devrait tenir juste dans le main:

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

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 800), "SFML works!");
    sf::Texture image;
    QFile file(":/img/uuu.jpg");
    image.loadFromMemory(file.???,file.size());
    sf::Sprite sprite;
    sprite.setTexture(image);
    sprite.setPosition(0,0);
    sprite.setScale(0.5,0.5);
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(sprite);
        window.display();
    }

    return 0;
}

 


On doit toucher au but avec ça le problème est juste dans le image.loadFromMemory(). On a la taille de l'image et reste plus qu'à trouver le pointeur de l'image. J'ai pensé à file.map() d'après la doc http://qt-project.org/doc/qt-4.8/qfile.html qui est la seule fonction qui renvoie un pointeur... Après je sais pas quoi donner au paramètre "qint64 offset" de ce map().
Titre: Re : Chemin d'une image et .qrc
Posté par: Laurent le Mai 31, 2013, 10:51:30 pm
"offset" c'est simplement 0, puisque tu veux commencer au début du fichier.

C'est pas la méthode la plus efficace mais ça devrait marcher.
Titre: Re : Chemin d'une image et .qrc
Posté par: MadMaXx le Juin 01, 2013, 09:27:16 am
Merci, en effet ça marche avec ceci:

image.loadFromMemory(file.map(0,file.size()),file.size());
 

Quand vous dites que la méthode n'est pas la plus efficace, vous voulez dire au niveau du code ou de la vitesse d’exécution ? Vous auriez fait avec InputStream ?
Titre: Re : Chemin d'une image et .qrc
Posté par: Laurent le Juin 01, 2013, 09:36:24 am
Oui, j'aurais fait un sf::InputStream. C'est plus fastidieux à écrire mais une fois que c'est fait c'est beaucoup plus propre et simple à utiliser.

En termes de performances, je ne sais pas trop ce que vaux le mapping de fichier. C'est plus rapide que de charger tout le contenu en mémoire, mais je ne sais pas si ça vaut la lecture directe.