简体   繁体   中英

SDL 3d OpenGL: texture on cube produces blank screen

I have been trying to load a texture on to a cube using SDL_image and OpenGL. For some reason, the entire window remains blank when I attempt to use textures. By commenting out my texture initialisation call, the window renders as it should, except with a white texture. The same applies when my call to glEnable(GL_TEXTURE_2D) gets commented out. I have been trying for several hours now to fix this, and have spent most of those looking online for whether anyone has come up with a solution, but nothing I tried worked. I have posted only sections of my code below, if more is required, please let me know.

OpenGL initialisation (The order for glEnable(GL_TEXTURE_2D) may be incorrect):

//Configures OpenGL for 3d rendering
//Needs to know the window height and width
void setUpOpenGL(int width, int height)
{
//Enable depth testing, necessary for 3d worlds
glEnable(GL_DEPTH_TEST);
glEnable(GL_TEXTURE_2D);

//Set the background colour to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
//Set the clear depth at 1m?
glClearDepth(1.0f);

//Configure the viewport, giving height and width
glViewport(0, 0, width, height);

//Clear the colour buffer
glClear(GL_COLOR_BUFFER_BIT);

//Initiate OpenGL for projection drawing
glMatrixMode(GL_PROJECTION);
//Load identity, purpose still unknown
glLoadIdentity();

//Initiate viewport as perspective, give the field of view, aspect ratio (width/height), minimum distance and maximum distance
gluPerspective(45.0f, (float)width / (float)height, 0.01f, 500.0f);

//Initiate OpenGL for model drawing, preparation for frame rendering
glMatrixMode(GL_MODELVIEW);
//Load identity again (identity matrix?)
glLoadIdentity();

//Set the shading model to smooth.  Other options feasable, but don't look as good
glShadeModel(GL_SMOOTH);
//For whatever reason, we need to state how to calculate depth.  Grouped under "Alpha Function"
glDepthFunc(GL_LEQUAL);

//Calculate perspective as "nicest"; "don't care" and "fastest" are other options
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

//Finished configuring OpenGL
return;
}

Here my loadTexture function (errorCode remains 0 through the entire function, and nothing is printed to stderr):

//Function to load textures from file.  Needs to know the filename / relative location.
//Load textures from file
int loadTexture(char *filename)
{
GLuint returnValue = -1;
SDL_Surface *image;
void *raw;
int width, height, bpp;
Uint8 *srcPixel, *dstPixel;
Uint32 truePixel;
GLenum errorCode;

image = IMG_Load(filename);

if(!image)
{
    fprintf(stderr, "Warning: Error loading image %s: %s\n", filename, IMG_GetError());
    return -2;
}

if(image->format->BytesPerPixel < 2)
{
    fprintf(stderr, "Warning: %s is a bad image, not true colour\n", filename);
    return -3;
}

width = image->w;
height = image->h;

raw = (void *)malloc(width * height * 4);
dstPixel = (Uint8 *)raw;

SDL_LockSurface(image);

bpp = image->format->BytesPerPixel;

for(int i = height - 1; i >= 0; i--)
{
    for(int j = 0; j < width; j++)
    {
        srcPixel = (Uint8 *)image->pixels + i * image->pitch + j * bpp;

        switch(bpp)
        {
        case 1:
            truePixel = *srcPixel;
            break;
        case 2:
            truePixel = *(Uint16 *)srcPixel;
            break;
        case 3:
            if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
                truePixel = srcPixel[0] << 16 | srcPixel[1] << 8 | srcPixel[2];
            else
                truePixel = srcPixel[0] | srcPixel[1] << 8 | srcPixel[2] << 16;
            break;
        case 4:
            truePixel = *(Uint32 *)srcPixel;
            break;
        default:
            fprintf(stderr, "Warning: image BPP of %d in image %s unuseable\n", bpp, filename);
            SDL_UnlockSurface(image);
            SDL_FreeSurface(image);
            free(raw);
            return -4;
        }

        SDL_GetRGBA(truePixel, image->format, &(dstPixel[0]), &(dstPixel[1]), &(dstPixel[2]), &(dstPixel[3]));
        dstPixel++;
        dstPixel++;
        dstPixel++;
        dstPixel++;
    }
}

SDL_UnlockSurface(image);
SDL_FreeSurface(image);

while(glGetError());

glGenTextures(1, &returnValue);
glBindTexture(GL_TEXTURE_2D, returnValue);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_LINEAR*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *)raw);

errorCode = glGetError();
if(errorCode)
{
    if(errorCode == GL_OUT_OF_MEMORY)
        fprintf(stderr, "Warning: Texture memory full while binding texture from image %s\n", filename);
    else
        fprintf(stderr, "OpenGL error while creating texture: %d", (int)errorCode);

    glDeleteTextures(1, &returnValue);
    free(raw);
    return -5;
}

//gluBuild2DMipmaps(GL_TEXTURE_2D, 4, width, height, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *)raw);

errorCode = glGetError();
if(errorCode)
{
    if(errorCode == GL_OUT_OF_MEMORY)
        fprintf(stderr, "Warning: Texture memory full while building texture from image %s\n", filename);
    else
        fprintf(stderr, "OpenGL error while creating texture: %s", (int)errorCode);

    glDeleteTextures(1, &returnValue);
    free(raw);
    return -6;
}

return returnValue;
}

Finally, my actual render code. Note that the return value for the loadTexture function is copied into all elements of the texture array (right, left, top, bottom, front, back (enums)).

void cube::render(void)
{
float xMinOffset, xMaxOffset, yMinOffset, yMaxOffset, zMinOffset, zMaxOffset;
//getoffset(xMinOffset, xMaxOffset, yMinOffset, yMaxOffset, zMinOffset, zMaxOffset);

xMinOffset = yMinOffset = zMinOffset = 0.0f;
xMaxOffset = yMaxOffset = zMaxOffset = 1.0f;

//Positive x, or right
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, texture[right]);

    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
}
glEnd();

//Negative x, or left
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(-1.0f, 0.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, texture[left]);

    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMinOffset, yMinOffset, zMinOffset);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
}
glEnd();

//Positive y, or top
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(0.0f, 1.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, texture[top]);

    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
}
glEnd();

//Negative y, or bottom
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(0.0f, -1.0f, 0.0f);
    glBindTexture(GL_TEXTURE_2D, texture[bottom]);

    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMinOffset, yMinOffset, zMinOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
}
glEnd();

//Positive z, or front
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(0.0f, 0.0f, 1.0f);
    glBindTexture(GL_TEXTURE_2D, texture[front]);

    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMinOffset, yMinOffset, zMaxOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMaxOffset);
    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMaxOffset);
}
glEnd();

//Negative z, or back
glBegin(GL_QUADS);
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glNormal3f(0.0f, 0.0f, -1.0f);
    glBindTexture(GL_TEXTURE_2D, texture[back]);

    glTexCoord2f(1.0f, 1.0f);
    glVertex3f(xMinOffset, yMinOffset, zMinOffset);
    glTexCoord2f(1.0f, 0.0f);
    glVertex3f(xMinOffset, yMaxOffset, zMinOffset);
    glTexCoord2f(0.0f, 0.0f);
    glVertex3f(xMaxOffset, yMaxOffset, zMinOffset);
    glTexCoord2f(0.0f, 1.0f);
    glVertex3f(xMaxOffset, yMinOffset, zMinOffset);
}
glEnd();
}

And here the render function, along with some other drawing-related functions. Note that initDisplayLists() is called in initialisation.

void redraw(void)
{
//Still has the data from the previous frame
//Clear the colour and depth buffers before rendering
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Load identity, purpose unknown
glLoadIdentity();

//Draw horizontal crosshair
glBegin(GL_LINES);
{
    //White colour
    glColor3f(1.0f, 1.0f, 1.0f);
    //x, y, z
    //Vertex2f would be ideal, but doesn't appear (min view distance for perspective?)
    glVertex3f(-0.0001f, 0.0f, -0.01f);
    glVertex3f(0.0001f, 0.0f, -0.01f);
}
glEnd();
//Draw vertical crosshair
glBegin(GL_LINES);
{
    //Also white
    glColor3f(1.0f, 1.0f, 1.0f);
    //Again: x, y, z
    glVertex3f(0.0f, -0.0001f, -0.01f);
    glVertex3f(0.0f, 0.0001f, -0.01f);
}
glEnd();

//Rotate on the x axis (pitch)
glRotatef(se::pl0.rX, 1.0f, 0.0f, 0.0f);
//Rotate viewport on the y axis (yaw)
glRotatef(se::pl0.rY, 0.0f, 1.0f, 0.0f);
//Translate the world by the negative of our coordinates
//Camera one way = objects the other...
glTranslatef(-se::pl0.x, -se::pl0.y, -se::pl0.z);

glCallList(1);

//Show the screen we have been calculating, preparing the screen we were showing for drawing
SDL_GL_SwapBuffers();
return;
}

void initDisplayLists(void)
{
glGenLists(1);

cube block = cube();

glNewList(1, GL_COMPILE);
{
    block.render();
}
glEndList();

return;
}

You should probably beef up your error checking a bit (you're not doing it very often).

For one thing, it's illegal to call glBindTexture in a glBegin/glEnd block (it needs to go before glBegin). Fix these illegal calls, add some extra error checking in your render loop, and see if that solves your problem.

Also, don't do this: while(glGetError());

If you have errors you should be throwing exceptions or logging them at the very least, it's not very smart to just throw away any outstanding OpenGL errors. Generally they are trying to tell you something important.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM