[GLFW] 多线程多窗口的一种实现

#include <glad/glad.h>
#include <GLFW/glfw3.h>

#include <glm/glm.hpp>
using namespace glm;

#include <cassert>

#include <iostream>
#include <thread>
#include <mutex>
#include <set>
#include <map>
#include <concepts>

using namespace std;

namespace toz::gl
{
	template <typename ENUM>
	static constexpr auto enumValue(ENUM e)
	{
		return static_cast<underlying_type_t<ENUM>>(e);
	}

	enum class CullFace : GLenum
	{
		Front = GL_FRONT,
		Back = GL_BACK,
	};

	enum class Key
	{
		Escape = GLFW_KEY_ESCAPE,
	};

	class Context
	{
	protected:
		GLFWwindow* window = nullptr;

	public:
		struct CreateArg
		{
			const char* title = "";
			GLFWmonitor* monitor = nullptr;
			Context* shared = nullptr;
		};

	protected:
		Context(uint version, uvec2 size, const CreateArg& args = { })
		{
			assert(args.title);
			assert(version >= 100);
			static set<thread::id> invoked;
			assert(invoked.emplace(this_thread::get_id()).second);
			static struct AllContext
			{
				AllContext() { glfwInit(); }
				~AllContext() { glfwTerminate(); }
			} ac;
			glfwDefaultWindowHints();
			glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, version / 100);
			glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, version % 100 / 10);
			glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
			window = glfwCreateWindow(
				size.x,
				size.y,
				args.title,
				args.monitor,
				args.shared ? args.shared->window : nullptr);
			assert(window);
			glfwMakeContextCurrent(window);
			assert(gladLoadGLLoader((GLADloadproc)glfwGetProcAddress));
		}

		virtual ~Context()
		{
			glfwDestroyWindow(window);
		}

		virtual void init() = 0;

		virtual bool update() = 0;

	public:
		bool keyPressing(int ch)
		{
			return glfwGetKey(window, ch) == GLFW_PRESS;
		}

		bool keyPressing(Key key)
		{
			return keyPressing(enumValue(key));
		}

		bool shouldClose()
		{
			return glfwWindowShouldClose(window);
		}

		void start()
		{
			thread_local bool invoked = false;
			assert(!invoked);
			invoked = true;
			init();
			do
			{
				glfwPollEvents();
			} while (!update());
		}
	};

	struct Function330
	{
		auto getError()
		{
			return glGetError();// 110, just for test
		}
	};

	struct Function450 : public Function330
	{
		void cullFace(CullFace face)
		{
			glCullFace(enumValue(face));// 110, just for test
		}
	};
}

using namespace toz::gl;

class App final : public Context, Function450
{
public:
	App(uvec2 size, const CreateArg& args = { }) : Context(450, size, args) { }

	template <typename... ARG>
	static auto create(ARG&&... args)
	{
		return thread([&] { App(forward<ARG>(args)...).start(); });
	}

private:
	void init() override
	{
	};

	bool update() override
	{
		if (keyPressing('A'))
		{
			cullFace(CullFace::Front);
			cout << getError() << endl;
		}

		if (keyPressing('B'))
		{
			cullFace(CullFace(998));
			cout << getError() << endl;
		}

		return shouldClose() || keyPressing(Key::Escape);
	};
};

int main()
{
	auto a = App::create(uvec2{ 800, 600 });
	auto b = App::create(uvec2{ 800, 600 });
	a.join();
	b.join();
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据