Article     Discussion     Modifier     Historique     Forums     Salon IRC

Fondus enchaînés complexes avec SDL

Un article de Games Creators Network.


Cet article est la suite logique du premier article sur les fondus enchaînés.

Un schéma de transition
Un schéma de transition

Cette fois-ci, au lieu de simplement réaliser un fondu linéaire ou toute l'image apparaît en même temps, nous allons privilégier certaines zones afin de créer de nouveaux effets.

Pour cela, il nous faut un nouveau paramètre qui va schématiser l'effet de fondu. Dans cet article, ce paramètre prendra la forme d'une image ressemblant à l'image ci-contre.

[modifier] Principe du fondu

Un fondu réalise une transition animée de l'image A vers l'image B.

Le principe algorithmique est le suivant:

  1. Affichage de l'image B
  2. Modification de la couche alpha de l'image A
  3. Affichage de l'image A


Le point clé réside dans la modification de la couche alpha de l'image A. Au départ, l'image A est totalement opaque (tous les pixels ont leur composante alpha à 255). Le but est de faire converger les composantes alpha vers la valeur 0 (surface totalement transparente).

Contrairement à l'article précédent, nous allons utiliser le schéma de transition afin de faire converger les composantes plus ou moins rapidement vers zéro selon leur position dans l'image.

Ainsi, à chaque tour de boucle, on diminue la couche alpha de chaque pixel proportionnellement à la composante rouge du pixel situé à la même position dans le schéma de transition.

Comparons l'évolution de la composante alpha d'un pixel aillant une composante forte ou faible dans le schéma de transition:

Composante du pixel dans le schéma de transition à 10 Composante du pixel dans le schéma de transition à 200
255 255
250 155
245 55
240 0
235 0
etc. etc.

Cette différence entre les couches alphas des pixels va créer l'effet de mouvement durant le fondu.


NB: Les valeurs données sont théoriques. Les coefficients diffèrent de ceux du programme final.


[modifier] Code source

La fonction FonduEnchaine prend en paramètre:

  • avant un pointeur vers l'image de départ (nommée image A plus haut)
  • après un pointeur vers l'image de d'arrivée (nommée image B)
  • file_transition contient le chemin vers le schéma de transition
  • duree est la durée du fondu en millisecondes
  • vitesse est la vitesse du fondu variant de 1 (rapide) à 255 (lent)

La fonction renvoit 1 si l'utilisateur a tenté de quitter le programme durant la transition, 0 sinon.

Les surfaces passées en paramètre ne sont pas modifiées. La surface avant est, de plus, copiée dans une surface temporaire. Si vous lui affectez un pointeur vers l'écran (SDL_GetVideoSurface()), l'effet rendu sera bien celui voulu (une transition de l'écran tel qu'il est au début de la transition vers la surface apres).


int FonduEnchaine(
  SDL_Surface *avant,
  SDL_Surface *apres,
  char *file_transition,
  unsigned int duree,
  unsigned int vitesse)
{
  SDL_Event event;
  SDL_Surface *copie, *transition;
  unsigned int rmask, gmask, bmask, amask,
               time,
               i;
  Uint32       temp,
               *pt, *pta; /* pointeurs vers les surfaces */
  Uint8        r,g,b,a;
  Uint8        comp;
  Uint8 v;
 
  /* Quelques vérifications pour éviter les principales
     sources de segfault */
  if((!avant)||(!apres)) return 0;
  if(avant->w!=apres->w) return 0;
  if(avant->h!=apres->h) return 0;
 
  /* On copie la surface "avant" afin de pouvoir traviller
     dessus sans crainte */
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
  rmask = 0xff000000;
  gmask = 0x00ff0000;
  bmask = 0x0000ff00;
  amask = 0x000000ff;
#else
  rmask = 0x000000ff;
  gmask = 0x0000ff00;
  bmask = 0x00ff0000;
  amask = 0xff000000;
#endif
  copie = SDL_CreateRGBSurface(SDL_SWSURFACE, 800, 600, 32,
                                   rmask, gmask, bmask, amask);
  SDL_BlitSurface(avant, NULL, copie, NULL);
 
  /* Chargement de la transition */
  transition = SDL_LoadBMP(file_transition);
  transition = SDL_ConvertSurface(transition,copie->format,SDL_SWSURFACE|SDL_SRCALPHA);
  if(!transition)
  {
    SDL_FreeSurface(copie);
    return 0;
  }
 
  /* On fixe la transparence de la surface */
  SDL_SetAlpha(copie, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
 
  /* Début de la boucle */
  time=SDL_GetTicks();
  v=vitesse;
  while((SDL_GetTicks()-time)<duree)
  {
 
    while(SDL_PollEvent(&event))
    {
      switch(event.type)
      {
        case SDL_QUIT:
          SDL_FreeSurface(transition);
          SDL_FreeSurface(copie);
          return 1;
          break;
      }
    }
 
    /* Affiche fond */
    SDL_BlitSurface(apres, NULL, SDL_GetVideoSurface(), NULL);
 
    /* Mise à jour de la couche alpha */
    SDL_LockSurface(copie);
    SDL_LockSurface(transition);
    pt=((Uint32*)copie->pixels);
    pta=((Uint32*)transition->pixels);
 
    for(i=0;i<(copie->w*copie->h);i++)
    {
      SDL_GetRGBA(pt[i],copie->format,&r,&g,&b,&a);
 
      /* je ne récupère qu'une composante... c'est du niveau de gris! */
      temp=pta[i]&transition->format->Rmask;
      temp=temp>>transition->format->Rshift;
      temp=temp<<transition->format->Rloss;
      comp=(Uint8)temp;
 
      if(comp<v) comp=v;
      if(a>(comp/v))
        a-=(comp/v==0)?1:(comp/v);
      else
        a=0;
 
      pt[i]=SDL_MapRGBA(copie->format,r,g,b,a);
    }
    SDL_UnlockSurface(transition);
    SDL_UnlockSurface(copie);
 
    /* On augmente petit à petit la vitesse afin d'éviter
       les fins de transition trop longs */
    if(v>1)
      v--;
 
    /* On affiche la deuxième surface */
    SDL_BlitSurface(copie, NULL, SDL_GetVideoSurface(), NULL);
 
    /* Inversion des tampons */
    SDL_Flip(SDL_GetVideoSurface());
  }
 
  SDL_FreeSurface(transition);
  SDL_FreeSurface(copie);
 
  return 0;
}

Exemple d'appel de cette fonction:

fond1=SDL_LoadBMP("fond1.bmp");
  fond2=SDL_LoadBMP("fond2.bmp");
  FonduEnchaine(fond1, fond2, "transition.bmp", 5000, 50);

Cet appel génère un fondu de 5 secondes à vitesse moyenne entre l'image fond1.bmp et l'image fond2.bmp à l'aide du schéma transition.bmp.


[modifier] Démo

La démo exploite le code ci-dessus afin de générer 6 transitions différentes.


Rendu final

 

Rechercher
Installer l'extension de recherche Plus d'informations

 

Comprendre
Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. - Benjamin Franklin

 

Partager
La connaissance est la seule chose qui s'accroit lorsqu'on la partage. - Sacha Boudjema

 

Créer
L'imagination est plus importante que la connaissance. - Albert Einstein

 

 

Le wiki en images Le wiki en images Image du mois: «Snowball: un prototype de jeu développé avec NeL.