text: #include "DurnaPCH.h"
  #include "WindowsWindow.h"
  
  #include "Runtime/Events/ApplicationEvent.h"
  #include "Runtime/Events/KeyEvent.h"
  #include "Runtime/Events/MouseEvent.h"
  #include "Runtime/Platform/OpenGL/OpenGLContext.h"
  
  #include <GLFW/glfw3.h>
  
  namespace Durna
  {
  	static bool GLFWInitialized;
  
  	static void GLFWErrorCallback(int Error, const char* Description)
  	{
  		LOG_ERR(LOGCAT_GLFW, std::string("Error: {0}: {1}"), Error, Description);
  	}
  
  	Window* Window::Create(const WindowProps& Props)
  	{
  		return new WindowsWindow(Props);
  	}
  
  	WindowsWindow::WindowsWindow(const WindowProps& props)
  	{
  		DRN_PROFILE_FUNCTION();
  
  		Init(props);
  	}
  
  	WindowsWindow::~WindowsWindow()
  	{
  		DRN_PROFILE_FUNCTION();
  
  		ShutDown();
  	}
  
  	void WindowsWindow::Init(const WindowProps& Props)
  	{
  		DRN_PROFILE_FUNCTION();
  
  		Data.Title = Props.Title;
  		Data.Width = Props.Width;
  		Data.Height = Props.Height;
  
  		LOG_INFO(LOGCAT_CORE, "Creating window '{0}' {1}, {2}", Props.Title, Props.Width, Props.Height);
  
  		if (!GLFWInitialized)
  		{
  			{
  				DRN_PROFILE_SCOPE("glfwInit");
  				int success = glfwInit();
  				DRN_ASSERT(success, "Could not intialize GLFW!")
  					GLFWInitialized = true;
  			}
  			
  			glfwSetErrorCallback(GLFWErrorCallback);
  
  			{
  				DRN_PROFILE_SCOPE("glfwCreateWindow");
  				GlWindow = glfwCreateWindow(Props.Width, Props.Height, Props.Title.c_str(), nullptr, nullptr);
  			}
  			
  			Context = new OpenGLContext(GlWindow);
  			Context->Init();
  
  			glfwSetWindowUserPointer(GlWindow, &Data);
  			SetVSync(true);
  		}
  
  		glfwSetWindowSizeCallback(GlWindow, [](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(GlWindow, [](GLFWwindow* Window)
  			{
  				WindowData& Data = *(WindowData*)glfwGetWindowUserPointer(Window);
  
  				WindowCloseEvent event;
  				Data.EventCallback(event);
  			});
  
  		glfwSetKeyCallback(GlWindow, [](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;
  					}
  				}
  			});
  
  		glfwSetCharCallback(GlWindow, [](GLFWwindow* Window, unsigned int KeyCode)
  			{
  				WindowData& Data = *(WindowData*)glfwGetWindowUserPointer(Window);
  				KeyTypedEvent event(KeyCode);
  				Data.EventCallback(event);
  
  			});
  
  		glfwSetMouseButtonCallback(GlWindow, [](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(GlWindow, [](GLFWwindow* Window, double xOffset, double yOffset)
  			{
  				WindowData& Data = *(WindowData*)glfwGetWindowUserPointer(Window);
  
  				MouseScrolledEvent event((float)xOffset, (float)yOffset);
  				Data.EventCallback(event);
  			});
  
  		glfwSetCursorPosCallback(GlWindow, [](GLFWwindow* Window, double xPos, double yPos)
  			{
  				WindowData& Data = *(WindowData*)glfwGetWindowUserPointer(Window);
  
  				MouseMovedEvent event((float)xPos, (float)yPos);
  				Data.EventCallback(event);
  			});
  	}
  
  	void WindowsWindow::ShutDown()
  	{
  		DRN_PROFILE_FUNCTION();
  
  		glfwDestroyWindow(GlWindow);
  	}
  
  	void WindowsWindow::OnUpdate()
  	{
  		DRN_PROFILE_FUNCTION();
  
  		glfwPollEvents();
  		Context->SwapBuffers();
  	}
  
  	void WindowsWindow::SetVSync(bool Enabled)
  	{
  		DRN_PROFILE_FUNCTION();
  
  		if (Enabled)
  			glfwSwapInterval(1);
  		else
  			glfwSwapInterval(0);
  
  		Data.VSync = Enabled;
  	}
  
  	bool WindowsWindow::IsVSync() const
  	{
  		return Data.VSync;
  	}
  
  	void* WindowsWindow::GetNativeWindow() const
  	{
  		return GlWindow;
  	}
  
  }