跟着cherno手搓游戏引擎【6】ImGui和ImGui事件

news2024/11/16 21:39:44

导入ImGui:

下载链接:

GitHub - TheCherno/imgui: Dear ImGui: Bloat-free Immediate Mode Graphical User interface for C++ with minimal dependencies

 新建文件夹,把下载好的文件放入对应路径:

 SRC下的premake5.lua文件:添加ImGui

workspace "YOTOEngine"		-- sln文件名
	architecture "x64"	
	configurations{
		"Debug",
		"Release",
		"Dist"
	}
-- https://github.com/premake/premake-core/wiki/Tokens#value-tokens
-- 组成输出目录:Debug-windows-x86_64
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
-- 包含相对解决方案的目录
IncludeDir={}
IncludeDir["GLFW"]="YOTOEngine/vendor/GLFW/include"
IncludeDir["Glad"]="YOTOEngine/vendor/Glad/include"
IncludeDir["ImGui"] ="YOTOEngine/vendor/imgui"
--项目中包含某包
include "YOTOEngine/vendor/GLFW"
include "YOTOEngine/vendor/Glad"
include "YOTOEngine/vendor/imgui"

project "YOTOEngine"		--YOTOEngine项目
	location "YOTOEngine"--在sln所属文件夹下的YOTOEngine文件夹
	kind "SharedLib"--dll动态库
	language "C++"
	targetdir ("bin/" .. outputdir .. "/%{prj.name}") -- 输出目录
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")-- 中间目录
	pchheader "ytpch.h"
	pchsource "YOTOEngine/src/ytpch.cpp"
	-- 包含的所有h和cpp文件
	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 包含目录
	includedirs{
		"%{prj.name}/src",
		"%{prj.name}/vendor/spdlog-1.x/include",
		"%{IncludeDir.GLFW}",
		"%{IncludeDir.Glad}",
		"%{IncludeDir.ImGui}"
	}
	links{
		"GLFW",-- GLFW.lib库链接到YOTOEngine项目中
		"Glad",-- Glad.lib库链接到YOTOEngine项目中
		"ImGui",-- ImGui.lib库链接到YOTOEngine项目中
		"opengl32.lib"
	}
	-- 如果是window系统
	filter "system:windows"
		cppdialect "C++17"
		-- On:代码生成的运行库选项是MTD,静态链接MSVCRT.lib库;
		-- Off:代码生成的运行库选项是MDD,动态链接MSVCRT.dll库;打包后的exe放到另一台电脑上若无这个dll会报错
		staticruntime "On"	
		systemversion "latest"	-- windowSDK版本
		-- 预处理器定义
		defines{
			"YT_PLATFORM_WINDOWS",
			"YT_BUILD_DLL",
			"YT_ENABLE_ASSERTS",
			"GLFW_INCLUDE_NONE"-- 让GLFW不包含OpenGL
		}
		-- 编译好后移动Hazel.dll文件到Sandbox文件夹下
		postbuildcommands{
			("{COPY} %{cfg.buildtarget.relpath} ../bin/" .. outputdir .. "/Sandbox")
		}
	-- 不同配置下的预定义不同
	filter "configurations:Debug"
		defines "YT_DEBUG"
		buildoptions"/MDd"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		buildoptions"/MD"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		buildoptions"/MD"
		optimize "On"

project "Sandbox"
	location "Sandbox"
	kind "ConsoleApp"
	language "C++"

	targetdir ("bin/" .. outputdir .. "/%{prj.name}")
	objdir ("bin-int/" .. outputdir .. "/%{prj.name}")

	files{
		"%{prj.name}/src/**.h",
		"%{prj.name}/src/**.cpp"
	}
	-- 同样包含spdlog头文件
	includedirs{
		"YOTOEngine/vendor/spdlog-1.x/include",
		"YOTOEngine/src"
	}
	-- 引用YOTOEngine
	links{
		"YOTOEngine",
		"GLFW",
		"opengl32.lib"
	}

	filter "system:windows"
		cppdialect "C++17"
		staticruntime "On"
		systemversion "latest"

		defines{
			"YT_PLATFORM_WINDOWS"
		}

	filter "configurations:Debug"
		defines "YT_DEBUG"
		buildoptions"/MDd"
		symbols "On"

	filter "configurations:Release"
		defines "YT_RELEASE"
		buildoptions"/MD"
		optimize "On"

	filter "configurations:Dist"
		defines "YT_DIST"
		buildoptions"/MD"
		optimize "On"

在Platform下创建OpenGl,将imgui_impl_opengl3.cpp和.h加入到该文件夹。

并且更名:

150行改为:#include "backends/imgui_impl_opengl3_loader.h"

96行添加:#include"ytpch.h" 至此错误消除,导入成功。

创建ImGui层:

在YOTO下创建ImGui文件夹创建ImGuiLayer.cpp和.h:

ImGuiLayer.h:UI层的.h文件

#pragma once
#include"YOTO/Layer.h"
namespace YOTO {

	class YOTO_API ImGuiLayer:public Layer
	{
	public:
		ImGuiLayer();
		~ImGuiLayer();
		void OnAttach();
		void OnDetach();
		void OnUpdate();
		void OnEvent(Event& event);
	private:
		float m_Time = 0.0f;

	};


}

ImGuiLayer.cpp:在层初始化的时候和刷新的时候对io的参数进行修改,达到修改UI的目的

#include"ytpch.h"
#include"ImGuiLayer.h"
#include"Platform/OpenGL/ImGuiOpenGLRenderer.h"
#include"GLFW/glfw3.h"
#include"YOTO/Application.h"
namespace YOTO {
	ImGuiLayer::ImGuiLayer()
	:Layer("ImGuiLayer") {

	}
	ImGuiLayer::~ImGuiLayer() {

	}
	void ImGuiLayer::OnAttach()
	{
		//创建上下文
		ImGui::CreateContext();
		//设置颜色
		ImGui::StyleColorsDark();
		//配置类:ImGuiIO
		ImGuiIO& io = ImGui::GetIO();
		io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标
		io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;

		// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的key
		io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
		io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
		io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
		io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
		io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
		io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
		io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
		io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
		io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
		io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
		io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
		io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
		io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
		io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
		io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
		io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
		io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
		io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
		io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
		io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
		io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;

		ImGui_ImplOpenGL3_Init("#version 410");
	
	}
	void ImGuiLayer::OnDetach()
	{
	}
	void ImGuiLayer::OnUpdate() {
		//每帧刷新UI配置
		ImGuiIO& io = ImGui::GetIO();
		Application& app = Application::Get();
		//显示的size大小
		io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
	
		
		float time = (float)glfwGetTime();
		//时间
		io.DeltaTime = m_Time > 0.0f ? (time - m_Time) : (1.0f / 60.0f);
		m_Time = time;

		ImGui_ImplOpenGL3_NewFrame();
		ImGui::NewFrame();

		static bool show = true;
		// 显示ImGui Demo
		ImGui::ShowDemoWindow(&show);

		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

	}
	void ImGuiLayer::OnEvent(Event& event) {

	}
}

 Application.h:将Application变为单例,添加Get方法和GetWindow方法

#pragma once
#include"Core.h"
#include"Event/Event.h"
#include"Event/ApplicationEvent.h"
#include "YOTO/Window.h"
#include"YOTO/LayerStack.h"
namespace YOTO {
	class YOTO_API Application
	{
	public:
		Application();
		virtual ~Application();
		void Run();
		void OnEvent(Event &e);
		void PushLayer(Layer* layer);
		void PushOverlay(Layer* layer);

		inline static Application& Get() {return * s_Instance;}
		inline Window& GetWindow() { return *m_Window; }
	private:
		bool  OnWindowClosed(WindowCloseEvent& e);
		std::unique_ptr<Window>  m_Window;
		bool m_Running = true;
		LayerStack m_LayerStack;
		
		static Application* s_Instance;
	};
	//在客户端定义
	Application* CreateApplication();
}

  Application.cpp:构造时候令s_Instance = this

#include"ytpch.h"
#include "Application.h"

#include"Log.h"
#include<glad/glad.h>
namespace YOTO {
#define BIND_EVENT_FN(x) std::bind(&x, this, std::placeholders::_1)

	 Application* Application::s_Instance = nullptr;

	Application::Application() {

		YT_CORE_ASSERT(!s_Instance, "Application需要为空!")
		s_Instance = this;
		//智能指针
		m_Window = std::unique_ptr<Window>(Window::Creat());
		//设置回调函数
		m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));
		unsigned int id;
		glGenBuffers(1, &id);
	}
	Application::~Application() {

	}
	/// <summary>
	/// 所有的Window事件都会在这触发,作为参数e
	/// </summary>
	/// <param name="e"></param>
	void Application::OnEvent(Event& e) {
		//根据事件类型绑定对应事件
		EventDispatcher dispatcher(e);
		dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClosed));
		//输出事件信息
		YT_CORE_INFO("{0}",e);
		for (auto it = m_LayerStack.end(); it != m_LayerStack.begin();) {
			(*--it)->OnEvent(e);
			if (e.m_Handled)
				break;
		}
	}

	bool Application::OnWindowClosed(WindowCloseEvent& e) {
		m_Running = false;
		return true;
	}
	void Application::Run() {
		WindowResizeEvent e(1280, 720);
		if (e.IsInCategory(EventCategoryApplication)) {
			YT_CORE_TRACE(e);
		}
		if (e.IsInCategory(EventCategoryInput)) {
			YT_CORE_ERROR(e);
		}

		while (m_Running)
		{
			glClearColor(1,0,1,1);
			glClear(GL_COLOR_BUFFER_BIT);

			for (Layer* layer : m_LayerStack) {
				layer->OnUpdate();
			}

			m_Window->OnUpdate();
		}
	}
	void Application::PushLayer(Layer* layer) {
		m_LayerStack.PushLayer(layer);
		layer->OnAttach();
	}
	void Application::PushOverlay(Layer* layer) {
		m_LayerStack.PushOverlay(layer);
		layer->OnDetach();
	}
}

YOTO.h:添加ImGuiLayer.h

#pragma once
#include "YOTO/Application.h"
#include"YOTO/Layer.h"
#include "YOTO/Log.h"
#include"YOTO/ImGui/ImGuiLayer.h"
//入口点
#include"YOTO/EntryPoint.h"

 SandboxApp.cpp:new且push这个层

#include<YOTO.h>
#include<stdio.h>

class ExampleLayer:public YOTO::Layer
{
public:
	ExampleLayer()
	:Layer("Example") {

	}
	void OnUpdate()override {
		//YT_CLIENT_INFO("测试update");
	}
	void	OnEvent(YOTO::Event& e)override {

		YT_CLIENT_TRACE("测试event{0}",e);
	}

private:

};


class Sandbox:public YOTO::Application
{
public:
	Sandbox() {
		PushLayer(new ExampleLayer());
		PushLayer(new YOTO::ImGuiLayer());
	}
	~Sandbox() {

	}

private:

};

YOTO::Application* YOTO::CreateApplication() {
	printf("helloworld");
	return new Sandbox();
}

 测试:

Bug:这里莫名爆红

注释掉:

 暂时解决(不知道这个bug会不会未来给我一脚)

运行成功但是什么都不能点,因为没添加事件。

 谢谢大家的支持,我会把每次可成改动的整个代码、类都粘上来,虽然有点儿多,但是防止迷路然后出现一些蜜汁bug。有问题欢迎评论区讨论(博主也是菜鸡,希望大佬指点)

ImGui事件:

ImGuiLayer.h:创建各种事件的函数声明

#pragma once
#include"YOTO/Layer.h"
#include"YOTO/Event/KeyEvent.h"
#include"YOTO/Event/MouseEvent.h"
#include"YOTO/Event/ApplicationEvent.h"
namespace YOTO {

	class YOTO_API ImGuiLayer:public Layer
	{
	public:
		ImGuiLayer();
		~ImGuiLayer();
		void OnAttach();
		void OnDetach();
		void OnUpdate();
		void OnEvent(Event& event);
	private:
		bool OnMouseButtonPressedEvent(MouseButtonPressedEvent& e);
		bool OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e);
		bool OnMouseMovedEvent(MouseMovedEvent& e);
		bool OnMouseScrolledEvent(MouseScrolledEvent& e);
		bool OnKeyPressedEvent(KeyPressedEvent& e);
		bool OnKeyReleasedEvent(KeyReleasedEvent& e);
		bool OnKeyTypedEvent(KeyTypedEvent& e);
		bool OnWindowResizedEvent(WindowResizeEvent& e);
		float m_Time = 0.0f;

	};


}

 ImGuiLayer.h:绑定拦截器,实现方法

#include"ytpch.h"
#include"ImGuiLayer.h"
#include"Platform/OpenGL/ImGuiOpenGLRenderer.h"

#include"YOTO/Application.h"

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

namespace YOTO {
	ImGuiLayer::ImGuiLayer()
	:Layer("ImGuiLayer") {

	}
	ImGuiLayer::~ImGuiLayer() {

	}
	void ImGuiLayer::OnAttach()
	{
		//创建上下文
		ImGui::CreateContext();
		//设置颜色
		ImGui::StyleColorsDark();
		//配置类:ImGuiIO
		ImGuiIO& io = ImGui::GetIO();
		io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标
		io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;

		// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的key
		io.KeyMap[ImGuiKey_Tab] = GLFW_KEY_TAB;
		io.KeyMap[ImGuiKey_LeftArrow] = GLFW_KEY_LEFT;
		io.KeyMap[ImGuiKey_RightArrow] = GLFW_KEY_RIGHT;
		io.KeyMap[ImGuiKey_UpArrow] = GLFW_KEY_UP;
		io.KeyMap[ImGuiKey_DownArrow] = GLFW_KEY_DOWN;
		io.KeyMap[ImGuiKey_PageUp] = GLFW_KEY_PAGE_UP;
		io.KeyMap[ImGuiKey_PageDown] = GLFW_KEY_PAGE_DOWN;
		io.KeyMap[ImGuiKey_Home] = GLFW_KEY_HOME;
		io.KeyMap[ImGuiKey_End] = GLFW_KEY_END;
		io.KeyMap[ImGuiKey_Insert] = GLFW_KEY_INSERT;
		io.KeyMap[ImGuiKey_Delete] = GLFW_KEY_DELETE;
		io.KeyMap[ImGuiKey_Backspace] = GLFW_KEY_BACKSPACE;
		io.KeyMap[ImGuiKey_Space] = GLFW_KEY_SPACE;
		io.KeyMap[ImGuiKey_Enter] = GLFW_KEY_ENTER;
		io.KeyMap[ImGuiKey_Escape] = GLFW_KEY_ESCAPE;
		io.KeyMap[ImGuiKey_A] = GLFW_KEY_A;
		io.KeyMap[ImGuiKey_C] = GLFW_KEY_C;
		io.KeyMap[ImGuiKey_V] = GLFW_KEY_V;
		io.KeyMap[ImGuiKey_X] = GLFW_KEY_X;
		io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
		io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;

		ImGui_ImplOpenGL3_Init("#version 410");
	
	}
	void ImGuiLayer::OnDetach()
	{
	}
	void ImGuiLayer::OnUpdate() {
		//每帧刷新UI配置
		ImGuiIO& io = ImGui::GetIO();
		Application& app = Application::Get();
		//显示的size大小
		io.DisplaySize = ImVec2(app.GetWindow().GetWidth(), app.GetWindow().GetHeight());
	
		
		float time = (float)glfwGetTime();
		//时间
		io.DeltaTime = m_Time > 0.0f ? (time - m_Time) : (1.0f / 60.0f);
		m_Time = time;

		ImGui_ImplOpenGL3_NewFrame();
		ImGui::NewFrame();

		static bool show = true;
		// 显示ImGui Demo
		ImGui::ShowDemoWindow(&show);

		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

	}
	void ImGuiLayer::OnEvent(Event& event) {


		EventDispatcher dispatcher(event);
		dispatcher.Dispatch<MouseButtonPressedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonPressedEvent));
		dispatcher.Dispatch<MouseButtonReleasedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseButtonReleasedEvent));
		dispatcher.Dispatch<MouseMovedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseMovedEvent));
		dispatcher.Dispatch<MouseScrolledEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnMouseScrolledEvent));
		dispatcher.Dispatch<KeyPressedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyPressedEvent));
		dispatcher.Dispatch<KeyReleasedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyReleasedEvent));
		dispatcher.Dispatch<KeyTypedEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnKeyTypedEvent));
		dispatcher.Dispatch<WindowResizeEvent>(YT_BIND_EVENT_FN(ImGuiLayer::OnWindowResizedEvent));

	
	}	
	bool ImGuiLayer::OnMouseButtonPressedEvent(MouseButtonPressedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.MouseDown[e.GetMouseButton()] = true;
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseButtonReleasedEvent(MouseButtonReleasedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.MouseDown[e.GetMouseButton()] = false;
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseMovedEvent(MouseMovedEvent& e)
	{
		ImGuiIO &io = ImGui::GetIO();
		io.MousePos = ImVec2(e.GetX(), e.GetY());
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnMouseScrolledEvent(MouseScrolledEvent& e)
	{
		ImGuiIO&io = ImGui::GetIO();
		io.MouseWheel += e.GetXOffset();
		io.MouseWheelH += e.GetYOffset();
		return false;//返回false是因为希望其他层也处理这个事件(事件穿透)
	}
	bool ImGuiLayer::OnKeyPressedEvent(KeyPressedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.KeysDown[e.GetKeyCode()] = true;
		io.KeyCtrl = io.KeysDown[GLFW_KEY_LEFT_CONTROL] || io.KeysDown[GLFW_KEY_RIGHT_CONTROL];
		io.KeyShift = io.KeysDown[GLFW_KEY_LEFT_SHIFT] || io.KeysDown[GLFW_KEY_RIGHT_SHIFT];
		io.KeyAlt = io.KeysDown[GLFW_KEY_LEFT_ALT] || io.KeysDown[GLFW_KEY_RIGHT_ALT];
		io.KeySuper = io.KeysDown[GLFW_KEY_LEFT_SUPER] || io.KeysDown[GLFW_KEY_RIGHT_SUPER];

		return false;
	}
	bool ImGuiLayer::OnKeyReleasedEvent(KeyReleasedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.KeysDown[e.GetKeyCode()] = false;
		return false;
	}
	bool ImGuiLayer::OnKeyTypedEvent(KeyTypedEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		int keycode = e.GetKeyCode();
		if (keycode > 0 && keycode < 0x10000)
			io.AddInputCharacter((unsigned short)keycode);

		return false;
	}
	bool ImGuiLayer::OnWindowResizedEvent(WindowResizeEvent& e)
	{
		ImGuiIO& io = ImGui::GetIO();
		io.DisplaySize = ImVec2(e.GetWidth(), e.GetHeight());
		io.DisplayFramebufferScale = ImVec2(1.0f, 1.0f);
		glViewport(0, 0, e.GetWidth(), e.GetHeight());
		return false;
	}
}

KeyEvent.h:添加KeyTypedEvent类

#pragma once
#include"Event.h"
#include "ytpch.h"

namespace YOTO {
	/// <summary>
	/// 键盘事件基类
	/// </summary>
	class YOTO_API KeyEvent:public Event
	{
	public:
		inline int GetKeyCode() const { return m_KeyCode; }
		EVENT_CLASS_CATEGORY(EventCategoryKeyboard | EventCategoryInput)
	protected:
		KeyEvent(int keycode)
			:m_KeyCode(keycode){}
		int m_KeyCode;

	};
	/// <summary>
	/// 键盘按下回调
	/// </summary>
	class YOTO_API KeyPressedEvent :public KeyEvent
	{
	public:
		KeyPressedEvent(int keycode, int repeatCount)
			:KeyEvent(keycode),m_RepeatCount(repeatCount){}
		inline int GetRepeatCount() const { return m_RepeatCount; }
		std::string ToString() const override{
			std::stringstream ss;
			ss << "键盘按下事件:" << m_KeyCode << "(" << m_RepeatCount << "重复)";
			return ss.str();
		}
		//static EventType GetStaticType() { return EventType::KeyPressed; }
		//virtual EventType GetEventType()const override { return GetStaticType(); }
		//virtual const char* GetName()const override { return "KeyPressed"; }
		EVENT_CLASS_TYPE(KeyPressed)
	private:
		int m_RepeatCount;

	};
	/// <summary>
	/// 键盘释放回调
	/// </summary>
	class YOTO_API KeyReleasedEvent:public KeyEvent
	{
	public:
		KeyReleasedEvent(int keycode)
		:KeyEvent(keycode){

		}
		std::string ToString()const override {
			std::stringstream ss;
			ss << "键盘释放事件:" << m_KeyCode;
			return ss.str(); 
		}
	EVENT_CLASS_TYPE(KeyReleased)
			
	};
	/// <summary>
	/// 输入字符回调
	/// </summary>
	class YOTO_API KeyTypedEvent :public KeyEvent
	{
	public:
		KeyTypedEvent(int keycode)
			:KeyEvent(keycode) { 

		}
		std::string ToString()const override {
			std::stringstream ss;
			ss << "键盘类型事件:" << m_KeyCode;
			return ss.str();
		}
		EVENT_CLASS_TYPE(KeyTyped)

	};

}

 WindowsWindow.cpp:Init里添加KeyTyped的回调:

#include "ytpch.h"
#include "WindowsWindow.h"
#include"YOTO/Event/ApplicationEvent.h"
#include"YOTO/Event/MouseEvent.h"
#include"YOTO/Event/KeyEvent.h"
#include<glad/glad.h>

namespace YOTO {

	static bool s_GLFWInitialized = false;

	Window* Window::Creat(const WindowProps& props) {
		return new WindowsWindow(props);
	}
	WindowsWindow::WindowsWindow(const WindowProps& props) {
		Init(props);
	}
	WindowsWindow::~WindowsWindow() {
		ShutDown();
	}

	void WindowsWindow::Init(const WindowProps& props) {
		m_Data.Title = props.Title;
		m_Data.Width = props.Width;
		m_Data.Height = props.Height;
		YT_CORE_INFO("创建了{0},{1},{2}", props.Title, props.Width, props.Height);
		if (!s_GLFWInitialized) {
			int success = glfwInit();
			YT_CLIENT_ASSERT("不能创建新的glfw,{0}",success );
			glfwSetErrorCallback([](int error_code, const char* description) {
				YT_CORE_ERROR("GLFW错误:错误码({0}):{1} ", error_code, description);
				});
			s_GLFWInitialized = true;

		}
		m_Window = glfwCreateWindow((int)props.Width, (int)props.Height, m_Data.Title.c_str(), nullptr, nullptr);
		glfwMakeContextCurrent(m_Window); 
		//在运行时获取OpenGL函数地址并将其保存在函数指针中供以后使用
		int status = gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
		YT_CORE_ASSERT(status, "glad初始化错误");
		glfwSetWindowUserPointer(m_Window, &m_Data);
		SetVSync(true);


		//GLFW回调,每次改变调用lambda里的部分
		//窗口大小回调
		glfwSetWindowSizeCallback(m_Window, [](GLFWwindow* window, int width, int height) {
			WindowData& data=*(WindowData*)glfwGetWindowUserPointer(window);
			data.Width = width;
			data.Height = height;
			WindowResizeEvent event(width, height);
			//调用回调函数
			data.EventCallback(event);
			});
		//窗口关闭回调
		glfwSetWindowCloseCallback(m_Window, [](GLFWwindow* window) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			WindowCloseEvent event;
			data.EventCallback(event);
			});
		//键盘按键回调
		glfwSetKeyCallback(m_Window, [](GLFWwindow* window, int key, int scancode, int action, int mods) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			switch (action) {
				case GLFW_PRESS:
				{
					KeyPressedEvent event(key, 0);
					data.EventCallback(event);
					break;
				}
				case GLFW_RELEASE:
				{
					KeyReleasedEvent event(key);
					data.EventCallback(event);
					break;
				}
				case GLFW_REPEAT:
				{
					KeyPressedEvent event(key, 1);
					data.EventCallback(event);
					break;
				}
				}
			});
		//鼠标按键回调
		glfwSetMouseButtonCallback(m_Window, [](GLFWwindow* window, int button, int action, int mods) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			switch (action)
			{
				case GLFW_PRESS:
				{
					MouseButtonPressedEvent event(button);
					data.EventCallback(event);
					break;
				}

				case GLFW_RELEASE:
				{
					MouseButtonReleasedEvent event(button);
					data.EventCallback(event);
					break;
				}
			}
			});
		//滚轮回调
		glfwSetScrollCallback(m_Window, [](GLFWwindow* window, double xoffset, double yoffset) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			MouseScrolledEvent event((float)xoffset, (float)yoffset);
			data.EventCallback(event);
			});
		//鼠标位置回调
		glfwSetCursorPosCallback(m_Window, [](GLFWwindow* window, double xpos, double ypos) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			MouseMovedEvent event((float)xpos, (float)ypos);
			data.EventCallback(event);
			});
		//字符回调
		glfwSetCharCallback(m_Window, [](GLFWwindow* window, unsigned int codepoint) {
			WindowData& data = *(WindowData*)glfwGetWindowUserPointer(window);
			KeyTypedEvent event(codepoint);
			data.EventCallback(event);
			});
	}
	void WindowsWindow::ShutDown() {
		glfwDestroyWindow(m_Window);
	}
	void WindowsWindow::OnUpdate()
	{
		//轮询事件
		glfwPollEvents();
		//交换缓冲区
		glfwSwapBuffers(m_Window);


	}
	void WindowsWindow::SetVSync(bool enable) {
		if (enable)
			glfwSwapInterval(1);
		else
			glfwSwapInterval(0);
		m_Data.VSync = enable;
		}
	bool WindowsWindow::IsVSync() const {
		return m_Data.VSync;
		}
}

Core.h:添加绑定事件的定义

#pragma once
//用于dll的宏
#ifdef YT_PLATFORM_WINDOWS
#ifdef YT_BUILD_DLL
#define YOTO_API __declspec(dllexport) 
#else
#define YOTO_API __declspec(dllimport) 

#endif // DEBUG
#else
#error YOTO_ONLY_SUPPORT_WINDOWS
#endif // YOTO_PLATFORM_WINDOWS

#ifdef YT_ENABLE_ASSERTS
#define YT_CLIENT_ASSERT(x,...) {if(!(x)){YT_CLIENT_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#define YT_CORE_ASSERT(x,...) {if(!(x)){YT_CORE_ERROR("断言错误:{0}",__VA_ARGS__);__debugbreak();}}
#else
#define YT_CLIENT_ASSERT(x,...)
#define YT_CORE_ASSERT(x,...)

#endif // YT_ENABLE_ASSERTS



#define BIT(x)(1<<x)
//绑定事件定义
#define YT_BIND_EVENT_FN(fn) std::bind(&fn, this, std::placeholders::_1)

测试:

 cool现在ImGui就能接收到咱的事件了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1390721.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

48 WAF绕过-权限控制之代码混淆及行为造轮子

目录 Safedog代码层手写及脚本绕过BT Aliyun代码层手写及脚本绕过safedog&#xff0c;BT&#xff0c;Aliyun-基于覆盖加密变异下编码解码绕过-代码层Safedog&#xff0c;BT&#xff0c;Aliyun-基于冰蝎新型控制器绕过全面测试-行为层Safedog,BT,Aliyun-基于手写新型控制器绕过全…

kotlin运行

1.使用android studio 由于我本身是做android的&#xff0c;android studio本身有内置kotlin的插件。但若只是想跑kotlin的程序&#xff0c;并不像和android程序绑在一起&#xff0c;可以创建一个kt文件&#xff0c;在里面写一个main函数&#xff0c;就可以直接运行kotlin程序…

如何隐藏服务器真实IP地址,隐藏服务器IP有什么好处

首先我们介绍了隐藏服务器IP的概念及工作模式&#xff0c;接着阐述了其对于DDoS攻击的防护作用。然后介绍了如何利用隐藏服务器IP增加系统性能和稳定性。接着我们讲述了如何隐藏服务器IP防止黑客攻击&#xff0c;最后总结了隐藏服务器IP在保护服务器和用户数据方面发挥的作用。…

10分钟读完一篇 AI 论文!​

已经2024年了&#xff0c;该出现一个写论文解读的AI Agent了。 大家肯定也在经常刷论文吧。 但真正尝试过用GPT去刷论文、写论文解读的小伙伴&#xff0c;一定深有体验——费劲。其他agents也没有能搞定的&#xff0c;今天我发现了一个超级厉害的写论文解读的agent &#xff…

计算机网络期末复习(基础概念+三套卷子练习)

文章目录 第一章&#xff1a;计算机网络概念计算机网络的概念计算机网络体系结构 第二章&#xff1a;物理层物理层的基本概念物理层的基本通信技术 练题专题练习码分多址地址聚合 1.0选择填空大题练习 2.0选择填空大题练习 3.0选择填空大题练习 第一章&#xff1a;计算机网络概…

【驱动】TI AM437x(内核调试-06):网卡(PHY和MAC)、七层OSI

1、网络基础知识 1.1 七层OSI 第一层:物理层。 1)需求: 两个电脑之间如何进行通信? 具体就是一台发比特流,另一台能够收到。于是就有了物理层:主要是定义设备标准,如网线的额接口类型、管线的接口类型、各种传输介质的传输速率等。它的主要作用是传输比特流,就是从1/0…

C++多线程学习[三]:成员函数作为线程入口

一、成员函数作为线程入口 #include<iostream> #include<thread> #include<string>using namespace std;class Mythread { public:string str;void Test(){cout << str << endl;} }; int main() {Mythread test;test.str "Test";thr…

tidb Cloud 连接spring boot 项目

一、 免费试用tidbitcloud TiDB Cloud Documentation | PingCAP Docs 1.github账号登录 2.创建集群 3.点击对应集群cludter0 导入数据 导入 本地导入只支持csv文件&#xff0c;其他导入需要AWZ账号使用S3云存储 二、连接spingboot项目 选择java&#xff0c;复制下面的jd…

Matlab并行编程之GPU

Matlab并行编程之GPU Matlab提供GPU上计算支持: 基础数据类型(gpuArray和对应API),支持GPU计算的内置函数和多个工具包,支持PTX内核对象加载,支持MEX函数使用CUDA C/C开发等。对大规模数据处理&#xff0c;复杂计算&#xff0c;利用GPU计算能提供显著的性能加速效果. Matlab同…

Django教程第5章 | Web开发实战-数据统计图表(echarts、highchart)

专栏系列&#xff1a;Django学习教程 前言 highchart&#xff0c;国外。 echarts&#xff0c;国内。 本项目集成 hightchart和echarts图表库实现数据统计功能。 包括&#xff1a;折线图&#xff0c;柱状图&#xff0c;饼图和数据集图。 效果图 echats Highcharts 源代码…

BitLocker 驱动器加密

BitLocker 简介 BitLocker 驱动器加密是一项由微软开发并集成在Windows操作系统中的数据保护功能&#xff0c;其主要作用是通过加密存储在硬盘驱动器上的数据来增强信息安全。具体来说&#xff1a; 数据安全&#xff1a;BitLocker可以对整个操作系统卷&#xff08;包括系统分区…

【Unity实战100例】Unity对Ini格式的配置文件管理和读写

目录 一.编写ini格式配置文件 二.读取解析ini文件 三.调用属性 INI 文件以文本形式存储,易于阅读和编辑。这种人可读的格式使得调整配置参数变得更加直观,不需要专门的工具。 INI 文件是一种轻量级的配置文件格式,不需要复杂的解析器或库。它的结构相对简单,适用于小到

Jenkins自动化部署docker

Jenkins自动化部署docker和普通方式构建 docker外挂目录 准备测试服务器docker环境准备jdk环境将上传jar包修改为app.jar对外暴露1000端口启动jar FROM openjdk:8-jdk-alpine ARG JAR_FILE COPY ${JAR_FILE} app.jar EXPOSE 1000 ENTRYPOINT ["java","-jar&q…

生产力与生产关系 —— 浅析爱泼斯坦事件 之 弱电控制强电原理

据网络文字与视频资料&#xff0c;爱泼斯坦事件是犹太精英阶层&#xff0c;为了掌控美国国家机器为犹太利益集团服务&#xff0c;而精心设下的一个局。本文先假设这个结论成立&#xff0c;并基于此展开讨论。 我们知道&#xff0c;弱电管理强电是电气工程中的一门专门学问&…

使用CloudFlare-Woker搭建简易网站

使用CloudFlare-Woker搭建简易网站 1、首先到CloudFlare官网登录或注册自己的账号&#xff1a;Cloudflare 中国官网 | 智能化云服务平台 | 免费CDN安全防护 | Cloudflare (cloudflare-cn.com) 注册一个账号 2、登录账号后进入仪表盘网页&#xff0c;选择Workers & Pages页…

目标检测DETR:End-to-End Object Detection with Transformers

NMS 对一个目标生成了多个检测窗口&#xff0c;但是事实上这些窗口中大部分内容都是重复的&#xff0c;找到目标检测最优的窗口 选取多个检测窗口中分数最高的窗口&#xff0c;剔除掉其他同类型的窗口 anchor generator 首先在该点生成scale512, aspect ratio{1:2&#xff…

Xtuner实战+LLM微调

Finetune 微调 在实际对话中&#xff0c;通常会有三种角色 system&#xff1a;给定一些上下文信息&#xff0c;“你是一个专业的内科医生&#xff0c;能回答医疗领域的专业问题”User&#xff1a;用户的问题&#xff0c;”肿瘤如何治疗“Assistant&#xff1a;LLM的回答 增量…

Unity3D学习之数据持久化——PlayerPrefs

文章目录 1. 概念2. 存储2.1 存到内存当中2.2 存到硬盘当中2.3 局限性2.4 相同键会覆盖 3.读取3.1 int型3.2 float型3.3 string型3.4 判断数据是否存在 4. 删除数据5. 存储位置6. 反射6.1 判断一个类型的对象是否可以让另一个类型为自己分配空间6.2 通过反射获得泛型类型 7 数据…

Java类与对象详解(从语法到内部存储)

Java类与对象详解&#xff08;从语法到内部存储&#xff09; 一、什么是类&#xff1f;1、定义2、语法 二、类的实例化1、什么是实例化2、语法3、成员变量和成员方法的访问 三、构造方法1、什么是构造方法2、构造方法的重载3、构造方法的调用 四、this关键字五、类对象的内部存…

【STM32】STM32学习笔记-软件I2C读写MPU6050(33)

00. 目录 文章目录 00. 目录01. I2C简介02. MPU6050参数03. 软件I2C接线图04. I2C模拟应答时序示例05. I2C读取MPU6050程序示例06. 程序下载07. 附录 01. I2C简介 I2C(Inter&#xff0d;Integrated Circuit)总线是一种由NXP&#xff08;原PHILIPS&#xff09;公司开发的两线式…