I'm working on a project with a friend and we are using SDL with OpenGL, and we also have alpha blending.
Now, alpha blending is giving us a few oddities, and here is a link to how it normally looks.
http://img249.imageshack.us/img249/5103/normal.png
Sometimes, however, it transforms into this...
http://img249.imageshack.us/img249/9671/strange.png
When the program really hates me, it does this --
http://img256.imageshack.us/img256/4835/strange2.png
So, any ideas as to why its doing this?
-------------
I understand that rendering order is important: the screen is rendered as such:
(grid then selections then UI then units -- see code below if this was confusing)
void GameScreen::render()
{
grid.Draw();
if((draw_selection))
{
// If we are not in the panel's plane, then don't draw the selection box
if(!UI.CursorIsInPanels(MouseOffsetsScreen.x, MouseOffsetsScreen.y))
DrawPrimitives->DrawSquare(selection_startX - ClipPlane->GetX(), selection_startY - ClipPlane->GetY(), selection_endX - ClipPlane->GetX(), selection_endY - ClipPlane->GetY(), blue);
for(int i = 0; i < characters.size(); i++)
if(characters->Intersects(GetRect(selection_startX, selection_startY, selection_endX, selection_endY)))
characters->DrawRect();
}
glDepthMask(GL_FALSE);
RenderSelections();
UI.DrawTrans();
overlay.DrawTrans();
soundGUI.DrawTrans();
aNavGraph.DisplayEdges();
DrawPrimitives->DrawSquare(10, 555, 120, 590, black, 1.0f);
soundGUI.DrawOpaq();
overlay.DrawOpaq();
UI.DrawOpac();
glDepthMask(GL_TRUE);
//Calculate the frames per second and create the string
TextDisplay->DisplayMessage("FPS: ", red, 20, 560, float(FONT_SIZE_MEDIUM));
TextDisplay->DisplayMessage(fpsCaption, red, 80, 560, float(FONT_SIZE_MEDIUM));
if(fpsCounter.get_ticks() > 150)
{
_itoa_s(int(fpsFrame / (fpsCounter.get_ticks() / 1000.f)), fpsCaption, 10);
fpsCounter.start();
fpsFrame = 0;
}
fpsFrame++;
RenderEntities();
}
Here is how the grid is rendered
void Grid::Draw()
{
for(int x = 0; x < MAP_WIDTH; x++)
for(int y = 0; y < MAP_HEIGHT; y++)
{
Entity::ResetZLevel();
for(int i = 0; i < NUMBER_OF_LAYERS; ++i)
{
if(!gridButtons[x][y].IsIgnoredTile())
gridButtons[x][y].applySurface();
if(gridButtons[x][y].GetDrawBox())
gridButtons[x][y].DrawBox();
}
}
}
The DrawTrans // RenderSelection functions just call this function:
void GLPrimitives::DrawSquare(int x1, int y1, int x2, int y2, OGL_Color color)
{
glColor4f(color.r, color.g, color.b, color.a);
SDL_Rect aRect = GetRect(x1, y1, x2, y2);
glBegin(GL_QUADS);
glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y), 1.0f );
glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y), 1.0f );
glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y + aRect.h), 1.0f );
glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y + aRect.h), 1.0f );
glEnd();
}
The RenderEntities function just calls the applySurface function
void Entity::applySurface()
{
if(imageID == ignoredImage) // optimization; don't draw something that isn't going to show up!
return;
SDL_Rect aRect(Rect);
// Zooming in / out
aRect.x *= m_scaler;
aRect.y *= m_scaler;
aRect.w *= m_scaler;
aRect.h *= m_scaler;
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
if(ClipPlane->IsInPlane(aRect))
{
glScalef(m_scaler, m_scaler, 1.0f);
glTranslatef(Rect.x - ClipPlane->GetX(), Rect.y - ClipPlane->GetY(), m_z);
glCallList(m_displayLists[imageID]);
glLoadIdentity();
}
}
Here is the texture loading function (includes glCallList(...) marked with a big ----------------- comment)
void Entity::Load_Image(const char* filename)
{
// ... big or small endian code commented out
// Load in the image from the filename
SDL_Surface *orig;
orig = IMG_Load(filename);
if(orig == NULL)
{
assert("Texture not correctly loaded" && false);
}
SDL_Surface* paddedOrig = SDL_CreateRGBSurface(SDL_SWSURFACE, unsignedNextPowerOfTwo(orig->w), unsignedNextPowerOfTwo(orig->h), WINDOW_BPP,
RGBAFormat.Rmask, RGBAFormat.Gmask, RGBAFormat.Bmask, RGBAFormat.Amask);
SDL_Surface *surface;
if(orig->w != unsignedNextPowerOfTwo(orig->w) || orig->h != unsignedNextPowerOfTwo(orig->h))
{
SDL_BlitSurface(orig, NULL, paddedOrig, NULL);
surface = SDL_ConvertSurface(paddedOrig, &RGBAFormat, SDL_SWSURFACE);
}
else
surface = SDL_ConvertSurface(orig, &RGBAFormat, SDL_SWSURFACE);
// Convert the surface to a format readable by openGL
m_images_sizes.resize(m_images_sizes.size() + 1);
m_images_sizes[m_images_sizes.size() - 1].h = paddedOrig->h;
m_images_sizes[m_images_sizes.size() - 1].w = paddedOrig->w;
SDL_FreeSurface(orig);
SDL_FreeSurface(paddedOrig);
// get the number of channels in the SDL surface
nOfColors = surface->format->BytesPerPixel;
if (nOfColors == 4) // contains an alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGBA;
else
texture_format = GL_BGRA;
} else if (nOfColors == 3) // no alpha channel
{
if (surface->format->Rmask == 0x000000ff)
texture_format = GL_RGB;
else
texture_format = GL_BGR;
} else {
assert("Loaded image is not truecolor" && false);
}
// Have OpenGL generate a texture object handle for us
glGenTextures( 1, &texture );
// Bind the texture object
glBindTexture( GL_TEXTURE_2D, texture );
// Set the texture's stretching properties
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// Edit the texture object's image data using the information SDL_Surface gives us
glTexImage2D( GL_TEXTURE_2D, 0, nOfColors, surface->w, surface->h, 0,
texture_format, GL_UNSIGNED_BYTE, surface->pixels );
// Free memory and return the texture
SDL_FreeSurface(surface);
m_images.push_back(texture);
// Increase display list size
m_displayLists.resize(m_displayLists.size() + 1);
m_displayLists[m_displayLists.size() - 1] = glGenLists(1);
/* ---------------------------------------------------------------------- */
/* Build the list ------------------------------------------------------- */
/* ---------------------------------------------------------------------- */
glNewList(m_displayLists[m_displayLists.size() - 1], GL_COMPILE);
// Set color to (nothing)
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
// Bind the texture
glBindTexture(GL_TEXTURE_2D, texture);
SDL_Rect aRect;
aRect.x = 0;
aRect.y = 0;
aRect.x = (aRect.x - ClipPlane->GetX());
aRect.y = (aRect.y - ClipPlane->GetY());
aRect.w = m_images_sizes[m_images_sizes.size() - 1].w;
aRect.h = m_images_sizes[m_images_sizes.size() - 1].h;
glBegin(GL_QUADS);
//Top-left vertex (corner)
glTexCoord2i( 0, 0 );
glVertex3f( aRect.x, aRect.y, 0.0f );
//Bottom-left vertex (corner)
glTexCoord2i( 1, 0 );
glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y), 0.0f );
//Bottom-right vertex (corner)
glTexCoord2i( 1, 1 );
glVertex3f( GLfloat(aRect.x + aRect.w), GLfloat(aRect.y + aRect.h), 0.0f );
//Top-right vertex (corner)
glTexCoord2i( 0, 1 );
glVertex3f( GLfloat(aRect.x), GLfloat(aRect.y + aRect.h), 0.0f );
glEnd();
glEndList();
}
Here is how I have set up OpenGL
void initGL()
{
glClearColor( 0, 0, 0, 1 );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glOrtho( 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0.0f, -1.0f, 2.0f );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glFrontFace(GL_CW);
glEnable(GL_ALPHA_TEST);
glEnable(GL_TEXTURE_ENV);
}
Sorry for the long post; hopefully you all can help me solve this rather obnoxious issue.
Thanks.