rendering SDL_TTF text onto openGL Red Square instead of text - c++

I've been attempting to render text onto an openGL window using SDL and the SDL_TTF library on windows XP, VS2010.
Versions:
SDL version 1.2.14
SDL TTF devel 1.2.10
openGL (version is at least 2-3 years old).
I have successfully created an openGL window using SDL / SDL_image and can render lines / polygons onto it with no problems.
However, moving onto text it appears that there is some flaw in my current program, I am getting the following result when trying this code here
for those not willing to pastebin here are only the crutial code segments:
void drawText(char * text) {
glLoadIdentity();
SDL_Color clrFg = {0,0,255,0}; // set colour to blue (or 'red' for BGRA)
SDL_Surface *sText = TTF_RenderUTF8_Blended( fntCourier, text, clrFg );
GLuint * texture = create_texture(sText);
glBindTexture(GL_TEXTURE_2D, *texture);
// draw a polygon and map the texture to it, may be the source of error
glBegin(GL_QUADS); {
glTexCoord2i(0, 0); glVertex3f(0, 0, 0);
glTexCoord2i(1, 0); glVertex3f(0 + sText->w, 0, 0);
glTexCoord2i(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
glTexCoord2i(0, 1); glVertex3f(0, 0 + sText->h, 0);
} glEnd();
// free the surface and texture, removing this code has no effect
SDL_FreeSurface( sText );
glDeleteTextures( 1, texture );
}
segment 2:
// create GLTexture out of SDL_Surface
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
// The SDL_Surface appears to have BGR_A formatting, however this ends up with a
// white rectangle no matter which colour i set in the previous code.
int Mode = GL_RGB;
if(surface->format->BytesPerPixel == 4) {
Mode = GL_RGBA;
}
glTexImage2D(GL_TEXTURE_2D, 0, Mode, surface->w, surface->h, 0, Mode,
GL_UNSIGNED_BYTE, surface->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
return &texture;
}
Is there an obvious bit of code I am missing?
Thank you for any help on this subject.
I've been trying to learn openGL and SDL for 3 days now, so please forgive any misinformation on my part.
EDIT:
I notice that using
TTF_RenderUTF8_Shaded
TTF_RenderUTF8_Solid
Throw a null pointer exception, meaning that there is an error within the actual text rendering function (I suspect), I do not know how this means TTF_RenderUTF8_Blended returns a red square but I suspect all troubles hinge on this.

I think the problem is in the glEnable(GL_TEXTURE_2D) and glDisable(GL_TEXTURE_2D) functions which must be called every time the text is painted on the screen.And maybe also the color conversion between the SDL and GL surface is not right.
I have combined create_texture and drawText into a single function that displays the text properly. That's the code:
void drawText(char * text, TTF_Font* tmpfont) {
SDL_Rect area;
SDL_Color clrFg = {0,0,255,0};
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Blended( tmpfont, text, clrFg ));
area.x = 0;area.y = 0;area.w = sText->w;area.h = sText->h;
SDL_Surface* temp = SDL_CreateRGBSurface(SDL_HWSURFACE|SDL_SRCALPHA,sText->w,sText->h,32,0x000000ff,0x0000ff00,0x00ff0000,0x000000ff);
SDL_BlitSurface(sText, &area, temp, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, sText->w, sText->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
glTexCoord2d(0, 0); glVertex3f(0, 0, 0);
glTexCoord2d(1, 0); glVertex3f(0 + sText->w, 0, 0);
glTexCoord2d(1, 1); glVertex3f(0 + sText->w, 0 + sText->h, 0);
glTexCoord2d(0, 1); glVertex3f(0, 0 + sText->h, 0);
} glEnd();
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface( sText );
SDL_FreeSurface( temp );
}
screenshot
I'm initializing OpenGL as follows:
int Init(){
glClearColor( 0.1, 0.2, 0.2, 1);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho( 0, 600, 300, 0, -1, 1 );
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if( glGetError() != GL_NO_ERROR ){
return false;
}
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_COLOR, GL_ONE_MINUS_SRC_ALPHA);
}

I think you should just add glEnable(GL_BLEND), because the code for the text surface says TTF_RenderUTF8_Blended( fntCourier, text, clrFg ) and you have to enable the blending abilities of opengl.

EDIT
Okay, I finally took the time to put your code through a compiler. Most importantly, compiler with -Werror so that warning turn into errors
GLuint * create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return &texture;
}
I didn't see it first, because that's something like C coder's 101 and is quite unexpected: You must not return pointers to local variables!. Once the functions goes out of scope the pointer returned will point to nonsense only. Why do you return a pointer at all? Just return a integer:
GLuint create_texture(SDL_Surface *surface) {
GLuint texture = 0;
/*...*/
return texture;
}
Because of this you're also not going to delete the texture afterward. You upload it to OpenGL, but then loose the reference to it.
Your code misses a glEnable(GL_TEXTURE_2D) that's why you can't see any effects of texture. However your use of textures is suboptimal. They way you did it, you recreate a whole new texture each time you're about to draw that text. If that happens in a animation loop, you'll
run out of texture memory rather soon
slow it down significantly
(1) can be addressed by not generating a new texture name each redraw
(2) can be addresses by uploading new texture data only when the text changes and by not using glTexImage2D, but glTexSubImage2D (of course, if the dimensions of the texture change, it must be glTexImage2D).
EDIT, found another possible issue, but first fix your pointer issue.
You should make sure, that you're using GL_REPLACE or GL_MODULATE texture environment mode. If using GL_DECAL or GL_BLEND you end up with red text on a red quad.

There was leaking memory of of the function in my previous post and the program was crashing after some time...
I improved this by separating the texture loading and displaying:
The first function must be called before the SDL loop.It loads text string into memory:
Every string loaded must have different txtNum parameter
GLuint texture[100];
SDL_Rect area[100];
void Load_string(char * text, SDL_Color clr, int txtNum, const char* file, int ptsize){
TTF_Font* tmpfont;
tmpfont = TTF_OpenFont(file, ptsize);
SDL_Surface *sText = SDL_DisplayFormatAlpha(TTF_RenderUTF8_Solid( tmpfont, text, clr ));
area[txtNum].x = 0;area[txtNum].y = 0;area[txtNum].w = sText->w;area[txtNum].h = sText->h;
glGenTextures(1, &texture[txtNum]);
glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sText->w, sText->h, 0, GL_BGRA, GL_UNSIGNED_BYTE, sText->pixels);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
SDL_FreeSurface( sText );
TTF_CloseFont(tmpfont);
}
The second one displays the string, must be called in the SDL loop:
void drawText(float coords[3], int txtNum) {
glBindTexture(GL_TEXTURE_2D, texture[txtNum]);
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS); {
glTexCoord2f(0, 0); glVertex3f(coords[0], coords[1], coords[2]);
glTexCoord2f(1, 0); glVertex3f(coords[0] + area[txtNum].w, coords[1], coords[2]);
glTexCoord2f(1, 1); glVertex3f(coords[0] + area[txtNum].w, coords[1] + area[txtNum].h, coords[2]);
glTexCoord2f(0, 1); glVertex3f(coords[0], coords[1] + area[txtNum].h, coords[2]);
} glEnd();
glDisable(GL_TEXTURE_2D);
}

Related

Problems with updating a texture

I have a function that generates the obj texture and another one that displays it. In order not to leak memory, I tried to call only one time the first function and than, use glTexSubImage2D in the second one, the problem is that this function is not working for me. When I start the program, the texture isn't being updating.
Here is the generating texture function:
GLuint importText(const std::string &text,int font_size,int red,int green,int blue, texto_data *texto){
SDL_Color font_color = {blue,green,red};
TTF_Font* font=TTF_OpenFont("arial.ttf",font_size);
SDL_Surface *image = TTF_RenderText_Blended(font,text.c_str(),font_color);
SDL_DisplayFormatAlpha(image);
glGenTextures(1,&texto->texture);
glBindTexture(GL_TEXTURE_2D, texto->texture);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA,image->w,image->h,0,GL_RGBA,GL_UNSIGNED_BYTE,image->pixels);
SDL_FreeSurface(image);
TTF_CloseFont(font);
return texto->texture;
}
And here is the display function:
int carrega_texto(texto_data *texto) {
SDL_Color font_color = {texto->b,texto->g,texto->r};
TTF_Font* font = TTF_OpenFont("arial.ttf",texto->tamanho);
SDL_Surface *image = TTF_RenderText_Blended(font,texto->string,font_color);
SDL_DisplayFormatAlpha(image);
glBindTexture(GL_TEXTURE_2D, texto->texture);
glTexSubImage2D(GL_TEXTURE_2D, 0,0,image->w,image->h,0,GL_RGBA,GL_UNSIGNED_BYTE,image->pixels);
SDL_FreeSurface(image);
TTF_CloseFont(font);
glBindTexture(GL_TEXTURE_2D, texto->texture);
glColor4ub(255, 255, 255, 255);
glBegin(GL_QUADS);
glTexCoord2d(0,0); glVertex2f(texto->area.a.x, texto->area.a.y);
glTexCoord2d(1,0); glVertex2f(texto->area.b.x, texto->area.b.y);
glTexCoord2d(1,1); glVertex2f(texto->area.c.x, texto->area.c.y);
glTexCoord2d(0,1); glVertex2f(texto->area.d.x, texto->area.d.y);
glEnd();
}
Nt: I tried to just always call the generating texture and keeping deleting with glDeleteTextures, in order not to use glTexSubImage2D. The problem is that the glGenTexture always increases the variable texto->texture and than it overflow.

OpenGL texture appears to big on the screen

Okay so I am working on a toy 2d engine. I initially used regular SDL_Surfaces for rendering and the built in SDL_Renderer. But I thought why not use OpenGL, get some experience with that.
But I am stuck now. I have a context and things are rendered to the screen, but it looks like the textures I am trying to display are way to big to fit in the screen. Like I only see a couple of pixels, but not really.
The texture class can be found here:
#include "texture.h"
Texture::Texture(std::string path, bool loadNow) {
//Initialize texture ID
mTextureID = 0;
//Initialize texture dimensions
width = 0;
height = 0;
this->path = path;
if(loadNow) {
loadTexture(path);
}
}
Texture::~Texture() {
freeTexture();
}
bool Texture::loadTexture(std::string path) {
//Texture loading success
loaded = false;
SDL_Surface *image = IMG_Load(path.c_str());
//Image loaded successfully
if(image != NULL) {
if((image->w & (image->w - 1)) == 0) {
printf("Warning: image width not power of 2 -> %s\n", path.c_str());
}
if((image->h & (image->h - 1)) == 0) {
printf("Warning: image height not power of 2 -> %s\n", path.c_str());
}
loaded = loadTextureFromPixels32(image, (GLuint)image->w, (GLuint)image->h);
}
//Report error
if(!loaded) {
printf( "Unable to load %s\n", path.c_str() );
}
return loaded;
}
bool Texture::loadTextureFromPixels32(SDL_Surface *image, GLuint width, GLuint height ) {
//Free texture if it exists
freeTexture();
//Get texture dimensions
this->width = width;
this->height = height;
//Generate texture ID
glGenTextures(1, &mTextureID);
//Bind texture ID
glBindTexture(GL_TEXTURE_2D, mTextureID);
//Generate texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image->pixels);
//Set texture parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//Unbind texture
glBindTexture(GL_TEXTURE_2D, 0);
//Check for error
GLenum error = glGetError();
if(error != GL_NO_ERROR) {
printf("Error loading texture from %p pixels!\n", image->pixels);
return false;
}
return true;
}
void Texture::render(GLfloat x, GLfloat y) {
if(loaded) {
//If the texture exists
if(mTextureID != 0) {
GLfloat realX = x;// - (this->width / 2);
GLfloat realY = y;// - (this->height / 2);
//Remove any previous transformations
glLoadIdentity();
//Move to rendering point
glTranslatef(realX, realY, 0.f);
glClearDepth(1.0f);
//Set texture ID
glBindTexture(GL_TEXTURE_2D, mTextureID);
//Render textured quad
glBegin(GL_QUADS);
glTexCoord2f( 0.f, 0.f ); glVertex2f(0.f, 0.f);
glTexCoord2f( 1.f, 0.f ); glVertex2f(width, 0.f);
glTexCoord2f( 1.f, 1.f ); glVertex2f(width, height);
glTexCoord2f( 0.f, 1.f ); glVertex2f(0.f, height);
glEnd();
}
} else {
// do nothing
}
}
GLuint Texture::getWidth() {
return this->width;
}
GLuint Texture::getHeight() {
return this->height;
}
void Texture::freeTexture() {
//Delete texture
if(mTextureID != 0) {
glDeleteTextures(1, &mTextureID);
mTextureID = 0;
}
width = 0;
height = 0;
}
I am guessing the problem is here, but it could also be in how I initialize OpenGL so here is that:
void Main::initGL() {
/* Request opengl 3.2 context.
* SDL doesn't have the ability to choose which profile at this time of writing,
* but it should default to the core profile */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2);
/* Turn on double buffering with a 24bit Z buffer.
* You may need to change this to 16 or 32 for your system */
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 32);
glContext = SDL_GL_CreateContext(this->window);
glViewport(0.0, 0.0, SCREEN_WIDTH, SCREEN_HEIGHT);
glOrtho( 0.0, SCREEN_WIDTH, SCREEN_HEIGHT, 0.0, 1.0, -1.0 );
SDL_GL_SetSwapInterval(0);
//Initialize clear color
glClearColor( 0.f, 0.f, 0.f, 1.f );
//Enable texturing
glEnable( GL_TEXTURE_2D );
//Check for error
GLenum error = glGetError();
if(error != GL_NO_ERROR) {
printf("Error initializing OpenGL!\n");
}
}
SDL is correctly initialized otherwise there wouldn't be anything on the screen. I am completely new to OpenGL so any help would be appreciated.
You mix ordinate GL_TEXTURE_2D stuff with GL_TEXTURE_RECTANGLE, and enabling both is a very bad idea. You are using texcoords in the range [0,1], so you actually seem to want to use GL_TEXTURE_2D. You should rewrite your texture code to use that, and dropt those rectangle textures entirely.
The next thing is that your projection setup is wrong. Your glOrtho call has no effect since you completely overwrite this by loading the identity matrix a few lines later. You should make yourself familiar with the stae machine approach the GL is using. As your matrices are set up currently, you draw a huge quad with most of it completely ot of the screen.
Now that part is completely strange:
/* Request opengl 3.2 context.
* SDL doesn't have the ability to choose which profile at this time of writing,
* but it should default to the core profile */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
This code is will never create a core profile, because core profiles didn't even exist in GL2.1, they were introduced in GL3.2. It is unclear what SDL version you are using, but modern SDL is capable of selecting the profile.
However, your code is using completely outdated ande deprecated OpenGL, there is no way this will work with a core profile. If you learn OpenGL in this decade, I'd strongly suggest that you forget about all that and start with some documentation/tutorial on modern GL, and actually use a core profiel.

2D TTF Text Rendering with SDL & OpenGL Issues

So I have looked around and I haven't found the best way to actually implement this in SDL & OpenGL. At this moment I can display text to the screen with a TTF but its not really displaying the text the way it should be. Attached is a screen shot of how the engine looks like when displaying text. Basically from what I can see in my code, I think what is happening is that I am not blitting my text texture with the my main SDL_Surface that I am using as my window. I say that because in the picture my character who has a red collision box around him is being covered up my the text texture I'm rendering my text with. Any ideas of what I can do?
In my game loop I call beginDraw() and endDraw() before and after I draw everything to the screen.
Picture: http://public.gamedev.net/uploads/monthly_07_2012/post-200874-0-25909300-1342404845_thumb.png
All the engine code can be found here: https://github.com/Jevi/SDL_GL_ENGINE
P.S: I'm going to make another post for this but I might as well ask this also if you guys are already looking at my code. I have been noticing some memory issues with the engine. In task manager the memory allocated to my program is constantly climbing since its starts at around 11000 K.
void graphics::SDL_GL_RenderText(float x1, float y1, int width, int height, const char* text, int ptsize, const char* ttfLoc, int r, int g, int b){
SDL_Surface* temp;
SDL_Surface* temp2;
SDL_Rect rect;
TTF_Font* font;
SDL_Color textColor;
unsigned int texture;
font = TTF_OpenFont( ttfLoc , ptsize );
textColor.r = r;
textColor.g = g;
textColor.b = b;
temp = TTF_RenderText_Blended( font, text, textColor );
// width = nextpoweroftwo(width);
// height = nextpoweroftwo(height);
temp2 = SDL_CreateRGBSurface(0, width, height, 32, r, g, b, 0);
SDL_BlitSurface(temp, 0, temp2, 0);
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, temp2->w, temp2->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp2->pixels);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
/* prepare to render our texture */
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture);
glColor3f(1.0f, 1.0f, 1.0f);
/* Draw a quad at location */
glBegin(GL_QUADS);
glTexCoord2d(0,0);
glVertex2f(x1, y1);
glTexCoord2d(1,0);
glVertex2f(x1 + temp2->w, y1);
glTexCoord2d(1,1);
glVertex2f(x1 + temp2->w, y1 + temp2->h);
glTexCoord2d(0,1);
glVertex2f(x1, y1 + temp2->h);
glEnd();
glFinish();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
SDL_FreeSurface(temp);
SDL_FreeSurface(temp2);
TTF_CloseFont(font);
glDeleteTextures(1, &texture);
}
void graphics::GL_BeginDraw(){
glClear(GL_COLOR_BUFFER_BIT);
glPushMatrix(); //Start rendering phase
glOrtho(0,width,height,0,-1,1); //Set the matrix
}
void graphics::GL_EndDraw(){
glPopMatrix(); //End rendering phase
SDL_GL_SwapBuffers();
glFinish();
}

Why can I not load a texture into my app?

I think texture mapping is a really easy task. Actually, I implemented it many times but failed in this time and don't know why? And I can guarantee that the route to load the texture is right. Any other reasons for my confusion?
Here is my code:
GLuint mytexture;
// two functions below come from NeHe's tut. I think it works well.
AUX_RGBImageRec *LoadBMP(CHAR *Filename)
{
FILE *File=NULL;
if (!Filename)
{
return NULL;
}
File=fopen(Filename,"r");
if (File)
{
fclose(File);
return auxDIBImageLoadA(Filename);
}
return NULL;
}
int LoadGLTextures()
{
int Status=FALSE;
AUX_RGBImageRec *TextureImage[1];
memset(TextureImage,0,sizeof(void *)*1);
if (TextureImage[0]=LoadBMP("NeHe.bmp"))
{
Status=TRUE;
glGenTextures(1, &mytexture);
glBindTexture(GL_TEXTURE_2D, mytexture);
glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage[0]->sizeX, TextureImage[0]->sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, TextureImage[0]->data);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
}
if (TextureImage[0])
{
if (TextureImage[0]->data)
{
free(TextureImage[0]->data);
}
free(TextureImage[0]);
}
return Status;
}
//next is my Init() code:
bool DemoInit( void )
{
if (!LoadGLTextures())
{
return FALSE;
}
glEnable(GL_TEXTURE_2D);
........//other init is ok
}
bool DemoRender()
{
...///render other things
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, mytexture);
glColor3f(0,0,1);
glBegin(GL_QUADS);
glTexCoord2f(0, 0); glVertex2f(0, 0);
glTexCoord2f(1, 0); glVertex2f(200, 0);
glTexCoord2f(1, 1); glVertex2f(200, 200);
glTexCoord2f(0, 1); glVertex2f(0, 200);
glEnd();
glDisable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
Pretty clear, ha? However, the final result only has a blue rectangle without the texture. Anybody could give me a hint?
Assuming TextureImage[0]->data is correctly populated:
However, the final result only has a blue rectangle without the texture.
You're using the default GL_MODULATE texture environment. Either switch glColor3f(0,0,1) to glColor3f(1,1,1) or use GL_DECAL.
You might also try a glPixelStorei(GL_UNPACK_ALIGNMENT, 1) before your glTexImage2D() since you're using GL_RGB for format.
The problem is I set the GL_LINE mode before I load the texture and I failed to notice that. So after I set the GL_FILL mode, everything is fine!!!

I can't get the transparency in my images to work

Stemming from this question of mine: I'm seeing artifacts when I attempt to rotate an image
In the source code there, I am loading a TIF because I can't for the life of me get any other image format to load the transparency parts correctly. I've tried PNG, GIF, & TGA. I'd would like to be able to load PNGs. I hope the source code given in the question above will be enough, if not, then let me know.
For a better description of what happens when I attempt to load some other format -- One of the images I was attempting was a 128*128 orange triangle. Depending on the format, it would either make the entire 128*128 square orange, or make the transparent parts of the image white.
Make sure that you have alpha blending enabled with
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
otherwise primitives will draw solid colors where there should be transparency.
You may need a different blendfunc. This is a common setup.
OK, I'm new at OpenGL + SDL but here is what I have.. Loads all? formats SDL_image supports except I can't get .xcf to work and don't have a .lbm to test with.
//called earlier..
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//load texture
SDL_Surface* tex = IMG_Load(file.c_str());
if (tex == 0) {
std::cout << "Could not load " << file << std::endl;
return false;
}
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
//nearest works but linear is best when scaled?
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
width = tex->w;
height = tex->h;
//IMG_is* doesn't seem to work right, esp for TGA, so use extension instead..
std::string ext = file.substr(file.length() - 4);
bool isBMP = (ext.compare(".bmp") == 0) || (ext.compare(".BMP") == 0);
bool isPNG = (ext.compare(".png") == 0) || (ext.compare(".PNG") == 0);
bool isTGA = (ext.compare(".tga") == 0) || (ext.compare(".TGA") == 0);
bool isTIF = ((ext.compare(".tif") == 0) || (ext.compare(".TIF") == 0) ||
(ext.compare("tiff") == 0) || (ext.compare("TIFF") == 0));
//default is RGBA but bmp and tga use BGR/A
GLenum format = GL_RGBA;
if(isBMP || isTGA)
format = (tex->format->BytesPerPixel == 4 ? GL_BGRA : GL_BGR);
//every image except png and bmp need to be converted
if (!(isPNG || isBMP || isTGA || isTIF)) {
SDL_Surface* fixedSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
SDL_BlitSurface(tex, 0, fixedSurface, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, fixedSurface->pixels);
SDL_FreeSurface(fixedSurface);
} else {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, format, GL_UNSIGNED_BYTE, tex->pixels);
}
SDL_FreeSurface(tex);
list = glGenLists(1);
glNewList(list, GL_COMPILE);
GLint vertices[] = {
0,0, 0,0,
0,1, 0,height,
1,1, width,height,
1,0, width,0
};
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, texture);
glTexCoordPointer(2, GL_INT, 4*sizeof(GLint), &vertices[0]);
glVertexPointer(2, GL_INT, 4*sizeof(GLint), &vertices[2]);
glDrawArrays(GL_POLYGON, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glEndList();
And then to draw I set the color to opaque white (doesn't affect transparency?) then just call the list..
glColor4f(1,1,1,1);
glCallList(list);
And of course, any help for my code would be much appreciated too! :)
I'm not familiar with SDL, but since it's SDL that loading the image, I would look closer at their docs. I use .png in my own work along with OpenGL, and transparency works with no problem. (I use a .png parser called LightZPng.)
Also, I just noticed your linked post has:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
instead of:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
This would have the affect of adding the pixels that should be transparent to whatever is in the background (assuming the alpha is 0 in those texels).