c++ GLFW类多窗口

stszievb  于 2023-06-25  发布在  其他
关注(0)|答案(2)|浏览(224)

我是OpenGL的新手,目前我正在为OpenGL学习做我的测试OpenGL项目。而这个项目的一个组件是WindowManager。我已经尝试添加多个窗口创建支持,但它不工作的方式,我想要的。
当我启动我的应用程序时,两个窗口(让我们称之为A-FIRST_WINDOW,B-SECOND_WINDOW)同时被创建,但当我关闭B窗口时,我的应用程序仍然工作,这很好,因为A窗口仍然可用,我可以使用它,当我关闭A窗口时,我的应用程序被关闭。但是如果我先关闭A窗口,我的B窗口也会关闭,应用程序也会完成。
注:A窗口-第一个创建B窗口-第二个创建
密码...
WindowManager.hpp

#include <GLFW/glfw3.h>

#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 600
#define DEFAULT_TITLE "Soul Byte Engine Window"

namespace SoulByteEngineCore
{
    namespace WindowManager
    {
        class Window
        {
        public:
            Window(unsigned int width=DEFAULT_WIDTH, unsigned int height=DEFAULT_HEIGHT, const char *title = DEFAULT_TITLE);
        public:
            void Clear(float x_pos, float y_pos, float z_pos);
        public:
            unsigned int GetWidth();
            unsigned int GetHeight();
        public:
            static bool Init();
        public:
            void ShowWindowData();
        public:
            const char* GetTitle();
        public:
            bool SetLogging();
        public:
            void onUpdate();
        public:
            bool ShouldClose();
        public:
            void Destroy();
        private:
            bool CreateWindow();
        private:
            void Update();
        private:
            unsigned int m_windowWidth = DEFAULT_WIDTH;
            unsigned int m_windowHeight = DEFAULT_HEIGHT;
        private:
            const char* m_windowTitle = DEFAULT_TITLE;
        private:
            unsigned int OpenGLMajorVersion = 3;
            unsigned int OpenGLMinorVersion = 3;
        private:
            GLFWwindow* m_window_handle = NULL;
        };
    }
}
#include <glad/gl.h>
#include <WindowManager/WindowManager.hpp>

#include <utility>
#include <iostream>

namespace SoulByteEngineCore
{
    namespace WindowManager
    {
        Window::Window(unsigned int width, unsigned int height, const char *title)
            :m_windowWidth{std :: move(width)}
            ,m_windowHeight{std :: move(height)}
            ,m_windowTitle{std :: move(title)}
        {
            CreateWindow();
        }

        void Window::Update()
        {
            glfwSwapBuffers(this->m_window_handle);
            glfwPollEvents();
        }

        void Window::onUpdate()
        {
            Update();
        }

        void Window::Destroy()
        {
            glfwDestroyWindow(this->m_window_handle);
        }

        bool Window::ShouldClose()
        {
            return glfwWindowShouldClose(this->m_window_handle);
        }

        bool Window::Init()
        {
            if (!glfwInit())
            {
                std::cout << "SoulByteEngine :: CORE :: WINDOW_MANAGER :: ERROR :: CRITICAL :: GLFW CANNOT BE INITIALIZED! " << std::endl;

                return false;
            }
        }

        bool Window::CreateWindow()
        {
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
            m_window_handle = glfwCreateWindow(m_windowWidth, m_windowHeight, m_windowTitle, NULL, NULL);

            if (!m_window_handle)
            {
                std::cout << "SoulByteEngine :: CORE :: WindowManagerModule :: ERROR :: COULD'T CREATE WINDOW" << std::endl;

                return false;
            }

            glfwMakeContextCurrent(this->m_window_handle);

            if (!gladLoadGL(glfwGetProcAddress))
            {
                std::cout << "SoulByteEngine :: CORE :: WINDOW_MANAGER :: ERROR :: CRITICAL :: WINDOW HAS BEEN CREATED, BUT GLAD COULD NOT BE INITIALIZED! " << std::endl;
                return false;
            }

            return true;
        }

        bool Window::SetLogging()
        {
            return false;
        }

        unsigned int Window::GetWidth()
        {
            return this->m_windowWidth;
        }

        unsigned int Window::GetHeight()
        {
            return this->m_windowHeight;
        }

        const char* Window::GetTitle()
        {
            return this->m_windowTitle;
        }

        void Window::ShowWindowData()
        {
            std::cout << "Window Data:" << std::endl;
            std::cout << "Title: " << this->GetTitle() << std::endl;
            std::cout << "Width: " << this->GetWidth() << std::endl;
            std::cout << "Height: " << this->GetHeight() << std::endl;
        }

        void Window::Clear(float x_pos, float y_pos, float z_pos)
        {
            glClearColor(x_pos, y_pos, z_pos, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        }

    }
}

Application.cpp

#include <WindowManager/WindowManager.hpp>

int main()
{
    if (SoulByteEngineCore::WindowManager::Window::Init())
    {
        SoulByteEngineCore::WindowManager::Window first_window(DEFAULT_WIDTH, DEFAULT_HEIGHT, "First Fuckin SoulByteEngine Window");
        SoulByteEngineCore::WindowManager::Window second_window(DEFAULT_WIDTH, DEFAULT_HEIGHT, "Second Fuckin SoulByteEngine Window");

        while (!first_window.ShouldClose() || !second_window.ShouldClose())
        {
            if (first_window.ShouldClose() == true)
            {
                first_window.Destroy();
            }
            else
            {
                //first_window.Clear(0.0f, 1.0f, 0.0f);
                first_window.onUpdate();
            }
            if (second_window.ShouldClose() == true)
            {
                second_window.Destroy();
            }
            else
            {
                //second_window.Clear(0.0f, 1.0f, 0.0f);
                second_window.onUpdate();
            }

        }
    }
}
yzuktlbb

yzuktlbb1#

此答案基于用户@BDL的评论(架构问题)。
由于不能从回调调用glfwDestroyWindow(只能从主线程调用),所以必须采取不同的方法。
为此,我们需要两个列表(向量),一个是打开的(活动)窗口,另一个是关闭的(应该关闭标志集)窗口,例如:

std::vector<GLFWwindow*> opened_windows;
std::vector<GLFWwindow*> closing_windows;

两者最初都是空的,并且如果窗口被成功创建或被标记为被销毁,则被填充。
打开时(每当创建窗口时):

GLFWwindow *win = createWindow();
if (win) {
    opened_windows.push_back(win);
}

对于关闭案例,我们必须建立一个关闭处理程序:

void window_close_callback(GLFWwindow* win)
{
    //remove window from the opened list
    opened_windows.erase(std::find(..., win));
    //add to garbage list
    closing_windows.push_back(win);
}

然后在你的主循环中:

while (!opened_windows.empty()) {
    //1. do your stuff
    //2. process events (which might catch a close event)
    //3. destroy all windows in the garbage
    if (!closing_windows.empty()) {
        //foreach element in list, invoke glfwDestroyWindow
        closing_windows.clear();
    }
}
um6iljoc

um6iljoc2#

感谢所有回答我问题的人!特别感谢@BDL!我知道我的架构真的很糟糕,因为我没有检查我的窗口是否关闭,我的Destroy()方法正在关闭窗口,不管我的窗口是否已经关闭,因为你知道没有任何操作可以对已经关闭的窗口执行,并且对已经关闭的窗口采取的任何操作都会导致glfw崩溃。
所以,我已经修正了:
WindowManager.hpp:

#include <GLFW/glfw3.h>

#define DEFAULT_WIDTH 800
#define DEFAULT_HEIGHT 600
#define DEFAULT_TITLE "Soul Byte Engine Window"

namespace SoulByteEngineCore
{
    namespace WindowManager
    {
        class Window
        {
        public:
            Window(unsigned int width=DEFAULT_WIDTH, unsigned int height=DEFAULT_HEIGHT, const char *title = DEFAULT_TITLE);
        public:
            void Clear(float x_pos, float y_pos, float z_pos);
        public:
            unsigned int GetWidth();
            unsigned int GetHeight();
        public:
            bool IsClosed();
        public:
            static bool Init();
        public:
            void ShowWindowData();
        public:
            const char* GetTitle();
        public:
            bool SetLogging();
        public:
            void onUpdate();
        public:
            bool ShouldClose();
        public:
            void Destroy();
        private:
            bool CreateWindow();
        private:
            void Update();
        private:
            unsigned int m_windowWidth = DEFAULT_WIDTH;
            unsigned int m_windowHeight = DEFAULT_HEIGHT;
        private:
            const char* m_windowTitle = DEFAULT_TITLE;
        private:
            bool m_isClosed = false;
        private:
            unsigned int OpenGLMajorVersion = 3;
            unsigned int OpenGLMinorVersion = 3;
        private:
            GLFWwindow* m_window_handle = NULL;
        };
    }
}

WindowManager.cpp:

#include <glad/gl.h>
#include <WindowManager/WindowManager.hpp>

#include <utility>
#include <iostream>

namespace SoulByteEngineCore
{
    namespace WindowManager
    {
        Window::Window(unsigned int width, unsigned int height, const char *title)
            :m_windowWidth{std :: move(width)}
            ,m_windowHeight{std :: move(height)}
            ,m_windowTitle{std :: move(title)}
        {
            CreateWindow();
        }

        void Window::Update()
        {
            glfwSwapBuffers(this->m_window_handle);
            glfwPollEvents();
        }

        void Window::onUpdate()
        {
            Update();
        }

        void Window::Destroy()
        {
            if (!m_isClosed)
            {
                m_isClosed = true;
                glfwDestroyWindow(this->m_window_handle);
            }
        }

        bool Window::ShouldClose()
        {
            return glfwWindowShouldClose(this->m_window_handle);
        }

        bool Window::Init()
        {
            if (!glfwInit())
            {
                std::cout << "SoulByteEngine :: CORE :: WINDOW_MANAGER :: ERROR :: CRITICAL :: GLFW CANNOT BE INITIALIZED! " << std::endl;

                return false;
            }
        }

        bool Window::CreateWindow()
        {
            glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
            glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
            glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
            m_window_handle = glfwCreateWindow(m_windowWidth, m_windowHeight, m_windowTitle, NULL, NULL);

            if (!m_window_handle)
            {
                std::cout << "SoulByteEngine :: CORE :: WindowManagerModule :: ERROR :: COULD'T CREATE WINDOW" << std::endl;

                return false;
            }

            glfwMakeContextCurrent(this->m_window_handle);

            if (!gladLoadGL(glfwGetProcAddress))
            {
                std::cout << "SoulByteEngine :: CORE :: WINDOW_MANAGER :: ERROR :: CRITICAL :: WINDOW HAS BEEN CREATED, BUT GLAD COULD NOT BE INITIALIZED! " << std::endl;
                return false;
            }

            return true;
        }

        bool Window::SetLogging()
        {
            return false;
        }

        bool Window :: IsClosed()
        {
            return this->m_isClosed;
        }

        unsigned int Window::GetWidth()
        {
            return this->m_windowWidth;
        }

        unsigned int Window::GetHeight()
        {
            return this->m_windowHeight;
        }

        const char* Window::GetTitle()
        {
            return this->m_windowTitle;
        }

        void Window::ShowWindowData()
        {
            std::cout << "Window Data:" << std::endl;
            std::cout << "Title: " << this->GetTitle() << std::endl;
            std::cout << "Width: " << this->GetWidth() << std::endl;
            std::cout << "Height: " << this->GetHeight() << std::endl;
        }

        void Window::Clear(float x_pos, float y_pos, float z_pos)
        {
            glClearColor(x_pos, y_pos, z_pos, 1.0f);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        }

    }
}

Application.cpp:

#include <WindowManager/WindowManager.hpp>

int main()
{
    if (SoulByteEngineCore::WindowManager::Window::Init())
    {
        SoulByteEngineCore::WindowManager::Window first_window(DEFAULT_WIDTH, DEFAULT_HEIGHT, "First Fuckin SoulByteEngine Window");
        SoulByteEngineCore::WindowManager::Window second_window(DEFAULT_WIDTH, DEFAULT_HEIGHT, "Second Fuckin SoulByteEngine Window");

        while (!first_window.IsClosed() || !second_window.IsClosed())
        {
            if (first_window.ShouldClose())
            {
                first_window.Destroy();
            }
            else
            {
                first_window.onUpdate();
            }
            if (second_window.ShouldClose())
            {
                second_window.Destroy();
            }
            else
            {
                second_window.onUpdate();
            }
        }
    }
}

相关问题