zoukankan      html  css  js  c++  java
  • 关于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]
    ", new_monitor.device_name );
    
        for ( auto& mode : new_monitor.modes )
        {
            wprintf( L"Mode: Width=%d Height=%d Bits=%d Frequency=%d
    ", 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;
    }
  • 相关阅读:
    Linux环境下安装Tigase XMPP Server
    虚拟机几种网络连接方式的区别
    MySQL修改root密码
    Eclipse使用多个Console
    Eclipse导入Java项目时“No projects are found to import”错误的处理
    GitHub上下载源代码的方法
    Tigase XMPP Server的安装
    MySQL的安装与配置
    Windows下查看JDK是否安装以及安装路径
    archive for required library...
  • 原文地址:https://www.cnblogs.com/crsky/p/10339649.html
Copyright © 2011-2022 走看看