關於OpenGL游戲全屏模式的設置


使用DirectX的API的話可以給游戲窗口設置指定的顯示器和全屏獨占模式,但是如果使用OpenGL的API就比較遺憾不能直接設置。

以下內容基於Windows系統。

如果使用OpenGL渲染,第一步當然是創建窗口,如果想要設置全屏模式,需要做以下幾步操作:

一、把窗口設為無邊框

二、把窗口坐標設置到屏幕左上角,窗口大小設為跟屏幕同樣大小

三、如果有必要調整屏幕刷新率,要需要調用 ChangeDisplaySettingsEx 函數

四、窗口必須有焦點並且是激活的。

關於OpenGL全屏獨占模式,經過我在某404網站的努力搜索,得到如下的結論:

一、如果OpenGL窗口要使用全屏獨占模式,首先得按上面的幾步來做。

二、不斷調用 wglSwapBuffers 之后,顯卡驅動可能就會認為你的全屏OpenGL窗口需要加速渲染,然后把你的窗口設置為全屏獨占模式。

三、能不能用全屏獨占還得看顯卡驅動的心情。

以下是多顯示器測試的一點代碼:

// ConsoleApplication1.cpp : This file contains the 'main' function. Program execution begins and ends there.
//

#include "pch.h"
#include <iostream>
#include <vector>
#include <algorithm>

struct UsableMode
{
    // 分辨率寬度(像素)
    DWORD dmPelsWidth;
    // 分辨率高度(像素)
    DWORD dmPelsHeight;
    // 顏色深度(位)
    DWORD dmBitsPerPel;
    // 刷新率(Hz)
    DWORD dmDisplayFrequency;
};

// 這個操作符用於std::sort排序
bool operator<( const UsableMode& lhs, const UsableMode& rhs )
{
    if ( lhs.dmPelsWidth > rhs.dmPelsWidth )
    {
        return true;
    }
    else if ( lhs.dmPelsWidth == rhs.dmPelsWidth )
    {
        if ( lhs.dmPelsHeight > rhs.dmPelsHeight )
        {
            return true;
        }
        else if ( lhs.dmPelsHeight == rhs.dmPelsHeight )
        {
            if ( lhs.dmDisplayFrequency > rhs.dmDisplayFrequency )
            {
                return true;
            }
        }
    }

    return false;
}

struct UsableMonitor
{
    // 存儲顯示器的設備名,通過這個設備名可以改變任意一台顯示器的顯示模式
    // 此處的設備名是系統邏輯上的標識,這個設備名可以用來指定所有連接到電腦的顯示器,不管顯示器插在哪張顯卡上
    wchar_t                    device_name[32];

    // 存儲顯示器在系統桌面中的坐標范圍
    RECT                    rect;

    // 存儲所有該顯示器支持的顯示模式的基本數據
    std::vector<UsableMode>    modes;
};

BOOL CALLBACK MonitorEnumProc( HMONITOR hMonitor, HDC hDC, LPRECT lpRect, LPARAM lParam )
{
    std::vector<UsableMonitor>*    monitors = reinterpret_cast<decltype(monitors)>(lParam);
    
    monitors->push_back( UsableMonitor() );
    auto& new_monitor = monitors->back();

    MONITORINFOEX monitor_info;
    monitor_info.cbSize = sizeof( monitor_info );
    
    GetMonitorInfo( hMonitor, &monitor_info );

    // 存儲設備名
    wcscpy_s( new_monitor.device_name, monitor_info.szDevice );
    // 存儲坐標范圍
    new_monitor.rect = monitor_info.rcMonitor;

    DEVMODE    display_setting;
    int        mode_num;

    display_setting.dmSize = sizeof( display_setting );
    mode_num = 0;

    // 枚舉該顯示器所有支持的顯示模式
    while ( EnumDisplaySettings( monitor_info.szDevice, mode_num++, &display_setting ) )
    {
        UsableMode new_mode;

        // 只保存關心的數據就夠了
        new_mode.dmPelsWidth = display_setting.dmPelsWidth;
        new_mode.dmPelsHeight = display_setting.dmPelsHeight;
        new_mode.dmBitsPerPel = display_setting.dmBitsPerPel;
        new_mode.dmDisplayFrequency = display_setting.dmDisplayFrequency;

        new_monitor.modes.push_back( new_mode );
    }

    // 排序一下,分辨率高的模式排前面
    std::sort( new_monitor.modes.begin(), new_monitor.modes.end() );

    wprintf( L"Device: [%s]\n", new_monitor.device_name );

    for ( auto& mode : new_monitor.modes )
    {
        wprintf( L"Mode: Width=%d Height=%d Bits=%d Frequency=%d\n", mode.dmPelsWidth, mode.dmPelsHeight, mode.dmBitsPerPel, mode.dmDisplayFrequency );
    }

    return TRUE;
}

int main()
{
    // 存儲所有可用的顯示器
    std::vector<UsableMonitor> monitors;

    // 枚舉所有顯示器
    EnumDisplayMonitors( NULL, NULL, MonitorEnumProc, reinterpret_cast<LPARAM>(&monitors) );

    const UsableMonitor& use_monitor = monitors[0];        // 這里隨便選一個顯示器
    const UsableMode& use_mode = use_monitor.modes[2];        // 這里隨便選一個模式

    DEVMODE test_mode;
    ZeroMemory( &test_mode, sizeof( test_mode ) );
    test_mode.dmSize = sizeof( test_mode );
    test_mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;
    test_mode.dmPelsWidth = use_mode.dmPelsWidth;
    test_mode.dmPelsHeight = use_mode.dmPelsHeight;
    test_mode.dmBitsPerPel = use_mode.dmBitsPerPel;
    test_mode.dmDisplayFrequency = use_mode.dmDisplayFrequency;

    // 改變該顯示器的顯示模式
    // 使用 CDS_FULLSCREEN 這個標識之后系統會在進程退出后還原該顯示器的顯示模式
    ChangeDisplaySettingsEx( use_monitor.device_name, &test_mode, NULL, CDS_FULLSCREEN, NULL );

    system( "PAUSE" );

    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM