Partage
  • Partager sur Facebook
  • Partager sur Twitter

SDL_CreateTextureFromSurface plante

    19 novembre 2017 à 17:25:11

    Salut tout le monde,

    j'ai rencontré un problème assez particulier :

    Je charge des images avec stb_image, puis je transmets sur SDL avec des fonctions comme SDL_CreateRGBSurfaceWithFormatFrom et SDL_CreateTextureFromSurface, mais cette dernière fonction plante et ferme le programme, mais seulement au deuxième passage, parce-que je charge des images en boucle.

    Voici le code :

        int textureChannels = 0;
        int width, height;
        stbi_uc* pixels = stbi_load((static_cast<const std::string>(directory) + static_cast<const std::string>(object.filename)).c_str(), &width, &height, &textureChannels, textureChannels);
        if (!pixels)
        {
            const std::string error = "Error by loading an image : ";
            const std::string description = stbi_failure_reason();
    
            stbi_image_free(pixels);
    
            SDL_SetError((error + description).data());
            return -1;
        }
        SDL_Surface* surface = NULL;
        surface = SDL_CreateRGBSurfaceWithFormatFrom(reinterpret_cast<void*>(pixels), width, height,
                                                     textureChannels * 8, textureChannels * width, (textureChannels == STBI_rgb) ? SDL_PIXELFORMAT_RGB24 : SDL_PIXELFORMAT_RGBA32);
        stbi_image_free(pixels);
        if (surface == NULL)
        {
            const std::string error = "Error by creating a surface with a specific format : ";
            const std::string description = SDL_GetError();
    
            SDL_FreeSurface(surface);
    
            SDL_SetError((error + description).data());
            return -1;
        }
        if (transparentColor != NULL)
        {
            SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGB(surface->format, transparentColor->r, transparentColor->g, transparentColor->b));
        }
        SDL_SetSurfaceRLE(surface, SDL_TRUE);
        object.texture = NULL;
        object.texture = SDL_CreateTextureFromSurface(renderer, surface);
        SDL_FreeSurface(surface);
        if (object.texture == NULL)
        {
            const std::string error = "Error by creating a texture from surface : ";
            const std::string description = SDL_GetError();
    
            SDL_DestroyTexture(object.texture);
    
            SDL_SetError((error + description).data());
            return -1;
        }

    Oui j'utilise quelques trucs c++...

    La surface passée en argument a l'air valide.

    Merci davance pour vos réponses.

    Thomas

    -
    Edité par ThomasMoerschell 20 novembre 2017 à 17:19:44

    • Partager sur Facebook
    • Partager sur Twitter
      20 novembre 2017 à 7:20:59

      Salut,

      Ligne 33 et 34... Il faudrait peut-être attribuer la valeur de SDL_CreateTextureFromSurface(renderer, surface) à object.texture si tu veux que ce dernier ne soit pas NULL.

      object.texture = SDL_CreateTextureFromSurface(renderer, surface);

      Bon courage.

      • Partager sur Facebook
      • Partager sur Twitter

      Bonhomme !! | Jeu de plateforme : Prototype.

        20 novembre 2017 à 10:04:11

        Sinon, ton code est écrit en C++, si tu veux correctement utiliser une bibliothèque C comme SDL en C++, il faut l'encapsuler pour que les ressources soient gérées automatiquement (RAII, …).

        -
        Edité par Mad scientist 20 novembre 2017 à 12:17:56

        • Partager sur Facebook
        • Partager sur Twitter
        Un vrai cours de: (C | C++ | Haskell débutant | Haskell intermédiaire | Rust).
          20 novembre 2017 à 14:33:20

          Merci drx, j'ai fait une erreur de copie, c'est corrigé.

          Mad scientist, que veux tu dire par encapsuler la bibliothèque ? Que je transforme la structure Object en classe ? 

          -
          Edité par ThomasMoerschell 20 novembre 2017 à 17:20:52

          • Partager sur Facebook
          • Partager sur Twitter
            22 novembre 2017 à 14:45:02

            J'ai peut-être trouvé une partie de réponse : le problème survient seulement quand les images n'ont que 3 canaux (SDL_PIXELFORMAT_RGB24).

            Mon hypothèse est donc : les SDL_Texture ne supportent que le format rgba.

            Est-ce qu'on est donc obligé de recopier entièrement l'image en y ajoutant l'élément alpha ou y a-t-il une autre manière ?

            • Partager sur Facebook
            • Partager sur Twitter
              22 novembre 2017 à 18:23:00

              Hello,

              ThomasMoerschell a écrit:

              Est-ce qu'on est donc obligé de recopier entièrement l'image en y ajoutant l'élément alpha ou y a-t-il une autre manière ?

              sdl 1.x a une fonction ConvertSurface(). Elle existe peut-être encore en sdl 2.x....

              • Partager sur Facebook
              • Partager sur Twitter

              On écrit "j'ai tort", pas "tord" qui est le verbe "tordre" à la 3ème personne de l'indicatif présent

                22 novembre 2017 à 19:13:47

                Salut,

                Faisons les choses dans l'ordre s'il te plaît parce que je suis un peu perdu...

                En 1, est-ce que ta surface ressemble à quelque chose ?

                Ensuite pourquoi perdre du temps à travailler sur une surface si au final tu veux une texture ? Pourquoi ne pas directement créer une texture ?

                Et est-il vraiment nécessaire de charger tes images en boucle ? C'est généralement considéré comme un défaut de conception... Surtout que je ne vois pas de libération avant l'allocation de la texture...

                Ta fonction stbi_load fait quoi exactement ? Je trouve bizarre qu'elle prenne en argument et un pointeur sur int et la valeur du même int. Pourquoi pas, mais ça m'interpelle.

                Bonne continuation.

                • Partager sur Facebook
                • Partager sur Twitter

                Bonhomme !! | Jeu de plateforme : Prototype.

                  23 novembre 2017 à 13:46:14

                  Alors, personnellement, j'ai l'impression qu'elle n'a pas de problème (la bonne hauteur, largeur, le bon format...).

                  Ensuite, il est vrai qu'on pourrait contourner la surface comme ceci :

                  object.texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, width, height);
                      SDL_UpdateTexture(object.texture, NULL, pixels, width / textureChannels);

                  mais le résultat laisse à désirer :

                  Dites moi si il y a quelquechose de faux dans le code

                  Ensuite, mon programme charge ces images à partir de directives qui lui sont données à partir d'un fichier externe, et là, je ne vois pas trop comment me passer de la boucle.

                  Puis stbi_load prend en paramètre un int dans lequel est stocké le nombre de canaux désiré ou 0. et enregistre le nombre de canaux optimaux dans le pointeur qui lui est donné.

                  • Partager sur Facebook
                  • Partager sur Twitter
                    23 novembre 2017 à 19:56:44

                    Salut,

                    Cela ressemble à un défaut de pitch, mais c'est trop répétitif pour que ce soit uniquement ça. Sais tu nous montrer quelle résultat tu devrais obtenir ? Quelle type d'image ? png, jpg... ?

                    Comment as-tu défini la valeur de format (arg 2 de SDL_CreateTexture) ? Si ta texture change assez souvent, il serait préférable de la passer en SDL_TEXTUREACCESS_STREAMING, mais je te laisse voir ça... Aussi, il peut être prudent de passer ta texture au blend :

                    SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);

                    Quand j'ai décodé les animations GIF et que je bloquais sur ce genre de problème, je prenais une toute petite image (5*5 par exemple) puis je faisais un dump des pixels (chaque valeur rgba) dans un fichier pour voir si le résultat était cohérent à chaque étape. L'avantage d'une petite image est que ça reste interprétable.

                    Je ne connais pas trop cette lib STB_image, mais elle ne semble pas gérer les images avec une profondeur supérieure à 32bits (8bits/couleur) :
                    // DOCUMENTATION
                    //
                    // Limitations:
                    //    - no 16-bit-per-channel PNG
                    //    - no 12-bit-per-channel JPEG
                    //    - no JPEGs with arithmetic coding
                    //    - no 1-bit BMP
                    //    - GIF always returns *comp=4

                    Du coup, tu devrais choisir une image avec un format que tu vas pouvoir maîtriser (fais toi même un petit png32 ou plus simple, un bmp24) et fige ton code pour ce format en particulier dans un premier temps (textureChannels = 4 pour SBI_Load(), SDL_PIXELFORMAT_RGBA8888 pour la texture en figeant les dimensions à la création (valeurs données pour le png32)).

                    Au pire, utilise une image 4*4 avec une colonne de chaque couleur pure, ce sera plus facile à interpréter dans un fichier texte.

                    Quand tu poses ta texture sur le renderer, fais le en NULL, NULL pour étendre la texture sur l'affichage et y voir quelque chose...

                    Au delà de ça, au moins pour le côté SDL2 que je maîtrise plus, ton code semble correct... Attention si tu passes en SDL_TEXTUREACCESS_STREAMING, il faut lock/unlock la texture pour l'accès aux pixels...

                    Tiens nous au courant, ton souci m’intéresse ^^.

                    Bonne continuation.

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Bonhomme !! | Jeu de plateforme : Prototype.

                      26 novembre 2017 à 15:22:07

                      L'image devrait ressembler à cela.

                      Les PNGs que j'ai analysés semblent incontestablement corrects.

                      J'ai trouvé SDL_PIXELFORMAT_RGBA32 et SDL_PIXELFORMAT_RGB24 un peu par expérimentation, mais fonctionnait parfaitement jusqu'à maintenant.

                      Avec SDL_BLENDMODE_BLEND, la plupart tu blanc devient transparent.

                      Et le contenu de cette SDL_Texture n'est sensé être changé qu'à sa création    => SDL_TEXTUREACCESS_STATIC.

                      Je ne trouve vraiment pas

                      -
                      Edité par ThomasMoerschell 28 novembre 2017 à 19:56:09

                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 novembre 2017 à 20:00:32

                        Mais à force de modifier et de remodifier le code, j'ai dû corriger une erreur presque invisible sans le savoir. Du coup, si je passe par une SDL_Surface, les images s'affichent correctement. J'ai encore quelques problèmes de trigo et de conteneurs c++, mais c'est une autre histoire.

                        N'empêche que si quelqu'un a une idée pour ne pas devoir passer par une SDL_Surface, je suis preneur. Je vous dis si je trouve du nouveau.

                        Merci à tous.

                        • Partager sur Facebook
                        • Partager sur Twitter

                        SDL_CreateTextureFromSurface plante

                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                        • Editeur
                        • Markdown