在 OpenGL/GLFW 3.2 中在窗口和全屏之间切换

2023-11-24

我正在 Linux 上学习 OpenGL,但无法进行模式切换(窗口切换到全屏并返回)。

该窗口似乎正在全屏显示,但看起来不正确。要切换模式,将创建一个新窗口并销毁旧窗口。

void OpenGLWindow::FullScreen(bool fullScreen, int width, int height)
{
    GLFWwindow *oldHandle = m_window;

    m_fullscreen = fullScreen;
    m_width = width;
    m_height = height;

    m_window = glfwCreateWindow(width, height, m_caption.c_str(),
        fullScreen ? m_monitor : NULL, m_window);

    if (m_window == NULL)
    {
        glfwTerminate();
        throw std::runtime_error("Failed to recreate window.");
    }

    glfwDestroyWindow(oldHandle);

    m_camera->Invalidate();

    // Use entire window for rendering.
    glViewport(0, 0, width, height);

    glfwMakeContextCurrent(m_window);
    glfwSwapInterval(1);

    if (m_keyboardHandler) SetKeyboardHandler(m_keyboardHandler);
}

Initial Window enter image description here

Full Screen (incorrect) enter image description here

Return to Windowed enter image description here

问题更新

我已更新代码以使用您的代码并遇到相同的问题。根据您的建议,我现在正在更新相机,但再次无济于事:(

void OpenGLCamera::Invalidate()
{
    RecalculateProjection(m_perspProjInfo->Width(), m_perspProjInfo->Height());
    m_recalculateViewMatrix = true;
    m_recalculatePerspectiveMatrix = true;
    m_recalculateProjectionMatrix = true;
}

void OpenGLCamera::RecalculateProjection(int width, int height)
{
    float aspectRatio = float(width) / height;
    float frustumYScale = cotangent(degreesToRadians(
        m_perspProjInfo->FieldOfView() / 2));

    float frustumXScale = frustumYScale;

    if (width > height) 
    {
        // Shrink the x scale in eye-coordinate space, so that when geometry is
        // projected to ndc-space, it is widened out to become square.
        m_projectionMatrix[0][0] = frustumXScale / aspectRatio;
        m_projectionMatrix[1][1] = frustumYScale;
    }
    else {
        // Shrink the y scale in eye-coordinate space, so that when geometry is
        // projected to ndc-space, it is widened out to become square.
        m_projectionMatrix[0][0] = frustumXScale;
        m_projectionMatrix[1][1] = frustumYScale * aspectRatio;
    }
}

兔子:当我调整大小时:

enter image description here

Rabbid : When I go to full screen: enter image description here


下面,我将描述一个小但方便的类,它处理调整 GLFW 窗口的大小并处理全屏窗口的打开和关闭。
所有使用的 GLFW 函数都详细记录在GLFW 文档.

#include <GL/gl.h>
#include <GLFW/glfw3.h>
#include <array>
#include <stdexcept>

class OpenGLWindow
{
private:

    std::array< int, 2 > _wndPos         {0, 0};
    std::array< int, 2 > _wndSize        {0, 0};
    std::array< int, 2 > _vpSize         {0, 0};
    bool                 _updateViewport = true;
    GLFWwindow *         _wnd            = nullptr;
    GLFWmonitor *        _monitor        = nullptr;

    void Resize( int cx, int cy );

public:

    void Init( int width, int height );
    static void CallbackResize(GLFWwindow* window, int cx, int cy);
    void MainLoop ( void );
    bool IsFullscreen( void );
    void SetFullScreen( bool fullscreen );
};

创建窗口时,则用户函数指针(glfwSetWindowUserPointer) 设置为窗口管理类。调整大小回调由glfwSetWindowSizeCallback。窗口创建后,可以通过以下方式获取其当前大小和位置glfwGetWindowPos and glfwGetWindowSize.

void OpenGLWindow::Init( int width, int height )
{
    _wnd = glfwCreateWindow( width, height, "OGL window", nullptr, nullptr );
    if ( _wnd == nullptr )
    {
        glfwTerminate();
        throw std::runtime_error( "error initializing window" ); 
    }

    glfwMakeContextCurrent( _wnd );

    glfwSetWindowUserPointer( _wnd, this );
    glfwSetWindowSizeCallback( _wnd, OpenGLWindow::CallbackResize );

    _monitor =  glfwGetPrimaryMonitor();
    glfwGetWindowSize( _wnd, &_wndSize[0], &_wndSize[1] );
    glfwGetWindowPos( _wnd, &_wndPos[0], &_wndPos[1] );
    _updateViewport = true;
}

当调整大小通知发生时,可以通过以下方式获取指向窗口管理类的指针glfwGetWindowUserPointer:

static void OpenGLWindow::CallbackResize(GLFWwindow* window, int cx, int cy)
{
    void *ptr = glfwGetWindowUserPointer( window );
    if ( OpenGLWindow *wndPtr = static_cast<OpenGLWindow*>( ptr ) )
        wndPtr->Resize( cx, cy );
}

窗口大小的任何更改都会收到通知并存储新的窗口大小(glfwGetWindowSize):

void OpenGLWindow::Resize( int cx, int cy )
{
    _updateViewport = true;
}

当窗口大小发生变化时,视口必须适合窗口大小(glViewport)。这可以在应用程序的主循环中完成:

void OpenGLWindow::MainLoop ( void )
{
    while (!glfwWindowShouldClose(_wnd))
    {
        if ( _updateViewport )
        {
            glfwGetFramebufferSize( _wnd, &_vpSize[0], &_vpSize[1] );
            glViewport( 0, 0, _vpSize[0], _vpSize[1] );
            _updateViewport = false;
        }

        // ..... render the scene

        glfwSwapBuffers(_wnd);
        glfwPollEvents();
    }
}  

如果当前窗口处于全屏模式,可以通过询问窗口用于全屏模式的监视器来实现(glfwGetWindowMonitor):

bool OpenGLWindow::IsFullscreen( void )
{
    return glfwGetWindowMonitor( _wnd ) != nullptr;
} 

要打开和关闭全屏模式,glfwSetWindowMonitor必须使用全屏模式的监视器或使用nullptr:

void OpenGLWindow::SetFullScreen( bool fullscreen )
{
    if ( IsFullscreen() == fullscreen )
        return;

    if ( fullscreen )
    {
        // backup window position and window size
        glfwGetWindowPos( _wnd, &_wndPos[0], &_wndPos[1] );
        glfwGetWindowSize( _wnd, &_wndSize[0], &_wndSize[1] );
        
        // get resolution of monitor
        const GLFWvidmode * mode = glfwGetVideoMode(_monitor);

        // switch to full screen
        glfwSetWindowMonitor( _wnd, _monitor, 0, 0, mode->width, mode->height, 0 );
    }
    else
    {
        // restore last window size and position
        glfwSetWindowMonitor( _wnd, nullptr,  _wndPos[0], _wndPos[1], _wndSize[0], _wndSize[1], 0 );
    }

    _updateViewport = true;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 OpenGL/GLFW 3.2 中在窗口和全屏之间切换 的相关文章

  • 以相反的顺序迭代可变参数模板参数

    如果我手动反转传递给它的模板参数的顺序 以下代码将起作用 template
  • C 中的变量定义是什么意思[重复]

    这个问题在这里已经有答案了 你们能告诉我 这在 C 中意味着什么吗 define Privileged Data Privileged Data static int dVariable 编译器对变量进行寻址有特殊意义吗 这只是一个宏Pri
  • 为什么opencv videowriter这么慢?

    你好 stackoverflow 社区 我有一个棘手的问题 我需要你的帮助来了解这里发生了什么 我的程序从视频采集卡 Blackmagic 捕获帧 到目前为止 它工作得很好 同时我用 opencv cv imshow 显示捕获的图像 它也工
  • Android NDK C++“wstring”支持

    我有用 C 编写的源代码 lib 现在我想在 Android NDK 项目 NDK 6 中编译并使用相同的源代码 lib 我能够编译大多数 C 文件 除了基于 std wstring 的功能 在 Application mk 中 当我指定时
  • 如何将pdf页面设置设置为打印属性对话框?

    大家好 我想知道如何设置 pdf 页面设置到打印属性对话框 例如 如果我的 PDF 页面设置为横向 则布局会自动显示横向而不是纵向 如果我的 PDF 页面设置为纵向 则布局会自动显示纵向 我在这个主题上做了很多研发 但没有找到任何满意的链接
  • 返回 int& 的函数[重复]

    这个问题在这里已经有答案了 我在网上查了一下发现一篇试图解释的文章std move和右值 http thbecker net articles rvalue references section 01 html并发现了一些我实在无法掌握的东
  • 关闭 XDOCUMENT 的实例

    我收到这个错误 该进程无法访问文件 C test Person xml 因为它是 被另一个进程使用 IOException 未处理 保存文件内容后如何关闭 xml 文件的实例 using System using System Collec
  • 为什么假设 send 可能返回的数据少于在阻塞套接字上传输的请求数据?

    在流套接字上发送数据的标准方法始终是调用 send 并写入一大块数据 检查返回值以查看是否发送了所有数据 然后再次调用 send 直到整个消息被接受 例如 这是一个常见方案的简单示例 int send all int sock unsign
  • 如何将字节块读入结构体

    我有一个需要处理的资源文件 它包含一组文件 首先 资源文件列出了其中包含的所有文件 以及一些其他数据 例如在此结构中 struct FileEntry byte Value1 char Filename 12 byte Value2 byt
  • 在通过网络发送之前压缩位图

    我正在尝试通过网络发送位图屏幕截图 因此我需要在发送之前对其进行压缩 有一个库或方法可以做到这一点吗 当您将图像保存到流时 您have选择一种格式 几乎所有位图格式 bmp gif jpg png 都使用一种或多种压缩形式 因此 只需选择适
  • c# 如何生成锦标赛括号 HTML 表

    所以我已经被这个问题困扰了三个星期 但我一生都无法弄清楚 我想做的是使用表格获得这种输出 演示 http www esl world net masters season6 hanover sc2 playoffs rankings htt
  • 数据损坏 C++ 和 Python 之间的管道

    我正在编写一些代码 从 Python 获取二进制数据 将其通过管道传输到 C 对数据进行一些处理 在本例中计算互信息度量 然后将结果通过管道传输回 Python 在测试时 我发现如果我发送的数据是一组尺寸小于 1500 X 1500 的 2
  • 不要声明只读可变引用类型 - 为什么不呢?

    我一直在阅读这个问题 https stackoverflow com questions 2274412 immutable readonly reference types fxcop violation do not declare r
  • 是什么原因导致 Linq 错误:此方法无法转换为存储表达式?

    我有一堆具有相同 select 语句的 Linq to Entity 方法 所以我想我会很聪明 并将其分离到它自己的方法中以减少冗余 但是当我尝试运行代码时 我得到了以下内容错误 该方法不能转化为 商店表达式 这是我创建的方法 public
  • 将一个 long 转换为两个 int 以进行重构

    我需要将一个参数作为两个 int 参数传递给 Telerik Report 因为它不能接受长参数 将 long 拆分为两个 int 并在不丢失数据的情况下重建它的最简单方法是什么 使用掩蔽和移位是最好的选择 根据文档 long 保证为 64
  • 如何强制执行特定的 UserControl 设计

    我正在编写一个基本用户控件 它将由一堆其他用户控件继承 我需要对所有这些后代控件强制执行某种设计 例如 顶部必须有几个按钮以及一个或两个标签 后代用户控件区域的其余部分可以自由放置任何内容 最初 我认为我可以将一个面板放到 Base Use
  • 正在获取“未终止 [] 设置”。 C# 中的错误

    我正在 C 中使用以下正则表达式 Regex find new Regex url
  • 如何使用 ASP.NET Web 表单从代码隐藏中访问更新面板内的文本框、标签

    我在更新面板中定义了一些控件 它们绑定到中继器控件 我需要根据匿名字段隐藏和显示用户名和国家 地区 但问题是我无法以编程方式访问更新面板中定义的控件 我如何访问这些控件 我也在网上查找但找不到很多参考资料 下面是来自aspx页面和 cs页面
  • 程序退出后,TcpListener Socket 仍处于活动状态

    当我的程序退出时 我试图停止 TCP 侦听器 我不关心套接字或任何活动客户端套接字上当前活动的任何数据 套接字清理代码本质上是 try myServer Server Shutdown SocketShutdown Both catch E
  • 创建带有部分的选项卡式侧边栏 WPF

    我正在尝试创建一个带有部分的选项卡式侧边栏 如 WPF 中的以下内容 我考虑过几种方法 但是有没有更简单 更优雅的方法呢 方法一 列表框 Using a ListBox并将 SelectedItem 绑定到右侧内容控件所绑定的值 为了区分标

随机推荐