简体   繁体   English

使用 SDL 加载 OpenGL 纹理

[英]OpenGL texture loading with SDL

I have started learning OpenGL using NeHe tutorials for a little while.This is the code for lesson 6.It should load a bmp image and use it as texture for the cube I'm drawing.But It doesn't work properly and the cube remains white at all.The function for loading the image is "loadGLTextures".Can anyone help?我已经开始使用 NeHe 教程学习 OpenGL 一段时间了。这是第 6 课的代码。它应该加载一个 bmp 图像并将其用作我正在绘制的立方体的纹理。但是它不能正常工作,并且立方体仍然是白色的。加载图像的功能是“loadGLTextures”。有人可以帮忙吗? My image bit depth is 24.I'm working with Visual Studio 2010.我的图像位深度是 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();
    }

}

This is the image I'm trying to load.这是我正在尝试加载的图像

I use the SOIL library, http://www.lonesock.net/soil.html ,我使用 SOIL 库, http://www.lonesock.net/soil.html

It's a very easy to use OpenGL texture loader library, you don't have to worry about the image format or make any loading code yourself, it will do it all for you.这是一个非常易于使用的 OpenGL 纹理加载库,您不必担心图像格式或自己编写任何加载代码,它会为您完成所有工作。

Loading a texture is as easy as this:加载纹理就像这样简单:

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 };

I was able to get your program to produce a texture (although it was mirrored) by changing:通过更改,我能够让您的程序生成纹理(尽管它是镜像的):

        textureImage->h , 0 , GL_RGB , GL_UNSIGNED_BYTE , 

to:到:

        textureImage->h , 0 , GL_RGBA , GL_UNSIGNED_BYTE , 

Getting that field wrong unfortunately does not produce any error.不幸的是,将该字段弄错并不会产生任何错误。 It may cause your program to crash if you attempt to tell the GL that the image data is bigger than it really is, but passing GL_RGB instead of GL_RGBA has the effect of saying it's smaller than it really is.如果你试图告诉 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.请记住, SDL_LoadBMP()不会尝试转换图像数据,因此您必须确保 BMP 文件的格式是程序所期望的。 you probably need to use GL_RGBA or GL_RGB.您可能需要使用 GL_RGBA 或 GL_RGB。

Everything depends on your image's format.一切都取决于您的图像格式。 As Michael said SDL_LoadBMP does not convert the image data.正如迈克尔所说SDL_LoadBMP不转换图像数据。 So you can't be sure which flag you should pass.所以你不能确定你应该通过哪个标志。
I recommend you to use SDL_Image library.我建议您使用SDL_Image库。 Which converts all the image formats to one specific format.它将所有图像格式转换为一种特定格式。 Then you can use (for example) GL_RGBA flag and make sure everything works!然后您可以使用(例如) GL_RGBA标志并确保一切正常!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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