用SDL加载OpenGL纹理

时间:2012-04-26 08:31:01

标签: c++ opengl sdl sdl-opengl

我已经开始使用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();
    }

}

这是我正在尝试加载的image

3 个答案:

答案 0 :(得分: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 };

答案 1 :(得分:0)

通过更改:

,我能够让你的程序产生一个纹理(虽然它是镜像的)
        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。

答案 2 :(得分:0)

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