Partage
  • Partager sur Facebook
  • Partager sur Twitter

[SDL2][C] Surface et tableau de pixels

Construire une surface et une texture à partir d'un tableau de pixels.

    12 novembre 2022 à 16:08:26

    Bonjour !

    Je me remets au code et récemment, je me suis lancé dans le projet d'un petit jeu en SDL2 et avec des threads et les problèmes sont venus lors de l'optimisation de certains temps de calculs.

    En effet, lors de la création de la Map, j'ai choisi la direction d'une image composée de pixels colorés dont la couleur permetrait de connaitre la tile de l'objet à placer aux coordonnées du pixel coloré et ça pour tous les pixel de cette image dite "Matrice".

    Cela devient très vite énormément gourmand car une image peut vite monter à 1M de pixels et pour une map facilement à 5M ou 10M si on est fou.

    Donc pour ce faire, j'ai pris le parti d'initaliser la map selon le principe suivant :

    1) On prend l'image Matrice.

    2) On la lit pixel par pixel

    3) Pour le pixel dont le rouge et de 254, On connait sa surface d'Id (ici un simple carré vert).

    4) On lit la surface qui correspond à cette couleur.

    5) On copie les pixels de cette surface dans une surface aux dimensions de la Matrice pixel par pixel.

    6) On a créé notre surface de Map après un certain temps de calcul qui ne m'importe pas encore.

     Voici mes fonctions dédiées dans leur ordre d'appel (qui est inverse à celui de leur ordre de déclaration) :

    void Init_Map()
    {
        /**Cette fonction a pour rôle d'initialiser l'image COMPLETE de la map à partir de sa matrice.
        Pour ce faire on envoie la Matrice dans creerSurface() la Matrice de la Map.**/
    
        SDL_Surface *surface = SDL_LoadBMP("images\\Matrice.bmp"); //On déclare la surface de base, composée de la MatriceMap;
        Map.TextrMap = SDL_CreateTextureFromSurface(Window.pRenderer, creerSurface(surface)); //On créé la texture de la Map en à partir du render et de la surface qu'on a créé.
    
        printf("Etape 4\n");//Balise pour se repérer dans le débug.
    
        SDL_FreeSurface(surface);   //On libère surface.
    
        printf("Etape 5 : FIN INIT MAP\n");//Balise pour se repérer dans le débug.
    }
    SDL_Surface *creerSurface(SDL_Surface *MatriceMap)
    {
        /**Cette fonction prend une surface d'image pour en lire les pixels.
        Selon la couleur des pixel de MatriceMap, elle va charger une nouvelle surface qui a pour coordonnées la position du pixel.
        Cette nouvelle surface sera ensuite chargée pixel par pixel dans une surface de retour**/
    
    
        SDL_Surface *surfTampon = NULL; //On déclare une surface tampon dont les pixels seront copiés dans la surface retour.
        SDL_Surface *retour = NULL; //On déclare la surface retour.
        int i, j, w = MatriceMap->w, h = MatriceMap->h;//On déclare les variables qui parcourront la largeur et la hauteur de la surface MatriceMap.
        int x, y;   //On déclare les variables qui parcourront la largeur et la hauteur de surfTampon.
        Uint32 *pixels = NULL;  //On créé un tableau de pixels.
        SDL_Color color;    //Servira à prendre les couleurs des pixels de MatriceMap.
        SDL_Color colorTampon; //Servira à prendre les couleurs des pixels de surfTampon et à les copier dans le tableau de pixel à i+x et j+y.
        Uint32 dataA;   //Données du pixel à la position i, j de la surface MatriceMap.
        Uint32 dataB;   //Données du pixel à la position x de surfTampon.
    
    
        if(SDL_LockSurface(MatriceMap) < 0) //On Lock la surface que l'on va lire.
        {
            fprintf(stderr, "Erreur SDL_LockSurface : %s", SDL_GetError());
            goto lock_surface_fail;
        }
    
        pixels = malloc(w*h);
    
        if(pixels == NULL)
        {
            perror("Erreur malloc : ");
            goto alloc_memory_fail;
        }
    
        printf("Etape 1\n");//Balise pour se repérer dans le débug.
    
        for(i = 0; i < w; i++)
        {
            for(j = 0; j < h; j++)
            {
                dataA = getpixel(MatriceMap, i, j); //On prend la donnée du pixel en i, j dans dataA.
                SDL_GetRGB(dataA, MatriceMap->format, &color.r, &color.g, &color.b);    //On prend la couleur du pixel selon dataA.
                if(color.r == 254)  //Si le pixel dans MatriceMap a un rouge 254, alors surfTampon = carré vert.
                {
                    surfTampon = SDL_LoadBMP("images\\vert.bmp");
                }
                else    //Sinon, pas de surface.
                {
                    surfTampon = NULL;
                }
    
                if(surfTampon != NULL)  //S'il y a une surface, alors la lire selon x et y sur les dimmensions de la surface.
                {
                    for(x = 0; x < surfTampon->w; x++)
                    {
                        for(y = 0; y < surfTampon->h; y++)
                        {
                            dataB = getpixel(surfTampon, x, y); //On prend la donnée du pixel en x, y dans dataB.
                            SDL_GetRGB(dataB, surfTampon->format, &colorTampon.r, &colorTampon.g, &colorTampon.b);  //On prend la couleur du pixel selon dataB.
                           if((i+x) + (j+y)*w <= w*h)//On vérifie qu'on ne dépasse pas les valeurs du tableau.
                           {
                              pixels[(i+x) + (j+y)*w] = SDL_MapRGB(MatriceMap->format, colorTampon.r, colorTampon.g, colorTampon.b);  //On donne les couleurs de dataB dans notre tableau de pixels au pixel de coordonnées i+x et j+y.
                           }
                        }
                    }
                }
    
            }
        }
    
        printf("Etape 2\n");//Balise pour se repérer dans le débug.
    
                /* On modifie chaque pixel */
    
        retour = SDL_CreateRGBSurfaceWithFormatFrom(pixels, MatriceMap->w, MatriceMap->h, 32, MatriceMap->pitch, MatriceMap->format->format);    //On définit alors la surface compléte de retour.
    
        if(retour == NULL)  //On vérifie les erreurs.
        {
            fprintf(stderr, "Erreur SDL_CreateRGBSurface : %s", SDL_GetError());
            goto creatergbsurfacefrom_fail;
        }
    
        printf("Etape 3\n");//Balise pour se repérer dans le débug.
    
        creatergbsurfacefrom_fail:
        free(pixels);   //On laisse se reposer en paix le tebleau de pixels.
        alloc_memory_fail:
        SDL_UnlockSurface(MatriceMap);  //On unlock la surface MatriceMap.
        lock_surface_fail: 
        SDL_FreeSurface(surfTampon)
        return retour;  //On retourne notre nouvelle surface.
    }



    Le problème est le suivant : le programme crash à l'étape 3..

    Je pense que cela est dû à la dimension de mon tableau de pixels mais je ne vois pas réellement comment le corriger d'autant qu'il s'agit d'un code tiré d'un tutoriel sur zestedesavoir.com à propos de la manipulation pixel par pixel de surface.

    La deuxième piste que j'envisage, serait un soucis au moment où je copie les couleurs de dataB dans le tableau de pixels.


    Pour le moment je n'arrive absolument pas à aller plus loin... Auriez vous une piste pour m'aider à faire fonctionner mon petit code ?

    Merci beaucoup pour votre attention et votre aide !

    A bientôt !

    -
    Edité par Emilien 1er 13 novembre 2022 à 19:15:33

    • Partager sur Facebook
    • Partager sur Twitter
      12 novembre 2022 à 18:04:36

      Hello,

      Deux choses que je vois en lisant rapidement creerSurface()

      • ligne 39: tu emploies x et y, qui n'ont pas été initialisés
      • si cilor..r vaut 254 tu cées surfTampon, que tu ne libères jamais
      • 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

        13 novembre 2022 à 13:24:44

        Hello !

        Merci de ta réponse

        edgarjacobs a écrit:

        • ligne 39: tu emploies x et y, qui n'ont pas été initialisés
        • si cilor..r vaut 254 tu cées surfTampon, que tu ne libères jamais
        Effectivement pour le premier point il s'agit même complétement d'une erreur de ma part car pour la ligne 39 je ne voulais pas utiliser x et y mais respectivement i et j à la place.
        J'ai également libéré surfTampon comme tu le disais à la fin de creerSurface().
        Pour l'heure rien ne marche mais il y a du nouveau merci beaucoup !
        Je me suis permis de modifier quelques petites choses en plus de tes corrections, par exemple
        désormais :
        pixels = malloc(w * h);
        Et j'ai ajouté la condition suivante dans ma boucle de x et y vers la ligne 55:
        if((i+x) + (j+y)*w <= w*h)//On vérifie qu'on ne dépasse pas les valeurs du tableau.
        {
          pixels[(i+x) + (j+y)*w] = SDL_MapRGB(MatriceMap->format, colorTampon.r, colorTampon.g, colorTampon.b);  //On donne les couleurs de dataB dans notre tableau de pixels au pixel de coordonnées i+x et j+y.
        }


        Cependant maintenant l'erreur semble venir lors de cette dite boucle x et y.

        J'ai réjouté un témoin en affichant dans la console où en est mon processus.. il s'arrete systématiquement lorsque x = 0, y = 82 et i = 0, j  = 0 en retournant la fameuse erreur : -1073741819 (0xC0000005)

        Je m'avoue un peu vaincu mais n'en démord pas pour comprendre :lol:

        Une idée sur la situation ?

        Mon manque de pratique avec les tableaux de pixels joue probablement énormément.

        Remarque : Si je définis manuellement la dimension de pixels, par exemple pixels[1000*1000], alors j'arrive au bout des boucles et i, j et x, y. Puis le programme retourne la même erreur mais cette fois-ci par rapport au moment où je créé ma texture(vers entre Etape 3 et 4).
        Aussi je me demande si ce n'est pas parce que pour certains pixels il n'y aurait pas de données écrite dans le tableau et donc la création de la surface serait buguée, résultant d'une erreur lors de création de la texture.. (je vais essayer de tester ça) 


        PS : Ma surface Matrice est actuellement de 300x300px avec un unique pixel en (0,0) ayant r =  254. Et surfTampon qui prend l'image vert.bmp est de 200x200px. 

        PS : Le code que j'ai montré a été changé sur ces points pour éviter qu'on se perde

        -
        Edité par Emilien 1er 13 novembre 2022 à 19:05:33

        • Partager sur Facebook
        • Partager sur Twitter
          13 novembre 2022 à 20:12:28

          Emilien 1er a écrit:

          PS : Le code que j'ai montré a été changé sur ces points pour éviter qu'on se perde

          Ne jamais faire ça ! C'est justement là qu'un autre lecteur va perdre le fil de l'histoire. Il faut toujours poster le code modifié !

          -
          Edité par edgarjacobs 13 novembre 2022 à 20:13:16

          • 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

            14 novembre 2022 à 9:42:28

            Désolééé !!

            Ça me servira de leçon 

            • Partager sur Facebook
            • Partager sur Twitter

            [SDL2][C] Surface et tableau de pixels

            × 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