Hazel游戏引擎(011)窗口抽象和GLFW创建窗口

文中若有代码、术语等错误,欢迎指正

文章目录

  • 前言
  • 步骤
    • GIT添加GLFW子模块及编译
    • Window类
    • 其它修改
  • 效果
  • Bug记录

前言

  • 此节目的

    为了有窗口效果,但不想使用原生的window32写起,所以用glfw窗口库。

    也为了完成008计划事件系统的创建窗口部分

  • 图示

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第1张图片

步骤

GIT添加GLFW子模块及编译

  • 添加glfw子模块

    git add submodule https://github.com/TheCherno/glfw Hazel/vendor/GLFW
    

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第2张图片

  • 修改premake

    解决方案下的premake修改

    -- 包含相对解决方案的目录
    IncludeDir = {}
    IncludeDir["GLFW"] = "Hazel/vendor/GLFW/include"
    -- 这个include,相当于把glfw下的premake5.lua内容拷贝到这里
    include "Hazel/vendor/GLFW"
    project "Hazel"		--Hazel项目
    	location "Hazel"--在sln所属文件夹下的Hazel文件夹
    	kind "SharedLib"--dll动态库
    	-- 包含目录
    	includedirs{
    		"%{prj.name}/src",
    		"%{prj.name}/vendor/spdlog/include",
    		"%{IncludeDir.GLFW}"
    	}
    	-- Hazel链接glfw项目
    	links 
    	{ 
    		"GLFW",
    		"opengl32.lib"
    	}
    	filter "system:windows"
    		defines{
    			"HZ_PLATFORM_WINDOWS",
    			"HZ_ENABLE_ASSERTS"
    		}
    
  • 效果

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第3张图片

Window类

  • 目前类图

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第4张图片

    Application类可以调用创建窗口函数,而窗口类使用glfw库创建真正的窗口。

    窗口类检测glfw窗口的事件,并回调给Application的处理事件函数。

  • 代码

    window.h

    #pragma once
    #include "hzpch.h"
    #include "Hazel/Core.h"
    #include "Hazel/Events/Event.h"
    namespace Hazel {
    	struct WindowProps{// 窗口初始化设置的内容
    		std::string Title;
    		unsigned int Width;
    		unsigned int Height;
    		WindowProps(const std::string& title = "Hazel Engine",
    			unsigned int width = 1280,
    			unsigned int height = 720)
    			: Title(title), Width(width), Height(height){}
    	};
    	class HAZEL_API Window{
    	public:
    		using EventCallbackFn = std::function<void(Event&)>;
    		virtual ~Window() {}
    		virtual void OnUpdate() = 0;
    		virtual unsigned int GetWidth() const = 0;
    		virtual unsigned int GetHeight() const = 0;
    		// Window attributes
    		virtual void SetEventCallback(const EventCallbackFn& callback) = 0;
    		virtual void SetVSync(bool enabled) = 0;
    		virtual bool IsVSync() const = 0;
            // 在Window父类声明创建函数
    		static Window* Create(const WindowProps& props = WindowProps());
    	};
    }
    

    WindowsWindow.h

    #pragma once
    #include "Hazel/Window.h"
    #include 
    namespace Hazel {
    	class WindowsWindow : public Window{
    	public:
    		WindowsWindow(const WindowProps& props);
    		virtual ~WindowsWindow();
    		void OnUpdate() override;
    		inline unsigned int GetWidth() const override { return m_Data.Width; }
    		inline unsigned int GetHeight() const override { return m_Data.Height; }
    		// 设置Application的回调函数
    		inline void SetEventCallback(const EventCallbackFn& callback) override { m_Data.EventCallback = callback; }
    		void SetVSync(bool enabled) override;
    		bool IsVSync() const override;
    	private:
    		virtual void Init(const WindowProps& props);
    		virtual void Shutdown();
    	private:
    		GLFWwindow* m_Window;
    		struct WindowData{
    			std::string Title;
    			unsigned int Width, Height;
    			bool VSync;
    			EventCallbackFn EventCallback;
    		};
    		WindowData m_Data;
    	};
    }
    

    WindowsWindow.cpp

    #include "hzpch.h"
    #include "WindowsWindow.h"
    
    namespace Hazel {
    	static bool s_GLFWInitialized = false;
        // 在WindowsWindow子类定义在Window父类声明的函数
    	Window* Window::Create(const WindowProps& props){
    		return new WindowsWindow(props);
    	}
    	WindowsWindow::WindowsWindow(const WindowProps& props){
    		Init(props);
    	}
    	void WindowsWindow::Init(const WindowProps& props){
    		m_Data.Title = props.Title;
    		m_Data.Width = props.Width;
    		m_Data.Height = props.Height;
    		HZ_CORE_INFO("Creating window {0} ({1}, {2})", props.Title, props.Width, props.Height);
    		if (!s_GLFWInitialized){
    			// TODO: glfwTerminate on system shutdown
    			int success = glfwInit();
    			HZ_CORE_ASSERT(success, "Could not intialize GLFW!");// 是Core.h里面预处理器指令定义了HZ_CORE_ASSERT
    			s_GLFWInitialized = true;
    		}
    		// 创建窗口//
    		m_Window = glfwCreateWindow((int)props.Width, (int)props.Height, m_Data.Title.c_str(), nullptr, nullptr);
    		// 设置glfw当前的上下文
    		glfwMakeContextCurrent(m_Window);
    		/*
    			设置窗口关联的用户数据指针。这里GLFW仅做存储,不做任何的特殊处理和应用。
    			window表示操作的窗口句柄。
    			pointer表示用户数据指针。
    		*/
    		glfwSetWindowUserPointer(m_Window, &m_Data);
    		SetVSync(true);
    	}
    	void WindowsWindow::OnUpdate(){
    		glfwPollEvents();			// 轮询事件	
    		glfwSwapBuffers(m_Window);	// 交换缓冲
    	}
    	.....
    }
    
  • HZ_CORE_ASSERT

    在Core.h中

    #ifdef HZ_ENABLE_ASSERTS
    #define HZ_ASSERT(x, ...) { if(!(x)) { HZ_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } }
    #define HZ_CORE_ASSERT(x, ...) { if(!(x)) { HZ_CORE_ERROR("Assertion Failed: {0}", __VA_ARGS__); __debugbreak(); } }
    #else
    #define HZ_ASSERT(x, ...)
    #define HZ_CORE_ASSERT(x, ...)
    #endif
    
    HZ_CORE_ASSERT(success, "Could not intialize GLFW!");
    // 转换成
    { if(!(success)) { ::Hazel::Log::GetCoreLogger()->error("Assertion Failed: {0}", "Could not intialize GLFW!"); __debugbreak(); } };
    

    可见:…当做参数包被__VA_ARGS__展开;__debugbreak();是在debug模式下的断点

其它修改

  • Application

    #pragma once
    #include "Core.h"
    #include "Events/Event.h"
    #include "Window.h"
    namespace Hazel {
    	class HAZEL_API Application{
    	public:
    		Application();
    		virtual ~Application();
    		void Run();
    	private:
    		std::unique_ptr<Window> m_Window;
    		bool m_Running = true;
    	};
    	Application* CreateApplication();
    }
    
    #include "hzpch.h"
    #include "Application.h"
    #include "Hazel/Events/ApplicationEvent.h" // 包含事件
    #include "Hazel/Log.h"
    #include 
    namespace Hazel {
    	Application::Application(){
    		m_Window = std::unique_ptr<Window>(Window::Create()); // 创建窗口
    	}
    	Application::~Application() {}
    	void Application::Run(){
    		while (m_Running){
                // 清屏
    			glClearColor(1, 0, 1, 1);
    			glClear(GL_COLOR_BUFFER_BIT);
    			m_Window->OnUpdate();	// 更新glfw
    		}
    	}
    }
    

效果

Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第5张图片

Bug记录

  • glfw找不到函数定义

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第6张图片

  • 解决方法一

    修改GLFW的premake

    filter "configurations:Debug"
        defines "HZ_DEBUG"
        buildoptions "/MTd"
        symbols "On"
    
        filter "configurations:Release"
        defines "HZ_RELEASE"
        buildoptions "/MT"
        symbols "On"
    
        filter "configurations:Dist"
        defines "HZ_DIST"
        buildoptions "/MT"
        symbols "On"
    

    使GLFW项目的运行库,只能是MT或者MTD不能是MD或者MDD

    重新生成项目解决方案才行

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第7张图片

    关于运行库选项:

    // 运行库选项是MTD,静态链接MSVCRT.lib库;
    // 运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
    
    • 为什么GLFW要改为MT或者MTD才行

      Hazel是MTD静态链接MSVCRT.dll库、而引用GLFW项目却是MDD动态链接MSVCRT.dll库,可能不兼容。如下是Hazel项目的运行库选项

      Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第8张图片

  • 解决方法二

    由于Hazel默认是MTD,GLFW默认是MDD,那么就将Hazel用premake改为MDD动态链接MSVCRT.dll库,符合Hazel作为dll库(SharedLib)的方式

    更改解决方案下的premake5.lua文件

    project "Hazel"
        ......
       filter "configurations:Debug"
    		defines "HZ_DEBUG"
    		buildoptions "/MDd"
    		symbols "On"
    
    	filter "configurations:Release"
    		defines "HZ_RELEASE"
    		buildoptions "/MD"
    		optimize "On"
    
    	filter "configurations:Dist"
    		defines "HZ_DIST"
    		buildoptions "/MD"
    		optimize "On"
    
    project "Sandbox"
    	......
    	filter "configurations:Debug"
    		defines "HZ_DEBUG"
    		buildoptions "/MDd"
    		symbols "On"
    
    	filter "configurations:Release"
    		defines "HZ_RELEASE"
    		buildoptions "/MD"
    		optimize "On"
    
    	filter "configurations:Dist"
    		defines "HZ_DIST"
    		buildoptions "/MD"
    		optimize "On"
    

    重新编译后,Hazel的运行库依旧是MTd,但是添加了命令行/MDd 会覆盖/MTd

    Hazel游戏引擎(011)窗口抽象和GLFW创建窗口_第9张图片

    • 后面017节才发现为什么Hazel依旧为MTD,需要添加了命令行/MDd 才会覆盖/MTd

      由于premake设置了staticruntime为on

      -- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;
      -- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
      staticruntime "On"	
      

      只需staticruntime 为off即可

你可能感兴趣的:(Hazel游戏引擎,游戏引擎,glfw,窗口,git)