SDL2 的一个主要新功能是纹理渲染 API。这为您提供了快速、灵活的基于硬件的渲染。在本教程中,我们将使用这种新的渲染技术。
//将单个图像作为纹理加载
SDL_Texture* loadTexture( std::string path );
//我们要渲染的窗口
SDL_Window* gWindow = NULL;
//窗口渲染器
SDL_Renderer* gRenderer = NULL;
//当前显示的纹理
SDL_Texture* gTexture = NULL;
SDL中的纹理有自己的数据类型,直观地称为SDL_Texture。当我们处理SDL纹理时,你需要一个SDL_Renderer来将它渲染到屏幕上,这就是为什么我们要声明一个名为 "gRenderer "的全局渲染器。
你也可以看到,我们有一个loadTexture的新图像加载例程和一个我们将要加载的全局声明的纹理。
//创建窗口
gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
if( gWindow == NULL )
{
printf( "Window could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//创建窗口的渲染器
gRenderer = SDL_CreateRenderer( gWindow, -1, SDL_RENDERER_ACCELERATED );
if( gRenderer == NULL )
{
printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
success = false;
}
else
{
//初始化渲染器颜色
SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF );
//初始化PNG加载
int imgFlags = IMG_INIT_PNG;
if( !( IMG_Init( imgFlags ) & imgFlags ) )
{
printf( "SDL_image could not initialize! SDL_image Error: %s\n", IMG_GetError() );
success = false;
}
}
}
在我们创建了窗口之后,我们必须为我们的窗口创建一个渲染器,这样我们就可以在上面渲染纹理,幸运的是这很容易通过调用SDL_CreateRenderer[1]来完成。幸运的是,只要调用SDL_CreateRenderer就可以轻松完成。
创建渲染器后,我们要使用SDL_SetRenderDrawColor[2]来初始化渲染颜色。这可以控制各种渲染操作使用什么颜色。
SDL_Texture* loadTexture( std::string path ){
//最终的纹理
SDL_Texture* newTexture = NULL;
//在指定路径加载图像
SDL_Surface* loadedSurface = IMG_Load( path.c_str() );
if( loadedSurface == NULL )
{
printf( "Unable to load image %s! SDL_image Error: %s\n", path.c_str(), IMG_GetError() );
}
else
{
//用表面像素创建纹理
newTexture = SDL_CreateTextureFromSurface( gRenderer, loadedSurface );
if( newTexture == NULL )
{
printf( "Unable to create texture from %s! SDL Error: %s\n", path.c_str(), SDL_GetError() );
}
//Get rid of old loaded surface
SDL_FreeSurface( loadedSurface );
}
return newTexture;
}
我们的纹理加载函数看起来和之前基本相同,只是现在我们没有将加载的表面转换为显示格式,而是使用SDL_CreateTextureFromSurface[3]从加载的表面中创建一个纹理。和之前一样,这个函数从一个现有的表面创建一个新的纹理,这意味着和之前一样,我们必须释放加载的表面,然后返回加载的纹理。
bool loadMedia(){
//Loading success flag
bool success = true;
//Load PNG texture
gTexture = loadTexture( "07_texture_loading_and_rendering/texture.png" );
if( gTexture == NULL )
{
printf( "Failed to load texture image!\n" );
success = false;
}
return success;
}
void close(){
//Free loaded image
SDL_DestroyTexture( gTexture );
gTexture = NULL;
//Destroy window
SDL_DestroyRenderer( gRenderer );
SDL_DestroyWindow( gWindow );
gWindow = NULL;
gRenderer = NULL;
//Quit SDL subsystems
IMG_Quit();
SDL_Quit();
}
由于纹理加载与我们的图像加载函数一起被抽象化了,所以loadMedia()函数的工作原理和之前差不多。
在我们的清理函数中,我们必须记住使用SDL_DestroyTexture[4]来deallocate我们的纹理。
//While application is running
while( !quit )
{
//Handle events on queue
while( SDL_PollEvent( &e ) != 0 )
{
//User requests quit
if( e.type == SDL_QUIT )
{
quit = true;
}
}
//清空屏幕
SDL_RenderClear( gRenderer );
//将纹理渲染到屏幕上
SDL_RenderCopy( gRenderer, gTexture, NULL, NULL );
//更新屏幕
SDL_RenderPresent( gRenderer );
}
在事件循环之后的主循环中,我们调用SDL_RenderClear[5]。这个函数用上次SDL_SetRenderDrawColor设置的颜色填充屏幕。
清空屏幕后,我们用SDL_RenderCopy[6]渲染纹理。纹理渲染完成后,我们仍然需要更新屏幕,但由于我们没有使用SDL_Surfaces来渲染,所以不能使用SDL_UpdateWindowSurface。相反,我们必须使用SDL_RenderPresent[7]。
在 这里[8]下载本教程的媒体和源代码。
原文链接[9]
关注我的公众号:编程之路从0到1
[1]
SDL_CreateRenderer: https://wiki.libsdl.org/SDL_CreateRenderer
[2]
SDL_SetRenderDrawColor: https://wiki.libsdl.org/SDL_SetRenderDrawColor
[3]
SDL_CreateTextureFromSurface: https://wiki.libsdl.org/SDL_CreateTextureFromSurface
[4]
SDL_DestroyTexture: https://wiki.libsdl.org/SDL_DestroyTexture
[5]
SDL_RenderClear: https://wiki.libsdl.org/SDL_RenderClear
[6]
SDL_RenderCopy: https://wiki.libsdl.org/SDL_RenderCopy
[7]
SDL_RenderPresent: https://wiki.libsdl.org/SDL_RenderPresent
[8]
这里: http://www.lazyfoo.net/tutorials/SDL/07_texture_loading_and_rendering/07_texture_loading_and_rendering.zip
[9]
原文链接: http://www.lazyfoo.net/tutorials/SDL/07_texture_loading_and_rendering/index.php