`

SDL源码阅读笔记(3)渲染模块

 
阅读更多

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie

讨论新闻组及文件

这是SDL中我最关心的模块,即SDL是怎么抽象渲染模块的接口然后实现跨平台的,已经在DirectX/OpenGL中绘制图形的。
本文与前面两篇使用不同的描述方式,前面两篇文章以结构性的铺开分析为主,本文决定使用流程分析。

SDL+OpenGL

对于OpenGL版本,由于主要的绘制都是由OpenGL的API来完成,与SDL关系并不大,所以只看SDL_SetVideoMode 部分。
在写上一篇文章 的时候,我很惊讶的发现,即使是在SDL使用了DirectX版本的video driver后,仍然可以使用OpenGL来完成渲染。关键点在SDL_SetVideoMode 函数上,先看此函数。
使用OpenGL时,用以下方式调用此函数:
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 16, SDL_OPENGL);
即最后一个参数为SDL_OPENGL。
此时,最后使用DirectX来渲染还是使用OpenGL来渲染,最大的不同自然在于surface的创建,
在SDL_SetVideoMode中会有这么一句:
mode = video->SetVideoMode(this, prev_mode,video_w,video_h,video_bpp,flags);
即使用当前video driver来设置video mode,由于我已经选中了directX的video driver了,所以实际调用的是:
SDL_Surface *DX5_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
此函数中,有这么一段代码:

/* If we are setting a GL mode, use GDI, not DirectX (yuck) */
if ( flags & SDL_OPENGL ) {
Uint32 Rmask, Gmask, Bmask;

/* Recalculate the bitmasks if necessary */
if ( bpp == current->format->BitsPerPixel ) {
video = current;
} else {
switch (bpp) {
case 15 :
case 16 :
if ( 0 /* DIB_SussScreenDepth() == 15 */ ) {
/* 5-5-5 */
Rmask = 0x00007c00 ;
Gmask = 0x000003e0 ;
Bmask = 0x0000001f ;
} else {
/* 5-6-5 */
Rmask = 0x0000f800 ;
Gmask = 0x000007e0 ;
Bmask = 0x0000001f ;
}
break ;
case 24 :
case 32 :
/* GDI defined as 8-8-8 */
Rmask = 0x00ff0000 ;
Gmask = 0x0000ff00 ;
Bmask = 0x000000ff ;
break ;
default :
Rmask = 0x00000000 ;
Gmask = 0x00000000 ;
Bmask = 0x00000000 ;
break ;
}
video = SDL_CreateRGBSurface(SDL_SWSURFACE, 0 , 0 , bpp,
Rmask, Gmask, Bmask, 0 );
if ( video == NULL ) {
SDL_OutOfMemory();
return (NULL );
}
}

看作者的注释:
/* If we are setting a GL mode, use GDI, not DirectX (yuck) */
啥都明白了,原来即使是使用DirectX的video driver,SDL会在SetVideoMode的时候判断是否是使用OpenGL,是的话还是改用了GDI。
然后,WIN_GL_SetupWindow函数中,完成了在Windows下使用OpenGL需要设定的内容。具体的内容可以参考《Win32下的OpenGL编程必须步骤 》。

既然使用DirectX版本video driver的SDL最后其实也是使用GDI版本的surface,这里回头来看看GDI版本创建surface的步骤。
在GDI版本的video driver实际调用的是DIB_SetVideoMode函数来设定VideMode。

/* Recalculate the bitmasks if necessary */
if ( bpp == current->format->BitsPerPixel ) {
video = current;
} else {
switch (bpp) {
case 15 :
case 16 :
if ( DIB_SussScreenDepth() == 15 ) {
/* 5-5-5 */
Rmask = 0x00007c00 ;
Gmask = 0x000003e0 ;
Bmask = 0x0000001f ;
} else {
/* 5-6-5 */
Rmask = 0x0000f800 ;
Gmask = 0x000007e0 ;
Bmask = 0x0000001f ;
}
break ;
case 24 :
case 32 :
/* GDI defined as 8-8-8 */
Rmask = 0x00ff0000 ;
Gmask = 0x0000ff00 ;
Bmask = 0x000000ff ;
break ;
default :
Rmask = 0x00000000 ;
Gmask = 0x00000000 ;
Bmask = 0x00000000 ;
break ;
}
video = SDL_CreateRGBSurface(SDL_SWSURFACE,
0 , 0 , bpp, Rmask, Gmask, Bmask, 0 );
if ( video == NULL ) {
SDL_OutOfMemory();
return (NULL );
}
}

其实与DX5_SetVideoMode中创建Surface的代码一模一样,DX5_SetVideoMode函数中所谓的使用GDI的surface其实指的就是拷贝一份GDI创建surface的代码过去吧。。。。。接下来,同样的调用WIN_GL_SetupWindow完成Windows下设置OpenGL使用的必要操作。
看完相关源代码后,发现一切还是比较简单。

SDL GDI video driver

看完了SDL+OpenGL,这里了解一下SDL在使用GDI video driver时,自己附带的渲染功能。至于DirectX部分我就不看了,毕竟我对DirectX了解的不算太多,而且SDL用的DirectX版本实在太老了,但是,其实应该也不难懂,使用DDraw的方法其实和SDL的surface差不多。
SDL_LoadBMP其实是这样定义的一个宏:
#define SDL_LoadBMP(file) SDL_LoadBMP_RW(SDL_RWFromFile(file, "rb"), 1)
SDL用SDL_Surface * SDL_LoadBMP_RW (SDL_RWops *src, int freesrc)这个函数来完成自己的从二进制数据中对BMP的解析,没有使用Windows提供的API(为了不同平台使用一套代码),加上BMP图形的数据解析起来还是比较简单的。

用类似
SDL_Surface *screen = SDL_SetVideoMode(640 , 480 , 16 , SDL_DOUBLEBUF);
的代码创建surface的时候,(即不是使用OpenGL的时候)
在SetVideoMode的时候,SDL用以下代码来完成offscreen buffer:(这也是我第一次了解怎么使用Windows API来创建offscreen buffer)

/* Create the offscreen bitmap buffer */
hdc = GetDC(SDL_Window);
screen_bmp = CreateDIBSection(hdc, binfo, DIB_RGB_COLORS,
(void **)(&video->pixels), NULL , 0 );
ReleaseDC(SDL_Window, hdc);
SDL_free(binfo);
if ( screen_bmp == NULL ) {
if ( video != current ) {
SDL_FreeSurface(video);
}
SDL_SetError("Couldn't create DIB section" );
return (NULL );
}

最主要的API自然是CreateDIBSection,我查了下MSDN:

CreateDIBSection Function

The CreateDIBSection function creates a DIB that applications can write to directly. The function gives you a pointer to the location of the bitmap bit values. You can supply a handle to a file-mapping object that the function will use to create the bitmap, or you can let the system allocate the memory for the bitmap.


按API的意思,其实这也不是原生用于offscreen buffer的,仅仅是一个可以直接写bitmap的内存。
在最后flip的时候,下面这段函数很关键:

static void DIB_NormalUpdate(_THIS, int numrects, SDL_Rect *rects)
{
HDC hdc, mdc;
int i;

hdc = GetDC(SDL_Window);
if ( screen_pal ) {
SelectPalette(hdc, screen_pal, FALSE);
}
mdc = CreateCompatibleDC(hdc);
SelectObject(mdc, screen_bmp);
for ( i=0 ; i
BitBlt(hdc, rects[i].x, rects[i].y, rects[i].w, rects[i].h,
mdc, rects[i].x, rects[i].y, SRCCOPY);
}
DeleteDC(mdc);
ReleaseDC(SDL_Window, hdc);
}

在这里,使用了

mdc = CreateCompatibleDC(hdc);
SelectObject(mdc, screen_bmp);

选择offscreen buffer到新创建的mdc中,然后从新创建的mdc向当前的hdc进行BitBlt,完成flip操作。当然,个人感觉,这种GDI模拟offscreen buffer的操作,在flip的时候还需要进行BitBlt,即使在两个dc间进行BitBlt比从内存到dc的快,但是效率上还是与OpenGL/D3D那种直接支持offscrren buffer的不在一个数量级,那可是直接切换显示不同区域的显存数据而已。

SDL源码大概浏览了一遍,没有细看,总的来说,看源码还是挺有帮助的,对于开源软件来说,文档也不能完全的详细说明每一个API的使用,但是对于开源软件,源码就是最好的文档。就此结束SDL的源码阅读过程,下一步,也许是略看Orx源码的时候了。。。。。。。。。。。。。。。。。。。。。。

总结

基本上,对于游戏来讲,OpenGL的渲染部分其实并没有太大价值,虽然其接口的确非常简单,(也许不是游戏可以考虑使用一下)但是,作为一个跨平台的库,SDL还是有其独特的价值,SDL提供了一个跨平台的窗口管理模块,事件系统,多线程模块,声音模块,并且能够让你很方便的使用OpenGL渲染与其配置,基本上可以看做是一个非常强大并且完整的OpenGL使用环境。就像glut/free glut曾经想要做到的那样,只不过SDL比其走的更远而已。类似的库还有GLFW ,完成的其实也不错。对于只想好好的关心渲染部分,对其他跨平台的脏活累活不感兴趣的,SDL算是不错的选择。

原创文章作者保留版权 转载请注明原作者 并给出链接

write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie







分享到:
评论

相关推荐

    Qt使用SDL2\D3D渲染YUV420p

    在本文中,我们将深入探讨如何在Qt环境中利用SDL2和Direct3D(D3D)渲染YUV420p视频格式。YUV420p是一种常见的视频颜色空间,广泛应用于数字视频编码和解码中,因为它可以有效降低存储和传输的带宽需求。 首先,让...

    SDL2.0.3源码安装包

    **标题解析:** "SDL2.0.3源码安装包" 指的是Simple DirectMedia Layer(SDL)的版本2.0.3的源代码安装包。SDL是一个跨平台的开发库,主要用于处理图形、音频、输入设备等多媒体功能,尤其在游戏开发和图形用户界面...

    sdl的linux源码包SDL2-2.0.2

    描述中的“sdl的linux源码包SDL2-2.0.2”进一步确认了这是针对Linux操作系统的SDL2库的特定版本。SDL2是SDL的第二个主要版本,它提供了一些新特性和改进,以适应现代开发需求。 **Linux运维与服务器关联** 在Linux...

    sdl.rar SDL2-2.0.14 SDL源码

    标题"SDL.rar SDL2-2.0.14 SDL源码"表明这个压缩包包含了SDL库的源代码,具体版本为2.0.14。SDL是"Simple DirectMedia Layer"的缩写,它是一个跨平台的开发库,主要用于处理图形、音频、输入设备等多媒体功能,常...

    SDL 2.0 源码下载

    **SDL 2.0 源码解析与应用** **一、SDL库介绍** Simple DirectMedia Layer(简称SDL)是一个跨平台的开发库,主要用于处理底层的多媒体资源,包括图形、音频、输入设备等。SDL 2.0是其最新的版本,提供了许多改进...

    SDL库及源码.rar

    SDL库的源码通常分为多个子模块,如audio、video、render、joystick、timer等,每个模块对应库的一个功能领域。源码中包含头文件(.h)和实现文件(.c),以及构建脚本和配置文件,使得在不同平台上编译和链接变得...

    SDL2源码包

    3. **渲染图形**:通过`SDL_Renderer`对象,可以进行2D渲染。创建渲染器,设置渲染目标,然后使用`SDL_RenderDrawPoint`、`SDL_RenderDrawLine`等函数绘制图形。 4. **处理事件**:通过`SDL_PollEvent`或`SDL_...

    SDL2-2.0.2.tar.gz源码

    标题"SDL2-2.0.2.tar.gz源码"表明这是一个开源软件库的源代码包,使用的是版本控制格式`.tar.gz`,具体来说是SDL2库的2.0.2版本。SDL2是Simple DirectMedia Layer的第二版,是一个跨平台的开发库,主要用于处理...

    SDL-1.2.15-lib包含源码

    源码通常按照模块组织,例如音频处理、视频渲染、事件处理、文件I/O等。在`SDL-1.2.15`中,你可能会找到如下的目录结构: - `include/`:包含了SDL头文件,这些头文件定义了API接口,供程序员在他们的程序中引用。 ...

    SDL2源码.tar.gz

    3. **图形渲染**:SDL2支持2D图形渲染,包括颜色填充、线条绘制和位图操作。源码展示了如何使用OpenGL或Direct3D进行硬件加速,提升性能。 4. **音频处理**:SDL2提供了音频流的播放、混音和管理功能。通过源码,...

    SDL2_SDL2_SDL2_

    3. **图像加载与显示**:SDL2 支持多种图像格式(如 PNG、JPEG、BMP 等),可以方便地加载和显示这些图像,用于游戏背景、角色动画等。 4. **音频处理**:SDL2 包含了音频混音器,可以播放音频文件,支持多种音频...

    FFMpeg+SDL源码和编译好的动态库

    你可以使用FFmpeg读取和解码视频流,然后通过SDL将解码后的帧渲染到屏幕上,并处理用户的控制输入。此外,还可以利用SDL的音频子系统播放视频的伴音,实现完整的多媒体体验。 总的来说,这个压缩包提供了FFmpeg和...

    SDL-1.3源码包

    通过阅读和调试源码,开发者可以学习到如何利用SDL进行窗口管理、渲染图像、播放音频等。 5. **跨平台特性** SDL的设计目标之一就是跨平台兼容性。因此,源码包中的代码不仅适用于Android,还可以移植到其他操作...

    SDL2视频渲染库

    `SDL_Renderer`是SDL2视频渲染的核心组件,它是渲染目标的抽象接口,负责将图像数据转化为像素并显示在屏幕上。开发者可以通过创建一个渲染器实例来选择不同的渲染后端,如OpenGL、Direct3D或软件渲染器。创建渲染器...

    纯c实现最新的SDL2调用mp3源码

    【标题】"纯C实现最新的SDL2调用mp3源码"揭示了使用C语言编写的一个程序,该程序借助SDL2库的Mixer模块来播放MP3音频文件。SDL(Simple DirectMedia Layer)是一个跨平台的开发库,设计用于处理图形、音频和输入设备...

    SDL-1.2.13游戏引擎源码

    2. **图形渲染**:SDL提供了简单的2D图形绘制功能,包括颜色填充、线条绘制、位图操作等。源码中可以找到这些函数的实现,以及如何在屏幕上更新图像。 3. **事件处理**:SDL通过事件驱动模型处理用户输入,如键盘、...

    SDL Android下编译源码

    在实际开发中,你还需要编写自己的C/C++代码,调用SDL API来实现具体功能,如渲染图像、处理用户输入和播放音频。SDL提供了丰富的函数和结构体,如`SDL_Init()`、`SDL_CreateWindow()`、`SDL_Event`等,可以帮助你...

    SDL Game Development 源码_基于SDL2.0

    3. **渲染上下文**:`SDL_Renderer`用于图像渲染,创建渲染器用`SDL_CreateRenderer`,并可选择不同的渲染器类型(如硬件加速的GPU渲染)。`SDL_RenderClear`和`SDL_RenderPresent`用于清空和显示帧缓冲区。 4. **...

    SDL1.2编译完成文件,包括SDL.dll, SDLMain.lib,以及SDL1.2.6的源码

    对SDL1.2的源码进行编译,生成SDL.dll和SDLMain.lib文件,便于不想要进行搭建编译环境,而想要学习SDL1.2的朋友,因为SDL1和SDL2之间的差别还是很大的,对于Focus On SDL而言,就是利用的SDL1.*,而网上下载很少有...

    SDL库移植笔记

    记录了SDL库成功移植到s3c6410开发板上,很详细,帮你完成移植工作

Global site tag (gtag.js) - Google Analytics