在 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 中在窗口和全屏之间切换 的相关文章

  • 与 for_each 或 std::transform 一起使用时,如何调用 C++ 函子构造函数

    我以前从未使用过 C 函子 所以我只是想了解它们是如何工作的 例如假设我们有这个函子类 class MultiplyBy private int factor public MultiplyBy int x factor x int ope
  • 格式说明符%02x

    我有一个简单的程序 include
  • 静态构造函数和 BeforeFieldInit?

    如果类型没有静态构造函数 则将执行字段初始值设定项 就在使用该类型之前 或者在某个时间点突发奇想 运行时 为什么这段代码 void Main start Dump Test EchoAndReturn Hello end Dump clas
  • 在 Mono 中反序列化 JSON 数据

    使用 Monodroid 时 是否有一种简单的方法可以将简单的 JSON 字符串反序列化为 NET 对象 System Json 只提供序列化 不提供反序列化 我尝试过的各种第三方库都会导致 Mono Monodroid 出现问题 谢谢 f
  • C# 中一次性对象克隆会导致内存泄漏吗?

    检查这个代码 class someclass IDisposable private Bitmap imageObject public void ImageCrop int X int Y int W int H imageObject
  • 为什么这个 makefile 在“make clean”上执行目标

    这是我当前的 makefile CXX g CXXFLAGS Wall O3 LDFLAGS TARGET testcpp SRCS main cpp object cpp foo cpp OBJS SRCS cpp o DEPS SRCS
  • if constexpr 中的 not-constexpr 变量 – clang 与 GCC

    struct A constexpr operator bool const return true int main auto f auto v if constexpr v A a f a clang 6 接受该代码 GCC 8 拒绝它
  • 来自嵌入图像的 BitmapSource

    我的目标是在 WPF 窗口上重写 OnRender 方法中绘制图像 someImage png 它是嵌入资源 protected override void OnRender System Windows Media DrawingCont
  • 保证复制省略是否适用于函数参数?

    如果我理解正确的话 从 C 17 开始 这段代码现在要求不进行任何复制 Foo myfunc void return Foo auto foo myfunc no copy 函数参数也是如此吗 下面的代码中的副本会被优化掉吗 Foo myf
  • 让网络摄像头在 OpenCV 中工作

    我正在尝试让我的网络摄像头在 Windows 7 64 位中的 OpenCV 版本 2 2 中捕获视频 但是 我遇到了一些困难 OpenCV 附带的示例二进制文件都无法检测到我的网络摄像头 最近我发现这篇文章表明答案在于重新编译一个文件 o
  • 如何在多线程应用程序中安全地填充数据并 Refresh() DataGridView?

    我的应用程序有一个 DataGridView 对象和一个 MousePos 类型的列表 MousePos 是一个自定义类 它保存鼠标 X Y 坐标 类型为 Point 和该位置的运行计数 我有一个线程 System Timers Timer
  • 如何从 Boost.PropertyTree 复制子树

    我有一些boost property tree ptree 我需要树来删除一些具有特定标签名称的元素 例如 xml 表示源ptree如下
  • ASP.NET Core 中间件与过滤器

    在阅读了 ASP NET Core 中间件之后 我对何时应该使用过滤器以及何时应该使用中间件感到困惑 因为它们似乎实现了相同的目标 什么时候应该使用中间件而不是过滤器 9频道有一个关于此的视频 ASP NET 怪物 91 中间件与过滤器 h
  • 读取依赖步行者输出

    I am having some problems using one of the Dlls in my application and I ran dependency walker on it i am not sure how to
  • C++ 指针引用混淆

    struct leaf int data leaf l leaf r struct leaf p void tree findparent int n int found leaf parent 这是 BST 的一段代码 我想问一下 为什么
  • C:设置变量范围内所有位的最有效方法

    让我们来int举个例子 int SetBitWithinRange const unsigned from const unsigned to To be implemented SetBitWithinRange应该返回一个int其中所有
  • 如何从 Windows Phone 7 模拟器获取数据

    我有一个 WP7 的单元测试框架 它在手机上运行 结果相当难以阅读 因此我将它们写入 XDocument 我的问题是 如何才能将这个 XML 文件从手机上移到我的桌面上 以便我可以实际分析结果 到目前为止 我所做的是将 Debugger B
  • Streamwriter 覆盖 txt 文件中的文本

    有没有什么方法可以重新打开流写入器而不创建新的写入对象 因为此时 当调用 WriteOdd 时 streamwriter 正在覆盖在它之前调用的 WriteEven public void WriteEven StreamWriter wr
  • 如果将变量设置为等于新对象,旧对象会发生什么?

    假设我们有一个 X 类not有一个超载的operator 功能 class X int n X n 0 X int n n n int main X a 1 an object gets constructed here more code
  • winform c# 中的弹出窗口

    我正在开发一个需要弹出窗口的项目 但问题是我还希望能够通过表单设计器在此弹出窗口中添加文本框等 所以基本上我有一个按钮 当您单击它时 它将打开我在表单设计器中设计的另一个窗口 我一直在谷歌搜索 但还没有找到我需要的东西 所以我希望你们能帮助

随机推荐