里面有些单词不好翻译所以放在开头,以备查验。
BLock Image Transfer, a computer graphics operation in which two bitmap patterns are combined
In computing, the Blit was a programmable bitmap graphics terminal designed by Rob Pike and Bart Locanthi Jr. of Bell Labs in 1982.
Steam,不知怎么翻译,eg:Steam Big Picture Mode,Steam passes this configuration
a working Steam Overlay
原文地址 https://wiki.libsdl.org/MigrationGuide
简介
经过多年的开发,SDL2.0版本终于发布了!
我们为它感到自豪,并且我们希望那些应用了SDL1.2的游戏能够立刻升级到SDL2.0.也许这是个让人感到气馁的任务,这是一篇关于如何升级到新库的简单指导。我们想你会发现它并不是你想象的那样难,很多时候, 你要么直接替换函数,要么在代码中撤销一些操作来处理1.2中的缺陷。
我们相信,你会为SDL2.0感到高兴,新的特性和比SDL1.2更好的体验。这篇文档并不会尝试包含所有SDL2中好的东西--有很多--仅仅是那些你为了能正确运行而必须去做的事情。一旦你升级完你的代码,一定要检查这些新的东西,你可能需要在你的程序中去增加这些新的东西。
新特性总览
这里列举出了SDL2.0中大部分重要的新属性:
- 全3D硬件加速
- 支持OpenGL3.0+的多种配置(核心、兼容性、调试、鲁棒性等)
- 支持OpenGL ES
- 支持多窗口
- 支持多显示器
- 支持多音频设备
- 安卓和IOS系统的支持
- 简单的2D渲染API,它可以利用 Direct3D, OpenGL, OpenGL ES, 或者幕后的软件渲染。
- 自适应于 Windows, Mac OS X 和Linux 操作系统
- Windows中支持XInput 和 XAudio2
- 原子操作
- 电源管理(显示剩余电池的电量等)
- 适应形状的窗口
- 32位音频(整型和浮点型)
- 简化的游戏控制器API(摇杆的API这里也有)
- 触控支持(多点触控、手势识别等)
- 更好的全屏支持
- 更好的键盘支持(扫描码与键码等)
- 消息框
- 剪贴板支持
- 基本的拖放支持
- 正常的unicode输入和输入法的支持
- 一个很强大的assert宏
- 许可协议由LGPL变为zlib
- 很多1.2版本令人烦恼的东西移除了
- 许多其他的事情!
简介页面上有大量关于SDL特性的列表(包括老的1.2版的特性)
查看更多内容
SDL从1.2迁移到2.0
一些基本的事实
在SDL2中没有添加不兼容层。如果一个API在2.0版中被改变了,那是因为我们更改或者移除旧的函数是有意义的。如果你1.2版的程序使用2.0版的头部,它可能会编译失败。本文将会尝试告诉你最重要的和那些最容易绊倒你的改变。
没有SDL_main!好吧,还有就是它现在做的总是意味着:一小段代码隐藏在windows系统中的main()和WinMain()之间。在它里面没有任何初始化代码,并且它完全是可选的。这就意味着,你能够在不使用SDL_main代替主线程的情况下使用SDL,在插件中使用SDL是很棒的,或者在脚本语言中调用SDL模块。1.2版SDL_main中的所有东西现在都在SDL_Init() 中了。
现在没有SDL降落伞了。在1.2中的SDL_INIT_NOPARACHUTE现在是默认的,并且仅仅是个状态值。这会引起一些问题,如果除了主线程之外地方崩溃了,它会干扰程序所建立的信号/异常处理。缺点:一些平台在崩溃的时候没有很好的清理全屏。如果你关心这些事情,你应当建立自己的崩溃处理机制,或者在atexit()函数(或者其它类似的函数)中调用SDL_Quit()函数。注意在Unix平台,SDL仍然捕获SIGNINT并且把它映射到SDL_QUIT事件上。
视频部分
用新的视频应用程序接口创建一个游戏
与1.2版本相比,视频API发生了最明显的变化。SDL的老的API是在上个世纪90年代后期设计的,而现在需求已经发生了很大的变化。为了配合当前的硬件和操作系统的特性,我们几乎完全替换了1.2版本中老的视频API。
放心各位,这个新的相当完美,一旦你理解了这些改变,你将会为这些可以加入你1.2版游戏中的新特性感到高兴。这些我们稍后讨论。
告诉你个好消息:如果你的游戏中使用了OpenGL,那么你可能将不需要做太多事情:将少数函数的调用形式改为SDL2的方式,你会非常顺利的做完这些。
对于2D图形,SDL1.2给出了一个称为“surfaces”的概念(存储像素的缓冲区)。屏幕就是一个“surfaces”,如果你做2D软件渲染,我们提供了一个函数用来在surfaces之间进行像素复制(“blit”位块传输),必要时进行一下格式转换。以前你是让CPU在系统内存上,而不是在GPU的显存上运行。SDL2.0改变了这种状况;现在你总能使用硬件加速,并且API因为这点也发生了改变。
如果你有一个2D游戏,你可以采用三种方法之一来渲染。我们都会介绍这些方法,但是首先,让我们来谈点入门的东西。
记得SDL_SetVideoMode()吗?它已经完全移除了。SDL2.0允许你有拥有多个窗口,所以旧的函数没有存在的意义了。
你可能这样写过:
SDL_WM_SetCaption("My Game Window", "game");
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 0, SDL_FULLSCREEN | SDL_OPENGL);
现在变为了:
SDL_Window *screen = SDL_CreateWindow("My Game Window",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
你可以看到这个函数跟1.2版的很相像。不同点是你可以创建多个窗口(如果你愿意的话),并能控制它们。SDL_WM_SetCaption移除了,因为我们想要每一个窗口都有属于自己的标题(过一会儿你可以用SDL_SetWindowTitle()来更改),同时我们希望可以让你指定一个窗口的位置(或者,在这种情形下,我们不关心系统把窗口放到什么地方,可以用SDL_WINDOWPOS_UNDEFINED。SDL_WINDOWPOS_CENTERED也是一个很不错的选择)。
额外的福利,可以让用户指定一个显示器来显示窗口:SDL2还允许你管理多个显示器。然而,现在先不要担心这些。
现在你的窗口又回到了屏幕上,让我们来谈谈战略层面的东东。SDL2仍然有SDL_Surface,但是你所想要的已经改成了新的SDL_Texture。Surfaces仍然存在于系统内存中,并且也还是始终被CPU控制着,因此我们想离这个区域远一些。SDL2有了一个新的用于渲染的API。它意味着可以被简单的2D游戏所使用,但最主要的是,它意味着所有使用软渲染的操作转移到了显存和GPU中。即使你只是想用它来使你的软渲染器输出到屏幕上,它同时也带来了一些非常好的优点:如果可能的话,它会在幕后使用OpenGL或者Direct3D,这意味你将能得到更快的位块传输、一个一直工作的Steam覆盖层和自由的缩放。
设置如下所示。
正如我们前面讨论过的SDL_SetVideoMode() 变成了SDL_CreateWindow()。但是我们应该设置什么样的分辨率呢?如果你的游戏需要硬编码到640x480,例如,在这种情况下你在显示器上运行时可能不能将它全屏显示,并且在窗口模式下,你的游戏可能看起来像是一张显示在高端显示器上的动态邮票。SDL2提供了一个很好的解决方案。
我们不再调用SDL_ListModes()。在SDL2中才在一个等效的方法(在循环中调用SDL_GetDisplayMode(),SDL_GetNumDisplayModes()次),但是我们将会使用一个名为“fullscreen desktop全屏桌面”的新特性,这会告诉SDL“给我整个屏幕并且不要改变分辨率”。对于我们假设的640x480的游戏,它可能看起来像这样:
SDL_Window *sdlWindow = SDL_CreateWindow(title,
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
0, 0,
SDL_WINDOW_FULLSCREEN_DESKTOP);
注意,我们没有指定640或者480……,全屏桌面带给你的将是整个显示区域并且它会忽略你指定的任何尺寸。游戏窗口应当立即被显示,而不是等待显示器去指定一个新的分辨率,我们会利用GPU去缩放到桌面的大小,这往往比液晶显示器伪造一个低的分辨率更快、看起来更整洁。额外的好处是:现在你不用对窗口背景做什么,它将自动调整。
现在我们需要一个用于渲染的上下文。
SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
渲染器隐藏了我们如何绘制到窗口上的细节。在幕后可能使用Direct3D, OpenGL, OpenGL ES,或者软surfaces,这取决于系统提供了什么;无论SDL怎么选择,你的代码都不用改变什么(虽然你喜欢指定某种类型的渲染器)。如果你想尝试强制同步到竖直方向的空白来减少拉伸感,你应当使用SDL_RENDERER_PRESENTVSYNC而不是0作为第三个参数去赋值。你不应当在创建窗口的时候使用SDL_WINDOW_OPENGL 标志位。如果SDL_CreateRenderer()自己决定要使用OpenGL,它会为你恰当的更新窗口。
现在你理解这是如何工作的了,如果你没有什么别的想法了的话,你可以用SDL_CreateWindowAndRenderer()来一步完成这些设置。
SDL_Window *sdlWindow;
SDL_Renderer *sdlRenderer;
SDL_CreateWindowAndRenderer(0, 0, SDL_WINDOW_FULLSCREEN_DESKTOP, &sdlWindow, &sdlRenderer);
假设这些函数没有调用失败(记得要检查是否返回了NULL),你现在就可以在屏幕上绘制了。让我们先从清理屏幕到黑屏状态开始。
SDL_SetRenderDrawColor(sdlRenderer, 0, 0, 0, 255);
SDL_RenderClear(sdlRenderer);
SDL_RenderPresent(sdlRenderer);
如你所想;画了黑色(R,G,B都为零,全透明),清理整个窗口,在屏幕上显示出了清理好的窗口。就是这个样子,如果你一直使用SDL_UpdateRect()或者SDL_Flip()来在屏幕上显示你的bits,现在的渲染API变为了SDL_RenderPresent()。
一个更为一般的操作在这里设置。由于我们使用了SDL_WINDOW_FULLSCREEN_DESKTOP,我们实际上并不知道要在多大的屏幕上绘制。幸运的是,我们不需要知道。1.2版中的一个好处是你可以这样写“我想要一个 640x480的窗口,并且我不需要关心你是如何做到的”,即使这么做意味着在较大的分辨率下的中间窗口代表着你的应用程序。
在2.0版本中,用于渲染的API可以这个样子……
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); //使缩放渲染看起来更平滑
SDL_RenderSetLogicalSize(sdlRenderer, 640, 480);
……它会很好的为你完成这些事情。你可以改变逻辑渲染大小来实现各种效果,但是主要实现是这样的:不是让系统去适应你渲染的尺寸,而是我们让你的渲染的尺寸去适应系统。在我的1920x1200显示器上,这个应用程序认为它当前正在在跟一个640x480分辨率的显示器交流,但是SDL使用GPU来放大它以使用全部的像素。需要注意的是640×480和1920x1200长宽比不一样:SDL也注意到了这一点,尽可能的缩放并且信箱状处理(letterboxing)不同。
现在,我们开始真正的绘制。
如果你的游戏只是想要将得到的完全渲染的帧画面输出到屏幕上
一种特殊的情况出现在以前的软件在渲染游戏时:应用程序要绘制每个像素,并且最终将经过大位块传输的像素有效的输出到屏幕。举个这样游戏的例子:毁灭战士、毁灭公爵3D等等.
对于这点,你会希望有一个唯一SDL_Texture用于在屏幕上渲染。让我们来为我的640x480游戏创建一个。
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STREAMING,
640, 480);
这代表GPU上的一种纹理。通过上传像素到这个纹理上来填充每一帧,在窗口上绘制这种纹理,最后翻转这张图片到屏幕上。SDL_TEXTUREACCESS_STREAMING这个值告诉SDL,这个纹理的内容经常会经常发生改变。
在你的程序绘制到屏幕之前你很可能需要一个SDL_Surface,接着调用SDL_Flip()函数来让它在屏幕上显示。现在你可以创建一个常驻内存中而不是从SDL_SetVideoMode()中得到的SDL_Surface,或者申请一块像素块用于写入。你最好在缓存中写入的是RGBA格式的像素,但如果你需要通过一个转换来得到这种格式也是可以的。
extern Uint32 *myPixels;//这么可能是 surface->pixels,或者通过malloc()申请得到的内存地址,或者其它的东东。
在帧的末尾,我们会像这样更新纹理:
SDL_UpdateTexture(sdlTexture, NULL, myPixels, 640 * sizeof (Uint32));
这会将你的像素更新到GPU内存中。如果你想用脏的矩形弄乱你的周围那么可以将子区域设为空,但是可能现在的硬件已经能够方便的直接处理整个帧缓存了。最后一个参数是间距--从一行的开始到下一行所占的字节数,同时在这个例子中我们有个线性的RGBA缓存,它的值仅仅是640*4(r,g,b,a)。
现在将纹理设置到屏幕上:
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
完成了。SDL_RenderClear()擦除了现有的视频帧缓冲(换句话说,写覆盖最后一帧),SDL_RenderCopy()将纹理的内容移动到视频帧缓冲中(多亏了SDL_RenderSetLogicalSize(),如果显示器是 640x480的话,它会进行缩放或者居中操作), SDL_RenderPresent() 则是将它输出到屏幕上。
如果你的游戏想要传送surfaces到屏幕上。
有一种情况,你的SDL1.2版的游戏从磁盘中加载了大量的图片输送到的大量的SDL_Surfaces中,尝试将它们输入到显存中(使用SDL_HWSURFACE属性)。只需加载一次,就可以一遍又一遍的在需要的时候blit它们,但在其他方面不用改变。一个简单的2D平台游戏可以这么做。如果你认为你的界面是“游戏界面”,而不是缓冲区的像素,那么这仅仅是你的想法。
你可以创建自己的纹理(存在于GPU内存中的surfaces)就像我们做的那个大的纹理一样。
sdlTexture = SDL_CreateTexture(sdlRenderer,
SDL_PIXELFORMAT_ARGB8888,
SDL_TEXTUREACCESS_STATIC,
myWidth, myHeight);
正如你所想得到的。我们使用SDL_TEXTUREACCESS_STATIC,是因为我们想一次就上传完我们的像素而不是一次又一次。一个更方便的解决方案可能是:
sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, mySurface);
利用这一句,你像往常一样加载你的SDL_Surface,但是在最后时刻你创建了一个在你SDL_Surface之外的纹理。一旦你拥有了一个SDL_Texture,你就可以释放掉原先的surface了。
从这一点上看,你的1.2版游戏有一大堆SDL_Surfaces,使用SDL_BlitSurface()传输到屏幕的surface,以组成最终的帧缓冲,并且最终调用SDL_Flip()来显示到屏幕上。在SDL2.0下,你将拥有大量的SDL_Textures,通过调用SDL_RenderCopy()来将你的渲染器组成最终的帧缓冲,并最终通过调用SDL_RenderPresent()来显示到屏幕上。就这么简单。如果这些渲染器从不需要修改,你可能会发现你的帧率已经飙的比屋顶都高了。
如果你的游戏两方面都要
如果你既想要blit surfaces又想要在帧缓冲中修改单个的像素。折返跑--从纹理中读取数据---昂贵而痛苦;一般说来你想总是往一个方向推送数据。你可能是最好的了,在这种情况下,保持程序中的任何东西都不变,直到最后推送到屏幕上,因此我们组合了这两种老技术。
好消息来了:1.2版中SDL_Surface 的大部分API仍然存在。下面是教你改变屏幕的surface:
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, 0);
... 变成这样...
//如果你对这些十六进制感到害怕,可以通过调用SDL_PixelFormatEnumToMasks()来找出相应的枚举值
SDL_Surface *screen = SDL_CreateRGBSurface(0, 640, 480, 32,
0x00FF000,
0x0000FF00,
0x000000FF,
0xFF000000);
SDL_Texture*sdlTexture=SDL_CreateTexture(sdlRenderer,SDL_PIXELFORMAT_ARGB8888,SDL_TEXTUREACCESS_STREAMING,640, 480);
...继续像以前一样传输位块和调整像素,组成最终的帧缓冲输出到SDL_Surface中去。一旦你准备在屏幕上获取这些像素,你可以像我们第一个方案中那样做:
SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
SDL_RenderClear(sdlRenderer);
SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
SDL_RenderPresent(sdlRenderer);
注意:创建纹理可能既昂贵有浪费资源:不要每一帧都调用SDL_CreateTextureFromSurface()。设置一个纹理和一个former,并且前者的更新是由后者推动的。
渲染用的API还有很多其他特性。其中一些可能能够替代你程序中代码:缩放、划线等等。如果你阅读这个章节是因为你的简单需要超过了传送surface,你可能会不再指定单个像素和将一切到移动到GPU中,这将会给你的程序一个显著的性能提升并且可能极大的简化你的代码。
其他渲染器API的注意事项
你可以使用渲染器API做一些简单的特效,而不用直接去操作像素。其中一些在1.2版的surfaces中也是可用的。
- 颜色alpha:SDL_Color现在有了第四个值,alpha分量。在你的1.2版代码中SDL_Colors可能无法复制/设置该值(被命名了但没使用)。在2.0版中,你可以了。
- Alpha混合:使用 SDL_SetSurfaceAlphaMod 和SDL_SetTextureAlphaMod来代替SDL_SetAlpha().Alpha-混合在surfaces中可以通过SDL_SetSurfaceBlendMode()来禁用,在纹理可以通过SDL_SetTextureBlendMode()来实现。
- 色键:当调用SDL_SetColorKey()时,你应该传送SDL_TRUE而不是SDL_SRCCOLORKEY。
- 颜色幅度:一些渲染器现在支持一种全局的颜色变更(srcC = srcC * color),查看SDL_SetTextureColorMod()可以了解到详情。
OpenGL
如果你直接使用了OpenGL,你的迁移将会相当简单。在SDL_GL_CreateContext()后,更改SDL_SetVideoMode()为 SDL_CreateWindow(),更改SDL_GL_SwapBuffers()为SDL_GL_SwapWindow(window)。所有进入GL的调用都是一样的。
如果你使用了SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, x),这个改了。现在调用SDL_GL_SetSwapInterval(x)函数,这样你就可以在现有的GL上下文中改变这一点了。
需要注意的是SDL2.0使用OpenGL时可以切换窗口/全屏和背面而不会丢失GL的上下文(欢呼~~~)。对于这个使用SDL_SetWindowFullscreen()。
输入
好消息是,SDL2.0已经可以用Unicode 输入了。坏消息是,这需要在你的程序中做些小改动。
在1.2中,许多应用只关心美国英语是不是仍然调用SDL_EnableUNICODE(1),因为它对得到按键相关联的字符非常有用。但是一旦你获取英语之外的就会可能不正常,并且一旦你选择的是亚洲语言会发现它根本就不工作。
事实证明,国际化是很难的。
SDL改变了这一点。SDL_EnableUNICODE()移除了,同样的还有SDL_Keysym的unicode区域。你不再需要从SDL_KEYDOWN事件中获取字符输入。使用SDL_KEYDOWN,对待键盘就像是一个有着101个按钮的摇杆一样。文字输入来自别的地方。
新的事件叫做SDL_TEXTINPUT。当有新的文本被用户输入时它就会被触发。注意的是,这个文本可能来自按下按键,或者某种输入法(这是一种输入复杂的多字符文本的奇特方式)。这个事件返回了整个字符串,它可能是1个字符那么长,或者是多字符数据的多个码点的数值。这个字符串使用的是UTF-8编码。
如果你所关心的仍然是用户是否按下了某个键,那么仍然是用SDL_KEYDOWN,但是从1.2版以来,我们分离这个系统为两个部分:键码和扫描码。
扫描码的目的是键布局无关。想象一下这种情形“用于按下了一个Q键,认为当前是在美国的QWERTY键盘上”不管这实际上是一个欧洲键盘或Dvorak键盘等等。扫描码的键位置相同。
键码是布局依赖的。想象一下这种情形“用户在他的专有键盘上按下了一个标记为‘Q’的按键”。
举个例子,如果你在美国的QWERTY键盘上按下了一个键那意味着按下了两个大小写正确的键,它将会报告一个扫描码SDL_SCANCODE_S和一个键码SDLK_S。在Dvorak 键盘上的相同键,将会报告一个扫描码SDL_SCANCODE_S和一个键码SDLK_O。
注意的是键码和扫描码目前都是32位,并且使用了一个非常宽的数字范围。并没有SDLK_LAST。如果你的程序有一个SDLK_LAST元素的查找表,用来在SDL关键字和你程序内部中的东西进行映射,那将不再可行。使用哈希表来代替。std::map就不错。如果你映射扫描码而不是键码,你可以在数组边界上使用SDL_NUM_SCANCODES。当前它的值是512。
SDLMod现在是SDL_Keymod,同时"META"键(“Windows”键)现在称为”图形用户界面”键。
SDL_GetKeyState()现在更名为SDL_GetKeyboardState()。返回的数组现在通过SDL_SCANCODE_* values(见SDL_Scancode)而不是SDL_Keysym值进行索引。
现在,是关于鼠标输入的部分。
第一个变化,很简单,鼠标滚轮不再是一个按钮。这个一个历史错误,我们在SDL2.0版本中改正了它。查看SDL_MOUSEWHEEL事件。我们支持纵向和横向的滚轮,在一些平台上会将两个手指在触控板上的滚动作为轮输入。你将不会在鼠标滚轮上收到SDL_BUTTONDOWN事件,并且现在按钮4和5是真正的鼠标按钮了。
如果你的游戏只需要在一个方向上滚动鼠标,例如玩家在射击类游戏中旋转时没有鼠标点击屏幕边缘和停止,你可能会隐藏鼠标光标并且获取输入:
SDL_ShowCursor(0);
SDL_WM_GrabInput(SDL_GRAB_ON);
在SDL2中,方式略有不同。调用:
SDL_SetRelativeMouseMode(SDL_TRUE);
...同时,SDL也轻松了。
事件
SDL_PushEvent()现在变为了成功返回1,而不是原先的0、
事件的掩码现在指定了范围。
SDL_PeepEvents(&event,1,SDL_GETEVENT,SDL_EVENTMASK(SDL_MOUSEBUTTONDOWN));
变为了:
SDL_PeepEvents(&event,1,SDL_GETEVENT,SDL_MOUSEBUTTONDOWN,SDL_MOUSEBUTTONDOWN);
音频
关于音频的好消息,除了一点例外,它与1.2版完全兼容。如果你想用新的特性,这些特性可能对你有用,但是呢,你可能仅仅只能编译通过而不能再运行的时候得到这些特性。
有一个很重要的例外:音频的回调不是在完全初始化缓冲之后才开始的。你必须想尽办法填满缓冲区。如果你没有足够的声音,你的回调函数应该写入静音。如果你不能做到这点,你将会听到重复声音,或者损坏的声音。如果你想恢复为旧的行为(无条件初始化缓冲区),仅仅需要在你的回调开始的时候调用SDL_memset(stream, 0, len)。
摇杆
摇杆事件引入了SDL_JoystickID。这是因为SDL2.0能够处理摇杆的插入与拔出,就像在你游戏时设备会插入和拔出一样,所以1.2版本使用的那种在设备列表中索引的方法变的没意义了,因为可用的设备列表变化了。
为SDL_Joystick*获取SDL_JoystickID 的方法是调用:
SDL_JoystickID myID = SDL_JoystickInstanceID(myOpenedStick);
并且摇杆事件与使用myID相比。如果不再因为摇杆而使用事件队列,可以用SDL_JoystickGetAxis(),这个函数很友好,就像在SDL1.2中一样。
你也应该检查新游戏控制器的API,因为它很酷,也许你使用1.2的API敲了很多代码,新的代码将会精简很多。你会在SDL_gamecontroller.h中发现,游戏控制器API与Steam大图片模式整合的非常好:你会得到大部分控制器的自动配置,如果你想手动配置的话还会有一个漂亮的界面。在这两种情况下,Stream传递这个配置到你的SDL应用中。
SDL2中已经不再支持Linux下旧的摇杆API了(/dev/input/js*)。SDL2.0仅仅支持摇杆较新的API(/dev/input/event*)。这些事件不能被正常用户正常读取,所以,即使摇杆插入了你也可能检测不到什么。这些事使用者必须自己配置它们。
线程
移除了SDL_KillThread()。它既不安全又不可靠。最好的替代是设置一个标识来告诉线程它该退出了。线程应该以一定的频率来检查这个标识,然后”杀死”线程,调用SDL_WaitThread()来清理。
SDL_CreateThread() 现在需要获取一个额外的参数,线程的名称,它可以在调试的时候识别它,如果你不关心它,可以在你函数调用的时候塞入一个NULL。
CD
1.2版中的CD API完全移除了。没有替代品。目前的状况是你很可能不会再购买以光盘为载体的CD音乐了,更何况你可能根本没买过光盘。你可以使用Ogg Vorbis或者其他的音频文件格式的音乐,许多可以由SDL_mixer支持。
挂了的平台
我们移除了一些旧平台的支持,像是OS/2和Mac OS 9。当然我们可以轻松的列出大量仍然支持的平台:Windows (XP 及后续版本)、Linux、Mac OS X、iOS、 Android。在SDL的传统中,还有一些边缘的系统支持的并不是很完美,像是 Haiku和Sony PSP。我们将会给一些人发送增加某些平台支持的补丁,但是现在看起来是时候移到新平台并跟老朋友说再见了。
移动平台
多年以来,SDL1.2到iOS和Android的非官方端口已经存在了。现在SDL已经直接支持这些平台了,并且2.0的API更适合它们。这篇文档中的大部分建议都很实用,但是也有值得注意的地方。
首先,有一些事件只适用于移动设备,或者说,适用于后iphone时代的移动设备操作系统操作。我们曾经尝试将这些事件映射到现有的SDL事件中(例如“你的应用程序即将前往后台运行”可以认为是桌面窗口的失焦点),但是这有一个更迫切的关注点:大部分的事件需要立刻做出反应,并且如果程序不能给出反应,操作系统就会杀死你的程序。
因此,我们为一些Android和iOS的一些特定的细节增加了新的SDL事件,但是你应当建立一个SDL事件过滤器用于系统报告他们的时候捕获他们,因为等到你的下一个SDL_PollEvent()循环的时候已经太晚了。
例如,SDL_APP_WILLENTERBACKGROUN,它是iOS'的applicationWillResignActive(),如果你在这个事件到达后才绘制到屏幕上,iOS就会结束你的进程。所以你要立即捕获它:
int SDLCALL myEventFilter(void *userdata, SDL_Event * event)
{
if (event->type == SDL_APP_WILLENTERBACKGROUND) {
// free up resources, DON'T DRAW ANY MORE until you're in the foreground again!
}
// etc
return 1;
}
// somewhere near startup...
// this calls myEventFilter(data, event) as soon as event is generated.
SDL_AddEventWatch(myEventFilter, data);
第二,现在有了真实的触控事件,而不是试图将其映射到鼠标输入。你可以跟踪触摸轨迹,多个手指,甚至是复杂的手势。你可能想使用这些操作。请参阅SDL_touch.h中的这些函数的列表,同时在SDL_events.h中查找SDL_Finger*。
当然也有其它的对移动设备友好的函数,像是SDL_StartTextInput(),将会显示一个屏幕键盘。利用它们。
此外,也有 Android 和 iOS特定的函数,让你来使用特定平台的特性但在通用API上不起作用。请参阅SDL_system.h来查看这些函数列表。
RWops
SDL_RWread()和SDL_RWwrite()现在变为了失败返回0,而不是-1.
如果你实现自己的SDL_RWops,那么该函数的签名就更改了。函数现在使用的是Sint64和size_t类型而不是int类型,所以他们能够处理大文件。在许多情况下,你要做的仅仅是更新函数签名并保持跟原先一样的处理,但是一旦你遇到了这些限制,你可能会很高兴有了一个解决方案。调用程序时应当会知道返回值已经改变了。
现在还有一种得到RWops大小的方法。这会让RWops报告流的大小而不用使程序在末尾寻找0字节;换句话说,你可以报告流的总大小而不用搜索。对于那些不能这么做的流,你仍然可以返回-1。
附加库
官方扩展库SDL_image, SDL_ttf, SDL_mixer 和 SDL_net都有了对应SDL2.0的版本:SDL2_image, SDL2_ttf, SDL2_mixer 和 SDL2_net.你可能需要从mercurial源码库去下载这些最新修补程序。随后,当然,你必须去链接像是 SDL2_image而不是SDL_image,然后编译你的程序。
这些库不会支持1.2以前的版本,并且与1.2的兼容很可能会在某个新版本后消息。
SDL_gfx从2.0.21版开始也能跟2.0编译了(2010年5月)
重命名和替换的总结
将旧功能和其它一些东西去掉的一份简短的备忘单:
- SDL_SetVideoMode():使用SDL_CreateWindow()替换(以及SDL_CreateRenderer(),如果你想要做传统的2D渲染而不是OpenGL的话)
- SDL_ListModes():使用SDL_GetDisplayMode()/SDL_GetNumDisplayModes()替换
- SDL_UpdateRect()/SDL_Flip():使用 SDL_RenderPresent() 替换
- SDL_Surface/2D 渲染:surfaces仍然存在,但是建议使用SDL_Surfaces代替,如果可能的话SDL_Textures和2D加速渲染器(SDL_CreateRenderer())一起使用
- SDL_VideoInfo:使用SDL_GetRendererInfo()/SDL_GetRenderDriverInfo()替换
- SDL_GetCurrentVideoDisplay():使用SDL_GetWindowDisplayIndex() 替换
- SDL_VIDEORESIZE事件:新的等价事件是SDL_WINDOWEVENT_RESIZE
其他的东东
在SDL2.0中有大量新的和有趣的功能,这在1.2版中是不能想象的。我们只是在试图向你解释将你的程序从1.2运行到2.0要做的事情,但是你应该去探索那些你常常期望的东西,到现在为止,还没有这么做过。例如,每一次游戏结束的时候的会调用一个消息框函数,就像下面一样:
#if USING_SDL
fprintf(stderr, "MSGBOX: %s\n%s\n", title, text); // oh well.
#endif
现在有了SDL_ShowSimpleMessageBox()。不用客气!
如果你跳过了前面部分,返回并且查看所有新功能的概述。