Je cherche à afficher du texte 2D devant une scène 3D générée avec openGL.
Etant donné que je connais bien la SDL_ttf (j'y ai même élaboré tout un système de classes en C++), je tiens vraiment à l'utiliser plutôt que la gestion du texte intégrée dans openGL.
Après de très longues recherches et tentatives, mon texte ne s'affiche toujours pas : à la place, j'ai le rectangle blanc ci-dessous :
Voici mon code brièvement commenté :
//J'ai créé une classe CTexture afin de gérer la génération/suppression des textures automatiquement ; ici le constructeur à partir d'une instance de la classe CText ; je pense que les noms parlent d'eux-mêmes
CTexture::CTexture(CText text)
{
unsignedint
w = (int)floor(pow(2, ceil(log(text.getWidth()) / log(2)))),
h = (int)floor(pow(2, ceil(log(text.getHeight()) / log(2))));
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32
RMask = 0xff000000,
GMask = 0x00ff0000,
BMask = 0x0000ff00,
AMask = 0x000000ff;
#else
Uint32
RMask = 0x000000ff,
GMask = 0x0000ff00,
BMask = 0x00ff0000,
AMask = 0xff000000;
#endif
SDL_Surface *temp = SDL_CreateRGBSurface
(
SDL_HWSURFACE,
w,
h,
32,
RMask,
GMask,
BMask,
AMask
);
if(!temp)
{
SDL_FreeSurface(temp);
cerr << "Fatal error : unable to create texture from SDL surface : " << SDL_GetError() << endl;
bool error;
throw error;
}
SDL_Rect position;
position.x = 0; position.y = 0;
{
CSurface temp2(temp);//La classe CSurface correspond à une SDL_Surface*
text.blit(&position, &temp2);//CText hérite de CSurface, la méthode blit() correspond à SDL_BlitSurface()
}
SDL_PixelFormat format = text.getFormat();
format.BitsPerPixel = 32;
format.BytesPerPixel = 4;
format.Rmask = RMask;
format.Gmask = GMask;
format.Bmask = BMask;
format.Amask = AMask;
text.convert(&format, SDL_SWSURFACE);//correspond à SDL_ConvertSurface()
text.flip();//Je vous ai posté le code de cette méthode plus bas
glGenTextures(1, &texture);//texture est un attribut GLuint de CTexture
Je ne vous poste pas le code de chargement du texte par SDL_ttf qui utilise d'autres classes que j'ai créées, je pense que le problème n'y est pas et que vous avez suffisamment de code comme ça .
Il ne me reste plus qu'à vous demander : où est mon erreur ?
Merci d'avance !
hum.
ça peut venir de ta texture Hello qui est mal chargée.
Essaie, juste pour voir, de texturer tes cubes derriere avec la texture Hello, pour voir.
Ou alors l'inverse, essaie de mettre tes textures de cubes sur ton Quad porteur (le blanc) pour voir.
(dans les 2 cas, il suffit de binder l'autre texture)
Tu seras ainsi fixé sur le fait de savoir si ça vient de la texture qui est mal chargée ou pas.
Dis moi ce que donnent ces tests, on verra en conséquence
ok, donc ça confirmerait que ça vient de ta surface qui est mal chargée.
Examine ta fonction de chargement de texture :
- vérifie que ton nom de fichier appelé est correct
- vérifie que ta fonction de SDL_ttf qui te genere la font ne renvoie pas NULL
- vérifie tes parametres pour glTexImage2D.
Au besoin, décactive ton traitement ".flip", qui retourne l'image, pour voir.
J'ai déjà implémenté et validé 2 classes CFont et CText, en cas de nom de fichier incorrect ou tout autre problème j'aurais eu un message d'erreur, ce qui n'est pas le cas. Je te poste le chargement de texte, a priori mes noms de méthodes sont assez explicites pour que tu devines leur role, je vais néanmoins commenter brièvement :
//Setting text
CFont font("georgia.ttf", 30);//se contente d'appeler TTF_OpenFont() et d'en vérifier le retour
SDL_Color color;
color.r = 255; color.g = 255; color.b = 255;
CText text("Hellolololol", &font, color, BLENDED);//appelle TTF_RenderText_Blended() ; CText hérite de CSurface qui contient un attribut SDL_Surface*
SDL_Rect position;
position.x = 100; position.y = 100;
unsignedint
w = (int)floor(pow(2, ceil(log(text.getWidth()) / log(2)))),
h = (int)floor(pow(2, ceil(log(text.getHeight()) / log(2))));
//Creating textures
CTexture
cube("cube.bmp"),
hello(text);//constructeur à partir d'un CText que j'ai posté plus haut
Quant aux paramètres pour glTexImage2D(), je ne suis pas très familier avec les différents flags possibles, il n'est pas impossible qu'il y ait une erreur, que me conseilles-tu de rentrer comme paramètres ?
Concernant mon traitement ".flip", le désactiver ne provoque pas d'erreur mais me laisse sur mon rectangle blanc.
Alors c'est peut etre une erreur au niveau de glTexImage2D(). Je n'utilise quasiement plus cette fonction : j'utilise du mipmapping.
Je te propose la fonction que j'utilise personnellement pour convertir une texture SDL en Texture OpenGL.
Avec TexOGL = unsigned int.
min et max sont les filtres que tu veux appliquer :
avec comme bon compromis :
int mag=GL_LINEAR,int min=GL_LINEAR_MIPMAP_NEAREST
Merci, cela fonctionne, même si ce n'est pas joli joli !
Existe-t-il un moyen d'améliorer le rendu et d'enlever le fond noir ?
Je me demande si je ne vais pas finalement me tourner vers l'affichage de texte via openGL directement, je ne suis même pas certain de pouvoir continuer à utiliser SDL_ttf pour du texte 3D...
OpenGL ne sait pas gérer des textes en natif, glut sait le faire, mais c'est bien plus laid
Pour enlever le fond :
j'utilise l'alpha-test : c'est a dire que je demande au PC de ne pas afficher le pixel si son canal alpha est plus grand que 128 (par exemple)
Pour activer ça :
glEnable(GL_ALPHA_TEST);
glAlphaFunc(GL_LESS ,128);
Et tu vas me dire : oui, mais je définis ou les pixels qui seront a alpha>128 ?
Quand tu as encore ta texture SDL : donc avant de la monter en mémoire avec OpenGL, appelle cette fonction (qui fait un peu comme ta méthode flip, finalement : tu traitement au niveau des pixels)
Je te laisse adapter les fonctions par contre
void SetTransColor(SDL_Surface* tmp,uchar r,uchar v,uchar b)
{
int i,j;
ulong key = Color(r,v,b,0); // construit le ulong a partir de r,v,b
ulong aliaseBorder = Color(0,0,0,255); // pixel qui remplacera
ulong pix;
Lock(tmp); // SDL_LockSurface
for(j=0;j<tmp->h;j++)
for(i=0;i<tmp->w;i++)
{
if(GetPixel(tmp,i,j)==key)
{
PutPixel(tmp,i,j,aliaseBorder);
}
if(i==0 || j==0 || j==tmp->h-1 || j==tmp->w-1)
{
pix = GetPixel(tmp,i,j);
PA(pix)=255; // composante Alpha de pix modifiée
PutPixel(tmp,i,j,pix);
}
else
PA(pix)=0;
}
Unlock(tmp); // UNLockSurface
}
Pour un exemple de cela fini, regarde mon programme Klostro-Laby, que tu trouveras dans ma signature : il utitise cette méthode de rendu de texte.
Alors là cela devient compliqué, la scène 3D n'apparaît plus :
En m'appropriant un peu ta fonction, voici ce que j'obtiens :
void CSurface::setTransColor(Uint8 r,Uint8 v,Uint8 b)
{
unsignedint
i = 0,
j = 0;
Uint32
oldPixel = SDL_MapRGBA(surface->format, r, v, b, 0),//Si j'ai bien compris, tes "Color" correspondent à SDL_MapRGBA() qui renvoit un Uint32 et demande des Uint8
if(getPixel(surface, i, j) == oldPixel)//J'ai trouvé les fonctions getPixel() et putPixel sur la documentation officielle de la SDL
{
putPixel(surface, i, j, newPixel);
}
//Je n'ai pas saisi l'utilité du code qui suit, je suppose que PA signifie PutAlpha, mais à quoi sert donc la variable pix ? Elle n'est jamais utilisée dans le reste du code de la fonction...
Il faut noter qu'avec ou sans appel à cette fonction, le résultat est le même... J'ai dû faire plusieurs erreurs
Je n'ai pas pu lancer ton jeu car je suis sous linux, mais d'après la capture d'écran la police semble lissée et jolie, pourquoi est-ce que j'obtiens quelque chose "beurré" ?
Autre question : pourquoi ne pas utiliser SDL_SetColorKey() avec le flag SDL_SRCCOLORKEY ?
Il est a noter que c'est la surface ou il y a le texte a traiter pour l'alpha, et non pas la surface d'écran.
Ben faut faire d'autres tests
"pourquoi ne pas utiliser SDL_SetColorKey() avec le flag SDL_SRCCOLORKEY ? "
--> openGL n'utilise pas la meme gestion de textures/surfaces que SDL. A partir de la, je doute que SDL_SetColorKey fonctionne. Mais tu peux essayer !
Il est a noter que c'est la surface ou il y a le texte a traiter pour l'alpha, et non pas la surface d'écran.
Que veux-tu dire exactement ? J'ai ajouté le traitement alpha comme ci-dessous, l'ai-je mal positionné ?
<...>
SDL_PixelFormat format = text.getFormat();
format.BitsPerPixel = 32;
format.BytesPerPixel = 4;
format.Rmask = RMask;
format.Gmask = GMask;
format.Bmask = BMask;
format.Amask = AMask;
text.setTransColor(0, 0, 0);
text.convert(&format, SDL_SWSURFACE);
text.flip();
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
<...>
Citation : Fvirtman
openGL n'utilise pas la meme gestion de textures/surfaces que SDL. A partir de la, je doute que SDL_SetColorKey fonctionne. Mais tu peux essayer !
A vrai dire j'avais déjà essayé, le résultat était le même... J'aurais juste pensé que SDL_SetColorKey() effectuait exactement la même chose que la fonction setTransColor() ; après tout, cette dernière agit également sur le texte en tant que surface SDL, et non en tant que texture openGL, donc il serait normal qu'elle ne fonctionne pas puisque "openGL n'utilise pas la meme gestion de textures/surfaces que SDL"...
Je serais justement plutôt tenté de réécrire setTransColor() à partir de la texture openGL si cela est possible, mais puisque tu as réussi à faire ton programme sans c'est que la solution n'est pas là...
J'ai trouvé !!!
En finale il y a plus simple que l'alpha-test, il faut bien utiliser SDL_SetColorKey() (m'est avis que tu l'as recodée à travers SetTransColor()), combinée avec SDL_DisplayFormatAlpha().
De plus j'avais fait des erreurs au niveau des différentes surfaces temp, voici le code complet brièvement commenté de la très controversée conversion surface SDL/texture openGL, enfin fonctionnelle :
CTexture::CTexture(CText text)
{
unsignedint
w = (int)floor(pow(2, ceil(log(text.getWidth()) / log(2)))),
h = (int)floor(pow(2, ceil(log(text.getHeight()) / log(2))));
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
Uint32
RMask = 0xff000000,
GMask = 0x00ff0000,
BMask = 0x0000ff00,
AMask = 0x000000ff;
#else
Uint32
RMask = 0x000000ff,
GMask = 0x0000ff00,
BMask = 0x00ff0000,
AMask = 0xff000000;
#endif
SDL_Surface *temp = SDL_CreateRGBSurface
(
SDL_HWSURFACE,
w,
h,
32,
RMask,
GMask,
BMask,
AMask
);
if(!temp)
{
SDL_FreeSurface(temp);
cerr << "Fatal error : unable to create texture from SDL surface : " << SDL_GetError() << endl;
bool error;
throw error;
}
SDL_Rect position;
position.x = 0; position.y = 0;
CSurface temp2(temp);
text.blit(&position, &temp2);
//Toutes les instructions suivantes sont en fait inutiles
/*SDL_PixelFormat format = text.getFormat();
format.BitsPerPixel = 32;
format.BytesPerPixel = 4;
format.Rmask = RMask;
format.Gmask = GMask;
format.Bmask = BMask;
format.Amask = AMask;
temp2.setTransColor(0, 0, 0);
temp2.convert(&format, SDL_SWSURFACE);
temp2.flip();*/
SDL_Color color;
color.r = 0; color.g = 0; color.b = 0;
//Les 2 lignes suivantes permettent la transparence du fond noir
gluBuild2DMipmaps(GL_TEXTURE_2D, 4, temp2.getWidth(), temp2.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, temp2.getPixels());//j'avais utilisé la CSurface text, alors qu'il faut bien la nouvelle CSurface temp2 de dimensions compatibles openGL (en puissance de 2)
Ah j'oubliais : il faut activer GL_BLEND ponctuellement pour l'affichage du texte.
Voili voilou ! Un grand merci à toi Fvirtman !
Dommage que je manque de temps libre, cela fait un parfait petit sujet de mini-tuto utile à beaucoup je pense !
[EDIT] Dernière petite parenthèse : il semble que mon texte ne soit pas antialiasé... Pourtant j'écris en mode Blended et j'utilise le mipmapping... Comment y remédier ?
Le probleme avec le blend, c'est que c'est plus calculatoire que l'alpha test, et il me semble que tu peux avoir des problemes avec le Z-buffer avec.
L'alpha test est sympa car il fait un "tout ou rien" en ce qui concerne le rendu de chaque pixel.
En l'occurrence, le tout-ou-rien ne me satisfait pas, puisque les bords noirs sont sensés être des pixels rouges semi-transparents vis-à-vis de la scène 3D, non vis-à-vis du fond noir...
La méthode manuelle que je propose plus haut "SetTransColor" modifie les alpha en fonction d'une condition ou une autre.
Si tu veux utiliser cette méthode, alors oui, c'est possible il te suffit de modifier la fonction pour la personnaliser.
Si tu utilises une méthode toute faite, il faut voir ce qu'elle propose
× 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.
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html
Recueil de code C et C++ http://fvirtman.free.fr/recueil/index.html