Search code examples
openglgraphicssdldtexture-mapping

OpenGL texture mapping stubbornly refuses to work


I'm writing a 2D game using SDL and OpenGL in the D programming language. At the moment it simply tries to render a texture-mapped quad to the screen. Problem is, the whole texture-mapping part doesn't quite seem to work. Despite the texture apparently loading fine (gets assigned a nonzero texture number, doesn't cause glGetError to return values other than zero), the quad is rendered with the last color set in glColor, entirely ignoring the texture.

I've looked for common reasons for texture mapping to fail, including this question, to no avail. The image file being loaded is 64x64, a valid power-of-2 size.

Please don't get scared off because this is in D—it's almost entirely C-style SDL and OpenGL calls.

SDL initialization code:

if (SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) == -1 ||
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 0) == -1)
    throw new Exception("An OpenGL attribute could not be set!");

uint videoFlags = SDL_OPENGL | SDL_HWSURFACE | SDL_ANYFORMAT;

if (threadsPerCPU() > 1)
    videoFlags |= SDL_ASYNCBLIT;

SDL_Surface* screen = SDL_SetVideoMode(800, 600, 32, videoFlags);

if (screen == null)
    throw new Exception("SDL_SetVideoMode failed!");

OpenGL initialization code:

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0., 800, 600, 0., 0., 1.);
glMatrixMode(GL_MODELVIEW);

glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);

glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glEnable(GL_TEXTURE_2D);

glClearColor(0.f, 0.f, 0.f, 0.f);

Texture loading code:

SDL_Surface* s = IMG_Load(toStringz("hello.png"));

if (s == null)
    throw new Exception("Image file could not be loaded!");

uint texFormat;

switch (s.format.BytesPerPixel)
{
case 4:
    texFormat = (s.format.Rmask == 0x000000ff ? GL_RGBA : GL_BGRA);
    break;
case 3:
    texFormat = (s.format.Rmask == 0x000000ff ? GL_RGB : GL_BGR);
    break;
default:
    throw new Exception("Bad pixel format!");
    break;
}

if ((s.w & (s.w - 1)) != 0)
    throw new Exception("Width must be a power of 2!");
if ((s.h & (s.h - 1)) != 0)
    throw new Exception("Height must be a power of 2!");

uint glName;

glGenTextures(1, &glName);

glBindTexture(GL_TEXTURE_2D, glName);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, s.format.BytesPerPixel, s.w, s.h, 0,
    texFormat, GL_UNSIGNED_BYTE, s.pixels);

SDL_FreeSurface(s);

Rendering code:

glClear(GL_COLOR_BUFFER_BIT);

glBegin(GL_QUADS);
    glColor4ub(255, 255, 255, 255);
    glBindTexture(GL_TEXTURE_2D, glName);
    glTexCoord2i(0, 0); glVertex2i(0, 0);
    glTexCoord2i(1, 0); glVertex2i(64, 0);
    glTexCoord2i(1, 1); glVertex2i(64, 64);
    glTexCoord2i(0, 1); glVertex2i(0, 64);
glEnd();

SDL_GL_SwapBuffers();

My program uses Derelict2, a library that provides SDL and OpenGL bindings for D.

Any ideas on exactly what is going awry here?

Edit: For future reference, here's the solution to my problem:

http://www.opengl.org/wiki/Common_Mistakes#Creating_a_Texture

I needed to set a couple parameters prior to calling glTexImage2D or else my texture was technically incomplete. Adding the following four lines just before that call did the trick:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

Solution

  • One common mistake is to create/use an incomplete texture, see here.

    Your code does not show any call to :

    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR/*or GL_NEAREST*/);
    glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*or GL_NEAREST*/);
    

    and also does not show any mipmap creation.

    You problem may be related to your texture being incomplete.