(轉載翻譯) SDL編程 第1課:Hello World

第1課:你好世界

         在本課中,我們將學習如何打開一個窗口,創建一個渲染上下文,並繪製一個我們已經加載到屏幕上的圖像。獲取BMP,我們將在下面繪製並保存它在你的項目中的某個地方,讓我們開始吧!

 

啓動SDL

      爲了使用SDL,我們首先需要初始化我們想要使用的各種SDL子系統。這是通過 SDL_Init 完成的,它使用一組標誌或一起指定要初始化的子系統。現在我們只需要視頻子系統,但我們將添加更多的標誌,因爲我們需要更多的功能。注意,當視頻系統本身沒有顯式請求而文件I/O和線程系統默認被初始化時,事件處理系統被自動初始化。如果一切順利,SDL_Init 將返回0,如果不是,我們將打印出錯誤並退出。

if (SDL_Init(SDL_INIT_VIDEO) != 0){
	std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
	return 1;
}

創建窗口

      我們需要一個窗口來顯示我們的渲染,我們可以創建一個帶有SDL_CreateWindow的渲染窗口,它獲取窗口的標題、創建它的x和y位置、窗口寬度和高度以及一些設置窗口屬性的標誌,並返回一個SDL_.*。如果創建窗口時出現任何錯誤,此指針將爲空。如果確實發生錯誤,我們需要在退出程序之前清理SDL。

SDL_Window *win = SDL_CreateWindow("Hello World!", 100, 100, 640, 480, SDL_WINDOW_SHOWN);
if (win == nullptr){
	std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
	SDL_Quit();
	return 1;
}

 

創建渲染器

      現在我們可以創建一個渲染器來使用SDL_CreateRenderer繪製到窗口。 此函數使用窗口將渲染器與要使用的渲染驅動程序的索引相關聯(或-1以選擇滿足我們要求的第一個)以及用於指定我們想要的渲染器類型的各種標誌。 這裏我們要求啓用了vsync的硬件加速渲染器。 我們將返回一個SDL_Renderer *,如果出現問題,它將爲NULL。 如果確實發生了錯誤,我們需要清理我們之前創建的任何內容,並在退出程序之前退出SDL。

SDL_Renderer *ren = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if (ren == nullptr){
	SDL_DestroyWindow(win);
	std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
	SDL_Quit();
	return 1;
}

 

加載位圖圖像 

       要渲染BMP圖像,我們需要將其加載到內存中,然後加載到我們正在使用的渲染平臺上(在本例中爲GPU)。 我們可以使用SDL_LoadBMP加載圖像,它會返回一個SDL_Surface *然後我們可以將其上傳到渲染器能夠使用的SDL_Texture。
SDL_LoadBMP獲取我們圖像的文件路徑,您應該更改它以匹配您的項目結構,並在出現問題時返回SDL_Surface *或NULL。

std::string imagePath = getResourcePath("Lesson1") + "hello.bmp";
SDL_Surface *bmp = SDL_LoadBMP(imagePath.c_str());
if (bmp == nullptr){
	SDL_DestroyRenderer(ren);
	SDL_DestroyWindow(win);
	std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
	SDL_Quit();
	return 1;
}

加載圖像後,我們現在可以使用SDL_CreateTextureFromSurface將其上傳到渲染器。 我們傳入渲染上下文以上傳到內存中的圖像(SDL_Surface)並獲取加載的紋理,如果出現問題,我們將返回NULL。 此時我們還完成了原始表面,所以我們現在就把它釋放出來。

SDL_Texture *tex = SDL_CreateTextureFromSurface(ren, bmp);
SDL_FreeSurface(bmp);
if (tex == nullptr){
	SDL_DestroyRenderer(ren);
	SDL_DestroyWindow(win);
	std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
	SDL_Quit();
	return 1;
}

繪製紋理

剩下要做的就是在屏幕上獲取我們的紋理! 首先,我們將清除渲染器,然後渲染紋理,然後顯示更新的屏幕以顯示結果。 由於我們想要渲染整個圖像並使其伸展以填充屏幕,因此我們將傳遞NULL作爲SDL_RenderCopy的源和目標矩形。 我們還希望保持窗口一段時間,以便我們可以在程序退出之前看到結果,因此我們將添加對SDL_Delay的調用。

我們將所有這些渲染代碼放在我們程序的主循環中,現在這將是一個簡單的for循環。 通過循環的每次迭代我們都會睡一秒鐘,所以我們可以增加或減少計數器,使我們的程序運行更長或更短的時間。 當我們進入事件處理時,我們將改爲跟蹤一個布爾值,該布爾值指示用戶是否想要退出我們的程序(例如,單擊窗口上的X)並在這種情況下退出循環。

//A sleepy rendering loop, wait for 3 seconds and render and present the screen each time
for (int i = 0; i < 3; ++i){
	//First clear the renderer
	SDL_RenderClear(ren);
	//Draw the texture
	SDL_RenderCopy(ren, tex, NULL, NULL);
	//Update the screen
	SDL_RenderPresent(ren);
	//Take a quick break after all that hard work
	SDL_Delay(1000);
}

打掃乾淨

       在退出之前,我們必須通過各種SDL_DestroyX函數銷燬創建的所有對象並退出SDL。 錯誤處理注意事項:以前在程序中我們可能遇到錯誤並提前退出,在這種情況下,我們必須銷燬我們創建的任何SDL對象並退出SDL以在退出之前正確清理。 從課程中省略了錯誤處理的這一部分,因爲它們是如此小的例子,它有助於保持代碼更短,但在現實世界的程序中,絕對需要正確的錯誤處理和清理。

SDL_DestroyTexture(tex);
SDL_DestroyRenderer(ren);
SDL_DestroyWindow(win);
SDL_Quit();

 

課程結束 

      如果一切順利,你應該看到你加載的圖像在整個窗口上呈現,等待2秒然後退出。 如果您有任何問題,請確保已安裝SDL並正確配置項目,如第0課:設置SDL中所述,或在下面發佈問題。

 

 

完整代碼:

#include "SDL.h"
    #include <iostream>
    //#include <stdio.h>
     
    int main(int argc, char* argv[]) {
     
        SDL_Window* window = NULL;             // Declare a pointer
        SDL_Renderer* renderer = NULL;         //渲染器
        SDL_Surface* bmp = NULL;
     
        
        // 初始化SDL
        // int SDLCALL SDL_Init(Uint32 flags)
        //SDL_INIT_TIMER:定時器
        //SDL_INIT_AUDIO:音頻
        //SDL_INIT_VIDEO:視頻
        //SDL_INIT_JOYSTICK:搖桿
        //SDL_INIT_HAPTIC:觸摸屏
        //SDL_INIT_GAMECONTROLLER:遊戲控制器
        //SDL_INIT_EVENTS:事件
        //SDL_INIT_NOPARACHUTE:不捕獲關鍵信號(這個不理解)
        //SDL_INIT_EVERYTHING:包含上述所有選項 
        if(SDL_Init(SDL_INIT_EVERYTHING) != 0)
        {
            std::cout << "SDL_Init Error: " << SDL_GetError() << std::endl;
            return 1;
        }
     
        
        // 使用以下設置創建應用程序窗口:
        // SDL_Window * SDLCALL SDL_CreateWindow(const char *title,int x, int y, int w, int h, Uint32 flags);
        //參數含義如下。
        //title	:窗口標題
        // x	:窗口位置x座標。也可以設置爲SDL_WINDOWPOS_CENTERED或SDL_WINDOWPOS_UNDEFINED。
        // y	:窗口位置y座標。同上。
        // w	:窗口的寬
        // h	:窗口的高
        // flags :支持下列標識。包括了窗口的是否最大化、最小化,能否調整邊界等等屬性。
        // SDL_WINDOW_FULLSCREEN    全屏窗口
        // SDL_WINDOW_FULLSCREEN_DESKTOP  當前桌面分辨率下的全屏窗口
        // SDL_WINDOW_OPENGL    使用OpenGL上下文的窗口
        // SDL_WINDOW_VULKAN  與Vulkan實例一起使用的窗口
        // SDL_WINDOW_HIDDEN    窗口不可見
        // SDL_WINDOW_BORDERLESS  無窗裝飾
        // SDL_WINDOW_RESIZABLE  窗口可以調整大小
        // SDL_WINDOW_MINIMIZED   最小化窗口
        // SDL_WINDOW_MAXIMIZED  最大化窗口
        // SDL_WINDOW_INPUT_GRABBED  窗口抓住輸入焦點
        // SDL_WINDOW_ALLOW_HIGHDPI  如果支持,窗口應該在高DPI模式下創建(> = SDL2.0.1)
        // SDL_WINDOW_SHOWN  可見窗口
        // SDL_WINDOW_POPUP_MENU  窗口應被視爲彈出式菜單(x11,>=SDL 2.0.5)
        // SDL_WINDOW_TOOLTIP  窗口應被視爲工具提示(X11,> = SDL 2.0.5)
        // SDL_WINDOW_UTILITY  窗口應視爲實用窗口(x11,>=SDL 2.0.5)
        // SDL_WINDOW_SKIP_TASKBAR  窗口不應該添加到任務欄(X11,> = SDL 2.0.5)
        // SDL_WINDOW_ALWAYS_ON_TOP  窗口應該總是高於其他(x11,>=SDL 2.0.5)
        // SDL_WINDOW_MOUSE_CAPTURE  窗口已捕獲鼠標(與輸入的抓取無關,> = SDL 2.0.4)
        // SDL_WINDOW_FOREIGN  不由SDL創建的窗口
        // SDL_WINDOW_MOUSE_FOCUS   窗口有鼠標焦點
        // SDL_WINDOW_INPUT_FOCUS   窗口有輸入焦點
        // 返回創建完成的窗口的ID。如果創建失敗則返回0。
        window = SDL_CreateWindow(
            "開軟網絡科技有限公司",                  // window title
            SDL_WINDOWPOS_UNDEFINED,           // initial x position
            SDL_WINDOWPOS_UNDEFINED,           // initial y position
            1365,                               // width, in pixels
            768,                               // height, in pixels
            SDL_WINDOW_SHOWN                  // flags - see below
        );
        // 檢查窗口是否成功創建
        if (window == nullptr)
        {
            std::cout << "SDL_CreateWindow Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
        
        
        // SDL中使用SDL_CreateRenderer()基於窗口創建渲染器。SDL_CreateRenderer()原型如下。
        // SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags);
        // 參數含義如下。
        // window	: 渲染的目標窗口。
        // index	:打算初始化的渲染設備的索引。設置“-1”則初始化默認的渲染設備。
        // flags	:支持以下值(位於SDL_RendererFlags定義中)
        // SDL_RENDERER_SOFTWARE :使用軟件渲染
        // SDL_RENDERER_ACCELERATED :使用硬件加速
        // SDL_RENDERER_PRESENTVSYNC:和顯示器的刷新率同步
        // SDL_RENDERER_TARGETTEXTURE :不太懂
        // 返回創建完成的渲染器的ID。如果創建失敗則返回NULL。
        renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
        // 檢查渲染器是否成功創建
        if (renderer == nullptr)
        {
            SDL_DestroyWindow(window);
            std::cout << "SDL_CreateRenderer Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
        
        
        
        
        //加載圖片
        bmp = SDL_LoadBMP("images/kairuan.bmp");
        if (bmp == nullptr)
        {
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            std::cout << "SDL_LoadBMP Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
        
        
        
        
        
        SDL_Texture *tex = SDL_CreateTextureFromSurface(renderer, bmp);
	SDL_FreeSurface(bmp);
        if (tex == nullptr)
        {
            SDL_DestroyRenderer(renderer);
            SDL_DestroyWindow(window);
            std::cout << "SDL_CreateTextureFromSurface Error: " << SDL_GetError() << std::endl;
            SDL_Quit();
            return 1;
        }
        
        
        
        
        
        
	// 窗口是打開的:可以在這裏輸入程序循環(see SDL_PollEvent())
        //A sleepy rendering loop, wait for 3 seconds and render and present the screen each time
        for (int i = 0; i < 3; ++i)
        {
            //First clear the renderer
            SDL_RenderClear(renderer);
            //Draw the texture
            SDL_RenderCopy(renderer, tex, NULL, NULL);
            //Update the screen
            SDL_RenderPresent(renderer);
            //Take a quick break after all that hard work
            SDL_Delay(1000);
        }
        
        
        
        
        // 關閉並摧毀窗戶
        SDL_DestroyTexture(tex);
	SDL_DestroyRenderer(renderer);
        SDL_DestroyWindow(window);
        
     
        // 清理
        SDL_Quit();
        return 0;
    }

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章