2

我已经开始使用 NeHe 教程学习 OpenGL。这是第 6 课的代码。它应该加载一个 bmp 图像并将其用作我正在绘制的立方体的纹理。但是它不能正常工作并且立方体完全保持白色。加载图像的功能是“loadGLTextures”。有人可以帮忙吗?我的图像位深度是 24。我正在使用 Visual Studio 2010。

#include <Windows.h>
#include <stdio.h>
#include <gl\GL.h>
#include <gl\GLU.h>
#include <SDL\SDL.h>


#pragma comment(lib , "SDL.lib")
#pragma comment(lib , "SDLmain.lib")
#pragma comment(lib , "OPENGL32.lib")
#pragma comment(lib , "glu32.lib")


//height , width and bit depth
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define SCREEN_BPP 16

//SDL surface
SDL_Surface* surface;

//Texture storage.
GLuint texture[1];

//Quit func.
void Quit(int returnCode)
{
    SDL_Quit();
    exit(returnCode);
}

//This function will load a bitmap image.
bool loadGLTextures(void)
{
    SDL_Surface* textureImage;
    textureImage = SDL_LoadBMP("123.bmp");
    if(!textureImage)
    {
        fprintf(stderr , "Couldn't load %s.\n" , "123.bmp");
        return false;
    }

    else
    {
        //Create the texture.
        glGenTextures(1 , &texture[0]);

        //Typical texture generation using data from the bitmap.
        glBindTexture(GL_TEXTURE_2D , texture[0]);

        //Generate the texture.
        glTexImage2D(GL_TEXTURE_2D , 0 , 3 , textureImage->w , 
            textureImage->h , 0 , GL_RGB , GL_UNSIGNED_BYTE , 
            textureImage->pixels);

        //Linear filtering.
        glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR);

        //Free up the memory.
        if(textureImage)
            SDL_FreeSurface(textureImage);

        return true;
    }

}

//All of the drawing goes throw this.
int drawGLScene(void)
{
    static float xrot = 0 , yrot = 0 , zrot = 0;
    //Clear screen and depth buffer.
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glTranslatef(0.0f , 0.0f , -5.0f);
    glRotatef(xrot , 1.0f , 0.0f , 0.0f);
    glRotatef(yrot , 0.0f , 1.0f , 0.0f);
    glRotatef(zrot , 0.0f , 0.0f  ,1.0f);

    //Select the texture.
    glBindTexture(GL_TEXTURE_2D , texture[0]);

    glBegin(GL_QUADS);
    //Front:
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(-1.0f , -1.0f , 1.0f);
    //Bottom right fo the texture and quad.
    glTexCoord2f(1.0f , 0.0f); glVertex3f(1.0f , -1.0f , 1.0f);
    //Top right of the texture and quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(1.0f , 1.0f , 1.0f);
    //Top left of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(-1.0f , 1.0f , 1.0f);

    //Back:
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(1.0f , -1.0f , -1.0f);
    //Bottom right of the texture and quad.
    glTexCoord2f(1.0f , 0.0f); glVertex3f(-1.0f , -1.0f , -1.0f);
    //Top right of the texture and the quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(-1.0f , 1.0f , -1.0f);
    //Top left of the texture and the quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(1.0f , 1.0f , -1.0f);

    //Top:
    //Top right of the texture and quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(1.0f , 1.0f , -1.0f);
    //Top left of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(-1.0f , 1.0f , -1.0f);
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(-1.0f , 1.0f , 1.0f);
    //Bottom right of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(1.0f , 1.0f , 1.0f);

    //Bottom:
    //Top left of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(-1.0f , -1.0f , 1.0f);
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(-1.0f , -1.0f , -1.0f);
    //Bottom right of the texture and quad.
    glTexCoord2f(1.0f , 0.0f); glVertex3f(1.0f , -1.0f , -1.0f);
    //Top right of the texture and quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(1.0f , -1.0f , 1.0f);

    //Right:
    //Bottom right of the texture and quad.
    glTexCoord2f(1.0f , 0.0f); glVertex3f(1.0f , -1.0f , -1.0f);
    //Top right of the texture and quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(1.0f , 1.0f , -1.0f);
    //Top left of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(1.0f , 1.0f , 1.0f);
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(1.0f , -1.0f , 1.0f);

    //Left:
    //Bottom left of the texture and quad.
    glTexCoord2f(0.0f , 0.0f); glVertex3f(-1.0f , -1.0f , -1.0f);
    //Bottom right of the texture and quad.
    glTexCoord2f(1.0f , 0.0f); glVertex3f(-1.0f , -1.0f , 1.0f);
    //Top right of the texture and quad.
    glTexCoord2f(1.0f , 1.0f); glVertex3f(-1.0f , 1.0f , 1.0f);
    //Top left of the texture and quad.
    glTexCoord2f(0.0f , 1.0f); glVertex3f(-1.0f , 1.0f , -1.0f);
    glEnd();

    SDL_GL_SwapBuffers();

    xrot += 0.1;
    yrot += 0.1;
    zrot += 0.1;

    return true;

}

//This function will reset our viewport after a windows resize.
int resizeWindow(int width , int height)
{
    //Height / width ration.
    float ratio;

    //Protect against a division by zero.
    if(height == 0)
        height = 1;

    ratio = width / height;

    //Setup viewport
    glViewport(0 , 0 , width , height);

    //Change to the projection matrix and reset it.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //set perspective.
    gluPerspective(45.0f , ratio , 0.1f , 100.0f);

    //Change to model view matrix and reset it.
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    return true;
}

//Toggle fullScreen.
void toggleFullscreen(SDL_Surface* screen)
{
    int videoFlags = screen->flags;
    (videoFlags & SDL_FULLSCREEN) == SDL_FULLSCREEN ? videoFlags ^= SDL_FULLSCREEN : videoFlags |= SDL_FULLSCREEN;//NICE!!
    screen = SDL_SetVideoMode(SCREEN_WIDTH , SCREEN_HEIGHT , SCREEN_BPP , videoFlags);
    resizeWindow(surface->w , surface->h);
    drawGLScene();
}

//OpenGL initialization.
int initGL(void)
{
    if(!loadGLTextures())
        return false;

    glShadeModel(GL_SMOOTH);
    glEnable(GL_TEXTURE_2D); //Enable texture mapping.
    glClearColor(0.0f , 0.0f , 0.0f , 0.5f);
    glClearDepth(1.0f);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LEQUAL);
    //Nice perspective.
    glHint(GL_PERSPECTIVE_CORRECTION_HINT , GL_NICEST);
    return true;
}

//This func will handle any key inputs.
void handleKeyPress(SDL_keysym* keysym)
{
    switch(keysym->sym)
    {
    case SDLK_ESCAPE:
            Quit(0);
            break;
    case SDLK_F1:
        toggleFullscreen(surface);
        break;
    case SDLK_r:
        drawGLScene();
        break;
    default:
        break;
    }
    return;
}


int main(int argc , char* argv[])
{
    //Flags to pass to SDL_SetVideoMode : awsome!! ints can be compiled.
    int videoFlags;
    //Event
    SDL_Event event;
    //Holds information about display.
    const SDL_VideoInfo* videoInfo;
    //Is window active?
    bool isActive = true;

    //SDL initialization.
    if(SDL_Init(SDL_INIT_VIDEO) < 0)
    {
        fprintf(stderr , "SDL video initialization failed : %s\n" , SDL_GetError());
        Quit(1);
    }

    //Fetch the video info.
    videoInfo = SDL_GetVideoInfo();

    if(!videoInfo)
    {
        fprintf(stderr , "Video query failed : %s\n" , SDL_GetError());
        Quit(1);
    }

    //Add flags to pass to SDL_SetVideoMode.
    videoFlags = SDL_OPENGL;              //Enable OpenGL in SDL.
    videoFlags |= SDL_GL_DOUBLEBUFFER;    //Enable double buffering.
    videoFlags |= SDL_HWPALETTE;          //Store the palette in hardware.
    videoFlags |= SDL_RESIZABLE;          //Enable window resizing.

    //This checks to see if surfaces can be stored in hardware.
    videoInfo->hw_available ? videoFlags |= SDL_HWSURFACE : SDL_SWSURFACE;

    //This checks if harware blits can be done.
    if(videoInfo->blit_hw)
        videoFlags |= SDL_HWACCEL;

    //Set OpenGL double buffering.
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER , 1);

    surface = SDL_SetVideoMode(SCREEN_WIDTH , SCREEN_HEIGHT , 16 , videoFlags);

    //verify the surface.
    if(!surface)
    {
        fprintf(stderr , "Video mode set failed : %s\n" , SDL_GetError());
        Quit(1);
    }

    SDL_WM_SetCaption("OpenGL-Sample" , 0);

    //initialize OpenGL
    if(initGL() == false)
    {
        fprintf(stderr , "Could not initialize OpenGL.\n");
        Quit(1);
    }

    //Main loop
    while(1)
    {
        //Handle the events in the queue.
        if(SDL_PollEvent(&event))
        {
            switch(event.type)
            {
            case SDL_ACTIVEEVENT:
                if(event.active.gain == 0)
                    isActive = false;
                else
                    isActive = true;
                break;
            case SDL_VIDEORESIZE:
                //Handle resize event.
                surface = SDL_SetVideoMode(event.resize.w , event.resize.h , SCREEN_BPP , videoFlags);
                if(!surface)
                {
                    fprintf(stderr , "Could not get a surface after resize : %s\n" , SDL_GetError());
                    Quit(1);
                }
                resizeWindow(event.resize.w , event.resize.h);
                break;
            case SDL_KEYDOWN:
                handleKeyPress(&event.key.keysym);
                break;
            case SDL_QUIT:
                Quit(0);
            default:
                break;
            }
        }
        if(isActive)
            drawGLScene();
    }

}

这是我要加载的图像。

4

3 回答 3

1

我使用 SOIL 库http://www.lonesock.net/soil.html

这是一个非常易于使用的 OpenGL 纹理加载器库,您不必担心图像格式或自己编写任何加载代码,它会为您完成这一切。

加载纹理就像这样简单:

int textureID = SOIL_load_OGL_texture("img.png", SOIL_LOAD_AUTO, 
    SOIL_CREATE_NEW_ID, SOIL_FLAG_MIPMAPS);
if(textureID == 0) { cout << "Failed to load texture!" << endl };
于 2012-11-08T21:41:57.600 回答
0

Everything depends on your image's format. As Michael said SDL_LoadBMP does not convert the image data. So you can't be sure which flag you should pass.
I recommend you to use SDL_Image library. Which converts all the image formats to one specific format. Then you can use (for example) GL_RGBA flag and make sure everything works!

于 2012-04-26T09:22:29.273 回答
0

通过更改,我能够让您的程序生成纹理(尽管它是镜像的):

        textureImage->h , 0 , GL_RGB , GL_UNSIGNED_BYTE , 

至:

        textureImage->h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 

不幸的是,弄错该字段不会产生任何错误。如果您试图告诉 GL 图像数据比实际数据大,它可能会导致您的程序崩溃,但是传递 GL_RGB 而不是 GL_RGBA 的效果是说它比实际数据小。

Keep in mind that SDL_LoadBMP() doesn't attempt to convert the image data, so you have to make sure the format of the BMP file is what the program expects. you probably need to use GL_RGBA or GL_RGB.

于 2012-04-26T09:03:46.123 回答