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

导入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"}-- 引用YOTOEnginelinks{"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();//配置类:ImGuiIOImGuiIO& io = ImGui::GetIO();io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的keyio.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 DemoImGui::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();//配置类:ImGuiIOImGuiIO& io = ImGui::GetIO();io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;// 光标io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;// imgui输入key对应glfw的key,临时的:最终会对应引擎自身的keyio.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 DemoImGui::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);elseglfwSwapInterval(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.mzph.cn/news/628265.shtml

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

相关文章

k8s 存储卷和pvc,pv

存储卷---数据卷 容器内的目录和宿主机的目录进行挂载。 容器在系统上的生命周期是短暂的&#xff0c;deletek8s用控制器创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态。 一旦回到初始状态&#xff0c;所有的后天编辑的文件的都会消失。 …

SpringBoot教程(十六) | SpringBoot集成swagger(全网最全)

SpringBoot教程(十六) | SpringBoot集成swagger&#xff08;全网最全&#xff09; 一. 接口文档概述 swagger是当下比较流行的实时接口文文档生成工具。接口文档是当前前后端分离项目中必不可少的工具&#xff0c;在前后端开发之前&#xff0c;后端要先出接口文档&#xff0c…

Mysql-redoLog

Redo Log redo log进行刷盘的效率要远高于数据页刷盘,具体表现如下 redo log体积小,只记录了哪一页修改的内容,因此体积小,刷盘快 redo log是一直往末尾进行追加,属于顺序IO。效率显然比随机IO来的快Redo log 格式 在MySQL的InnoDB存储引擎中,redo log(重做日志)被用…

C++ 输入用户名和密码 防止注入攻击

1、问题解释&#xff1a;注入攻击 &#xff0c;无密码直接登录数据库 可视化展示 1.1、当你的数据库为&#xff1a;其中包含三个字段id user 以及md5密码 1.2、在使用C堆数据库信息进行访问的时候&#xff0c;使用多条语句进行查询 string sql "select id from t_user…

Spring自带分布式锁你用过吗?

环境&#xff1a;SpringBoot2.7.12 本篇文章将会为大家介绍有关spring integration提供的分布式锁功能。 1. 简介 Spring Integration 是一个框架&#xff0c;用于构建事件驱动的应用程序。在 Spring Integration 中&#xff0c;LockRegistry 是一个接口&#xff0c;用于管理…

使用Postman测试WebService接口

文章目录 使用Postman测试WebService接口1. 访问wsdl地址2. Postman配置1. URL及Headers设置2. Body设置3. 响应结果 使用Postman测试WebService接口 1. 访问wsdl地址 接口地址如&#xff1a;http://localhost:8101/ws/hello?wsdl 2. Postman配置 1. URL及Headers设置 2. B…

跟着小德学C++之数据库基础

嗨&#xff0c;大家好&#xff0c;我是出生在达纳苏斯的一名德鲁伊&#xff0c;我是要立志成为海贼王&#xff0c;啊不&#xff0c;是立志成为科学家的德鲁伊。最近&#xff0c;我发现我们所处的世界是一个虚拟的世界&#xff0c;并由此开始&#xff0c;我展开了对我们这个世界…

【揭秘】sleep()、wait()、park()三种休眠方式的终极对比

在Java中&#xff0c;线程休眠的三种方式包括Thread.sleep、Object.wait和LockSupport.park。Thread.sleep使线程在指定时间后进入休眠&#xff0c;状态为TIMEDWAITING&#xff0c;不会释放锁。Object.wait需在对象锁的保护下调用&#xff0c;会释放该对象的锁&#xff0c;使线…

leetcode 动态规划(单词拆分)

139.单词拆分 力扣题目链接(opens new window) 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 …

图解智慧:数据可视化如何助你高效洞悉信息?

在信息爆炸的时代&#xff0c;数据扮演着越来越重要的角色&#xff0c;而数据可视化则成为解读和理解海量数据的得力工具。那么&#xff0c;数据可视化是如何帮助我们高效了解数据的呢&#xff1f;下面我就以可视化从业者的角度来简单聊聊这个话题。 无需深奥的专业知识&#x…

第1章 数据结构与算法介绍

文章目录 1.1 数据结构和算法内容介绍1.1.1 先看几个经典的算法面试题1.1.2 数据结构和算法的重要性1.1.3 本套数据结构和算法内容介绍1.1.4 课程亮点和授课方式 1.1 数据结构和算法内容介绍 1.1.1 先看几个经典的算法面试题  字符串匹配问题&#xff1a;&#xff1a; 有一…

wpf使用Popup封装数据筛选框

(关注博主后,在“粉丝专栏”,可免费阅读此文) 类似于DevExpress控件的功能 这是DevExpress的winform筛选样式,如下: 这是DevExpress的wpf筛选样式,如下: 这是Excel的筛选样式,如下: 先看效果 本案例使用wpf原生控件封装,功能基本上都满足,只是颜色样式没有写…

为何我选择山海鲸可视化:五大优势解析

在众多的可视化产品中&#xff0c;我选择了山海鲸可视化&#xff0c;这并非偶然。在对比了其他同类产品后&#xff0c;我发现山海鲸可视化具有许多独特的优势和特点&#xff0c;使得它成为了我心目中的理想选择。下面我简单说一下我选择这款产品的几大原因&#xff0c;希望对在…

最新国内可用GPT4、Midjourney绘画、DALL-E3文生图模型教程

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…

【python 的各种模块】(9) 在python使用PIL( 即pillow模块 ) 修改图片

目录 1 导入PIL模块&#xff08;pillow&#xff09; 1.1 PIL的全称&#xff1a;Python Imaging Library 1.2 导入PIL模块 1.2.1 可用的导入形式 1.2.2 常用的导入形式 1.2.3 PIL下面的常用子模块 2 PIL.Image的方法 (读入&#xff0c;生成和显示图片) 2.1 用 PIL.Image…

蓝桥杯AcWing学习笔记 8-2数论的学习(下)

蓝桥杯 我的AcWing 题目及图片来自蓝桥杯C AB组辅导课 数论&#xff08;下&#xff09; 蓝桥杯省赛中考的数论不是很多&#xff0c;这里讲几个蓝桥杯常考的知识点。 约数个数定理 我们如何去求一个数的约数个数呢&#xff1f; N N N分解质因数的结果&#xff1a; N P 1 α…

HTML+CSS-02

阿里巴巴矢量图标库的使用 阿里巴巴网址矢量图标库网址 https://www.iconfont.cn/ 如何使用 选择需要的icon图标加入购物车下载代码 在将解压后的文件夹复制到项目中进入demo_index.html中打开就可以看到示例的三种用法 三种引入方法 Unicode 引用 Unicode 是字体在网页端…

vscode(visual studio code) 免密登陆服务器

1.生成密钥 首先&#xff0c;在本地&#xff0c;打开命令输入框&#xff1a; WinR–>弹出输入框&#xff0c;输入cmd,打开命令框。 然后&#xff0c;在命令框&#xff0c;输入 ssh-keygen -t rsa -C "love"按两次回车键&#xff0c;问你是否重写&#xff0c;选择…

人工智能SCI二区期刊Applied Intelligence高被引录用论文合集,含2024最新

今天给着急发论文的同学推荐一本期刊&#xff1a;《APPLIED INTELLIGENCE》。 该刊由SPRINGER出版商于1991年创刊&#xff0c;刊期Bimonthly&#xff0c;专注于人工智能和神经网络的研究&#xff0c;重点关注有关创新智能系统的方法论及其在解决现实生活复杂问题的研究进展&am…

Springboot中使用Filter过滤器

1、概述 springboot工程中使用Filter过滤器与其他地方使用基本相同&#xff0c;只是注入的方式不同。 2、创建Filter过滤器 实现Filter接口&#xff0c;重写doFilter方法 filterChain.doFilter(servletRequest,servletResponse);表示放行 public class MyFilter implement…