c++ - 如何设计窗口渲染循环?

标签 c++ window glfw software-design

我正在尝试设计一个窗口对象,其工作是处理 GLFW 窗口的所有功能(初始化、回调、输入处理...)

最重要的事情之一是渲染循环。我能想到的最幼稚的设计是让 renderloop 方法接受一个没有参数的函数指针,然后在循环方法中调用它,如下所示:

class Window
{
public:
    Window();
    ~Window();

    void WindowLoop(void (*f) (void));
protected:
    GLFWwindow* window;
};


void Window::WindowLoop(void (*f) (void))
{
    while(!glfwWindowShouldClose(window))
    {
        f();
        glfwPollEvents();
    }
}

然而,这带来了很多限制。一方面,它暗示函数不能接受任何参数。这可能是也可能不是问题。

我做了一些研究,显然你可以传递带有任意数量参数的函数指针,但这似乎既困难又不建议这样做。

另一种选择是通用仿函数,然后可以将参数定义为类/结构的一部分,从而避免必须处理它。

可能还有其他我不知道的潜在设计。

在 C++ 中,对于渲染循环,哪个是一个好的设计,首先尝试优先考虑使用的多功能性,其次是执行速度?

最佳答案

我的简短回答是:

使用std::function而不是原始函数指针。这为您提供了更大的灵 active ,因为它可以容纳:

  • 函数指针
  • 方法指针(当然是对象)
  • 仿函数
  • lambda(有或没有实际上重复上述一个或另一个的捕获)。

您仍然需要为调用定义签名,但您可以提供您的回调上下文,这可能就是您所需要的。

所以,这就是它的样子:

#include <functional>

class Window
{
public:
    Window();
    ~Window();

    void WindowLoop(std::function<void()> f);
protected:
    GLFWwindow* window;
};


void Window::WindowLoop(std::function<void()> f)
{
    while(!glfwWindowShouldClose(window))
    {
        f();
        glfwPollEvents();
    }
}

(看起来和OP的原始样本没有太大区别。)


三思而后行,我发现值得一提的是小部件集及其提供的解决方案(因为有同样的问题需要解决)。

两种通用的解决方案是

  • 信号/信号处理程序 ( signal slot concept )
  • virtual 事件处理程序的方法可以被覆盖。

信号基本上就是一个带有函数指针(或 std::function 或类似的东西)的容器。在某些情况下会发出信号(即调用存储的函数指针)。因此,其他对象可以在这种情况下得到通知(通过在信号中注册它们的信号处理程序)。因此,信号实际上与上述类似,只是函数指针不是临时提供的,而是存储在成员变量中。

另一种方法是在某些情况下调用虚拟 方法。要添加自定义行为,resp。必须派生基类,并且必须覆盖请求中的 virtual 方法。

在 OP 的情况下,这可能看起来像这样:

class Window
{
public:
    Window();
    ~Window();

    void WindowLoop();
protected:
    virtual void step();
protected:
    GLFWwindow* window;
};


void Window::WindowLoop()
{
    while(!glfwWindowShouldClose(window))
    {
        step();
        glfwPollEvents();
    }
}

void Window::step() { /* empty placeholder */ }

要在应用程序中使用它,Window 的派生类是必需的:

class GameWindow: public Window {
    protected:
        virtual void step() override;
};

void GameWindow::step()
{
    // Do the game step stuff (e.g. rendering)
    // where this (of type GameWindow) can provide the necessary context.
}

关于Qt ,有各种情况的信号和 virtual 方法,例如小部件中的事件处理程序。大多数情况下只能选择一个/或——我不记得两者都可以用于某事。例如。可以为 QPushButton::clicked() 注册一个信号处理程序,但要将事件处理程序自定义为 mousePressEvent(),必须重载 Qt 小部件以覆盖该事件处理程序方法。 (也有事件过滤器的概念,但恕我直言,这并不完全相同。)

gtkmm相反(至少在我过去使用的版本 2 中)提供了所有我能记住的 virtual 方法 信号。因此,始终可以选择派生 gtkmm 小部件或仅通过注册信号处理程序来更改/扩展 gtkmm 小部件的行为。这可能会引入很少的额外性能成本,但对于应用程序编程来说非常方便。

关于c++ - 如何设计窗口渲染循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54509768/

相关文章:

javascript - 如何为潮汐Sdk应用程序窗口设置固定大小?

c++ - 窗口 api 大小和移动控制台

javascript - 在没有文本框的情况下检测击键?

c++ - 非方形屏幕上的 OpenGL 绘图线

c++ - 指向派生类对象的基类指针有哪些用例

c# - 进程交互(c#和纯c++)

c++ - 在 sqlite 中将 char* 作为 vector<byte> 插入

c++ - 如何从结构中提取最高索引的特化?

c++ - xCode 8.1 GLFWWindow "first responder"问题

opengl - 在 GLFW3 中请求特定的 OpenGL 上下文版本