使用 SDL 加载 OpenGL 纹理

OpenGL texture loading with SDL

本文关键字:纹理 OpenGL 加载 SDL 使用      更新时间:2023-10-16

我开始使用NeHe教程学习OpenGL已经有一段时间了。这是课程的代码 6.It 应该加载一个 bmp 图像并将其用作我正在绘制的立方体的纹理。但它不能正常工作,立方体根本不是白色的。加载图像的函数是"loadGLTextures"。谁能帮忙?我的图像位深度是 24.我正在使用 Visual Studio 2010。

#include <Windows.h>
#include <stdio.h>
#include <glGL.h>
#include <glGLU.h>
#include <SDLSDL.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 : %sn" , SDL_GetError());
        Quit(1);
    }
    //Fetch the video info.
    videoInfo = SDL_GetVideoInfo();
    if(!videoInfo)
    {
        fprintf(stderr , "Video query failed : %sn" , 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 : %sn" , 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 : %sn" , 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();
    }
}

这是我尝试加载的图像。

我使用土壤库,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 };

我能够通过更改以下内容让您的程序产生纹理(尽管它是镜像的):

        textureImage->h , 0 , GL_RGB , GL_UNSIGNED_BYTE , 

自:

        textureImage->h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 

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

请记住,SDL_LoadBMP()不会尝试转换图像数据,因此您必须确保BMP文件的格式是程序期望的。 您可能需要使用GL_RGBA或GL_RGB。

一切都取决于您的图像格式。正如迈克尔所说SDL_LoadBMP不会转换图像数据。所以你无法确定你应该通过哪个标志。
我建议您使用SDL_Image库。它将所有图像格式转换为一种特定格式。然后,您可以使用(例如)GL_RGBA标志并确保一切正常!