废话不说了,开始。
我的电脑是XP系统,就先看win32源码,但是其他系统里的代码肯定也要一起分析。直接去下载SDL源码 for win32就可以了。
然后下载一个driect 9.0C SDK,头文件和lib设置一下 编译,一切OK。
先简单分析一下SDL的跨平台机制,大家都模仿。花了一个图,直观嘛
下面开始分析代码,最开始就从最简单的开始!看SDL自带的第一个例子
工程名字:graywin
程序流程:
首先运行SDL_Init(SDL_INIT_VIDEO) 这个参数标识我们的应用程序是一个显示应用程序,当然可以定义成为其他的步入音频等等。
程序里面几个重要的结构体先记录一下:
//sdl video drvier 驱动信息。
struct SDL_VideoDevice {
/* The name of this video driver */
const char *name; // example windib SDL在windows中默认使用的驱动。
int (*VideoInit)(_THIS, SDL_PixelFormat *vformat); //写这个的目的不是说他多有用,而是说明SDL一种惯用的手法,他喜欢在结构体里面定义很多和该结构体相关的函数,然后在需要的地方用 p->VideoInit(this, vformat);的形式调用,这样做对上层用户来说是不可见的,任何时候可以通过 p->VideoInit = otherVideoInit;的形式来重载,这样就方便上层用户插入处理。。可能MFC也是这样搞的。不过是用了C++ 和 链表而已(没有用纯虚函数)。
//这个结构体简单点说就是一个矩形的图形区域。
typedef struct SDL_Surface {
Uint32 flags; //是否支持硬件加速,也就是Surface是在内存中还是在显存中
SDL_PixelFormat *format; //像素格式
} SDL_Surface;
初始化完了SDL_VideoDevice之后,就开始注册窗口类,显示窗口,进入消息循环。WinMessage,这些都是系统相关的过程,其他的OS不一样。但是每个系统都会有消息泵,当消息泵接收到消息之后会把系统相关的消息封装成系统无关的消息,例如SDL_Event event; 然后通过SDL_PushEvent(&event);压入一个队列中。
接下来 主程序会进入一个获取 SDL_Event的消息循环如下
while(1)
{
SDL_WaitEvent(&event);
SDL_Sleep();
//...........handler operation.
}
讲了下大概的流程,接下来会具体分析每个部分。
总流程和消息机制
第一个工程分析 目录:\SDL\VisualC\tests\checkkeys.vcproj
首先了解,我使用的是系统缓冲,而不是显存。只有一个SDL_Surface可以显示 ,主要原因就在于它的元素pixels,其他的SDL_Surface都是这一个的助手。
一:主线程
1: 第一个重要函数 SDL_Init(SDL_INIT_VIDEO), 他所完成的工作:初始化 一个SDL_VideoDevice对象,这就是最大的地主,包含很多默认的处理函数,这个对象包含的内容很多,消息队列,屏幕显示和显示硬件等都和它有关。
win32里面默认有3个视频显示驱动,分别为 windib directx dummy,我的系统默认加载的是windib,他完成对SDL_VideoDevice对象的初始化。
2: 初始化窗口类,注册窗口,获取系统信息(语言,OS等) CreateWindow and ShowWindow
3: 等待初始化消息处理完毕,代码:
while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
if ( msg.message == WM_QUIT ) break;
TranslateMessage( &msg );
DispatchMessage( &msg );
}
4: 建立一个device-independent bitmap (DIB). 赋给 SDL_Surface对象
5: 键盘事件转化为跨平台。static SDLKey VK_keymap[SDLK_LAST]; 将系统相关的键盘代码转换为SDLKey。
例如VK_keymap[VK_BACK] = SDLK_BACKSPACE; //VK_BACK = 0x08 SDLK_BACKSPACE = 8 其他系统中VK_BACK可能不一样但是转化到SDLK_BACKSPACE之后都一样了。
6: 第一个重要函数 SDL_SetVideoMode, 他所完成的工作:通过CreateDIBSection获得FB地址
二:消息处理函数,极度缩减的伪代码来说明
SDL_Event event; //
WinMessage
{
if(we dont need)
{
系统默认的处理函数
}
if(the message we need)
{
event.type = 事件类型 例如 SDL_ACTIVE
event.**. = 每个事件类型需要的附加数据
AddMsg2Queen(&event); //将我们需要的事件加入到SDL事件队列中,其实就是个SDL_Event定长数组
}
}
最后一个关键地方,就是用户消息处理函数,SDL的做法很变态。具体如下:
while(1)
{
while(1) //只要有新消息到来就一直获取(后台会存入SDL消息队列)
{
if(no new message coming)
break;
else
GetMessage();
}
SDL_PopMsg(&sdl event); //如果SDL消息队列有消息就取出一条返回给调用者处理。
if(no new sdl event) //如果没有消息 延迟10ms
delay(10ms);
}
为什么要这样做?我怎么都觉得没有传统的消息循环效率高。
CreateCursor
signal
LoadKeyboardLayout
GetEnvironmentVariable
EnumDisplaySettings
AdjustWindowRectEx
SetCapture