SDL全名Simple DirectMedia Layer,是一个跨平台的底层音频、视频、键盘、鼠标操作库,操作实际通过更底层的OpenGL/Direct3D完成,在保留跨平台的兼容性之外提供了非常高的效率,所以广泛的应用在多种游戏和对速度敏感的应用中,比如鼎鼎大名的steam平台/ffmpeg/qemu/模拟器等,当前的版本是2.0。更详细的资料可以访问官网:https://www.libsdl.org/

SDL2的编程理念清晰易用,代码简洁高效,这里用显式一副图片的最简代码来作为入门的示例,正式的教学可以搜索很多国内的教学网站。

老办法,让代码自己来说话:

#include <stdio.h>
//引入SDL头文件
#include <SDL.h>
//显式bmp之外的图片需要用到sdl_image库,需要单独引入头文件
#include <SDL_image.h> #define bool int
#define false 0
#define true (!false) int main(int argc, char ** argv)
{
bool quit = false;
SDL_Event event; //SDL初始化,这里只显示图片,所以只初始化VIDEO系统,更多的支持查看官方文档
SDL_Init(SDL_INIT_VIDEO);
//为了显示png图片,额外使用了图片库,所以要单独初始化
IMG_Init(IMG_INIT_JPG); //建立SDL窗口
SDL_Window * window = SDL_CreateWindow("SDL2 Displaying Image",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, 0);
//渲染层
SDL_Renderer * renderer = SDL_CreateRenderer(window, -1, 0);
//如果只是显示一张bmp图片,使用sdl内置的功能即可
//SDL_Surface * image = SDL_LoadBMP("only_support_BMP.bmp");
//因为要显示png图片,所以使用了外部库,sdl_image库当前支持jpg/png/webp/tiff图片格式
SDL_Surface * image = IMG_Load("/Users/andrew/Downloads/webFavorite/3481980_orig.png");
//载入的图片生成SDL贴图材质
SDL_Texture * texture = SDL_CreateTextureFromSurface(renderer, image); while (!quit)
{//主消息循环
SDL_WaitEvent(&event); switch (event.type)
{ //用户从菜单要求退出程序
case SDL_QUIT:
quit = true;
break;
} //如果指定显示位置使用下面注释起来的两句
//SDL_Rect dstrect = { 5, 5, 320, 240 };
//SDL_RenderCopy(renderer, texture, NULL, &dstrect);
//把贴图材质复制到渲染器
SDL_RenderCopy(renderer, texture, NULL, NULL);
//显示出来
SDL_RenderPresent(renderer);
}
//典型的三明治结构,清理各项资源
SDL_DestroyTexture(texture);
SDL_FreeSurface(image);
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
//退出image库
IMG_Quit();
//退出SDL
SDL_Quit(); return 0;
}

代码中基本算是逐句注释,所以读起来应当很清晰。主要需要说明的有两点,但其实跟这段代码并没有直接关系,而是有关在众多的绘图技术、架构、方案中,SDL处于一个什么位置:

1.首先是绘图哲学,使用过OpenGL及Direct3D的看这些代码应当不陌生,但这里要单独给传统GUI绘图的同学多说两句。通常使用GUI绘图,大概是这样一个逻辑,请看伪代码:

准备画板();

画一个点(x,y);
画一条线(x1,y1,x2,y2,c);
画一个圆(x,y,r,c);
贴一张图(x,y,w,h,bmp); 结束绘图();

在伪代码的过程中,每执行一条命令,比如画了线,在屏幕上就会看到结果,然后那条线也会一直存在,直到程序清掉它或者其它屏幕元素遮住它。

而SDL所使用的模式用伪代码表示大致是这样的逻辑:

准备工作();
主循环 {
游戏逻辑处理();
界面元素1进场();
界面元素2进场();
界面元素n进场();
渲染();
是否退出判断();
}

比较主要的区别是,每一个界面元素,或者说屏上的元素进场,并非真正的绘图,只是像拍电影一样准备一个场景。等到所有屏幕元素都到齐,场景完全准备好,再一次性渲染,这时候是真正的绘制到屏幕上。更形象的比喻就好像演员都准备好了,相机快门按下,才真正成像。这个成像称为一帧,随后循环起来,一次次的准备好场景、渲染成像,就形成了连续不断的帧从而形成了帧动画,也就是我们熟悉的屏幕游戏画面。这里面每一秒钟能够进行多少次循环,就成为了游戏玩家熟悉的帧率,追求高帧率是大多游戏玩家对电脑的要求。

这两种绘图的方式,各有优劣,但依据特征,有不同的应用方向。前者多用于打印、绘图输出相关的办公、平面设计等场合,传统软件的界面也多用这种方式,还有比如我们都熟悉的上网浏览器页面也是采用这种渲染方式。这种方式对速度不敏感,虽然有可能硬件加速,但实际上大多工作是由CPU完成的。

后者也就是SDL所采用的方式,则在游戏、视频、3D动画、VR、AR等领域大放异彩,我们耳熟能详的OpenGL、Direct3D也都采用这种方式,这种方式的流程逻辑,也更适合把大量的数据和素材交给GPU去完成更耗时的计算。

显而易见,从绘图哲学的角度看,SDL/OpenGL/Direct3D所采用的绘图方式,显然更适合3D类绘图、动画的加速,那么这种技术对平面绘图,比如就是单纯的视频播放,是如何加速的呢?其实很简单,我们知道所有的3D绘图都包括至少两个主要的部分,一是3D物体的构造模型,比如是一个球体还是一个圆柱体;另一部分则是这个3D物体表面看起来是什么样子的,比如是一个石膏的球体还是一个毛绒玩具的球体。这第二部分就需要用到材质,材质实际上主要是由三维物体的表面积在二维展开的图片。所以3D绘图对二维的加速实际上就是在屏幕上绘制一个全屏幕的平面,然后把二维图像当做材质贴图上去的结果。你看上面SDL代码中载入的png图片,实际最后就是当做一副材质(texture)来使用了。

2.SDL/OpenGL/Direct3D同GTK/MFC/QT/Cocoa是什么关系?

刚才其实比较清楚的讲了SDL/OpenGL/Direct3D在绘图上的作用,其实它们就是一套绘图的体系。

GTK/MFC/QT/Cocoa也是显示相关这没错,但是它们主要是提供用户程序的界面管理、显示及事件处理。更具体一点说,比如你看到屏幕上的菜单、窗口、对话框、按钮、文字,几乎都是这些界面管理器来实现的,我们点了一个按钮、拖动一个窗口,都会产生事件,这些事件会由这些界面管理器收集、分类、排序,调用响应用户响应函数做出最后的处理。所以平常我们所见的应用程序,其实都是基于这一类软件库完成的。而重要的是,这些界面管理库,实际上最终也是经由OpenGL/Direct3D或者类似功能更底层一些的显示绘图库来完成界面部分的绘制功能。但是这些显示系统往往太庞大、臃肿了,对于对速度极为敏感的游戏、视频类应用而言,通常我们见到的这些界面所占比重又比较小,所以游戏类的应用,往往不采用或者较少部分采用这些传统的界面管理库。

这两类系统往往不是独立存在的,比如举例说一个视频播放器,播放器的窗口界面、菜单、文件打开等界面和操作,都是由界面管理器比如Windows上的MFC或者Mac上的Cocoa来完成的,到真正视频播放的环节,在窗口中给定的区域,则是由SDL、OpenGL、Direct3D出马,完成视频的逐帧绘制的功能。

回到今天的主题。上面的代码在编译的时候,因为使用了SDL2/SDL_image两个额外的附加库,所以在编译、执行代码之前,首先要安装这两个软件库。在mac电脑上安装这两个库的命令是:brew install sdl2 sdl2_image

编译代码使用:

gcc -o sdlpng sdlpng.c $(pkg-config --cflags --libs sdl2_image)

后面$(pkg-config --cflags --libs sdl2_image)的意思是,将sdl2_image代码库及其依赖库(这里当然就是sdl2库)的编译参数和引用库参数全部显示出来,作为字符串加入到编译命令中去。这个功能是由pkg-config这个包管理器完成的。如果不需要处理png图片,只是bmp图片,则不需要使用sdl2_image库,仅适用sdl2库即可。这个时候可以使用$(pkg-config --cflags --libs sdl2)。sdl2也提供了自己的包参数工具sdl2-config可以完成类似的功能,但仅对自己有效,所以为了通用起见,我们还是使用pkg-config更方便一些。

谈到附加包的编译参数,我们也经常看到一些教科书上写成类似:`pkg-config --cflags --libs sdl2`这样的形式,这是因为在bash下面,反单引号`就是用来执行命令、并将结果当做字符串返回的功能。但是这种方式在别的shell,比如fish中是不起作用的,但是$( ... )这样的方式就有了更好的通用性。

参考链接:

http://gigi.nullneuron.net/gigilabs/loading-images-in-sdl2-with-sdl_image/

使用SDL2显示一张图片,SDL2上手贴的更多相关文章

  1. 用 SDL2 显示一张图片

    来源: http://adolfans.github.io/sdltutorialcn/ (中文教程) http://www.willusher.io/pages/sdl2/ (英文教程) 环境:SD ...

  2. SDL2学习(一): 显示一张图片

    SDL是一个跨平台的多媒体库,它通过OpenGL和2D视频帧缓冲,提供了针对音频.视频.键盘.鼠标.控制杆及3D硬件的低级别的访问接口.这里使用较新的SDL2库. 1. 配置SDL开发环境 1.1 下 ...

  3. 仿AS语法来写HTML5—第1章,显示一张图片

    最近开始学习html5,因为一直都是研究as,所以还是觉得as顺眼一点,但是html5也不能不学,于是就想出了,可以把html5用as的语法来写出来,做游戏应该来的比较顺手一些,下面开始第一篇 第一篇 ...

  4. Python+OpenCV图像处理(一)——读取显示一张图片

    先在此处先声明,后面学习python+opencv图像处理时均参考这位博主的博文https://blog.csdn.net/u011321546/article/category/7495016/2? ...

  5. 用仿ActionScript的语法来编写html5——第一篇,显示一张图片

    第一篇,显示一张图片 一,代码对比 as代码: public var loader:Loader; public function loadimg():void{ loader = new Loade ...

  6. springmvc上传图片并显示--支持多图片上传

    实现上传图片功能在Springmvc中很好实现.现在我将会展现完整例子. 开始需要在pom.xml加入几个jar,分别是: <dependency> <groupId>comm ...

  7. @Html.Raw显示一张图片

    在ASP.NET MVC中,显示一张图片,是很方便的事情,完全可以在控制器中组合html代码,并传给视图. 下面一个简单的例子: public ActionResult HtmlRawImage() ...

  8. (转)C# WinForm中 获得当前鼠标所在控件 或 将窗体中鼠标所在控件名显示在窗体标题上

    原文地址:http://www.cnblogs.com/08shiyan/archive/2011/04/14/2015758.html /********************** * 课题:将窗 ...

  9. swiper轮播问题之二:默认显示3张图片,中间显示全部两边显示部分

    其二:项目遇到比较有点要求的轮播图,默认显示3张图片,中间显示全部,两边显示部分.如图: 网上找了也没有找到合适的,最后经过自己摸索写了出来,贴出代码分享给大家.         CSS .swipe ...

随机推荐

  1. Ubuntu 18.04 系统配置 NPM环境和mysql数据库问题解决

    Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境. Node.js 使用了一个事件驱动.非阻塞式 I/O 的模型,使其轻量又高效. 今天我就为大家 使用 Ubun ...

  2. 【转】腾讯云-解决Winscp permission denied的问题

    刚刚注册完腾讯云,因为要用来跑作业代码,所以操作系统选择的Ubuntu 16.04 32位 用Winscp登陆之后出现了错误代码为3的permission denied的错误,不能创建路径,也不能上传 ...

  3. Akka.net 性能测试兼使用小技巧

    最近想研究一下分布式开发,先拿了akka.net 跑一下性能 参考自己写个网络实现,一般在本机通讯,300M每秒的传输率,作为参考 嗯,先说结果,用Akka.net直接发bytearray,最后也只有 ...

  4. OI暑假集训游记

    莞中OI集训游记 Written BY Jum Leon. I        又是一载夏,本蒟蒻以特长生考入莞中,怀着忐忑的心情到了8月,是集训之际.怀着对算法学习的向往心情被大佬暴虐的一丝恐惧来到了 ...

  5. POJ3630

    Tire树裸题,一开始写动态的字典树,然后TLE,每次new一个新节点耗费时间较多.后来改成数组模拟的. //#include <bits/stdc++.h> #include <c ...

  6. ORACLE启动报错ORA-03113: end-of-file on communication channel

    使用过程中发现oracle运行很慢(其实应该先关注空间问题),就准备关机重启一下,关不掉就强制关闭,然后启动就报错了. 1.SQL> startup ORACLE instance starte ...

  7. Java-IO流之转换流的使用和编码与解码原理

    一.理论: 1.字符流和字节流区别是什么? 字符流=字节流+编码集,在实际读取的时候其实字符流还是按照字节来读取,但是会更具编码集进行查找编码集字典解析相应的字节,使得一次读取出一个字符: 2.什么是 ...

  8. 马昕璐 201771010118《面向对象程序设计(java)》第十六周学习总结

    第一部分:理论知识学习部分 程序:一段静态的代码,应用程序执行的蓝本. 进程:是程序的一次动态执行,它对应了从代码加载.执行至执行完毕的一个完整过程. 多线程:进程执行过程中产生的多条执行线索,比进程 ...

  9. D. Frets On Fire 前缀和+二分

    这个题真的难了我一天了,这种方法一开始没想出来,后来看了题解后明白了大致思路开始自己做但是!!!但是自己实现的时候老是一些细节出错!!!,调bug调了得有一个小时,蠢死了,这道题我一定要好好总结,总结 ...

  10. CSS-默认padding 和 margin

    一.h1~h6标签:有默认margin(top,bottom且相同)值,没有默认padding值. 在chrome中:16,15,14,16,17,19; 在firefox中:16,15,14,16, ...