1.0 SDL 简介

文章目录

  • 1.0 SDL 简介
    • 1.1 什么是 SDL?
    • 1.2 SDL 可以做什么?
  • 2. 在VS上获取和安装 SDL
    • 2.1 SDL2库下载
    • 2.2 安装SDL2
    • 2.3 在Visual Studio中使用SDL
  • 3. SDL2教程
    • 3.1 简单窗口
    • 3.2 在屏幕上显示一张图片
      • 模块化基本函数
        • 非全局变量
        • 全局变量
      • 显示图片
      • Surface直接修改像素
      • 指定输出坐标
      • 输出部分图片
    • 3.3 事件处理
      • 事件处理流程
      • 键盘事件
    • 3.4 渲染器
      • 窗口渲染器
      • 渲染器绘制图片

1.1 什么是 SDL?

Simple DirectMedia Layer 是一个跨平台开发库,旨在通过 OpenGL 和 Direct3D 提供对音频、键盘、鼠标、游戏杆和图形硬件的低级访问。它被视频播放软件、模拟器和流行游戏使用,包括Valve的获奖目录和许多Humble Bundle游戏。

1.2 SDL 可以做什么?

视频

  • 3D图形:SDL 可与 OpenGL API 或 Direct3D API 结合使用,用于 3D 图形
  • 加速 2D 渲染 API:支持简单的旋转、缩放和 alpha 混合,所有这些都使用现代 3D API 加速,使用 OpenGL 和 Direct3D 支持加速
  • 创建和管理多个窗口

输入事件

  • 提供的事件和 API 函数用于:

    • 应用程序和窗口状态更改
    • 鼠标输入
    • 键盘输入
    • 操纵杆和游戏控制器输入
    • 多点触控手势
  • 可以使用SDL_EventState ()启用或禁用每个事件
  • 事件在发布到内部事件队列之前通过用户指定的过滤器函数
  • 线程安全事件队列

力反馈

  • Windows、Mac OS X 和 Linux 支持力反馈

音频

  • 设置8位和16位音频、单声道立体声或5.1环绕声的音频播放,如果硬件不支持格式,可选择转换
  • 音频在单独的线程中独立运行,通过用户回调机制填充
  • 专为定制软件混音器设计,但SDL_mixer提供完整的音频/音乐输出库

文件 I/O 抽象

  • 用于打开、读取和写入数据的通用抽象
  • 对文件和内存的内置支持

共享对象支持

  • 加载共享对象(Windows 上的 DLL,Mac OS X 上的 .dylib,Linux 上的 .so)
  • 共享对象中的查找函数

线程

  • 简单的线程创建API
  • 简单线程本地存储API
  • 互斥体、信号量和条件变量
  • 无锁编程的原子操作

计时器

  • 获取经过的毫秒数
  • 等待指定的毫秒数
  • 在单独的线程中创建与代码一起运行的计时器
  • 使用高分辨率计数器进行分析

CPU 特性检测

  • 查询CPU数量
  • 检测 CPU 特性和支持的指令集

大端小端支持

  • 检测当前系统的字节序
  • 用于快速交换数据值的例程
  • 读取和写入指定字节序的数据

电池管理

  • 查询电源管理状态

2. 在VS上获取和安装 SDL

2.1 SDL2库下载

  • SDL2 核心库 SDL2

  • SDL2 拓展库 SDL2_image、SDL2_ttf、SDL2_mixer、SDL2_net

  • SDL2 第三方绘图库SDL2_gfx 官网 SDL2_gfx Github

2.2 安装SDL2

  1. 点击SDL2 核心库下载下载SDL2库,如下图根据编译器选择不同版本(Visual Studo系列选择第一个)。

  2. 下载出来会有一个压缩包,放到一个合适的目录(记住这个目录哦,经常要用的),解压。

  3. 进入解压后的目录,如下图:

  • docs:文档目录,只不过都是英文的
  • include:头文件目录,编程需要的
  • lib:库目录(静态库和动态库都有)

  1. 给环境变量添加库目录,让程序运行的时候能够找到动态库。PS:配置好了记得重启Vs

2.3 在Visual Studio中使用SDL

  1. 创建一个空项目,如下图:

  1. 进入菜单栏的项目->属性->VC++ 目录,配置包含目录和库目录(详见下图),注意库目录的版本和你的项目版本要一直哦(图中两个三角形标记的位置,我这是x64的)。

  1. 不要离开,还有静态库需要配置,进入链接器->输入->点击附加依赖项->填入SDL2.lib和SDLmain2.lib,然后确定就好

  2. 最后加入如下代码,Ctrl+F5运行

#include<SDL.h>int main(int argc,char*argv[])
{//初始化SDLif (SDL_Init(SDL_INIT_VIDEO) <0){SDL_Log("can not init SDL:%s", SDL_GetError());return -1;}return 0;
}

如果能出现黑窗口并且,没有任何错误提示,那么就恭喜你啦,SDL配置完成(不过麻烦的是每次创建新项目和在x86、x64之间切换时,都要进行配置后面将讲解更方便的方法)!

SDL 作为动态链接库。动态链接库包含 3 个部分:

  • 头文件 (Library.h)
  • 库文件(Windows 的Library.lib 或 *nix 的libLibrary.a)
  • 二进制文件(Windows 的Library.dll 或*nix 的Library.so)

你的编译器需要能够在编译时找到头文件,以便它知道SDL 函数和结构是什么。可以将编译器配置为在 SDL 头文件所在的附加目录中进行搜索,或者将头文件与编译器附带的其余头文件一起放入。如果编译器提示找不到 SDL.h,则意味着头文件不在编译器查找头文件的位置。

在编译器编译所有源文件后,它必须将它们链接在一起。为了使程序正确链接,它需要知道所有函数的地址,包括 SDL 函数的地址。对于动态链接库,这些地址在库文件中。库文件具有导入地址表,因此您的程序可以在运行时导入函数。与头文件一样,您可以将编译器配置为在 SDL 库文件所在的附加目录中进行搜索,或者将库文件与编译器附带的其余库文件一起放入。您还必须告诉链接器链接到链接器中的库文件。如果链接器报错找不到-lSDL或SDL2.lib,它意味着库文件不在链接器寻找库文件的地方。 如果链接器报错了一个未定义的引用,这可能意味着它没有链接这个库。

在您的程序被编译和链接之后,您需要能够在运行时链接到该库。为了运行动态链接的应用程序,您需要能够在运行时导入库二进制文件。当您运行程序时,您的操作系统需要能够找到库二进制文件。您可以将库二进制文件放在与可执行文件相同的目录中,也可以放在操作系统保存库二进制文件的目录中。

3. SDL2教程

  • SDL2 维基文档

  • SDL2各种教程集合

3.1 简单窗口

#include<SDL.h>//屏幕尺寸常量
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

首先包含SDL.h头文件。 然后定义我们需要的窗口宽度和高度常量。

int main(int argc,char*argv[])
{//初始化SDL子系统if (SDL_Init(SDL_INIT_VIDEO) != 0){SDL_Log("can not init SDL:%s", SDL_GetError());return -1;}
}

注意主函数的形参,必须是一个整型,后跟上一个char*数组(参数分别代表命令行参数个数和命令行参数数组),不能是其他形式的main函数!

在主函数中我们先调用SDL_init初始化函数,如果不先初始化 SDL,就不能调用任何 SDL 函数。暂时我们只需要SDL的视频子系统,所以我们先只将 SDL_INIT_VIDEO 标志传递给它。

当发生错误时,SDL_Init 返回 负数。当出现错误时,我们可以将具体的错误原因打印到控制台。

在SDL中有一个和printf函数功能相同的函数,即SDL_Log。然后用SDL_GetError获取错误字符串并打印出来。

 //创建窗口SDL_Window*window = SDL_CreateWindow(u8"在此处添加标题",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT,SDL_WINDOW_SHOWN);//判断是否创建成功if (!window){SDL_Log("can not  create window:%s", SDL_GetError());return -1;}

如果SDL成功初始化,我们将使用SDL_CreateWindow创建一个窗口。

  • 第一个参数设置窗口的标题;

  • 接下来两个参数分别是窗口的x和y,即窗口在屏幕上的位置,我们不关心位置在那里,所以直接传SDL_WINDOWPOS_UNDEFINED即可;

  • 接下来的两个参数分别表示窗口的宽度和高度

  • 最后一个参数表示窗口创建成功之后显示出来。

如果有错误,SDL_CreateWindow 返回 NULL。我们将错误打印到控制台。

如果窗口被成功创建,则会显示到桌面。

为了防止它消失,我们将调用SDL_Delay。 SDL_Delay将等待给定的毫秒数。 一毫秒是千分之一秒。 这意味着上面的代码将使窗口等待2000 /1000秒或2秒。

需要注意的重要一点是,当SDL延迟时,它不能接受来自键盘或鼠标的输入。 当您运行这个程序时,如果它没有响应,请不要惊慌。 我们没有给它处理鼠标和键盘的代码

 //延迟5秒SDL_Delay(5000);//销毁窗口SDL_DestroyWindow(window);//清理所有初始化的子系统SDL_Quit();return 0;
}

最后我们让程序延迟5秒再退出,否则窗口会一闪而过;退出之前需要调用SDL_DestroyWindow手动销毁窗口和调用SDL_Quit清理所有初始化的子系统

3.2 在屏幕上显示一张图片

既然你已经配置好了SDL, 是时候来建立一个能加载并显示一张图片的基本图形程序了。

//启动SDL并创建窗口
bool init(const char*title,int width,int height);//释放媒体并关闭SDL
void clean();

在第一个教程中,我们将所有内容都放在 main 函数中。由于它是一个小程序,我们可以这样,但在实际程序中,代码尽可能模块化。这意味着你的代码是整齐的块,每个块都易于调试和重用。

模块化基本函数

非全局变量

SDL_Surface这是一种称为 SDL 表面的新数据类型。SDL 表面只是一种图像数据类型,它包含图像的像素以及渲染它所需的所有数据。SDL 表面使用软件渲染,这意味着它使用 CPU 进行渲染。可以渲染硬件图像,但它有点困难,所以我们将首先通过简单的方法学习它。在以后的教程中,我们将介绍如何渲染 GPU 加速图像。

使用SDL_GetWindowSurface来获取窗口的表面,这样才能对窗口进行操作。

​ 注意是winsfc是指向 SDL 表面的指针

​ 使用的不是全局变量,是在main函数中定义的,当然你也可以定义全局变量

//初始化库
void init(SDL_Window** window, SDL_Surface** winsfc);
//清除库
void clear(SDL_Window** window);
void init(SDL_Window** window,SDL_Surface** winsfc)
{//先初始化SDL库if (0 != SDL_Init(SDL_INIT_VIDEO)){SDL_Log("sdl init failed,%s\n", SDL_GetError());exit(-1);}IMG_Init(IMG_INIT_PNG);//创建窗口*window = SDL_CreateWindow(u8"在这里输入标题", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);if (!(* window)){SDL_Log("window failed,%s\n", SDL_GetError());exit(-1);}//创建表面*winsfc = SDL_GetWindowSurface(*window);if (!(*winsfc)){SDL_Log("winsfc failed,%s\n", SDL_GetError());exit(-1);}
}
void clear(SDL_Window** window)
{//更新窗口SDL_UpdateWindowSurface(*window);//窗口延迟SDL_Delay(5000);//关闭窗口SDL_DestroyWindow(*window);//关闭SDLSDL_Quit();
}
全局变量

​ 将window 和 winsfc声明全局即可,无需传递二级指针对一级指针修改,但通常应当避免声明全局变量

//要渲染的窗口指针
SDL_Window* gWindow = NULL;//窗口包含的表面
SDL_Surface* gWinSfc = NULL;

请始终记住初始化您的指针。我们在声明它们时立即将它们设置为 NULL。

bool init(const char*title,int width,int height)
{//初始化SDLif (SDL_Init(SDL_INIT_VIDEO) != 0){return false;}//创建窗口gWindow = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, width, height, SDL_WINDOW_SHOWN);if (!gWindow){return false;}//获取窗口表面gWinSfc = SDL_GetWindowSurface(gWindow);if (!gWinSfc){return false;}return true;
}

在上面的代码中,我们已经获取了SDL初始化和窗口创建代码,并将其放在自己的函数中。

显示图片

我们想在窗口内显示图像,为了做到这一点,我们需要获得窗口内的图像。 因此,我们调用SDL_GetWindowSurface来获取窗口所包含的表面

void clean()
{SDL_DestroyWindow(gWindow);SDL_Quit();
}

在我们的清理代码中,我们像以前一样销毁窗口并退出SDL。

使用sdl_LoadBMP来加载图片,注意只能是bmp图片,但是可以通过安装SDL的扩展image插件来使用其他类型的图片,安装过程请看上面的安装部分

int main(int argc, char* argv[])
{if (!init(u8"SDL2教程", 640, 480)){SDL_Log("Failed to initialize!\n");}//加载图片SDL_Surface* sfc = SDL_LoadBMP("./assets/lesson02/hello_world.bmp");if (!sfc){SDL_Log("surface load failed,%s\n", SDL_GetError());}else{//把图片显示到窗口上SDL_BlitSurface(sfc, NULL, gWinSfc, NULL);}

在我们的主函数中,我们初始化 SDL 并加载图像。

如果成功,我们使用 SDL_BlitSurface 将加载的表面 blit 到屏幕表面上。

块传输的作用是获取源表面并将其副本标记到目标表面上。SDL_BlitSurface 的第一个参数是源图像。第三个参数是目的地。我们将在以后的教程中学习第二个和第四个参数。

现在,如果这是我们唯一的绘图代码,我们仍然不会在屏幕上看到我们加载的图像。还差一步。

        //更新窗口表面SDL_UpdateWindowSurface( gWindow );

在屏幕上绘制了我们想要为该帧显示的所有内容后。

我们必须使用 SDL_UpdateWindowSurface 更新屏幕

当你在屏幕上绘图时,你通常不会在屏幕上看到你看到的图像。默认情况下,大多数渲染系统都是双缓冲的。这两个缓冲区是前缓冲区和后缓冲区。

当你进行像 SDL_BlitSurface 这样的绘制调用时,你渲染到后台缓冲区。您在屏幕上看到的是前端缓冲区。我们这样做的原因是因为大多数框架需要在屏幕上绘制多个对象。如果我们只有一个前端缓冲区,我们将能够看到正在绘制的帧,这意味着我们会看到未完成的帧。所以我们要做的是首先将所有内容绘制到后台缓冲区,完成后我们交换后台缓冲区和前台缓冲区,这样现在用户就可以看到完成的帧了。

这也意味着您不会在每个 blit 之后调用 SDL_UpdateWindowSurface,只有在当前帧的所有 blit 都完成之后才会调用。

            //等待2秒SDL_Delay( 2000 );//释放表面SDL_FreeSurface(sfc);}}//释放资源和关闭SDLclean();return 0;
}

现在我们已经把所有东西都渲染到了窗口上,我们延迟了两秒钟,这样窗口就不会消失了。等待完成后,我们关闭我们的程序。

Surface直接修改像素

//输出像素格式
SDL_Log("%d\n", sfc->format->format);
//输出人看得懂的像素格式
SDL_Log("%s\n", SDL_GetPixelFormatName(sfc->format->format));

先输出sfc的像素格式,像素格式是由枚举SDL_PixelFormatEnum定义的,如果输出的是318769153,即对应的枚举是SDL_PIXELFORMAT_INDEX8,说明一个像素由八位表示(也就是图片是一张黑白图)。

如果要修改图片,让他能够呈现彩色,必须先对图片的格式进行转换。

sfc = SDL_ConvertSurface(sfc, gWinSfc->format, 0);

通过SDL_ConvertSurface可以把sfc的像素格式转为指定的像素格式(这里是窗口的),然后进行修改像素

//修改图片的像素
Uint32* pixels = sfc->pixels;
for (int i = 0; i < 100; i++)
{pixels[i] = 0xff00ff;//SDL_MapRGBA(sfc->format,255,0,0,255);
}

上面的代码在图片上画了一条品红色的线条。

指定输出坐标

SDL_Rect  rect = { 50,50,0,0 };
//把图片显示到窗口上
SDL_BlitSurface(sfc, NULL, gWinSfc, &rect);

SDL_BlitSurface可以将sfc输出到gWinSfc,那么如何指定输出坐标呢,这个可以通过最后一个参数指定,这个参数需要一个SDL_Rect结构,而且只有x,y有效,w,h将被忽略,所以置为0即可!

输出部分图片

SDL_Rect scaleRect = { 10,156,50,50 };
//把图片显示到窗口上
SDL_BlitSurface(sfc, &scaleRect, gWinSfc, NULL);

如果不想把整张图片都输出,则可以指定输出的图片中的某个矩形区域。

3.3 事件处理

事件处理流程

除了将图像放在屏幕上之外,游戏还要求您处理来自用户的输入。您可以使用 SDL事件处理系统来做到这一点。(把一下代码放到main函数中)

            //主循环标志bool isDone = false;

在输出表面和更新窗口表面之后,我们声明了一个退出标志,用于跟踪用户是否已退出。由于此时我们刚刚启动了应用程序,显然它被初始化为false。

我们还声明了一个SDL_Event联合。SDL事件是有意义的,比如 按键、 鼠标移动、 操纵杆 按钮按下等。在这个应用程序中,我们将找到退出事件来结束应用程序。

             //应用程序主循环while( !isDone ){

在之前的教程中,我们让程序在关闭前等待几秒钟。 在这个应用程序中,我们让应用程序等到用户退出后才关闭。

当用户没有退出时,我们会有应用程序循环。 这种在应用程序处于活动状态时持续运行的循环称为主循环,有时也称为游戏循环。 它是任何游戏应用程序的核心。

                 //事件处理static SDL_Event ev ={0};//处理队列上的事件while( SDL_PollEvent( &ev ) != 0 ){//用户请求退出if( ev.type == SDL_QUIT ){isDone = true;}}

在主循环里面写了事件循环。 这样做的作用是继续处理事件队列,直到它为空。

当您按下一个键、移动鼠标或触摸触摸屏时,事件就会被放到事件队列中。

然后事件队列将按照事件发生的顺序存储它们,等待您处理它们。 当您想知道发生了什么事件以便处理它们时,您可以轮询事件队列,通过调用SDL_PollEvent获取最近的事件。 SDL_PollEvent所做的就是从事件队列中取出最近的事件,并将该事件中的数据放入我们传递给函数的SDL_Event中。

SDL_PollEvent 将不断从队列中取出事件,直到队列为空。当队列为空时,SDL_PollEvent 将返回 0。所以这段代码所做的就是不断轮询事件队列中的事件,直到它为空。如果来自事件队列的事件是 SDL_QUIT 事件(用户点击窗口右上角关闭按钮产生的事件),我们将退出标志设置为 true,以便我们可以退出应用程序。

                //输出图片SDL_BlitSurface( gXOut, NULL, gScreenSurface, NULL );//更新窗口表面SDL_UpdateWindowSurface( gWindow );}

在我们处理完一帧的事件后,我们绘制到屏幕并更新它(如上一教程中所述)。如果退出标志设置为真,应用程序将在循环结束时退出。如果它仍然是假的,它将一直持续到用户 X 掉窗口。

键盘事件

退出事件只是 SDL 能够处理的事件之一。在游戏中大量使用的另一种输入是键盘。在本教程中,我们将根据您按下的键对图像进行移动

在全局变量中,我们声明了不同表面的枚举。

//要渲染的窗口指针
SDL_Window* gWindow = NULL;//窗口包含的表面
SDL_Surface* gWinSfc = NULL;//启动SDL并创建窗口
bool init(const char* title, int width, int height);//释放媒体并关闭SDL
void clean();//加载图片
SDL_Surface* loadSurface(const char* filename)

除了常用的函数原型之外,我们还有一个名为loadSurface的新函数。 专门用来加载图片,以及在出错时能快速定位。

对于这个程序来说,我们有一个指向SDL表面的指针,叫做gSfc,它指向了我们将要使用的图像。 根据用户按下的按键,我们将把gSfc进行移动。

SDL_Surface* loadSurface(const char* filename)
{SDL_Surface * surface = SDL_LoadBMP(filename);if (surface == NULL){SDL_Log("Unable to load image %s! SDL Error: %s\n", filename, SDL_GetError());return NULL;}return surface;
}

上面是loadSurface函数,它加载图像并在出现错误时报告错误。 它与以前的方法基本相同,但是将图像加载和错误报告包含在一个函数中可以很容易地添加和调试图像加载。

要记得最后要在clean函数中释放加载的表面哦~

    //加载图片gSfc = loadSurface("./assets/lesson02/hello_world.bmp");//定义坐标点int x = 0;int y = 0;//主循环标志bool quit = false;while (!quit){

在main函数中,在进入主循环之前,我们先将图片进行加载,并且定义坐标点x和y。

   static SDL_Event ev;//处理队列中的事件while (SDL_PollEvent(&ev)){if (ev.type == SDL_QUIT){quit = true;}//按键按下else if (ev.type == SDL_KEYDOWN){switch (ev.key.keysym.sym){case SDLK_UP:y--;break;case SDLK_DOWN:y++;break;case SDLK_LEFT:x--;break;case SDLK_RIGHT:x++;break;default:x = 0;y = 0;break;}}}//清屏SDL_FillRect(gWinSfc, NULL, 0xffff);SDL_Rect posRect = { x,y,0,0 };//在窗口上显示图片SDL_BlitSurface(gSfc, NULL, gWinSfc, &posRect);SDL_UpdateWindowSurface(gWindow);}

这是我们的事件循环。如您所见,我们像在上一个教程中一样处理关闭窗口,然后处理 SDL_KEYDOWN 事件。当您按下键盘上的某个键时,就会发生此事件。SDL 事件内部 是一个 SDL 键盘事件,它包含按键事件的信息。里面是一个 SDL Keysym,它包含有关按下的键的信息。该 Keysym 包含标识按下的键的 SDL 键码。 如您所见,此代码的作用是根据按下的键设置表面。如果您想了解其他键的其他键码是什么,请查看 SDL 文档。

键盘移动增强版本

​ SDL_GetKeyboardState函数

获取键盘当前状态的快照。返回的指针是一个指向内部 SDL数组的指针

它将在应用程序的整个生命周期内有效,不应该被调用者释放。值为1的数组元素表示该键已按下,值为0的表示该键未按下。这个数组的索引是使用 SDL_Scancode值。使用SDL_PumpEvents O更新状态数组。

     int num = 0;if (SDL_GetKeyboardState(&num)[SDL_SCANCODE_UP]){role_y--;}if (SDL_GetKeyboardState(&num)[SDL_SCANCODE_DOWN]){role_y++;}if (SDL_GetKeyboardState(&num)[SDL_SCANCODE_LEFT]){role_x--;}if (SDL_GetKeyboardState(&num)[SDL_SCANCODE_RIGHT]){role_x++;}

3.4 渲染器

​ 前面学习的图片是由surface加载的,SDL2中新增了texture渲染器

​ surface:软件加速

texture :硬件加速 (更快)

​ 渲染器:render

窗口渲染器

​ 1. SDL_CreateRenderer函数,创建窗口渲染器

//创建窗口渲染器SDL_Renderer* render = SDL_CreateRenderer(window, -1, 0);

​ 渲染器画一条线:SDL_RenderDrawLine函数

​ 设置画线的颜色:SDL_SetRenderDrawColor函数,可以设置任何东西的颜色,不局限于图形,比如设置窗口颜色,加上清屏函数SDL_RenderClear达到清屏的效果

//设置背景颜色
SDL_SetRenderDrawColor(render, 255, 0, 255, 255);
SDL_RenderClear(render);//设置渲染器绘制颜色
SDL_SetRenderDrawColor(render, 255, 255, 255, 255);
//绘制一条线
SDL_RenderDrawLine(render, 0, 0, 640, 480);

​ 渲染器绘制图形: 填充矩形

​ SDL_RenderFillRect

//绘制图形
SDL_SetRenderDrawColor(render, 255, 100, 100, 255);
SDL_Rect rect = { 100,100,50,50 }; //设置矩形的尺寸
SDL_RenderFillRect(render, &rect);

渲染器绘制图片

​ 首先要加载图片:利用surface加载图片然后将surface转换为texture,然后释放:surface;

​ SDL_CreateTextureFromSurface函数格式转换

​ SDL_FreeSurface函数释放surface

//加载图片
SDL_Surface* winsfc = IMG_Load("./1.png");
if (!winsfc)
{SDL_Log("%s\n", SDL_GetError());
}
//把surface转成texture
SDL_Texture* wintexture =SDL_CreateTextureFromSurface(render,winsfc);
//释放surface
SDL_FreeSurface(winsfc);

得到了渲染器texture格式的图片,然后再载入图片:SDL_RenderCopy函数载入图片

//绘制图片SDL_Rect srcRect = { 100,100,100,200 };   //设置原始图片的尺寸SDL_Rect dstRect = { 20,0,200,200 };    //设置目标图形的位置SDL_RenderCopy(render, wintexture, &srcRect, &dstRect);

别忘了调用渲染器:(否则不会显示图片与图形)

//渲染器登场
SDL_RenderPresent(render);

​ 销毁渲染器

SDL_DestroyTexture(wintexture);

总结:图片类型的加载渲染器要快于surface的加载

本章函数内容总结:

    SDL_Init();                      //初始化窗口SDL_Quit();                      //清除信息,用于退出SDL_Log();                        //相当于printf  cout 打印SDL_GetError();                 //输出错误信息SDL_CreateWindow();             //创建窗口SDL_DestroyWindow();          //销毁窗口SDL_Delay();                  //延迟窗户SDL_UpdateWindowSurface();        //更新窗口SDL_GetWindowSurface();           //获取窗口表面SDL_FillRect();                 //窗口填充颜色SDL_LoadBMP();                  //加载图片SDL_BlitSurface();                //显示图片到窗口SDL_PollEvent();               //处理事件消息SDL_GetKeyboardState();         //快速获取键盘消息SDL_CreateRenderer();         //创建渲染器窗口SDL_RenderDrawLine();          //渲染器画线SDL_SetRenderDrawColor();        //设置渲染器颜色SDL_RenderFillRect();          //渲染器画填充矩形SDL_RenderPresent();          //调用渲染器SDL_DestroyRenderer();           //销毁渲染器SDL_CreateTextureFromSurface();  //将surface的图片转换为texture渲染器格式SDL_FreeSurface();              //释放surface指针SDL_RenderCopy();              //载入图片

持续更新SDL2教程…

SDL教程零基础入门 简单操作 day1相关推荐

  1. 视频教程-19全新mysql教程零基础入门实战精讲mysql视频DBA数据库视频教程SQL教程-MySQL

    19全新mysql教程零基础入门实战精讲mysql视频DBA数据库视频教程SQL教程 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有node/ja ...

  2. 视频教程-20年Nodejs教程零基础入门到项目实战前端视频教程-Node.js

    20年Nodejs教程零基础入门到项目实战前端视频教程 7年的开发架构经验,曾就职于国内一线互联网公司,开发工程师,现在是某创业公司技术负责人, 擅长语言有node/java/python,专注于服务 ...

  3. Marvelous Designer布料和角色服装造型完整教程零基础入门到精通实用教学视频教程

    Marvelous Designer布料和角色服装造型完整教程零基础入门到精通实用教学视频教程 marvelous designer是目前世界上最流行的服装打板和模拟软件,能够即时的演算服装的打板,外 ...

  4. python零基础入门教程-零基础入门Python爬虫不知道怎么学?这是入门的完整教程...

    原标题:零基础入门Python爬虫不知道怎么学?这是入门的完整教程 这是一个适用于小白的Python爬虫免费教学课程,只有7节,让零基础的你初步了解爬虫,跟着课程内容能自己爬取资源.看着文章,打开电脑 ...

  5. 零基础自学python教程-零基础入门学习Python_Python教程

    教程名称:零基础入门学习Python 课程目录: [易源码www.pnp8.com]000愉快的开始 [易源码www.pnp8.com]001我和Python的第一次亲密接触 [易源码www.pnp8 ...

  6. go语言教程零基础入门到精通

    精选文章 在Windows10安装部署Golang开发环境 Go语言生成二维码是如此简单 一文让你知道为什么学了PHP的都要转学Go语言 免费获取Git GO Java视频教程 用 PHP和Golan ...

  7. rxjava面试题,android教程零基础入门

    网易游戏 严格来说我投的是网易互娱(区别于雷火&盘古,后面再说更多区别),走的内推.网易游戏以其笔试难度大著名,这次也不例外:所有的内推都要求参加统一笔试,我记得笔试有几场,我是在第一场.内推 ...

  8. 【JAVA零基础入门系列】Day1 开发环境搭建

    一.安装JDK java的sdk简称JDK ,去其官方网站下载最近的JDK即可. http://www.oracle.com/technetwork/java/javase/downloads/jdk ...

  9. python怎么输出浮点数_python 零基础入门教程第 2 章:基本数据类型 (一)

    一.什么是数据类型 编程语言通过一些复杂的计算机物理底层机制,创造不同类型的数据,用来表示现实世界中的不同信息,以便于计算机更好的存储和计算. 每种编程语言都会有一些基本的数据类型用来表示现实世界中的 ...

最新文章

  1. CSS学习18之小试牛刀
  2. [树状数组] Inverse
  3. 关于客户端用ASP参生报表
  4. 《Unbroken》
  5. centos-安装python3.6环境并配置虚拟环境
  6. linux下安装xz命令
  7. 菜单向上拉html,模拟select控件,CSS上拉菜单
  8. 【C++】内建函数对象
  9. 图书借阅系统UML建模
  10. 【期权系列】顶部和底部信号:期权看跌看涨比(PCR)
  11. UVA10142/PC110108Australian Voting
  12. dubbo问题:forbid consumer报错
  13. Python:缓存库mo-cache支持内存、文件、Redis
  14. Ubuntu之必装软件
  15. 美妆个护市场真的相信“小鲜肉”吗?
  16. Laravelblade模板语法初体验
  17. 老师教我们用计算机画画就是彩虹,拼音ang、eg、ing、ong教学课件.ppt
  18. mybatis ognl表达式
  19. Expires / Cache-Control / Last-Modified / If-Modified-Since / ETag / If-None-Match 区别使用
  20. MySQLPlugin之如何编写Auth Plugin

热门文章

  1. 华为深度Linux系统使用教程,华为笔记本OEM版本Linux系统安装深度商店(deepin-appstore)的方法...
  2. Berkeley DB
  3. EPB电子驻车制动系统Simulink模型(参考VDA305_100标准进行模型搭建)
  4. 从SGS认识晚安月亮纸尿裤,换个角度更专业
  5. php编写润平年,【PHP】制作日历
  6. 【JavaSE】java8 新特性
  7. TIA protal v17安装非C盘找不到step7 basic
  8. 转行程序员日记--2020-08-10
  9. 解决ublox无法定位问题(一直输出$GxTXT)
  10. 笔记本安装内存条、重装系统教程