既然你已經(jīng)配置好了SDL, 是時候來建立一個能加載并顯示一張圖片的基本圖形程序了。
//啟動SDL并創(chuàng)建窗口
bool initSDL();
//加載媒體
bool loadMedia();
//釋放媒體并關(guān)閉SDL
void closeSDL();
在第一個教程中,我們將所有內(nèi)容都放在 main 函數(shù)中。由于它是一個小程序,我們可以這樣,但在實(shí)際程序中,代碼盡可能模塊化。這意味著你的代碼是整齊的塊,每個塊都易于調(diào)試和重用。
這意味著我們有處理初始化、加載媒體和關(guān)閉 SDL 應(yīng)用程序的函數(shù)。我們在源文件的頂部附近聲明這些函數(shù)。
//要渲染的窗口指針
SDL_Window* gWindow = NULL;
//窗口包含的表面
SDL_Surface* gScreenSurface = NULL;
//我們將載入并顯示在屏幕上的圖像
SDL_Surface* gHelloWorld = NULL;
這里我們聲明了一些全局變量。通常,你應(yīng)該避免在大型程序中使用全局變量。我們在這里這樣做的原因是因?yàn)槲覀兿M创a盡可能簡單,但是在大型項(xiàng)目中全局變量會使事情變得更加復(fù)雜。由于這是一個單一的源文件程序,我們不必太擔(dān)心。
這是一種稱為 SDL 表面的新數(shù)據(jù)類型。SDL 表面只是一種圖像數(shù)據(jù)類型,它包含圖像的像素以及渲染它所需的所有數(shù)據(jù)。SDL 表面使用軟件渲染,這意味著它使用 CPU 進(jìn)行渲染。可以渲染硬件圖像,但它有點(diǎn)困難,所以我們將首先通過簡單的方法學(xué)習(xí)它。在以后的教程中,我們將介紹如何渲染 GPU 加速圖像。
我們將在這里處理的圖像是屏幕圖像(您在窗口內(nèi)看到的)和我們將從文件加載的圖像。
請注意,這些是指向 SDL 表面的指針。原因是 :
- 我們將動態(tài)分配內(nèi)存來加載圖像
- 最好按內(nèi)存位置引用圖像。想象一下,你有一個磚墻游戲,由多次渲染的相同磚塊圖像組成(如超級馬里奧兄弟)。當(dāng)您可以擁有圖像的一個副本并一遍又一遍地渲染它時,在內(nèi)存中擁有數(shù)十個圖像副本是很浪費(fèi)的。
另外,請始終記住初始化您的指針。我們在聲明它們時立即將它們設(shè)置為 NULL。
bool initSDL()
{
//初始化SDL
if (SDL_Init(SDL_INIT_VIDEO) < 0)
{
SDL_Log("SDL could not initialize! SDL_Error: %s\\n", SDL_GetError());
return false;
}
else
{
//創(chuàng)建窗口
gWindow = SDL_CreateWindow("SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
if (gWindow == NULL)
{
SDL_Log("Window could not be created! SDL_Error: %s\\n", SDL_GetError());
return false;
}
else
{
//獲取窗口表面
gScreenSurface = SDL_GetWindowSurface(gWindow);
}
}
return true;
}
在上面的代碼中,我們已經(jīng)獲取了SDL初始化和窗口創(chuàng)建代碼,并將其放在自己的函數(shù)中。
我們想在窗口內(nèi)顯示圖像,為了做到這一點(diǎn),我們需要獲得窗口內(nèi)的圖像。因此,我們調(diào)用SDL_GetWindowSurface來獲取窗口所包含的表面。
bool loadMedia()
{
//加載圖片
gHelloWorld = SDL_LoadBMP("assets/02/hello_world.bmp");
if (gHelloWorld == NULL)
{
SDL_Log("Unable to load image %s! SDL Error: %s\\n", "assets/02/hello_world.bmp", SDL_GetError());
return false;
}
return true;
}
在加載媒體功能中,我們使用 SDL_LoadBMP 加載我們的圖像。SDL_LoadBMP 接受 bmp 文件的路徑并返回加載的表面。如果該函數(shù)返回 NULL,則意味著它失敗,因此我們使用 SDL_GetError 將錯誤打印到控制臺。
需要注意的重要一點(diǎn)是,這段代碼假設(shè)您的工作目錄中有一個名為“assets/02”的目錄,其中包含一個名為“hello_world.bmp”的圖像。工作目錄是您的應(yīng)用程序認(rèn)為它正在運(yùn)行的地方。通常,您的工作目錄是可執(zhí)行文件所在的目錄,但某些程序(如 Visual Studio)會將工作目錄更改為 vcxproj 文件所在的位置。因此,如果您的應(yīng)用程序找不到該圖像,請確保它位于正確的位置。
同樣,如果程序正在運(yùn)行但無法加載圖像,則您可能有工作目錄問題。工作目錄的功能因操作系統(tǒng)和 IDE 不同而異。
void closeSDL()
{
//釋放表面內(nèi)存
SDL_FreeSurface(gHelloWorld);
gHelloWorld = NULL;
//銷毀窗口
SDL_DestroyWindow(gWindow);
gWindow = NULL;
//退出SDL子系統(tǒng)
SDL_Quit();
}
在我們的清理代碼中,我們像以前一樣銷毀窗口并退出SDL,但我們還必須注意我們裝載的表面。我們通過使用sdl_freessurface來釋放它。不要擔(dān)心屏幕表面,SDL_DestroyWindow會處理它。
當(dāng)指針沒有指向任何東西時,請確保養(yǎng)成讓指針指向NULL的習(xí)慣。
int main( int argc, char* args[] )
{
//啟動SDL并創(chuàng)建窗口
if( !initSDL() )
{
SDL_Log( "Failed to initialize!\\n" );
}
else
{
//加載媒體
if( !loadMedia() )
{
SDL_Log( "Failed to load media!\\n" );
}
else
{
//在窗口上顯示圖片
SDL_BlitSurface( gHelloWorld, NULL, gScreenSurface, NULL );
在我們的主函數(shù)中,我們初始化 SDL 并加載圖像。如果成功,我們使用 SDL_BlitSurface 將加載的表面 blit 到屏幕表面上。
塊傳輸?shù)淖饔檬谦@取源表面并將其副本標(biāo)記到目標(biāo)表面上。SDL_BlitSurface 的第一個參數(shù)是源圖像。第三個參數(shù)是目的地。我們將在以后的教程中學(xué)習(xí)第二個和第四個參數(shù)。
現(xiàn)在,如果這是我們唯一的繪圖代碼,我們?nèi)匀徊粫谄聊簧峡吹轿覀兗虞d的圖像。還差一步。
//更新窗口表面
SDL_UpdateWindowSurface( gWindow );
在屏幕上繪制了我們想要為該幀顯示的所有內(nèi)容后,我們必須使用 SDL_UpdateWindowSurface 更新屏幕。當(dāng)你在屏幕上繪圖時,你通常不會在屏幕上看到你看到的圖像。默認(rèn)情況下,大多數(shù)渲染系統(tǒng)都是雙緩沖的。這兩個緩沖區(qū)是前緩沖區(qū)和后緩沖區(qū)。
當(dāng)你進(jìn)行像 SDL_BlitSurface 這樣的繪制調(diào)用時,你渲染到后臺緩沖區(qū)。您在屏幕上看到的是前端緩沖區(qū)。我們這樣做的原因是因?yàn)榇蠖鄶?shù)框架需要在屏幕上繪制多個對象。如果我們只有一個前端緩沖區(qū),我們將能夠看到正在繪制的幀,這意味著我們會看到未完成的幀。所以我們要做的是首先將所有內(nèi)容繪制到后臺緩沖區(qū),完成后我們交換后臺緩沖區(qū)和前臺緩沖區(qū),這樣現(xiàn)在用戶就可以看到完成的幀了。
這也意味著您不會在每個 blit 之后調(diào)用 SDL_UpdateWindowSurface,只有在當(dāng)前幀的所有 blit 都完成之后才會調(diào)用。
//等待2秒
SDL_Delay( 2000 );
}
}
//釋放資源和關(guān)閉SDL
closeSDL();
return 0;
}
現(xiàn)在我們已經(jīng)把所有東西都渲染到了窗口上,我們延遲了兩秒鐘,這樣窗口就不會消失了。等待完成后,我們關(guān)閉我們的程序。
-
程序
+關(guān)注
關(guān)注
117文章
3788瀏覽量
81109 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4333瀏覽量
62705 -
main
+關(guān)注
關(guān)注
0文章
38瀏覽量
6170
發(fā)布評論請先 登錄
相關(guān)推薦
評論