IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> <2021SC@SDUSC>开源游戏引擎Overload代码分析一:OvWindowing——Window.cpp -> 正文阅读

[游戏开发]<2021SC@SDUSC>开源游戏引擎Overload代码分析一:OvWindowing——Window.cpp

2021SC@SDUSC

前言

这是Overload引擎相关的第三篇文章,同时也是正式开始分析Overload代码的第一篇。Overload引擎的Github主页在这里。
本着由易到难,先模块后整体和先表层后深入的原则,我们先看看OvWindowing这个模块干了些什么。选择这个模块是因为它与窗口相关,位于整个引擎的最表层,同时有OpenGL(GLFW)帮助解决了渲染相关问题,整个模块较为轻量且易懂,适合作为我们代码分析的切入口。
本篇文章作为第一篇代码分析文章,将分析OvWindowing最主要的Window.cpp及其相关代码,建立起OvWindowing的主体框架。

Window.cpp

我们将按代码顺序来讲解Window.cpp,同时会伴有少量的逻辑关联。主要因为Window.cpp实际上没有很强的逻辑关系,总体比较分散,只有在需要时我才会跳出去讲。

一、头文件

首先我们看看引入的头文件,但我们不会仔细地介绍这些头文件的实现:
headFile

iostream应该是每个学过C++的朋友都了解的,就不细说了,主要是输入输出流;
Window.h是OvWindowing自己定义的头文件,在之后会提及,在此就不一一介绍其中的声明了;
stb_image.h是一个图片库,用于导入、处理和导出图片,在Window.cpp中主要是用来导入加载图标(icon)的图片。顺便一提,自己用的时候最好解除注释,否则可能有问题。同时,虽然这个库很易用,但在大型项目中其实并不推荐使用,因为它的速度并不是非常快。在组织大型项目时,推荐使用更稳定的,使用SIMD指令集的一些图片库。

二、主体代码

接下来我们开始讲代码的主体部分:

1.GLFW与自定义Window对应

map
这行代码主要是为了把GLFW的window和Overload自定义的window对应起来,此后各种代码实际上都以此为基础。先创造Overload的window,再转到GLFW进行各种操作,使得代码结构清晰,并且实现较为简单,都可以通过GLFW进行。

2.Window构造函数

构造函数参数

接下来是我们自定义window的构造函数,先看看它的参数传递:
window

Device类

为了理解这些参数,我们可以先去看看参数的类是如何定义的,首先是Device:
device
我们看Device类的描述,我们可以了解这是window的环境基础。具体内部的函数定义,我不截图了,直接把代码放在下面:

	class Device
	{
	public:
		/**
		* Bind a listener to this event to receive device errors
		*/
		static OvTools::Eventing::Event<EDeviceError, std::string> ErrorEvent;

		/**
		* The constructor of the device will take care about GLFW initialization
		*/
		Device(const Settings::DeviceSettings& p_deviceSettings);

		/**
		* The destructor of the device will take care about GLFW destruction
		*/
		~Device();

		/**
		* Return the size, in pixels, of the primary monity
		*/
		std::pair<int16_t, int16_t> GetMonitorSize() const;

		/**
		* Return an instance of GLFWcursor corresponding to the given shape
		* @param p_cursorShape
		*/
		GLFWcursor* GetCursorInstance(Cursor::ECursorShape p_cursorShape) const;

		/**
		* Return true if the vsync is currently enabled
		*/
		bool HasVsync() const;

		/**
		* Enable or disable the vsync
		* @note You must call this method after creating and defining a window as the current context
		* @param p_value (True to enable vsync)
		*/
		void SetVsync(bool p_value);

		/**
		* Enable the inputs and events managments with created windows
		* @note Should be called every frames
		*/
		void PollEvents() const;

		/**
		* Returns the elapsed time since the device startup
		*/
		float GetElapsedTime() const;

	private:
		void BindErrorCallback();
		void CreateCursors();
		void DestroyCursors();

	private:
		bool m_vsync = true;
		bool m_isAlive = false;
		std::unordered_map<Cursor::ECursorShape, GLFWcursor*> m_cursors;
	};

各个函数的描述都有官方描述了,由于此处没有涉及实现,暂时就不细讲了,实际上就是各类基础设定,等有用到时再说。

WindowSettings类

接下来看一下WindowSettings类,直接上代码了:

	/**
	* Contains window settings
	*/
	struct WindowSettings 
	{
		/**
		* A simple constant used to ignore a value setting (Let the program decide for you)
		* @note You can you WindowSettings::DontCare only where it is indicated
		*/
		static const int32_t DontCare = -1;

		/**
		* Title of the window (Displayed in the title bar)
		*/
		std::string title;

		/**
		* Width in pixels of the window
		*/
		uint16_t width;

		/**
		* Height in pixels of the window
		*/
		uint16_t height;

		/**
		* Minimum width of the window.
		* Use WindowSettings::DontCare to disable limit
		*/
		int16_t minimumWidth = DontCare;

		/**
		* Minimum height of the window.
		* Use WindowSettings::DontCare to disable limit
		*/
		int16_t minimumHeight = DontCare;

		/**
		* Maximum width of the window.
		* Use WindowSettings::DontCare to disable limit
		*/
		int16_t maximumWidth = DontCare;

		/**
		* Maximum height of the window.
		* Use WindowSettings::DontCare to disable limit
		*/
		int16_t maximumHeight = DontCare;

		/**
		* Specifies if the window is by default in fullscreen or windowed mode
		*/
		bool fullscreen = false;

		/**
		* Specifies whether the windowed mode window will have window decorations such as a border, a close widget, etc.
		* An undecorated window may still allow the user to generate close events on some platforms. This hint is ignored
		* for full screen windows.
		*/
		bool decorated = true;

		/**
		* specifies whether the windowed mode window will be resizable by the user. The window will still be resizable using
		* the "SetSize(uint16_t, uint16_t)" method of the "Window" class. This hint is ignored for full screen windows
		*/
		bool resizable = true;

		/**
		* Specifies whether the windowed mode window will be given input focus when created. This hint is ignored for
		* full screen and initially hidden windows.
		*/
		bool focused = true;

		/**
		* Specifies whether the windowed mode window will be maximized when created. This hint is ignored for full screen windows.
		*/
		bool maximized = false;

		/**
		* Specifies whether the windowed mode window will be floating above other regular windows, also called topmost or always-on-top.
		* This is intended primarily for debugging purposes and cannot be used to implement proper full screen windows. This hint is
		* ignored for full screen windows.
		*/
		bool floating = false;

		/**
		* Specifies whether the windowed mode window will be initially visible. This hint is ignored for full screen windows.
		*/
		bool visible = true;

		/**
		* Specifies whether the full screen window will automatically iconify and restore
		* the previous video mode on input focus loss. This hint is ignored for windowed mode windows
		*/
		bool autoIconify = true;

		/**
		* Specifies the desired refresh rate for full screen windows. If set to WindowSettings::DontCare, the highest
		* available refresh rate will be used. This hint is ignored for windowed mode windows.
		*/
		int32_t refreshRate = WindowSettings::DontCare;

		/**
		* Specifies the default cursor mode of the window
		*/
		Cursor::ECursorMode cursorMode = Cursor::ECursorMode::NORMAL;

		/**
		* Specifies the default cursor shape of the window
		*/
		Cursor::ECursorShape cursorShape = Cursor::ECursorShape::ARROW;

		/**
		* Defines the number of samples to use (For anti-aliasing)
		*/
		uint32_t samples = 4;
	};

这就是窗口自己的各类属性设定了,包括标题,大小,是否可改变大小,是否悬浮可见等等,这些属性会在构造函数中被赋值给我们自定义的window。这些都是非常好懂的概念,更不用提还有官方的解释了,所以我在这里也不多说了,等用到具体的再说明。
唯一一个要提的,可能不是所有人都知道的一个概念,是此类的最后一个属性samples。它是与抗锯齿有关的,实际上就是超采样的个数,想要具体了解的可以搜索MSAA或SSAA等。

构造函数主体

看完了构造函数获得的参数,我们来看看构造函数的主体,直接上代码:

	/* Window creation */
	CreateGlfwWindow(p_windowSettings);

	/* Window settings */
	SetCursorMode(p_windowSettings.cursorMode);
	SetCursorShape(p_windowSettings.cursorShape);

	/* Callback binding */
	BindKeyCallback();
	BindMouseCallback();
	BindIconifyCallback();
	BindCloseCallback();
	BindResizeCallback();
	BindCursorMoveCallback();
	BindFramebufferResizeCallback();
	BindMoveCallback();
	BindFocusCallback();

	/* Event listening */
	ResizeEvent.AddListener(std::bind(&Window::OnResize, this, std::placeholders::_1, std::placeholders::_2));
	MoveEvent.AddListener(std::bind(&Window::OnMove, this, std::placeholders::_1, std::placeholders::_2));

这里面有许多函数非常相像,同时看函数名其实就能猜到它的作用。不过需要注意的是,这些函数大部分在Window.cpp中定义,所以之后再遇到时我们就跳过了。我们首先来讲讲CreateGlfwWindow():

CreateGlfwWindow
void OvWindowing::Window::CreateGlfwWindow(const Settings::WindowSettings& p_windowSettings)
{
	GLFWmonitor* selectedMonitor = nullptr;

	if (m_fullscreen)
		selectedMonitor = glfwGetPrimaryMonitor();

	glfwWindowHint(GLFW_RESIZABLE,		p_windowSettings.resizable);
	glfwWindowHint(GLFW_DECORATED,		p_windowSettings.decorated);
	glfwWindowHint(GLFW_FOCUSED,		p_windowSettings.focused);
	glfwWindowHint(GLFW_MAXIMIZED,		p_windowSettings.maximized);
	glfwWindowHint(GLFW_FLOATING,		p_windowSettings.floating);
	glfwWindowHint(GLFW_VISIBLE,		p_windowSettings.visible);
	glfwWindowHint(GLFW_AUTO_ICONIFY,	p_windowSettings.autoIconify);
	glfwWindowHint(GLFW_REFRESH_RATE,	p_windowSettings.refreshRate);
	glfwWindowHint(GLFW_SAMPLES,		p_windowSettings.samples);

	m_glfwWindow = glfwCreateWindow(static_cast<int>(m_size.first), static_cast<int>(m_size.second), m_title.c_str(), selectedMonitor, nullptr);

	if (!m_glfwWindow)
	{
		throw std::runtime_error("Failed to create GLFW window");
	}
	else
	{
		UpdateSizeLimit();

		auto[x, y] = GetPosition();
		m_position.first = x;
		m_position.second = y;

		__WINDOWS_MAP[m_glfwWindow] = this;
	}
}

可以看到,如果我们要创造全屏的窗口的话,就会调用 glfwGetPrimaryMonitor(),这是返回一个控制器,因为全屏后我们肯定只能操控它,所以需要返回一个控制器。
下面一连串的glfwWindowHint是用来绑定GLFW中window的参数和我们自定义window的参数,绑定后就可以用GLFW来创造窗口了,这也就是下面调用的glfwCreateWindow()。
之后如果没创建出窗口,那就会报错;如果创建成功了,会更新我们对窗口大小的限制,同时获得我们窗口在显示屏上的起始坐标。

SetCursor***

接下来我们说SetCursorMode()和SetCursorShape(),其实这两个函数非常简单。顾名思义,就是设置指针的模式和样子,实现的代码也非常简单,就是把对应的参数传给我们的window就好了。比如有显示和隐藏模式等,形状有指针和抓手等等,不多说了。

Bind***Callback

下面是一系列的Callback,我们就拿第一个BindKeyCallback来说说。这个函数是用来监听获取键盘输入的,实现如下:

void OvWindowing::Window::BindKeyCallback() const
{
	auto keyCallback = [](GLFWwindow* p_window, int p_key, int p_scancode, int p_action, int p_mods)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			if (p_action == GLFW_PRESS)
				windowInstance->KeyPressedEvent.Invoke(p_key);

			if (p_action == GLFW_RELEASE)
				windowInstance->KeyReleasedEvent.Invoke(p_key);
		}
	};

	glfwSetKeyCallback(m_glfwWindow, keyCallback);
}

首先定义了一个auto函数,并在之后的glfwSetKeyCallback中调用了,glfwSetKeyCallback的作用就是回应键盘操作。auto函数内部先获得了当前窗口的实例,如果存在窗口且有执行按下或释放的操作,那么就唤醒对应的事件。这里的事件系统包含在OvTools中,我暂时不会分析此处的实现,有需求的可以去看Egovix的博客

AddListener

此函数的作用就是为我们选定的事件添加一个监听,在此处具体为改变窗口大小和移动窗口位置的监听,实现在OvTools中,暂时不细讲。

3.析构函数

OvWindowing::Window::~Window()
{
	glfwDestroyWindow(m_glfwWindow);
}

普通的析构函数,不多讲了。

4.图标相关函数

接下来是和图标有关的函数,先看代码:

void OvWindowing::Window::SetIcon(const std::string & p_filePath)
{
	GLFWimage images[1];
	images[0].pixels = stbi_load(p_filePath.c_str(), &images[0].width, &images[0].height, 0, 4);
	glfwSetWindowIcon(m_glfwWindow, 1, images);
}

void OvWindowing::Window::SetIconFromMemory(uint8_t* p_data, uint32_t p_width, uint32_t p_height)
{
	GLFWimage images[1];
	images[0].pixels = p_data;
	images[0].height = p_width;
	images[0].width = p_height;
	glfwSetWindowIcon(m_glfwWindow, 1, images);
}

这就只是把图标的图片给定了,上下两个函数区别无非在于是从硬盘读入还是从内存读入,应该分属第一次设定和设定过后再次设定两个操作,简单易懂。我们可以看到官方对images的定义是一个数组,如果需要我们可以尝试给定多张图片在不同状态时显示,不过这不是我们在此要讲述的内容。

5.FindInstance()

OvWindowing::Window* OvWindowing::Window::FindInstance(GLFWwindow* p_glfwWindow)
{
	return __WINDOWS_MAP.find(p_glfwWindow) != __WINDOWS_MAP.end() ? __WINDOWS_MAP[p_glfwWindow] : nullptr;
}

我们在上面已经遇见过它了,就是找到一个window的实例,依靠的是unordered_map,不熟悉的可以看看c++的语法。

6.size相关函数

size相关的函数,因为写在一起了,所以我们就一起讲了:

void OvWindowing::Window::SetSize(uint16_t p_width, uint16_t p_height)
{
	glfwSetWindowSize(m_glfwWindow, static_cast<int>(p_width), static_cast<int>(p_height));
}

void OvWindowing::Window::SetMinimumSize(int16_t p_minimumWidth, int16_t p_minimumHeight)
{
	m_minimumSize.first = p_minimumWidth;
	m_minimumSize.second = p_minimumHeight;

	UpdateSizeLimit();
}

void OvWindowing::Window::SetMaximumSize(int16_t p_maximumWidth, int16_t p_maximumHeight)
{
	m_maximumSize.first = p_maximumWidth;
	m_maximumSize.second = p_maximumHeight;

	UpdateSizeLimit();
}

相关的属性我们已经见过了,此处的函数就如同所有的命名里带set的函数一样,是把我们传进去的参数赋给属性,后续的操作在此是依靠glfw来完成的,UpdateSizeLimit()内部也是调用了glfw的函数。

6.窗口操作函数

一些简单的窗口操作函数,不细分了,一起讲,先放代码:

void OvWindowing::Window::SetPosition(int16_t p_x, int16_t p_y)
{
	glfwSetWindowPos(m_glfwWindow, static_cast<int>(p_x), static_cast<int>(p_y));
}

void OvWindowing::Window::Minimize() const
{
	glfwIconifyWindow(m_glfwWindow);
}

void OvWindowing::Window::Maximize() const
{
	glfwMaximizeWindow(m_glfwWindow);
}

void OvWindowing::Window::Restore() const
{
	glfwRestoreWindow(m_glfwWindow);
}

void OvWindowing::Window::Hide() const
{
	glfwHideWindow(m_glfwWindow);
}

void OvWindowing::Window::Show() const
{
	glfwShowWindow(m_glfwWindow);
}

void OvWindowing::Window::Focus() const
{
	glfwFocusWindow(m_glfwWindow);
}

我们这里讲的所有函数都是直接调用glfw内函数的,如果要讲glfw又过于深入,不再属于Overload的范畴了,所以我们不细讲了。
按顺序介绍一下功能,依次是设置窗口位置,最小化窗口,最大化窗口,保存窗口(分辨率),隐藏窗口,显示窗口,以及聚焦窗口(可以视作将窗口置于顶层)。

7.是否关闭与全屏

void OvWindowing::Window::SetShouldClose(bool p_value) const
{
	glfwSetWindowShouldClose(m_glfwWindow, p_value);
}

bool OvWindowing::Window::ShouldClose() const
{
	return glfwWindowShouldClose(m_glfwWindow);
}

void OvWindowing::Window::SetFullscreen(bool p_value)
{
	if (p_value)
		m_fullscreen = true;

	glfwSetWindowMonitor
	(
		m_glfwWindow,
		p_value ? glfwGetPrimaryMonitor() : nullptr,
		static_cast<int>(m_position.first),
		static_cast<int>(m_position.second),
		static_cast<int>(m_size.first),
		static_cast<int>(m_size.second),
		m_refreshRate
	);

	if (!p_value)
		m_fullscreen = false;

}

void OvWindowing::Window::ToggleFullscreen()
{
	SetFullscreen(!m_fullscreen);
}

bool OvWindowing::Window::IsFullscreen() const
{
	return m_fullscreen;
}

事实上同样很简单,也几乎是调用glfw内置函数,因为和上面单纯的操作有些区别,包含了设定,所以分开来说。
两个close相关的不多说了,第一个是设置是否要关闭,第二个则是获取是否要关闭。
在SetFullScreen里有个特别的地方,就是glfw函数中通过p_value来确定是否给控制器,以此来设定全屏,除此之外没什么好说的。
ToggleFullscreen会在你按全屏按键后调用,即在全屏和不全屏之间切换;IsFullscreen则是返回当前是否全屏。

8.Is***函数

上面我们说到IsFullscreen,从它开始之后有许多Is函数,都是用于判断当前状态的。实现方式是先通过glfw来get到当前的状态,然后与我们像要判断的状态做个相等判断,实现很明了,所以下面只说功能。

bool OvWindowing::Window::IsHidden() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_VISIBLE) == GLFW_FALSE;
}

bool OvWindowing::Window::IsVisible() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_VISIBLE) == GLFW_TRUE;
}

bool OvWindowing::Window::IsMaximized() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_MAXIMIZED) == GLFW_TRUE;
}

bool OvWindowing::Window::IsMinimized() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_MAXIMIZED) == GLFW_FALSE;
}

bool OvWindowing::Window::IsFocused() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_FOCUSED) == GLFW_TRUE;
}

bool OvWindowing::Window::IsResizable() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_RESIZABLE) == GLFW_TRUE;
}

bool OvWindowing::Window::IsDecorated() const
{
	return glfwGetWindowAttrib(m_glfwWindow, GLFW_DECORATED) == GLFW_TRUE;;
}

函数功能依次是判断是否隐藏,判断是否可见,判断是否最大化,判断是否最小化,判断是否聚焦,判断是否可改变大小,判断是否被修改外形。
有意思的是,我们可以看到IsDecorated中最后多了一个分号,这可能是开发者不小心打多了。

9.MakeCurrentContext()

void OvWindowing::Window::MakeCurrentContext() const
{
	glfwMakeContextCurrent(m_glfwWindow);
}

还是用到了glfw的函数,这个函数是用来把我们窗口的环境给到一个线程,也就是咱们的窗口准备好了。

10.一些讲过的函数

void OvWindowing::Window::SwapBuffers() const
{
	glfwSwapBuffers(m_glfwWindow);
}

void OvWindowing::Window::SetCursorMode(Cursor::ECursorMode p_cursorMode)
{
	m_cursorMode = p_cursorMode;
	glfwSetInputMode(m_glfwWindow, GLFW_CURSOR, static_cast<int>(p_cursorMode));
}

void OvWindowing::Window::SetCursorShape(Cursor::ECursorShape p_cursorShape)
{
	m_cursorShape = p_cursorShape;
	glfwSetCursor(m_glfwWindow, m_device.GetCursorInstance(p_cursorShape));
}

第一个函数我们在上一篇博文中提到了,与之相关的是双缓冲技术,想知道在哪里用到了可以看上一篇博文,这里不再提了。
剩下两个在构造函数的setCursor部分提过,看名字就懂,不再说了。

11.一些set函数

void OvWindowing::Window::SetCursorPosition(int16_t p_x, int16_t p_y)
{
	glfwSetCursorPos(m_glfwWindow, static_cast<double>(p_x), static_cast<double>(p_y));
}

void OvWindowing::Window::SetTitle(const std::string& p_title)
{
	m_title = p_title;
	glfwSetWindowTitle(m_glfwWindow, p_title.c_str());
}

void OvWindowing::Window::SetRefreshRate(int32_t p_refreshRate)
{
	m_refreshRate = p_refreshRate;
}

很简单,上面也说过set函数的实现原理,不再重复。功能依次是设置鼠标位置,设置标题(窗口名),设置刷新率。还有一件事,我们在上面看到过刷新率的初值是DontCare,它是显示器支持的最大刷新率。

12.一些get函数

std::string OvWindowing::Window::GetTitle() const
{
	return m_title;
}

std::pair<uint16_t, uint16_t> OvWindowing::Window::GetSize() const
{
	int width, height;
	glfwGetWindowSize(m_glfwWindow, &width, &height);
	return std::make_pair(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
}

std::pair<int16_t, int16_t> OvWindowing::Window::GetMinimumSize() const
{
	return m_minimumSize;
}

std::pair<int16_t, int16_t> OvWindowing::Window::GetMaximumSize() const
{
	return m_maximumSize;
}

std::pair<int16_t, int16_t> OvWindowing::Window::GetPosition() const
{
	int x, y;
	glfwGetWindowPos(m_glfwWindow, &x, &y);
	return std::make_pair(static_cast<int16_t>(x), static_cast<int16_t>(y));
}

std::pair<uint16_t, uint16_t> OvWindowing::Window::GetFramebufferSize() const
{
	int width, height;
	glfwGetFramebufferSize(m_glfwWindow, &width, &height);
	return std::make_pair(static_cast<uint16_t>(width), static_cast<uint16_t>(height));
}

OvWindowing::Cursor::ECursorMode OvWindowing::Window::GetCursorMode() const
{
	return m_cursorMode;
}

OvWindowing::Cursor::ECursorShape OvWindowing::Window::GetCursorShape() const
{
	return m_cursorShape;
}

int32_t OvWindowing::Window::GetRefreshRate() const
{
	return m_refreshRate;
}

GLFWwindow* OvWindowing::Window::GetGlfwWindow() const
{
	return m_glfwWindow;
}

也是非常的简单,就是获取一些属性值,依次是标题,大小,最小尺寸,最大尺寸,(起始)位置,视口大小,指针模式,指针形状,刷新率和glfw下的window。

13.另一些讲过的函数

void OvWindowing::Window::CreateGlfwWindow(const Settings::WindowSettings& p_windowSettings)
{
	GLFWmonitor* selectedMonitor = nullptr;

	if (m_fullscreen)
		selectedMonitor = glfwGetPrimaryMonitor();

	glfwWindowHint(GLFW_RESIZABLE,		p_windowSettings.resizable);
	glfwWindowHint(GLFW_DECORATED,		p_windowSettings.decorated);
	glfwWindowHint(GLFW_FOCUSED,		p_windowSettings.focused);
	glfwWindowHint(GLFW_MAXIMIZED,		p_windowSettings.maximized);
	glfwWindowHint(GLFW_FLOATING,		p_windowSettings.floating);
	glfwWindowHint(GLFW_VISIBLE,		p_windowSettings.visible);
	glfwWindowHint(GLFW_AUTO_ICONIFY,	p_windowSettings.autoIconify);
	glfwWindowHint(GLFW_REFRESH_RATE,	p_windowSettings.refreshRate);
	glfwWindowHint(GLFW_SAMPLES,		p_windowSettings.samples);

	m_glfwWindow = glfwCreateWindow(static_cast<int>(m_size.first), static_cast<int>(m_size.second), m_title.c_str(), selectedMonitor, nullptr);

	if (!m_glfwWindow)
	{
		throw std::runtime_error("Failed to create GLFW window");
	}
	else
	{
		UpdateSizeLimit();

		auto[x, y] = GetPosition();
		m_position.first = x;
		m_position.second = y;

		__WINDOWS_MAP[m_glfwWindow] = this;
	}
}

void OvWindowing::Window::BindKeyCallback() const
{
	auto keyCallback = [](GLFWwindow* p_window, int p_key, int p_scancode, int p_action, int p_mods)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			if (p_action == GLFW_PRESS)
				windowInstance->KeyPressedEvent.Invoke(p_key);

			if (p_action == GLFW_RELEASE)
				windowInstance->KeyReleasedEvent.Invoke(p_key);
		}
	};

	glfwSetKeyCallback(m_glfwWindow, keyCallback);
}

void OvWindowing::Window::BindMouseCallback() const
{
	auto mouseCallback = [](GLFWwindow* p_window, int p_button, int p_action, int p_mods)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			if (p_action == GLFW_PRESS)
				windowInstance->MouseButtonPressedEvent.Invoke(p_button);

			if (p_action == GLFW_RELEASE)
				windowInstance->MouseButtonReleasedEvent.Invoke(p_button);
		}
	};

	glfwSetMouseButtonCallback(m_glfwWindow, mouseCallback);
}


void OvWindowing::Window::BindResizeCallback() const
{
	auto resizeCallback = [](GLFWwindow* p_window, int p_width, int p_height)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			windowInstance->ResizeEvent.Invoke(static_cast<uint16_t>(p_width), static_cast<uint16_t>(p_height));
		}
	};

	glfwSetWindowSizeCallback(m_glfwWindow, resizeCallback);
}

void OvWindowing::Window::BindFramebufferResizeCallback() const
{
	auto framebufferResizeCallback = [](GLFWwindow* p_window, int p_width, int p_height)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			windowInstance->FramebufferResizeEvent.Invoke(static_cast<uint16_t>(p_width), static_cast<uint16_t>(p_height));
		}
	};

	glfwSetFramebufferSizeCallback(m_glfwWindow, framebufferResizeCallback);
}

void OvWindowing::Window::BindCursorMoveCallback() const
{
	auto cursorMoveCallback = [](GLFWwindow* p_window, double p_x, double p_y)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			windowInstance->CursorMoveEvent.Invoke(static_cast<int16_t>(p_x), static_cast<int16_t>(p_y));
		}
	};

	glfwSetCursorPosCallback(m_glfwWindow, cursorMoveCallback);
}

void OvWindowing::Window::BindMoveCallback() const
{
	auto moveCallback = [](GLFWwindow* p_window, int p_x, int p_y)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			windowInstance->MoveEvent.Invoke(static_cast<int16_t>(p_x), static_cast<int16_t>(p_y));
		}
	};

	glfwSetWindowPosCallback(m_glfwWindow, moveCallback);
}

void OvWindowing::Window::BindIconifyCallback() const
{
	auto iconifyCallback = [](GLFWwindow* p_window, int p_iconified)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			if (p_iconified == GLFW_TRUE)
				windowInstance->MinimizeEvent.Invoke();

			if (p_iconified == GLFW_FALSE)
				windowInstance->MaximizeEvent.Invoke();
		}
	};

	glfwSetWindowIconifyCallback(m_glfwWindow, iconifyCallback);
}

void OvWindowing::Window::BindFocusCallback() const
{
	auto focusCallback = [](GLFWwindow* p_window, int p_focused)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			if (p_focused == GLFW_TRUE)
				windowInstance->GainFocusEvent.Invoke();

			if (p_focused == GLFW_FALSE)
				windowInstance->LostFocusEvent.Invoke();
		}
	};

	glfwSetWindowFocusCallback(m_glfwWindow, focusCallback);
}

void OvWindowing::Window::BindCloseCallback() const
{
	auto closeCallback = [](GLFWwindow* p_window)
	{
		Window* windowInstance = FindInstance(p_window);

		if (windowInstance)
		{
			windowInstance->CloseEvent.Invoke();
		}
	};

	glfwSetWindowCloseCallback(m_glfwWindow, closeCallback);
}

void OvWindowing::Window::OnResize(uint16_t p_width, uint16_t p_height)
{
	m_size.first = p_width;
	m_size.second = p_height;
}

void OvWindowing::Window::OnMove(int16_t p_x, int16_t p_y)
{
	if (!m_fullscreen)
	{
		m_position.first = p_x;
		m_position.second = p_y;
	}
}

void OvWindowing::Window::UpdateSizeLimit() const
{
	glfwSetWindowSizeLimits
	(
		m_glfwWindow,
		static_cast<int>(m_minimumSize.first),
		static_cast<int>(m_minimumSize.second),
		static_cast<int>(m_maximumSize.first),
		static_cast<int>(m_maximumSize.second)
	);
}

这些我们并不是都讲过,但在之前都提到了,至少提到了代表性的,所以我们直接略过了,有需要可以往上看看,大部分在构造函数主体,这也是Window.cpp的最后一部分。

总结

总体来说,Window.cpp的代码编写还是比较清晰的,同时与其他部分关联度不高,单看也能理解,所以咱们要第一个说它。下一次咱们会讲OvWindowing的其他部分,其实也不会太难,而且就算难,知难而上才能获得进步嘛。

Diana

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-10-07 14:07:54  更:2021-10-07 14:08:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/28 2:50:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码