关于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; }