Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème d'affichage avec la SDL2

Une texture s'affiche à des endroits où elle ne devrait pas

Sujet résolu
26 février 2022 à 18:04:21

Bonjour,

J'essaie de coder en C une petite librairie perso pour m'aider avec la SDL2. Elle me permettrai de créer des sprites, les déplacer, copier, etc.… facilement. J'ai une fonction nommée ```HobbesMoveSprite``` qui est censée me déplacer un sprite sur la fenêtre. Son fonctionnement est assez simple: elle prend en paramètre un pointeur vers le sprite en question, un int x pour le déplacement en abscisse et un int y pour le déplacement en ordonnée. Elle efface la zone de l'écran où se trouve le sprite, modifie ses coordonnées et le réaffiche. Le problème est que après un déplacement, les endroits où le sprite a été effacé continuent de clignoter avec l'image du sprite à chaque cycle de ma boucle principale. Je vous met mon code en dessous.

main.c:

#include <SDL2/SDL.h>

#include <stdio.h>

#include <stdalign.h>

#include "HobbesSDL.h"

int main(void){

if (SDL_Init(SDL_INIT_VIDEO) != 0){

    fprintf(stderr, "Error while initializing video system: %s\n", SDL_GetError());

    fclose(stderr);

    goto Quit;

}

SDL_Window *MainWindow = SDL_CreateWindow("Main window", 0, 0, 1024, 1024, 0);

if (MainWindow == NULL){

    fprintf(stderr, "Error while creating window: %s\n", SDL_GetError());

    fclose(stderr);

goto Quit;

}

SDL_Renderer *MainRenderer = SDL_CreateRenderer(MainWindow, -1, 0);

if (MainRenderer == NULL){

    fprintf(stderr, "Error while creating renderer: %s\n", SDL_GetError());

    fclose(stderr);

    goto Quit;

}

HobbesSprite *MainSprite = HobbesCreateSprite(MainRenderer, "Hobbes.bmp", 0, 0);

if (MainSprite == NULL){

    fprintf(stderr, "Error while creating sprite!");

    goto Quit;

}

SDL_Event EventStorer;

SDL_bool quit = SDL_FALSE;

int Timer = 0;

    while(!quit)

    {

        SDL_RenderPresent(MainRenderer);

        SDL_PollEvent(&EventStorer);

        HobbesDisplaySprite(MainSprite);

        if (EventStorer.type == SDL_KEYDOWN){

            HobbesMoveSprite(MainSprite, 64, 0);

}

    if(EventStorer.type == SDL_MOUSEBUTTONUP)

        quit = SDL_TRUE;

    SDL_Delay(10);

    Timer += 1;

}

goto Quit;

Quit:

HobbesDestroySprite(MainSprite);

SDL_DestroyRenderer(MainRenderer);

SDL_DestroyWindow(MainWindow);

SDL_Quit();

    return 0;

}



HobbesSDL.c:

#include <SDL2/SDL.h>

typedef struct HobbesSprite{

    SDL_Renderer *renderer;

    SDL_Surface *surface;

    SDL_Texture *texture;

    SDL_Rect *rect;

    _Bool hidden;

} HobbesSprite;

HobbesSprite *HobbesCreateSprite(SDL_Renderer *renderer, const char src[], int x, int y){

    HobbesSprite *structure = malloc(4 * (int)(sizeof (void *))+sizeof (_Bool));

    structure->renderer = renderer;

    structure->surface = SDL_LoadBMP(src);

    if (structure->surface == NULL){

        fprintf(stderr, "Error while loading image on surface\n");

        fclose(stderr);

        return NULL;

    }

    structure->texture = SDL_CreateTextureFromSurface(renderer, structure->surface);

    if (structure->texture == NULL){

        fprintf(stderr, "Error while creating texture from renderer\n");

        fclose(stderr);

        return NULL;

    }

    int rectw, recth;

    if (SDL_QueryTexture(structure->texture, NULL, NULL, &rectw, &recth) != 0){

        fprintf(stderr, "Error while getting texture info\n");

        fclose(stderr);

        return NULL;

    }

    size_t sizeint = sizeof (int);

    structure->rect = malloc(4*sizeint);

    structure->rect->x = x;

    structure->rect->y = y;

    structure->rect->w = rectw;

    structure->rect->h = recth;

    structure->hidden = 0;

    if (SDL_RenderCopy(structure->renderer, structure->texture, NULL, structure->rect) != 0){

        fprintf(stderr, "Error while displaying sprite\n");

        fclose(stderr);

        return NULL;

    }

    return structure;

}

void HobbesDestroySprite(HobbesSprite *sprite){

    free(sprite->rect);

    free(sprite);

}

int HobbesMoveSprite(HobbesSprite *sprite, int x, int y){

    if (/*SDL_RenderFillRect(sprite->renderer, sprite->rect)*/SDL_RenderClear(sprite->renderer) != 0){

        fprintf(stderr, "Error while hiding former image of the sprite\n");

        fclose(stderr);

        return -1;

    }

    sprite->rect->x += x;

    sprite->rect->y += y;

    if (SDL_RenderCopy(sprite->renderer, sprite->texture, NULL, sprite->rect) != 0){

        fprintf(stderr, "Error while displaying sprite at new position\n");

        fclose(stderr);

        return -2;

    }

    return 0;

}

int HobbesDisplaySprite(HobbesSprite *sprite){

    if (sprite->hidden){

        if (SDL_RenderFillRect(sprite->renderer, sprite->rect) != 0){

            fprintf(stderr, "Error while hiding sprite\n");

            fclose(stderr);

            return -1;

        }

    } else {

        if (SDL_RenderCopy(sprite->renderer, sprite->texture, NULL, sprite->rect) != 0){

            fprintf(stderr, "Error while displaying sprite\n");

            fclose(stderr);

            return -2;

        }

    }

    return 0;

}



Quelqu'un a-t-il une idée de ce qui se passe?

-
Edité par UnknownUnknown18 26 février 2022 à 18:10:40

  • Partager sur Facebook
  • Partager sur Twitter
26 février 2022 à 20:04:13

Salut,

La fonction SDL_RenderPresent doit être appelé une seule fois, tout à la fin de ta boucle principale, ici tu l'appelles au début avant de dessiner.

Pour ton problème, il faut simplement faire un SDL_RenderClear en début de boucle.

  • Partager sur Facebook
  • Partager sur Twitter

git is great because Linus did it, mercurial is better because he didn't.

26 février 2022 à 20:12:01

Salut,

Ta solution fonctionne, mais j'aurais aimé ne pas devoir effacer tout le renderer, et seulement la zone où se trouvait le sprite. Est-ce qu'il y a moyen de faire ça?

  • Partager sur Facebook
  • Partager sur Twitter
27 février 2022 à 8:49:33

Non ce n'est pas possible. Et c'est comme ça qu'on fait de toute façon. Les cartes graphiques font les choses bien, ne t'inquiète pas 😉
  • Partager sur Facebook
  • Partager sur Twitter

git is great because Linus did it, mercurial is better because he didn't.

3 mars 2022 à 21:40:06

markand a écrit:

Non ce n'est pas possible. Et c'est comme ça qu'on fait de toute façon. Les cartes graphiques font les choses bien, ne t'inquiète pas 😉


D'accord, j'avais juste peur pour la vitesse du jeu, mais au final ça marche bien (et effectivement personne n'a l'air de faire comme moi ;)).

J'ai aussi eu un commentaire sur StackOverflow qui m'a conseillé de regarder ce site: wiki.libsdl.org/SDL_RenderPresent

"The backbuffer should be considered invalidated after each present; do not assume that previous contents will exist between frames. You are strongly encouraged to call SDL_RenderClear() to initialize the backbuffer before starting each new frame's drawing, even if you plan to overwrite every pixel."


Merci pour ton aide!
  • Partager sur Facebook
  • Partager sur Twitter