(转载翻译) 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;
    }

 

 

 

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