Programmation avec la SDL/La transparence
Nous avons vu dans le chapitre sur le renderer que les couleurs se décomposaient en rouge, vert et bleu et qu'on ajoutait à la combinaison de ces trois couleurs la transparence de la couleur, notée a. Celle-ci est un nombre compris entre 0 et 255 de telle sorte que plus a est proche de 0, plus la couleur est transparente et plus a est près de 255, plus la couleur est opaque.
Mais dans tout ceci, il y a quelque chose d'insidieux et de sous-jacent : les pixels transparents ... ne sont pas transparents : seul le calcul permet qu'ils le soient.
Les modes de fusions
[modifier | modifier le wikicode]En fait, un pixel n'est composé au départ que du rouge, du vert et du bleu. Au total, pour mémoriser une couleur, on utilise donc 3 octets répartis entre les trois couleurs primaires. Mais vous savez qu'un ordinateur n'aime guère les nombres impairs, et qu'il adore les puissances de 2. Pour stocker une couleur, on utilise donc 4 octets. Comme il restait un octet de libre, on a ajouté un canal alpha complètement fictif. En fait, celui-ci va être utilisé au moment où l'on va vouloir afficher le pixel à l'écran. Il indique seulement à quel point nous devons prendre en compte la couleur du pixel qui va être remplacé (la destination) par le pixel qu'on veut afficher (la source). Pour cela, il existe de très nombreuses façons de calculer la couleur du pixel résultant de la superposition de la destination et de la source que l'on appelle des modes de fusion (blend mode en anglais). La SDL n'en compte que trois :
Mode de fusion | Formule | Description |
---|---|---|
SDL_BLENDMODE_NONE | Pas de transparence (ceci n'est pas un mode de fusion). | |
SDL_BLENDMODE_BLEND | Le résultat est une moyenne pondérée du pixel du dessous et du pixel du dessus. Le poids des pixels est déterminé par a. | |
SDL_BLENDMODE_ADD | Mode d'addition : Il rend les couleurs plus vive en additionnant la couleur de la source à celle de la destination. | |
SDL_BLENDMODE_MOD | Mode de multiplication : ici, plus besoin d'attribuer de la transparence à a, elle ne sera pas prise en compte. Il donne une image plutôt sombre. Ce mode peut être utile pour simuler la lumière d'un projecteur, par exemple. | |
Dans ce tableau, res signifie résultat, dst destination et src source. |
Renderer et textures
[modifier | modifier le wikicode]En pratique, on n'utilise que le mode SDL_BLENDMODE_BLEND. Par conséquent, si vous n'avez pas compris ce qui précède, utilisez ce mode sans vous poser de questions. Pour l'appliquer au renderer, il suffit d'utiliser la fonction
int SDL_SetRenderDrawBlendMode(SDL_Renderer* renderer, SDL_BlendMode blendMode)
Pour l'appliquer à une texture, il suffit d'utiliser :
int SDL_SetTextureBlendMode(SDL_Texture* texture, SDL_BlendMode blendMode);
Comme presque toujours dans la SDL, les fonctions pour récupérer le mode de fusion existent aussi. Celle-ci demandent en argument un pointeur de SDL_BlendMode qui sera rempli par le mode de fusion de la texture ou du renderer.
int SDL_GetTextureBlendMode(SDL_Texture* texture, SDL_BlendMode *blendMode);
int SDL_GetRenderDrawBlendMode(SDL_Renderer* renderer, SDL_BlendMode *blendMode);
Vous vous demandez probablement pourquoi il existe une fonction permettant de modifier le mode de fusion du renderer. En réalité, étant donné qu'il n'y a rien "derrière" le renderer, cette transparence ne va s'appliquer au pixels du renderer mais plutôt aux fonctions de dessin associées au renderer, même quand le renderer n'es pas la cible des modifications. En revanche, lorsqu'on applique une transparence aux texture, celle-ci s'exprimera lorsqu'on affichera la texture sur le renderer : on verra en transparent les pixels du renderer derrière la texture. Il est important de comprendre cette différence car le résultat n'est pas le même. Le mieux pour s'en rendre de compte est de la voir sur un exemple.
En supposant que le fond du renderer est noir, affichez une texture dont le fond est bleu et où l'on a tracé un superbe carré rouge totalement transparent. Voici le code correspondant :
SDL_Rect texture_pos = {0, 0, 0, 0};
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 100, 100);
SDL_QueryTexture(texture, NULL, NULL, &texture_pos.w, &texture_pos.h);
SDL_SetRenderDrawBlendMode(renderer ,SDL_BLENDMODE_NONE);
SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);
SDL_SetRenderTarget(renderer, texture);
SDL_RenderFillRect(renderer, &texture_pos);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 0);
SDL_Rect rectangle = {20, 20, 50, 50};
SDL_RenderFillRect(renderer, &rectangle);
SDL_SetRenderTarget(renderer, NULL);
En essayant les différentes possibilités avec SDL_BLENDMODE_BLEND et SDL_BLENDMODE_NONE, vous devriez obtenir :
- Si ni le renderer, ni la texture n'ont leur transparence activée, le carré apparaît rouge. Ceci s'explique par le fait que la transparence n'est pas du tout activée.
- Si la transparence du renderer est activée mais pas celle de la texture, le carré apparaît bleu : en effet, on a dessiné un carré transparent sur un fond bleu.
- Si la transparence de la texture est activée mais pas celle du renderer, le carré apparaît noir : en effet, on a en quelque sorte remplacé le fond bleu par un carré transparent.
- Si la transparence est activée pour les deux, le carré apparaît bleu : on dessine d'abord un carré transparent sur fond bleu, puis on affiche ce fond bleu (qui lui, n'est pas transparent).
Il apparaît donc que la gestion de la transparence n'est pas toujours aisée avec la SDL. Si vous avez eu du mal à suivre, le mieux serait peut-être d'essayer les différentes possibilités pour obtenir le résultat que vous souhaitez.
Les surfaces
[modifier | modifier le wikicode]Des fonctions similaire existent pour les surfaces (il suffit de remplacer texture par surface). Cependant, elles ne sont utiles que pour le fonctions de blit qui ne sont pas traitées dans ce livre étant donné qu'elles sont obsolètes puisqu'elles n'utilisent pas l'accélération matérielle.