使用 SDL 加载 OpenGL 纹理
Posted
技术标签:
【中文标题】使用 SDL 加载 OpenGL 纹理【英文标题】:OpenGL texture loading with SDL 【发布时间】:2012-04-26 08:31:00 【问题描述】:我已经开始使用 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。
【问题讨论】:
使用glGetError
在GL调用后检查无效条件。
我找到了这个。但它不起作用。 content.gpwiki.org/index.php/…
【参考方案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 ;
【讨论】:
【参考方案2】:我能够通过更改让您的程序生成纹理(尽管它是镜像的):
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。
【讨论】:
【参考方案3】:一切都取决于您的图片格式。正如迈克尔所说,SDL_LoadBMP
不会转换图像数据。所以你不能确定你应该通过哪个标志。
我建议您使用SDL_Image
库。它将所有图像格式转换为一种特定格式。然后您可以使用(例如)GL_RGBA
标志并确保一切正常!
【讨论】:
SDL_image 也无法正常工作。如果您想查看,我已在问题末尾添加了图片。以上是关于使用 SDL 加载 OpenGL 纹理的主要内容,如果未能解决你的问题,请参考以下文章