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. PTA L2-011 玩转二叉树 二叉树+bfs

    思路: 先建树,然后按层次输出. #include<iostream> #include<cstring> #include<cstdio> #include< ...

  2. python 基础知识整理

    列表推导式 类似 data=[x+1 for x in range(10)]执行结果就是 [1,2,3,4,5,6,7,8,9,10] 还有 even_numbers=[x for x in rang ...

  3. 32位二进制IP地址与十进制IP地址互相转换

    代码: import java.util.List; import java.util.ArrayList; import java.util.Scanner; public class Transf ...

  4. [转].Net-C#的委托(代理)和事件

    一.代理 首先我们要弄清代理是个什么东西.别让一串翻译过来的概念把大家搞晕了头.有的文章把代理称委托.代表等,其实它们是一个东西,英文表述都是“Delegate”.由于没有一本权威的书来规范这个概念, ...

  5. npm、cnpm、yarn 安装删除异同

    背景 一直觉得npm.cnpm.yarn的安装删除基本一样用哪个都行,不过俗话说的好,实践出真知,这里记录一下今天简单测试得到的结果总结. 可能会有错误,希望大家评论指正,十分感谢. 测试电脑系统:M ...

  6. 网页加水印 svg 方式

    /** *网页加水印 svg 方式 * * @export * @param {*} [{ * container = document.body, * content = '请勿外传', * wid ...

  7. Java中死锁的定位与修复

    死锁应该可以说是并发编程中比较常见的一种情况,可以说如果程序产生了死锁那将会对程序带来致命的影响:所以排查定位.修复死锁至关重要: 我们都知道死锁是由于多个对象或多个线程之间相互需要对方锁持有的锁而又 ...

  8. 树莓派0 ubuntu无显示器ssh登录终端

    在此记录倒腾树莓派的过程 一.本文前提 已经装好系统,我装的是官方的Raspbian系统,以下是系统下载地址和工具地址 (默认帐号:pi,默认密码:raspberry) 镜像下载: http://do ...

  9. CSS背景图片

    1.背景图片插入 代码格式:background-image:url(): 括号内填写图片路径 2.背景图片设置大小 代码格式:background-size:宽.高 3.背景图片设置不平铺 代码格式 ...

  10. Paper Reading——LEMNA:Explaining Deep Learning based Security Applications

    Motivation: The lack of transparency of the deep  learning models creates key barriers to establishi ...