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

前一篇文章 讲了SDL的除video以外的大部分模块。本文主要关注SDL的video模块部分。

SDL中的video模块包含了大部分与平台相关的代码,并且SDL处理的很有技巧性,这里利用C语言的函数指针来模拟了一种类似于面向对象的效果。
主要的关键点在
SDL_VideoDevice *current_video = NULL;
这一句定义的全局变量current_video上,我们先来看看这个变量类型SDL_VideoDevice。
主要在SDL_sysvideo.h这个文件中

struct  SDL_VideoDevice {
    /*  * * */ 
    /*  The name of this video driver */ 
    const  char  *name;

/*  * * */ 
    /*  Initialization/Query functions */

/*  Initialize the native video subsystem, filling 'vformat' with the 
       "best" display pixel format, returning 0 or -1 if there's an error. 
     */ 
    int  (*VideoInit)(_THIS, SDL_PixelFormat *vformat);

/*  List the available video modes for the given pixel format, sorted 
       from largest to smallest. 
     */ 
    SDL_Rect **(*ListModes)(_THIS, SDL_PixelFormat *format, Uint32 flags);

/*  Set the requested video mode, returning a surface which will be 
       set to the SDL_VideoSurface.  The width and height will already 
       be verified by ListModes(), and the video subsystem is free to 
       set the mode to a supported bit depth different from the one 
       specified -- the desired bpp will be emulated with a shadow 
       surface if necessary.  If a new mode is returned, this function 
       should take care of cleaning up the current mode. 
     */ 
    SDL_Surface *(*SetVideoMode)(_THIS, SDL_Surface *current,
                int  width, int  height, int  bpp, Uint32 flags);

/*  Toggle the fullscreen mode */ 
    int  (*ToggleFullScreen)(_THIS, int  on);

/*  This is called after the video mode has been set, to get the 
       initial mouse state.  It should queue events as necessary to 
       properly represent the current mouse focus and position. 
     */ 
    void  (*UpdateMouse)(_THIS);

/*  Create a YUV video surface (possibly overlay) of the given 
       format.  The hardware should be able to perform at least 2x 
       scaling on display. 
     */ 
    SDL_Overlay *(*CreateYUVOverlay)(_THIS, int  width, int  height,
                                     Uint32 format, SDL_Surface *display);

/*  Sets the color entries { firstcolor .. (firstcolor+ncolors-1) } 
       of the physical palette to those in 'colors'. If the device is 
       using a software palette (SDL_HWPALETTE not set), then the 
       changes are reflected in the logical palette of the screen 
       as well. 
       The return value is 1 if all entries could be set properly 
       or 0 otherwise. 
    */ 
    int  (*SetColors)(_THIS, int  firstcolor, int  ncolors,
             SDL_Color *colors);

/*  This pointer should exist in the native video subsystem and should 
       point to an appropriate update function for the current video mode 
     */ 
    void  (*UpdateRects)(_THIS, int  numrects, SDL_Rect *rects);

/*  Reverse the effects VideoInit() -- called if VideoInit() fails 
       or if the application is shutting down the video subsystem. 
    */ 
    void  (*VideoQuit)(_THIS);

/*  * * */ 
    /*  Hardware acceleration functions */

/*  Information about the video hardware */ 
    SDL_VideoInfo info;

/*  The pixel format used when SDL_CreateRGBSurface creates SDL_HWSURFACEs with alpha */ 
    SDL_PixelFormat* displayformatalphapixel;
    
    /*  Allocates a surface in video memory */ 
    int  (*AllocHWSurface)(_THIS, SDL_Surface *surface);

/*  Sets the hardware accelerated blit function, if any, based 
       on the current flags of the surface (colorkey, alpha, etc.) 
     */ 
    int  (*CheckHWBlit)(_THIS, SDL_Surface *src, SDL_Surface *dst);

/*  Fills a surface rectangle with the given color */ 
    int  (*FillHWRect)(_THIS, SDL_Surface *dst, SDL_Rect *rect, Uint32 color);

/*  Sets video mem colorkey and accelerated blit function */ 
    int  (*SetHWColorKey)(_THIS, SDL_Surface *surface, Uint32 key);

/*  Sets per surface hardware alpha value */ 
    int  (*SetHWAlpha)(_THIS, SDL_Surface *surface, Uint8 value);

/*  Returns a readable/writable surface */ 
    int  (*LockHWSurface)(_THIS, SDL_Surface *surface);
    void  (*UnlockHWSurface)(_THIS, SDL_Surface *surface);

/*  Performs hardware flipping */ 
    int  (*FlipHWSurface)(_THIS, SDL_Surface *surface);

/*  Frees a previously allocated video surface */ 
    void  (*FreeHWSurface)(_THIS, SDL_Surface *surface);

/*  * * */ 
    /*  Gamma support */

Uint16 *gamma;

/*  Set the gamma correction directly (emulated with gamma ramps) */ 
    int  (*SetGamma)(_THIS, float  red, float  green, float  blue);

/*  Get the gamma correction directly (emulated with gamma ramps) */ 
    int  (*GetGamma)(_THIS, float  *red, float  *green, float  *blue);

/*  Set the gamma ramp */ 
    int  (*SetGammaRamp)(_THIS, Uint16 *ramp);

/*  Get the gamma ramp */ 
    int  (*GetGammaRamp)(_THIS, Uint16 *ramp);

/*  * * */ 
    /*  OpenGL support */

/*  Sets the dll to use for OpenGL and loads it */ 
    int  (*GL_LoadLibrary)(_THIS, const  char  *path);

/*  Retrieves the address of a function in the gl library */ 
    void * (*GL_GetProcAddress)(_THIS, const  char  *proc);

/*  Get attribute information from the windowing system. */ 
    int  (*GL_GetAttribute)(_THIS, SDL_GLattr attrib, int * value);

/*  Make the context associated with this driver current */ 
    int  (*GL_MakeCurrent)(_THIS);

/*  Swap the current buffers in double buffer mode. */ 
    void  (*GL_SwapBuffers)(_THIS);

/*  OpenGL functions for SDL_OPENGLBLIT */ 
#if SDL_VIDEO_OPENGL 
#if !defined(__WIN32__) 
#define WINAPI 
#endif 
#define SDL_PROC(ret,func,params) ret (WINAPI *func) params; 
#include "SDL_glfuncs.h" 
#undef SDL_PROC

/*  Texture id */ 
    GLuint texture;
#endif 
    int  is_32bit;
 
    /*  * * */ 
    /*  Window manager functions */

/*  Set the title and icon text */ 
    void  (*SetCaption)(_THIS, const  char  *title, const  char  *icon);

/*  Set the window icon image */ 
    void  (*SetIcon)(_THIS, SDL_Surface *icon, Uint8 *mask);

/*  Iconify the window. 
       This function returns 1 if there is a window manager and the 
       window was actually iconified, it returns 0 otherwise. 
    */ 
    int  (*IconifyWindow)(_THIS);

/*  Grab or ungrab keyboard and mouse input */ 
    SDL_GrabMode (*GrabInput)(_THIS, SDL_GrabMode mode);

/*  Get some platform dependent window information */ 
    int  (*GetWMInfo)(_THIS, SDL_SysWMinfo *info);

/*  * * */ 
    /*  Cursor manager functions */

/*  Free a window manager cursor 
       This function can be NULL if CreateWMCursor is also NULL. 
     */ 
    void  (*FreeWMCursor)(_THIS, WMcursor *cursor);

/*  If not NULL, create a black/white window manager cursor */ 
    WMcursor *(*CreateWMCursor)(_THIS,
        Uint8 *data, Uint8 *mask, int  w, int  h, int  hot_x, int  hot_y);

/*  Show the specified cursor, or hide if cursor is NULL */ 
    int  (*ShowWMCursor)(_THIS, WMcursor *cursor);

/*  Warp the window manager cursor to (x,y) 
       If NULL, a mouse motion event is posted internally. 
     */ 
    void  (*WarpWMCursor)(_THIS, Uint16 x, Uint16 y);

/*  If not NULL, this is called when a mouse motion event occurs */ 
    void  (*MoveWMCursor)(_THIS, int  x, int  y);

/*  Determine whether the mouse should be in relative mode or not. 
       This function is called when the input grab state or cursor 
       visibility state changes. 
       If the cursor is not visible, and the input is grabbed, the 
       driver can place the mouse in relative mode, which may result 
       in higher accuracy sampling of the pointer motion. 
    */ 
    void  (*CheckMouseMode)(_THIS);

/*  * * */ 
    /*  Event manager functions */

/*  Initialize keyboard mapping for this driver */ 
    void  (*InitOSKeymap)(_THIS);

/*  Handle any queued OS events */ 
    void  (*PumpEvents)(_THIS);

/*  * * */ 
    /*  Data common to all drivers */ 
    SDL_Surface *screen;
    SDL_Surface *shadow;
    SDL_Surface *visible;
        SDL_Palette *physpal;   /*  physical palette, if != logical palette */ 
        SDL_Color *gammacols;   /*  gamma-corrected colours, or NULL */ 
    char  *wm_title;
    char  *wm_icon;
    int  offset_x;
    int  offset_y;
    SDL_GrabMode input_grab;

/*  Driver information flags */ 
    int  handles_any_size;  /*  Driver handles any size video mode */

/*  * * */ 
    /*  Data used by the GL drivers */ 
    struct  {
        int  red_size;
        int  green_size;
        int  blue_size;
        int  alpha_size;
        int  depth_size;
        int  buffer_size;
        int  stencil_size;
        int  double_buffer;
        int  accum_red_size;
        int  accum_green_size;
        int  accum_blue_size;
        int  accum_alpha_size;
        int  stereo;
        int  multisamplebuffers;
        int  multisamplesamples;
        int  accelerated;
        int  swap_control;
        int  driver_loaded;
        char  driver_path[256 ];
        void * dll_handle;
    } gl_config;

/*  * * */ 
    /*  Data private to this driver */ 
    struct  SDL_PrivateVideoData *hidden;
    struct  SDL_PrivateGLData *gl_data;

/*  * * */ 
    /*  The function used to dispose of this structure */ 
    void  (*free)(_THIS);
};

这个结构主要包含的是函数指针,每个函数指针表示了一个与平台相关的函数。在运行时,给这些函数指针赋值,指定成对应平台的函数实现,以此实现了使用此结构指针current_video的上层的代码的稳定与一致。

这里首先关心两个流程,其一,初始化给这些函数指针赋值的过程。

这个过程在SDL_VideoInit函数中实现:
SDL初始化基本流程:
SDL_Init(SDL_INIT_VIDEO)->SDL_InitSubSystem(SDL_INIT_VIDEO)->SDL_VideoInit()
中途会调用以"SDL_VIDEODRIVER"为参数调用SDL_getenv函数来获取全局配置中指定的对应的video driver。
代码如下:

if  ( SDL_VideoInit(SDL_getenv("SDL_VIDEODRIVER" ),
                           (flags&SDL_INIT_EVENTTHREAD)) < 0  ) {
            return (-1 );
        }

我没有设定,所以会以name = NULL为第一参数来调用SDL_VideoInit,也就是让SDL自己选择一个video driver。
SDL会从一个

typedef  struct  VideoBootStrap {
    const  char  *name;
    const  char  *desc;
    int  (*available)(void );
    SDL_VideoDevice *(*create)(int  devindex);
} VideoBootStrap;

结构的全局变量bootstrap数组中选取一个可以使用的video driver。
一共有这么多可能的video driver:

/*  Available video drivers */ 
static  VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_QUARTZ 
    &QZ_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_X11 
    &X11_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DGA 
    &DGA_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_NANOX 
    &NX_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_IPOD 
    &iPod_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_QTOPIA 
    &Qtopia_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_WSCONS 
    &WSCONS_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_FBCON 
    &FBCON_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DIRECTFB 
    &DirectFB_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_PS2GS 
    &PS2GS_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_PS3 
    &PS3_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_GGI 
    &GGI_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_VGL 
    &VGL_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_SVGALIB 
    &SVGALIB_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_GAPI 
    &GAPI_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_WINDIB 
    &WINDIB_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DDRAW 
    &DIRECTX_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_BWINDOW 
    &BWINDOW_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_TOOLBOX 
    &TOOLBOX_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DRAWSPROCKET 
    &DSp_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_PHOTON 
    &ph_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_EPOC 
    &EPOC_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_XBIOS 
    &XBIOS_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_GEM 
    &GEM_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_PICOGUI 
    &PG_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DC 
    &DC_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_NDS 
    &NDS_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_RISCOS 
    &RISCOS_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_OS2FS 
    &OS2FSLib_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_AALIB 
    &AALIB_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_CACA 
    &CACA_bootstrap,
#endif 
#if SDL_VIDEO_DRIVER_DUMMY 
    &DUMMY_bootstrap,
#endif 
    NULL 
};

都是通过宏来筛选的。
-        bootstrap    0x100a2b1c bootstrap    VideoBootStrap * [4]
+        [0x0]    0x100a1160 _WINDIB_bootstrap {name=0x10099428 "windib" desc=0x1009940c "Win95/98/NT/2000/CE GDI" available=0x1005eaf0 ...}    VideoBootStrap *
+        [0x1]    0x100a25e8 _DIRECTX_bootstrap {name=0x10099ab4 "directx" desc=0x10099a98 "Win95/98/2000 DirectX" available=0x100651d0 ...}    VideoBootStrap *
+        [0x2]    0x100a2aec _DUMMY_bootstrap {name=0x100995a4 "dummy" desc=0x1009b3e4 "SDL dummy video driver" available=0x10072090 ...}    VideoBootStrap *
+        [0x3]    0x00000000 {name=??? desc=??? available=??? ...}    VideoBootStrap *

在我的电脑上(Win32),一共有上面3种可能,windib(即GDI),directX,dummy。事实上OpenGL在Win32的环境中都没有列出来,当然,但是在以前的例子中,我还是使用了SDL+OpenGL来渲染,原因在于video毕竟不是如同其名字所示,仅仅包含渲染或者视频方面的东西,它其实代表了大部分SDL与平台相关的东西,渲染在SDL中也仅仅是占比较小的一部分。

选取video driver的时候,先调用VideoBootStrap 结构中的available 函数来判断此video driver有效则通过此结构的create函数来创建一个video driver.
如下:

for  ( i=0 ; bootstrap[i]; ++i ) {
            if  ( bootstrap[i]->available() ) {
                video = bootstrap[i]->create(index);
                if  ( video != NULL  ) {
                    break ;
                }
            }
        }

创建的时候附带index,并且一旦创建成功,就停止了创建过程,在我的例子中,由于GDI方式排在第一,所以事实上,SDL在Win32环境下默认是选择了使用GDI的video driver。
此GDI video driver的create函数如下:

static  SDL_VideoDevice *DIB_CreateDevice(int  devindex)
{
    SDL_VideoDevice *device;

/*  Initialize all variables that we clean on shutdown */ 
    device = (SDL_VideoDevice *)SDL_malloc(sizeof (SDL_VideoDevice));
    if  ( device ) {
        SDL_memset(device, 0 , (sizeof  *device));
        device->hidden = (struct  SDL_PrivateVideoData *)
                SDL_malloc((sizeof  *device->hidden));
        if (device->hidden){
            SDL_memset(device->hidden, 0 , (sizeof  *device->hidden));
            device->hidden->dibInfo = (DibInfo *)SDL_malloc((sizeof (DibInfo)));
            if (device->hidden->dibInfo == NULL )
            {
                SDL_free(device->hidden);
                device->hidden = NULL ;
            }
        }
        
        device->gl_data = (struct  SDL_PrivateGLData *)
                SDL_malloc((sizeof  *device->gl_data));
    }
    if  ( (device == NULL ) || (device->hidden == NULL ) ||
                         (device->gl_data == NULL ) ) {
        SDL_OutOfMemory();
        DIB_DeleteDevice(device);
        return (NULL );
    }
    SDL_memset(device->hidden->dibInfo, 0 , (sizeof  *device->hidden->dibInfo));
    SDL_memset(device->gl_data, 0 , (sizeof  *device->gl_data));

/*  Set the function pointers */ 
    device->VideoInit = DIB_VideoInit;
    device->ListModes = DIB_ListModes;
    device->SetVideoMode = DIB_SetVideoMode;
    device->UpdateMouse = WIN_UpdateMouse;
    device->SetColors = DIB_SetColors;
    device->UpdateRects = NULL ;
    device->VideoQuit = DIB_VideoQuit;
    device->AllocHWSurface = DIB_AllocHWSurface;
    device->CheckHWBlit = NULL ;
    device->FillHWRect = NULL ;
    device->SetHWColorKey = NULL ;
    device->SetHWAlpha = NULL ;
    device->LockHWSurface = DIB_LockHWSurface;
    device->UnlockHWSurface = DIB_UnlockHWSurface;
    device->FlipHWSurface = NULL ;
    device->FreeHWSurface = DIB_FreeHWSurface;
    device->SetGammaRamp = DIB_SetGammaRamp;
    device->GetGammaRamp = DIB_GetGammaRamp;
#if SDL_VIDEO_OPENGL 
    device->GL_LoadLibrary = WIN_GL_LoadLibrary;
    device->GL_GetProcAddress = WIN_GL_GetProcAddress;
    device->GL_GetAttribute = WIN_GL_GetAttribute;
    device->GL_MakeCurrent = WIN_GL_MakeCurrent;
    device->GL_SwapBuffers = WIN_GL_SwapBuffers;
#endif 
    device->SetCaption = WIN_SetWMCaption;
    device->SetIcon = WIN_SetWMIcon;
    device->IconifyWindow = WIN_IconifyWindow;
    device->GrabInput = WIN_GrabInput;
    device->GetWMInfo = WIN_GetWMInfo;
    device->FreeWMCursor = WIN_FreeWMCursor;
    device->CreateWMCursor = WIN_CreateWMCursor;
    device->ShowWMCursor = WIN_ShowWMCursor;
    device->WarpWMCursor = WIN_WarpWMCursor;
    device->CheckMouseMode = WIN_CheckMouseMode;
    device->InitOSKeymap = DIB_InitOSKeymap;
    device->PumpEvents = DIB_PumpEvents;

/*  Set up the windows message handling functions */ 
    WIN_Activate = DIB_Activate;
    WIN_RealizePalette = DIB_RealizePalette;
    WIN_PaletteChanged = DIB_PaletteChanged;
    WIN_WinPAINT = DIB_WinPAINT;
    HandleMessage = DIB_HandleMessage;

device->free = DIB_DeleteDevice;

/*  We're finally ready */ 
    return  device;
}

开始时为video driver分配内存,然后为相应的参数赋值,最最重要的就是为video driver的函数指针赋值,赋值成当前video driver的函数,以此实现我开始说的,以C语言实现类似面向对象的效果。
video driver的那一堆函数指针就像是抽象的接口,这里的函数就像是子类的实现。上层逻辑只需要使用video driver的指针并调用其中的函数即可,完全统一,并且不用关心指针具体是调用了哪个"子类“的函数。因为习惯了C++,我很少使用C语言来编写大规模的代码,所以对这些特性并不是非常熟悉,但是在C语言实现面向对象特性方面,我见过几派,我感觉这种方式算是比较好的,比完全使用宏来模拟C++的效果看上去要更加容易理解和自然。当然,因为C语言的确没有"标准"的面向对象实现方式,所以到底那个更好,也只能是见仁见智的问题了,估计也会像"大括号战争”一样没有休止。

此处还值得一提的是,SDL_VIDEO_OPENGL宏是默认开启的,也就是说,在Win32下使用GDI这个默认的video driver时,
SDL进行了
    device->GL_LoadLibrary = WIN_GL_LoadLibrary;
    device->GL_GetProcAddress = WIN_GL_GetProcAddress;
    device->GL_GetAttribute = WIN_GL_GetAttribute;
    device->GL_MakeCurrent = WIN_GL_MakeCurrent;
    device->GL_SwapBuffers = WIN_GL_SwapBuffers; 
这些函数的赋值。形成了对OpenGL的支持。这里与我以前了解的有些差异,因为我以前以为SDL在Win32下是默认使用DirectX加速的,现在看来并不是,就如侯捷所言,"源码面前了无秘密",这些点点滴滴的东西,也算是看源码的一种收获。

然后,我查看了文档:
SDL支持哪些系统平台? 》
有如下描述:

  • 有两个版本,一个是适合所有基于Win32的系统的安全版本,另一个是基于DirectX的高性能版本。
  • 安全版本的视频显示采用GDI。高性能版本采用DirectDraw,并支持硬件加速。
  • 安全版本的音频回放采用waveOut API。高性能版本采用DirectSound。

这里可以看出,默认的时候SDL使用了Win32系统的安全版本。

此步初始化后,再利用video driver自己的VideoInit函数再次进行针对特殊的video driver的初始化。然后再开始SDL的事件线程(详细内容见上节)
然后,此时已经回到SDL_InitSubSystem函数了,此函数还需要进行一些其他模块的初始化,比如时间模块,摇杆等,这里就不多讲了。

看到这里,对于初始化部分的流程应该就比较清楚了,现在有个问题:
怎么改变SDL使用的video driver的默认值?比如,改成DirectX版本的。
从上面来看,有两种办法,
其一,改变bootstrap 数组中各driver的顺序,将directX的driver提到第一,那样默认就初始化directX版本了。
其二,让SDL_getenv("SDL_VIDEODRIVER" ) 返回directX版本driver的名字。

个人感觉方法二明显更加自然一些,感觉也是SDL作者提供的选择方案。那么,尝试一下,这里我通过SDL提供的接口SDL_putenv来设置环境变量,看看效果。
根据SDL_getenv的调用及前面查看的bootstrap的值,知道SDL查看的环境变量名为SDL_VIDEODRIVER,directX表示的driver名字为directx,所以在初始化前添加如下代码:
SDL_putenv("SDL_VIDEODRIVER=directx");

可以看到效果是以"directx"为第一参数调用SDL_VideoInit,并且进入了一下代码:

for  ( i=0 ; bootstrap[i]; ++i ) {
            if  ( SDL_strcasecmp(bootstrap[i]->name, driver_name) == 0 ) {
                if  ( bootstrap[i]->available() ) {
                    video = bootstrap[i]->create(index);
                    break ;
                }
            }
        }
此时,通过SDL_strcasecmp的调用,略过了GDI的video driver,然后使用了directX的driver。首先进入的available函数是:DX5_Available,晕了,DX5。。。。。什么年代的东西啊。。。。。。无语中。
在DX5_Available的调用中,仅仅通过以下语句判断了DINPUT.DLL和DDRAW.DLL动态库及DirectDrawCreate函数的存在,来判断DX5 driver是否可用。
DInputDLL = LoadLibrary(TEXT("DINPUT.DLL"));
DDrawDLL = LoadLibrary(TEXT("DDRAW.DLL"));
DDrawCreate = (void *)GetProcAddress(DDrawDLL, TEXT("DirectDrawCreate"));

同时,上述语句也说明,SDL使用的DirectX加速使用的是DX5.....并且使用的是DirectDraw,在那古老的年代,我不知道有没有D3D,不过对DDraw的使用倒是印证了我初看SDL渲染接口时的印象,抽象的接口与DDraw太像了。。。。。。。下面函数赋值的时候应该还能看到。

DX5_CreateDevice为SDL DirectX driver的创建函数,如同GDI版本一样对函数进行赋值。

/*  Set the function pointers */ 
    device->VideoInit = DX5_VideoInit;
    device->ListModes = DX5_ListModes;
    device->SetVideoMode = DX5_SetVideoMode;
    device->UpdateMouse = WIN_UpdateMouse;
    device->CreateYUVOverlay = DX5_CreateYUVOverlay;
    device->SetColors = DX5_SetColors;
    device->UpdateRects = NULL ;
    device->VideoQuit = DX5_VideoQuit;
    device->AllocHWSurface = DX5_AllocHWSurface;
    device->CheckHWBlit = DX5_CheckHWBlit;
    device->FillHWRect = DX5_FillHWRect;
    device->SetHWColorKey = DX5_SetHWColorKey;
    device->SetHWAlpha = DX5_SetHWAlpha;
    device->LockHWSurface = DX5_LockHWSurface;
    device->UnlockHWSurface = DX5_UnlockHWSurface;
    device->FlipHWSurface = DX5_FlipHWSurface;
    device->FreeHWSurface = DX5_FreeHWSurface;
    device->SetGammaRamp = DX5_SetGammaRamp;
    device->GetGammaRamp = DX5_GetGammaRamp;
#if SDL_VIDEO_OPENGL 
    device->GL_LoadLibrary = WIN_GL_LoadLibrary;
    device->GL_GetProcAddress = WIN_GL_GetProcAddress;
    device->GL_GetAttribute = WIN_GL_GetAttribute;
    device->GL_MakeCurrent = WIN_GL_MakeCurrent;
    device->GL_SwapBuffers = WIN_GL_SwapBuffers;
#endif 
    device->SetCaption = WIN_SetWMCaption;
    device->SetIcon = WIN_SetWMIcon;
    device->IconifyWindow = WIN_IconifyWindow;
    device->GrabInput = WIN_GrabInput;
    device->GetWMInfo = WIN_GetWMInfo;
    device->FreeWMCursor = WIN_FreeWMCursor;
    device->CreateWMCursor = WIN_CreateWMCursor;
    device->ShowWMCursor = WIN_ShowWMCursor;
    device->WarpWMCursor = WIN_WarpWMCursor;
    device->CheckMouseMode = WIN_CheckMouseMode;
    device->InitOSKeymap = DX5_InitOSKeymap;
    device->PumpEvents = DX5_PumpEvents;

/*  Set up the windows message handling functions */ 
    WIN_Activate = DX5_Activate;
    WIN_RealizePalette = DX5_RealizePalette;
    WIN_PaletteChanged = DX5_PaletteChanged;
    WIN_WinPAINT = DX5_WinPAINT;
    HandleMessage = DX5_HandleMessage;

这里我们可以看到,相对GDI版本而言,除了速度之外,DirectX版本明显支持的特性更多,上面的函数指针赋值就没有GDI版本那么多NULL了,全部都有对应的函数。
最让人惊讶的时候,还是有OpenGL的函数。最后经过我测试,的确也是能够使用OpenGL。。。。。。
很显然,关键在于
SDL_Surface* screen = SDL_SetVideoMode( WINDOW_WIDTH, WINDOW_HEIGHT, 16, SDL_OPENGL);

一句的调用。

因为本文太长,在Google Document上输入都已经很卡了,所以留待下篇文章再看。

SDL源码阅读笔记(2) video dirver的初始化及选择的更多相关文章

  1. SDL源码阅读笔记(1) 基本模块

    write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 前言 对于大牛来说,写关于阅读源码的文章都会叫源码剖析或者深入浅出啥的,对于我,自己阅读阅读源码,写 ...

  2. CI框架源码阅读笔记5 基准测试 BenchMark.php

    上一篇博客(CI框架源码阅读笔记4 引导文件CodeIgniter.php)中,我们已经看到:CI中核心流程的核心功能都是由不同的组件来完成的.这些组件类似于一个一个单独的模块,不同的模块完成不同的功 ...

  3. CI框架源码阅读笔记4 引导文件CodeIgniter.php

    到了这里,终于进入CI框架的核心了.既然是“引导”文件,那么就是对用户的请求.参数等做相应的导向,让用户请求和数据流按照正确的线路各就各位.例如,用户的请求url: http://you.host.c ...

  4. CI框架源码阅读笔记3 全局函数Common.php

    从本篇开始,将深入CI框架的内部,一步步去探索这个框架的实现.结构和设计. Common.php文件定义了一系列的全局函数(一般来说,全局函数具有最高的加载优先权,因此大多数的框架中BootStrap ...

  5. CI框架源码阅读笔记2 一切的入口 index.php

    上一节(CI框架源码阅读笔记1 - 环境准备.基本术语和框架流程)中,我们提到了CI框架的基本流程,这里再次贴出流程图,以备参考: 作为CI框架的入口文件,源码阅读,自然由此开始.在源码阅读的过程中, ...

  6. 源码阅读笔记 - 1 MSVC2015中的std::sort

    大约寒假开始的时候我就已经把std::sort的源码阅读完毕并理解其中的做法了,到了寒假结尾,姑且把它写出来 这是我的第一篇源码阅读笔记,以后会发更多的,包括算法和库实现,源码会按照我自己的代码风格格 ...

  7. Three.js源码阅读笔记-5

    Core::Ray 该类用来表示空间中的“射线”,主要用来进行碰撞检测. THREE.Ray = function ( origin, direction ) { this.origin = ( or ...

  8. PHP源码阅读笔记一(explode和implode函数分析)

    PHP源码阅读笔记一一.explode和implode函数array explode ( string separator, string string [, int limit] )此函数返回由字符 ...

  9. AQS源码阅读笔记(一)

    AQS源码阅读笔记 先看下这个类张非常重要的一个静态内部类Node.如下: static final class Node { //表示当前节点以共享模式等待锁 static final Node S ...

随机推荐

  1. Xamarin开发的一个简单画图程序分享

    最近Xamarin比较火,于是稍微看了下,感觉接触过MVC的都应该能很快上手,还挺有意思,于是忍不住写了个简单的画图程序,之前看帖子有人说装不上或者无法部署,估计我比较幸运,编译完了一次就安装成功了, ...

  2. Oracle_安装问题

    [INS-07003] 访问 BeanStore 时出现意外错误   oracle安装时出现以下问题: 原因:未配置环境变量CLASSPASH 解决方法:新增系统变量,在我的电脑上右击-属性-高级系统 ...

  3. php 多个文件压缩到一起存储

    $zip = new ZipArchive();$res = $zip->open('test.zip', ZipArchive::CREATE); //不存在则创建$filepath = 's ...

  4. Pair Project 1 elevator

    结对编程——电梯调度 12061181 高孟烨 12061182 郝倩 1.结对编程的优缺点: 优点:结对编程可以结合两个人各自擅长之地,充分发挥两个人各自的优势,两个人一起合作效率会更高.一份工作两 ...

  5. Junit测试用例

    一.题目简介 返回一个给定整数参数的绝对值. 二.源码的github链接 https://github.com/liyan941016/test/blob/master/FileTest.java h ...

  6. PAT 1082 射击比赛

    https://pintia.cn/problem-sets/994805260223102976/problems/994805260990660608 本题目给出的射击比赛的规则非常简单,谁打的弹 ...

  7. JavaScript模拟表单(带数组的复杂数据结构)提交

    function test(){    var typeArray = new Array();    typeArray.push("mm");    typeArray.pus ...

  8. Array与Object

    typeof([ ])的返回值是object,因为数组叫做数组对象. Array有length属性,而Object没有length属性,所以可以根据length属性来判断数据属于数组还是对象. Arr ...

  9. [日常工作] Linux与Windows的连接访问以及数据共享等方法 vncserver smb xshell xftp winscp mount等

    日常办公机器是用 windows, 但是越来越多的测试和工作需求需要使用linux. 这里以最常用的系统centos为例进行说明 1. 远程连接 ssh的方式 建议使用xmange 系列的 xshel ...

  10. [安全]appscan 使用代理抓取其他客户端的请求

    自己安全测试技能很低, 上级给的安全测试的任务给了自动化组的同事来做, 自己之前使用appscan的时候 只知道使用appscan的内置浏览器测试抓取请求 今天与自动化美女同事沟通发现有一个代理的功能 ...