zoukankan      html  css  js  c++  java
  • SDL获得屏幕属性及实现分析

    [时间:2017-05] [状态:Open]
    [关键词:sdl2,屏幕分辨率,显示区域,多媒体渲染,窗口,sdl2源码分析]

    0 引言

    本文的主要目标在于使用SDL2获得屏幕相关的属性,比如分辨率、屏幕个数以及屏幕可用区域的范围。

    通常情况下,有过图形界面编程经验的人都知道桌面系统的构成,屏幕分辨率是指的整个屏幕区域的宽高,而通常屏幕区域有一些系统的任务栏或者菜单栏;举个例子,windows下的任务栏一般位于下面,并且通常非全屏窗口是不能占用任务栏的。

    1 获得屏幕个数

    SDL2中提供了获得屏幕个数的接口SDL_GetNumVideoDisplays,具体建议参考sdl2-wiki

    当然屏幕还有其他属性,比如显示模式等,可以通过SDL_GetNumDisplayModesSDL_GetDisplayMode获得SDL_DisplayMode的结构,其中包括显示格式(YUV、RGB等)、宽高、刷新率等。

    2 每个屏幕的分辨率

    SDL_GetDisplayBounds可以获得指定屏幕的显示区域,可以通过显示区域获取屏幕分辨率。

    3 获取实际显示区域的大小

    SDL_GetDisplayUsableBounds返回的是实际可用显示区域的大小,这个通常比屏幕分辨率小。

    4 SDL2内部实现的原理分析

    这里以SDL_GetDisplayBounds为例说明,如果读者对其他函数感兴趣,可以查看sdl2代码。

    int SDL_GetDisplayBounds(int displayIndex, SDL_Rect * rect)
    {
        CHECK_DISPLAY_INDEX(displayIndex, -1);
    
        if (rect) {
            SDL_VideoDisplay *display = &_this->displays[displayIndex];
    
            if (_this->GetDisplayBounds) {
                if (_this->GetDisplayBounds(_this, display, rect) == 0) {
                    return 0;
                }
            }
    
            /* Assume that the displays are left to right */
            if (displayIndex == 0) {
                rect->x = 0;
                rect->y = 0;
            } else {
                SDL_GetDisplayBounds(displayIndex-1, rect);
                rect->x += rect->w;
            }
            rect->w = display->current_mode.w;
            rect->h = display->current_mode.h;
        }
        return 0;  /* !!! FIXME: should this be an error if (rect==NULL) ? */
    }
    

    很明显这个函数直接调用了SDL_VideoDevice->GetDisplayBounds函数,那么我们找一个实现版本看看,比如windows下的,代码如下:

    static SDL_VideoDevice * WIN_CreateDevice(int devindex)
    {
    	// ...
    	device->GetDisplayBounds = WIN_GetDisplayBounds;
    	// ...
    }
    

    这个实现被重定向到WIN_GetDisplayBounds函数中,代码如下:

    int
    WIN_GetDisplayBounds(_THIS, SDL_VideoDisplay * display, SDL_Rect * rect)
    {
        SDL_DisplayModeData *data = (SDL_DisplayModeData *) display->current_mode.driverdata;
    
        rect->x = (int)SDL_ceil(data->DeviceMode.dmPosition.x * data->ScaleX);
        rect->y = (int)SDL_ceil(data->DeviceMode.dmPosition.y * data->ScaleY);
        rect->w = (int)SDL_ceil(data->DeviceMode.dmPelsWidth * data->ScaleX);
        rect->h = (int)SDL_ceil(data->DeviceMode.dmPelsHeight * data->ScaleY);
    
        return 0;
    }
    

    实现比较简单,直接从display->current_mode中获得数据。那么这个mode在哪里赋值的呢?
    在SDL_windowsvideo.c中查找下,发下如下调用:

    static SDL_bool WIN_AddDisplay(_THIS, LPTSTR DeviceName)
    {
        SDL_VideoDisplay display;
        SDL_DisplayData *displaydata;
        SDL_DisplayMode mode;
        DISPLAY_DEVICE device;
    
        if (!WIN_GetDisplayMode(_this, DeviceName, ENUM_CURRENT_SETTINGS, &mode)) {
            return SDL_FALSE;
        }
    
        displaydata = (SDL_DisplayData *) SDL_malloc(sizeof(*displaydata));
        if (!displaydata) {
            return SDL_FALSE;
        }
        SDL_memcpy(displaydata->DeviceName, DeviceName,
                   sizeof(displaydata->DeviceName));
    
        SDL_zero(display);
        device.cb = sizeof(device);
        if (EnumDisplayDevices(DeviceName, 0, &device, 0)) {
            display.name = WIN_StringToUTF8(device.DeviceString);
        }
        display.desktop_mode = mode;
        display.current_mode = mode;
        display.driverdata = displaydata;
        SDL_AddVideoDisplay(&display);
        SDL_free(display.name);
        return SDL_TRUE;
    }
    

    明显这是从EnumDisplayDevices中获取。
    至此所有实现逻辑基本理清。

    5 小结

    本文主要整理我近期遇到的SDL2关于窗口和屏幕属性获取的逻辑,同时分析了SDL_GetDisplayBounds在windows上的实现逻辑。

  • 相关阅读:
    oo第三单元学习总结
    oo第二单元学习总结
    OO第四单元UML作业总结兼OO课程总结
    OO第三单元JML作业总结
    OO第二单元电梯作业总结
    OO第一单元总结
    OOUnit4Summary
    OOUnit3Summary
    OOUnit2Summary
    OOUnit1Summary
  • 原文地址:https://www.cnblogs.com/tocy/p/sdl-screen-info-visible-region.html
Copyright © 2011-2022 走看看