https://github.com/zytc2009/BigTeam_learning
分类: C/C++
2010-12-02 15:50:14
基本是对所学的总结,并且内容东拼西凑。
SDL是Simple DirectMedia Layer(简易直控媒体层)的缩写。它是一个跨平台的多媒体库,以用于直接控制底层的多媒体硬件的接口。这些多媒体功能包括了音频、键盘和鼠标(事 件)、游戏摇杆等。当然,最为重要的是提供了2D图形帧缓冲(framebuffer)的接口,以及为OpenGL与各种操作系统之间提供了统一的标准接 口以实现3D图形。
SDL的安装不用多说了,到处都有讲。
SDL_Init();
SDL初始化函数,里面主要是初始化内存等。
SDL为我们提供了两种等待事件的方式:
int SDL_WaitEvent(SDL_Event *event); int SDL_PollEvent(SDL_Event *event);
嗯,其中SDL_Event是对OS相关的事件结构体的再封装。。一般来说系统应该只有一个消息队列,但是对于模态对话框就需要新的消息队列来覆盖原来的消息队列了。
SDL_Surface *SDL_SetVideoMode(int width, int height, int bitsperpixel, Uint32 flags);
恩,
这个函数是创建一个内存FB或者硬件FB。。SDL_Surface代表了这个FB的内容。需要注意的是系统中真实的显示FB只能有一个,但是需要其他的
来用于缓存显示。显示的时候先SDL_BlitSurface将其他FB赋给显示FB ,然后SDL_Flip即显示就OK了。
需要注意的是硬件加速问题,必须利用双缓冲,否则会有问题,什么问题?会出现撕裂效果。。。。。。。反正很不爽。另外需要注意在硬件加速下,不能直接访问到FB,因为没有权利。。。。。。。。。。。。还要注意SDL_Surface的深入复制问题。小心出错。
另外可以看看SDL_Surface结构体里面有一个SDL_PixelFormat *format;成员。我们一般会选择使用作为被抠色的矩形图片的颜色格式。
如果要显示文本,就使用用*.ttf文件,据我所知,freetype不错。。。 有机会还要深入研究一下。
感觉SDL的错误处理机制是学习了 MS的 getlasterror 机制。。。。。。。大家认为呢。
SDL_LoadBMP(char*)
没什么好说的就是加载图片,看看BMP图片格式就行了。这是最简单的图片格式,一般加载16或者32位色的。
一个界面离不开按钮等控件,我要说的就是不管是什么控件,你就按着要求画图就行了,状态改变的时候再重新画图或者对控件指定区域画图,其实不是画 图,是画FB。。。。。。。。。。。。。所以呢,所有控件都是对用户而言的,对程序而言只有图片和敏感区域而已。判断鼠标区域而已,程序麻烦一点罢了但是 不难。
多线程,还真没有什么好说的,和一般的一样用就行了。对了,要注意工作者线程和UI线程。。。。只有UI线程才处理事件。
下面开始分析代码,最开始就从最简单的开始!看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