IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

SDL Discussion :

Perte de qualité SDL_TTF avec copie dans SDL_Texture [SDL 2.0]


Sujet :

SDL

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 10
    Points : 13
    Points
    13
    Par défaut Perte de qualité SDL_TTF avec copie dans SDL_Texture
    Bonjour,

    J’utilise la SDL pour afficher des images principalement des textures.
    Et aussi SDL_TTF pour afficher du texte.
    Cependant, j’ai remarqué un problème mineur à l’écran.
    En effet, je crée une texture rempli de texte fait à l’aide de TTF.
    Ensuite, je décide de copie cette texture dans une autre.
    Et c’est là que je perçois une perte de qualité à l’écran.
    En recherchant sur le web, je trouve beaucoup de tutoriel pour installer TTF ou dessin un texte, mais rien sur ce genre de détail.
    Je vous ai écrit un code compressé avec suffisamment d’annotation pour que vous compreniez mieux mon problème.
    Avez-vous eu un problème similaire ?
    Ai-je fais une erreur quelque part ?


    Fonctionnenement du programme :
    - Une fenêtre de 800 par 800 est créée.
    - Le texte créer par TTF dans une texture est d’abord affiché.
    - Puis au bout de 2 seconde, il est remplacé par ce même texte qui à été copié dans une texture
    - Après 2 seconde, le programme d’arrête.
    Vous pouvez constatez que le deuxième texte a une moins bonne qualité sur les rebords des lettres.
    Avec une grande taille de lettre le problème est moins visible.
    Vous pouvez changer la taille au début du code en modifiant la constante ‘SIZE_TEXT

    Ps. la police arial.ttf se trouve dans le fichier C:\Windows\Fonts.
    Placer une copie de ce fichier dans votre projet.


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    #include <iostream>
    #include <SDL2/SDL.h>
    #include <SDL2/SDL_image.h>
    #include <SDL2/SDL_ttf.h>
     
    const int SIZE_TEXT = 15;
     
    int main(int argc, char* argv[]){
        // Initialisation SDL
        if(0 != SDL_Init(SDL_INIT_VIDEO)){
            std::cout << "Erreur d'initialisation de la SDL : " <<  SDL_GetError() << "\n";
            return -1;
        }
     
        // Création de Fenetre
        SDL_Window *window = NULL;
        window = SDL_CreateWindow("Test de rendu TTF et TTF dans SDL_Texture", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
                                  800, 800, SDL_WINDOW_SHOWN);
        if(window == NULL){
            std::cout << "Erreur de creation de la fenetre : " <<  SDL_GetError() << "\n";
            return -1;
        }
     
        // Création Renderer
        SDL_Renderer* renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
     
        // Initialisation TTF
        TTF_Init();
     
        // Création d'un text avec TTF
        const char* textTTF = "Text TTF mode Blended";
        TTF_Font* font = TTF_OpenFont("arial.ttf", SIZE_TEXT);
        if(!font){
            std::cout << "Impossible de charger la font.\n";
            return -1;
        }
        SDL_Color color; color.r = 255; color.g = 255; color.b = 255;
        SDL_Surface* textSurf = TTF_RenderText_Blended(font, textTTF, color);
        // Transforme la SDL_Surface en SDL_Texture
        SDL_Texture* textTexture = SDL_CreateTextureFromSurface(renderer, textSurf);
        // Enregistre la taille du texte
        SDL_Rect rectDest; rectDest.w = textSurf->w; rectDest.h = textSurf->h;
     
        // Copie de la texture du text dans une autre texture
        // ==============================================================================
        // Créer une texture vide de la meme taille que le text
        SDL_Texture* textureCopy = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, textSurf->w, textSurf->h);
        // Configure la destination des rendu future dans textureCopy
        SDL_SetRenderTarget(renderer, textureCopy);
        // Active le mode transparence avant la copie
        SDL_SetTextureBlendMode(textureCopy, SDL_BLENDMODE_BLEND);
        // Copie la texture TTF dans la nouvelle texture textureCopy
        SDL_RenderCopy(renderer, textTexture, 0, &rectDest);
        // Configure la destination des rendu future à l'écran
        SDL_SetRenderTarget(renderer, 0);
        // ==============================================================================
     
        // Affiche le premier text
        rectDest.x = 20; rectDest.y = 20;
        SDL_RenderCopy(renderer, textTexture, 0, &rectDest);
        SDL_RenderPresent(renderer);
     
        // Vide l'écran
        SDL_RenderClear(renderer);
     
        // Attend 2 secondes et affiche le texte copié dans une nouvelle texture
        SDL_Delay(2000);
        SDL_RenderCopy(renderer, textureCopy, 0, &rectDest);
        SDL_RenderPresent(renderer);
     
        // Attend 2 secondes et quitte le programme
        SDL_Delay(2000);
     
        // Fermeture du programme
        SDL_DestroyTexture(textureCopy);
        SDL_DestroyTexture(textTexture);
        SDL_FreeSurface(textSurf);
        SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        TTF_Quit();
        SDL_Quit();
        return 0;
    }

  2. #2
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Salut,

    Juste une petite question: pourquoi veux tu copier une SDL_Texture dans une autre cela n'a pas vraiment d'intérêt, et cela risque de saturer la mémoire à une allure incroyable.

    Le principe des textures, c'est qu'on les crée une fois, afin de pouvoir les utiliser souvent

    (non, je n'ai pas lu le code pour voir si c'était justifié ou non )

  3. #3
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 10
    Points : 13
    Points
    13
    Par défaut
    Bonjour,

    Lire le code ne t'expliquera pas pourquoi je fais une tel opération.
    Je l'ai codé pour vous simplifiez la compréhension du problème.
    De plus, le code ci dessus réalise les même opérations et le problème et aussi visible.
    Cependant, pour vous mettre dans le contexte voici quelques explications.
    J’ai créé des class qui me charge et dessin des éléments prêt à l’emploi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class ImageRAM	// Charge une image dans la mémoire vive (SDL_surface), cas ou l'image n'ai pas utiliser dans l'immédiat.
    class Image	// Charge et dessine une simple image (SDL_texture), possède un constructeur pour convertir une ImageRAM.
    class Sprite	// Hérite de Image, avec des fonctionnalités supplémentaires
    class TileSet	// Charge et configure une image servant de tileSet
    class Tile	// Stock des coordonnées d’une tileSet
    class Animate	// Stock des coordonnées d’animation pouvant être lié à Sprite ou Tile
    Function.cpp  	// Contient des fonctions pour manipuler les class
    		// Peut, découper des images, les copier les une dans les autres, ect…
    Extention TEXT:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    class TImg	// Transforme un texte TTF en Texture prêt à l’emploi
    class TTile	// Se sert d’une tileSet pour écrire du texte (utilise TileSet et Tile)
    class TFont	// Crée une Image pour chaque lettre de la font en paramètre
    Extention TEXT EDIT:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class TextEdit		// Créer une zone de saisie de texte (utilise TFont)
    Partant de ces fonctionnalités forte utile et de façon à optimiser le nombre de SDL_texture à afficher.
    J’utilise des fonctions contenu dans le fichier ‘function.cpp’ qui me permettent de manipuler toutes ces class et les copier les une dans les autres.
    Et c’est là que je me suis aperçu de cette perte de qualité.

    Voici précisément ou je l’ai remarqué…
    La class TFont fonctionne comme ceci :

    - Je crée une instance de class TFont (Celle-ci me crée une SDL_texture par caractère)

    - Si je veux par exemple afficher du texte à l’écran, je fais simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tFont.Draw(«Text à écrire », 20, 50) ;
    Cette affichage ne fais pas appel au fonctions TTF qui sont lente, mais a une SDL_Texture déjà créé préalablement pour chaque lettre.
    Ici l'affichage est propre et sans bavure ni détérioration.


    - Ensuite, je passe a la class TextEdit qui elle, permet de saisir du texte.

    - En créant une instance, je lui fournis en paramètre TFont et une zone de saisie, voici le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TextEdit  (GFX::TFont* tFont, int x, int y, int w)
    Vous remarquerez, que je ne fourni pas de hauteur car il s’agit d’une zone de saisie sur une seul ligne, la hauteur maximum des caractères me sert de référence.
    En effet, j’ai commencé par une ligne, je n’ai pas encore codé sur plusieurs lignes.


    - La saisie, les déplacement souris, tous fonctionne bien, mais en y réfléchissant, je me suis dit qu’il y avait un problème a ma méthode.
    En effet, pendant la saisie, il est intéressant et très simple de manipuler ce texte sous forme de lettre indépendante (une image par lettre) car je connais leur largeur.

    - Mais quand je valide ma saisie, le texte afficher dans la zone de saisie peut être très long.
    Et même si je tronque l’affichage à la zone de saisie.
    L’affichage se faisait de la même manière, les caractères sont dessiner un par un (je veux enlever cette boucle).


    Cette étape détériore la qualité ...
    - Je me suis dit, à la fin de ma saisie, je n’ai cas transformer ce texte en une seul image de la taille de ma zone de saisie.
    Donc, je copie les caractères du texte saisie dans une nouvelle texture.
    L’avantage est que je n’ai plus qu’une seul image à afficher au lieu d’une boucle qui affiche les caractères un par un.
    Encore plus évident quand j’ai de multiple zone de saisie à l’écran.


    Pour résumer, quand je saisie, la qualité des caractères est au rendez vous.
    Mais quand je fini ma saisie, les caractères perdent cette qualité sur les bords (y aurait'il un lien avec un lissage on dirait que c'est comme de l'antialiasing ?).
    Peut être un effet secondaire du mode BLENDER je ne sais pas.

    Je ne vois pas ou j’ai fais une erreur.
    Cependant, l’opération reste basique, copier une texture dans une autre.
    Je pense que c’est une pratique qui peut être très utile et qu’il est intéressant connaitre la bonne marche à suivre afin d'éviter les erreurs le cas échéant.

    Au début, je voulais vous épargniez le pavé d’explication en réalisant un code compresser qui reproduit le problème.

  4. #4
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Mais tu n'as pas répondu à ma question, et toutes les explications que tu m'as fournies ne font que confirmer mes premières impressions, à savoir :
    1. Tu n'as pas à copier une texture
    2. on crée une texture une fois (et une seule) pour pouvoir l'utiliser plusieurs fois

  5. #5
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 10
    Points : 13
    Points
    13
    Par défaut
    J'ai voulu me servir de ce que proposait la SDL :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SDL_TEXTUREACCESS_STREAMING
    et
    Pour rendre une texture libre d’être modifier en effectuant une copie de texture dessus.
    D'après ce que tu me dit, cela ne serait pas une bonne méthode.
    Je veux bien quelques explications supplémentaires pour savoir dans quel cas je peux me servir de ces fonctions.

    Si je comprend bien, tu me suggère de me basé sur d'autres type de modification possible tel que :
    et

  6. #6
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 10
    Points : 13
    Points
    13
    Par défaut
    J'ai réussi à résoudre mon problème.
    Pour ceux que cela intéresses, voici une solution.
    En effet, j'utilisais :
    Pour faire un rendu d'une texture dans une autre.
    Pour la plupart des images cela ne pose aucun problème si l'image est rectangulaire (bordure opaque et sans transparence).
    Mais quand l'image en question possèdent des pixels avec un alpha < 255, il faut utiliser le mode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SDL_SetTextureBlendMode(SDL_texture*, SDL_BLENDMODE_BLEND)
    Afin que la transparence soit prise en compte.
    Cette méthode modifie la qualité de la texture rendu dans l'autre, je ne sais pour quel raison.
    Cependant, dans mon cas, je faisais des rendu de lettres dans une texture (les lettres étant déja été créer avec TTF qui effectue un antialiasing sur les bordures pour avoir de 'joli' lettres).
    Le fait de rendre une texture lettre dans une autres modifie la valeur de l'alpha.
    Pour éviter cette perte, je modifie un paramètre pour un rendu fixe sans calcul de transparence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SDL_SetTextureBlendMode(SDL_texture*, SDL_BLENDMODE_NONE)

  7. #7
    Membre à l'essai
    Profil pro
    Inscrit en
    Mars 2013
    Messages
    10
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2013
    Messages : 10
    Points : 13
    Points
    13
    Par défaut
    Bonjour,

    J'aime bien savoir pourquoi un programme ne se déroule pas comme prévu.
    Et je pense avoir trouver ma réponse.
    En effet, une texture copié dans une autre à 4 mode de rendu possible.
    SDL_BLENDMODE_NONE, SDL_BLENDMODE_BLEND, SDL_BLENDMODE_ADD, SDL_BLENDMODE_MOD
    Moi j'utilise beaucoup le mode SDL_BLENDMODE_BLEND car c'est celui qui permet de ne pas copier les pixels transparents afin de laisser apparaitre ceux de la texture de destination
    Pratique pour faire un masque ou autre.
    Cependant, j'ai regardé son fonctionnement de plus prêt et voici le calcul des pixels du mode SDL_BLENDMODE_BLEND :

    Pour calculer la nouvelle couleur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
    Pour calculer la nouvelle transparence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    dstA = srcA + (dstA * (1-srcA))
    Pour rappel, ma texture de destination à des pixels complétement transparent (donc 0 d'opacité).
    L'opacité d'un pixel va de 0 jusqu'à 1 maximum

    Prenons exemple avec la formule qui calcul la transparence :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dstA = srcA + (dstA * (1-srcA))
    0,5 = 0,5 + (0 * (1 - 0,5))
    Ma texture source (celle qui se copie) à un pixel opaque à 50% (d’où le 0,5).
    La texture de destination à un pixel d'opacité à 0%
    Le résultat obtenu n'a aucune surprise puisque que la copie donne un pixel avec 50% d'opacité.

    Faisons la meme chose avec la formule qui calcul la nouvelle couleur :
    La couleur RGB est une valeur qui regroupe les trois couleurs rouge, vert et bleu, mais cela n'a aucune importance dans le calcul je prendrais une valeur quelconque, car le résultat sera le meme avec une autre valeur :
    Je decide donc de donner une valeur quelconque à RGB qui sera 1500.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
    750 = (1500 * 0,5) + (0 * (1 - 0,5))
    Et là, surprise, je n'ai plus la meme valeur de couleur mais la moitié de la valeur d'origine.
    Etant donner que les pixels de ma texture de destination sont tous a 0, 0, 0 (R, G, B) cela me semble logique maintenant.

    Conclusion, l'aspect de perte de qualité s'explique par une couleur qui a changé pendant la copie tandis que l'opacité ne change pas.
    J'espère que ces explications pourrons aider à mieux comprendre cette fonctionnalité.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [WD-2013] Perte de qualité d'images .png dans word 2013
    Par bendesarts dans le forum Word
    Réponses: 8
    Dernier message: 23/03/2014, 00h10
  2. Réponses: 4
    Dernier message: 27/09/2012, 18h22
  3. [AC-2010] Filtre sur formulaire avec copie dans une autre table
    Par alainnolahc dans le forum VBA Access
    Réponses: 1
    Dernier message: 09/10/2010, 20h26
  4. lire un fichier copié dans un dossier avec le meme code
    Par vieri31 dans le forum C++Builder
    Réponses: 22
    Dernier message: 27/05/2008, 04h23
  5. [GD] Perte de qualité avec ImageCreateFromJPEG
    Par julien.63 dans le forum Bibliothèques et frameworks
    Réponses: 2
    Dernier message: 17/10/2006, 19h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo