既然你已經配置好了SDL, 是時候來建立一個能加載并顯示一張圖片的基本圖形程序了。
//啟動SDL并創建窗口
bool initSDL();
//加載媒體
bool loadMedia();
//釋放媒體并關閉SDL
void closeSDL();
在第一個教程中,我們將所有內容都放在 main 函數中。由于它是一個小程序,我們可以這樣,但在實際程序中,代碼盡可能模塊化。這意味著你的代碼是整齊的塊,每個塊都易于調試和重用。
這意味著我們有處理初始化、加載媒體和關閉 SDL 應用程序的函數。我們在源文件的頂部附近聲明這些函數。
//要渲染的窗口指針
SDL_Window* gWindow = NULL;
//窗口包含的表面
SDL_Surface* gScreenSurface = NULL;
//我們將載入并顯示在屏幕上的圖像
SDL_Surface* gHelloWorld = NULL;
這里我們聲明了一些全局變量。通常,你應該避免在大型程序中使用全局變量。我們在這里這樣做的原因是因為我們希望源代碼盡可能簡單,但是在大型項目中全局變量會使事情變得更加復雜。由于這是一個單一的源文件程序,我們不必太擔心。
這是一種稱為 SDL 表面的新數據類型。SDL 表面只是一種圖像數據類型,它包含圖像的像素以及渲染它所需的所有數據。SDL 表面使用軟件渲染,這意味著它使用 CPU 進行渲染。可以渲染硬件圖像,但它有點困難,所以我們將首先通過簡單的方法學習它。在以后的教程中,我們將介紹如何渲染 GPU 加速圖像。
我們將在這里處理的圖像是屏幕圖像(您在窗口內看到的)和我們將從文件加載的圖像。
請注意,這些是指向 SDL 表面的指針。原因是 :
- 我們將動態分配內存來加載圖像
- 最好按內存位置引用圖像。想象一下,你有一個磚墻游戲,由多次渲染的相同磚塊圖像組成(如超級馬里奧兄弟)。當您可以擁有圖像的一個副本并一遍又一遍地渲染它時,在內存中擁有數十個圖像副本是很浪費的。
另外,請始終記住初始化您的指針。我們在聲明它們時立即將它們設置為 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
{
//創建窗口
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;
}
在上面的代碼中,我們已經獲取了SDL初始化和窗口創建代碼,并將其放在自己的函數中。
我們想在窗口內顯示圖像,為了做到這一點,我們需要獲得窗口內的圖像。因此,我們調用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 文件的路徑并返回加載的表面。如果該函數返回 NULL,則意味著它失敗,因此我們使用 SDL_GetError 將錯誤打印到控制臺。
需要注意的重要一點是,這段代碼假設您的工作目錄中有一個名為“assets/02”的目錄,其中包含一個名為“hello_world.bmp”的圖像。工作目錄是您的應用程序認為它正在運行的地方。通常,您的工作目錄是可執行文件所在的目錄,但某些程序(如 Visual Studio)會將工作目錄更改為 vcxproj 文件所在的位置。因此,如果您的應用程序找不到該圖像,請確保它位于正確的位置。
同樣,如果程序正在運行但無法加載圖像,則您可能有工作目錄問題。工作目錄的功能因操作系統和 IDE 不同而異。
void closeSDL()
{
//釋放表面內存
SDL_FreeSurface(gHelloWorld);
gHelloWorld = NULL;
//銷毀窗口
SDL_DestroyWindow(gWindow);
gWindow = NULL;
//退出SDL子系統
SDL_Quit();
}
在我們的清理代碼中,我們像以前一樣銷毀窗口并退出SDL,但我們還必須注意我們裝載的表面。我們通過使用sdl_freessurface來釋放它。不要擔心屏幕表面,SDL_DestroyWindow會處理它。
當指針沒有指向任何東西時,請確保養成讓指針指向NULL的習慣。
int main( int argc, char* args[] )
{
//啟動SDL并創建窗口
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 );
在我們的主函數中,我們初始化 SDL 并加載圖像。如果成功,我們使用 SDL_BlitSurface 將加載的表面 blit 到屏幕表面上。
塊傳輸的作用是獲取源表面并將其副本標記到目標表面上。SDL_BlitSurface 的第一個參數是源圖像。第三個參數是目的地。我們將在以后的教程中學習第二個和第四個參數。
現在,如果這是我們唯一的繪圖代碼,我們仍然不會在屏幕上看到我們加載的圖像。還差一步。
//更新窗口表面
SDL_UpdateWindowSurface( gWindow );
在屏幕上繪制了我們想要為該幀顯示的所有內容后,我們必須使用 SDL_UpdateWindowSurface 更新屏幕。當你在屏幕上繪圖時,你通常不會在屏幕上看到你看到的圖像。默認情況下,大多數渲染系統都是雙緩沖的。這兩個緩沖區是前緩沖區和后緩沖區。
當你進行像 SDL_BlitSurface 這樣的繪制調用時,你渲染到后臺緩沖區。您在屏幕上看到的是前端緩沖區。我們這樣做的原因是因為大多數框架需要在屏幕上繪制多個對象。如果我們只有一個前端緩沖區,我們將能夠看到正在繪制的幀,這意味著我們會看到未完成的幀。所以我們要做的是首先將所有內容繪制到后臺緩沖區,完成后我們交換后臺緩沖區和前臺緩沖區,這樣現在用戶就可以看到完成的幀了。
這也意味著您不會在每個 blit 之后調用 SDL_UpdateWindowSurface,只有在當前幀的所有 blit 都完成之后才會調用。
//等待2秒
SDL_Delay( 2000 );
}
}
//釋放資源和關閉SDL
closeSDL();
return 0;
}
現在我們已經把所有東西都渲染到了窗口上,我們延遲了兩秒鐘,這樣窗口就不會消失了。等待完成后,我們關閉我們的程序。
-
程序
+關注
關注
117文章
3791瀏覽量
81153 -
函數
+關注
關注
3文章
4338瀏覽量
62735 -
main
+關注
關注
0文章
38瀏覽量
6172
發布評論請先 登錄
相關推薦
評論