SDL 2 游戏编程(二)显示图片

原文链接Getting an Image on the Screen

注意:从这个教程开始,我们只会贴上关键的源代码,完整的程序在文章的最后。

//Starts up SDL and creates window
bool init();

//Loads media
bool loadMedia();

//Frees media and shuts down SDL
void close();

第一个教程中,我们把所有的操作都放在了main函数中。第一个教程的程序很小所以这么做并没有什么问题,然后在真正的程序中做好模块化是很重要的。

上面的代码片段分别声明了init,loadMedia,close三个函数,这些声明出现在源代码的开头附近。

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;

//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;

这段定义了一些全局变量,在较大的程序中你可能会尽量避免使用全局变量。但是我们这么做只是想让这个程序变得尽可能的简单,但是在较大的程序中全局变量会使得事情变得更复杂。由于这个程序只由一个文件组成,所以这方面不需要太多的担心。

这里有个新的数据类型叫做SDL Surface。它包含了图像的像素,以及渲染这个图像所需要的所有信息。SDL surface使用CPU进行渲染。当然我们也可以使用GPU进行更快速的渲染,但是这么做会复杂一点,以后再讲。

我们要处理的图像是屏幕图像(你在窗口里看到图像)还有从文件中读取的图像。

注意这些是指向SDL surface的指针。原因有两个,第一个是,我们将会动态的分配内存来读取图片。第二个是,使用地址来引用一个图片更好一点,假设你要画一面墙,这个墙由许多一模一样的砖块组成,那么你需要渲染很多次砖块。如果创建一堆砖块的拷贝是很浪费内存的。

还有要记得初始化你的指针,我们在声明的同时初始化为NULL。

bool init()
{
    //Initialization flag
    bool success = true;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = false;
    }
    else
    {
        //Create window
        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
        {
            //Get window surface
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }

    return success;
}

init函数包含了SDL的初始化以及创建窗口等操作。

这里调用了SDL_GetWindowSurface函数,这个函数返回一个窗口中图像框的指针,这样我们才能对图像框进行操作。

bool loadMedia()
{
    //Loading success flag
    bool success = true;

    //Load splash image
    gHelloWorld = SDL_LoadBMP( "02_getting_an_image_on_the_screen/hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
        success = false;
    }

    return success;
}

loadMedia函数中,使用了SDL_LoadBMP函数。SDL_LoadBMP函数需要一个bmp图片的地址作为参数,然后会返回读取的图片的SDL surface。如果返回值是NULL,说明读取图片失败了,这个时候可以调用SDL_GetError函数得到错误信息并在控制台打印错误信息。

图像地址的路径问题嘛,懒得翻了~

void close()
{
    //Deallocate surface
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;

    //Destroy window
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;

    //Quit SDL subsystems
    SDL_Quit();
}

close函数呢,和上一个教程最后的析构过程差不多,但是由于我们读取了一个图片文件,所以需要手动释放图片文件占用的内存。SDL_FreeSurface函数会帮助我们完成这个任务。

在使用完一个指针后记得将指针设定成NULL。这个是一个好习惯。

int main( int argc, char* args[] )
{
    //Start up SDL and create window
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        //Load media
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            //Apply the image
            SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );

main函数中,在成功执行完init和loadMedia函数后,我们需要将读取的文件放到窗口的图像框中。这里用到位块传输函数SDL_BlitSurface。第一个参数是刚才读取的图像文件的SDL surface,第三个参数是放置的位置,也就是窗口图像框的SDL surface。第二和第四个参数以后的教程里会讲的。

当然和上一个教程一样,我们需要更新窗口才能看到图片。所以~

            //Update the surface
            SDL_UpdateWindowSurface( gWindow );

需要这一步更深层的原因是,大部分的渲染系统都采用了双重缓冲区。这里就把这两个缓冲区称为前缓冲区和后缓冲区吧。

当你在屏幕上绘制图形或者调用SDL_UpdateWindowSurface函数的时候,绘制的图形会被渲染到后缓冲区,而在屏幕上看到的是前缓冲区。那为什么不能绘制的同时让它显示在屏幕上呢,原因很简单,如果只使用前缓冲区的话,你会看到没有绘制完的图形,影响用户体验~

            //Wait two seconds
            SDL_Delay( 2000 );
        }
    }

    //Free resources and close SDL
    close();

    return 0;
}

现在我们已经渲染完窗口的所有图形,窗口出现两秒后,程序会自动结束。

/*This source code copyrighted by Lazy Foo' Productions (2004-2015)
and may not be redistributed without written permission.*/

//Using SDL and standard IO
#include <SDL.h>
#include <stdio.h>

//Screen dimension constants
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

//Starts up SDL and creates window
bool init();

//Loads media
bool loadMedia();

//Frees media and shuts down SDL
void close();

//The window we'll be rendering to
SDL_Window* gWindow = NULL;

//The surface contained by the window
SDL_Surface* gScreenSurface = NULL;

//The image we will load and show on the screen
SDL_Surface* gHelloWorld = NULL;

bool init()
{
    //Initialization flag
    bool success = true;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        printf( "SDL could not initialize! SDL_Error: %s\n", SDL_GetError() );
        success = false;
    }
    else
    {
        //Create window
        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
        {
            //Get window surface
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }

    return success;
}

bool loadMedia()
{
    //Loading success flag
    bool success = true;

    //Load splash image
    gHelloWorld = SDL_LoadBMP( "../02_getting_an_image_on_the_screen/hello_world.bmp" );
    if( gHelloWorld == NULL )
    {
        printf( "Unable to load image %s! SDL Error: %s\n", "02_getting_an_image_on_the_screen/hello_world.bmp", SDL_GetError() );
        success = false;
    }

    return success;
}

void close()
{
    //Deallocate surface
    SDL_FreeSurface( gHelloWorld );
    gHelloWorld = NULL;

    //Destroy window
    SDL_DestroyWindow( gWindow );
    gWindow = NULL;

    //Quit SDL subsystems
    SDL_Quit();
}

int main( int argc, char* args[] )
{
    //Start up SDL and create window
    if( !init() )
    {
        printf( "Failed to initialize!\n" );
    }
    else
    {
        //Load media
        if( !loadMedia() )
        {
            printf( "Failed to load media!\n" );
        }
        else
        {
            //Apply the image
            SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );

            //Update the surface
            SDL_UpdateWindowSurface( gWindow );

            //Wait two seconds
            SDL_Delay( 2000 );
        }
    }

    //Free resources and close SDL
    close();

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值