/*
ApplicationFramework
by John Ryland
Copyright (c) 2023
*/
////////////////////////////////////////////////////////////////////////////////////
// Glfw Window System
#include "GlfwWindowSystem.h"
#include "GlfwPlatform.h"
#include "Window.h"
//#include "imgui_internal.h"
#define GLFW_INCLUDE_NONE
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <algorithm>
GLFWwindow* window;
static
void GlfwErrorCallback(int error, const char *message)
{
fprintf(stderr, "[glfw] Error: %d\n[glfw] Message: %s\n", error, message);
}
namespace ApplicationFramework {
struct IWindow
{
Window* m_window;
GLFWwindow* m_handle; // m_osData;
// any other extra data
void* m_osHandle;
void* m_rendererData;
void* m_uiSystemData;
void* m_surface;
void* m_userPointer;
};
GlfwWindowSystem::GlfwWindowSystem()
{
glfwSetErrorCallback(GlfwErrorCallback);
if (!glfwInit())
{
fprintf(stderr, "[glfw] failed to init!\n");
exit(1);
}
// if Vulkan
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
// else if OpenGL
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// #ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, true);
// #endif
/*
*/
// endif
}
// virtual
GlfwWindowSystem::~GlfwWindowSystem()
{
glfwTerminate();
}
// virtual
void GlfwWindowSystem::Initialize()
{
for (auto& win : m_windows)
win->m_window->Initialize();
}
// virtual
void GlfwWindowSystem::Shutdown()
{
for (auto& win : m_windows)
win->m_window->Shutdown();
}
// virtual
void GlfwWindowSystem::Update()
{
for (auto& win : m_windows)
{
//ImGui::SetCurrentViewport(NULL, (ImGuiViewportP*)ImGui::FindViewportByPlatformHandle(win->m_handle));
win->m_window->Update();
//GImGui->FrameCount++;
}
}
static
void GlfwMouseButtonCallback(GLFWwindow* window, int button, int action, int modifierKeys)
{
IWindow* iwindow = (IWindow*)glfwGetWindowUserPointer(window);
if (action == GLFW_PRESS)
iwindow->m_window->OnMousePress(button, modifierKeys);
else
iwindow->m_window->OnMouseRelease(button, modifierKeys);
}
static
void GlfwScrollCallback(GLFWwindow* window, double xoffset, double yoffset)
{
((IWindow*)glfwGetWindowUserPointer(window))->m_window->OnMouseScroll(xoffset, yoffset);
}
static
void GlfwKeyCallback(GLFWwindow* window, int keycode, int scancode, int action, int modifierKeys)
{
IWindow* iwindow = (IWindow*)glfwGetWindowUserPointer(window);
if (action == GLFW_PRESS)
iwindow->m_window->OnKeyPress(keycode, scancode, modifierKeys);
else if (action == GLFW_RELEASE)
iwindow->m_window->OnKeyRelease(keycode, scancode, modifierKeys);
else
iwindow->m_window->OnKeyRepeat(keycode, scancode, modifierKeys);
}
static
void GlfwWindowFocusCallback(GLFWwindow* window, int focused)
{
IWindow* iwindow = (IWindow*)glfwGetWindowUserPointer(window);
if (focused == GLFW_TRUE)
iwindow->m_window->OnFocusEnter();
else
iwindow->m_window->OnFocusLeave();
}
static
void GlfwCursorPosCallback(GLFWwindow* window, double x, double y)
{
((IWindow*)glfwGetWindowUserPointer(window))->m_window->OnMouseMove(x, y);
}
static
void GlfwCursorEnterCallback(GLFWwindow* window, int entered)
{
IWindow* iwindow = (IWindow*)glfwGetWindowUserPointer(window);
if (entered == GLFW_TRUE)
iwindow->m_window->OnEnter();
else
iwindow->m_window->OnLeave();
}
static
void GlfwCharCallback(GLFWwindow* window, unsigned int unicodeCodePoint)
{
((IWindow*)glfwGetWindowUserPointer(window))->m_window->OnTextEntered(unicodeCodePoint);
}
static
void InstallCallbacks(GLFWwindow* window)
{
glfwSetWindowFocusCallback(window, GlfwWindowFocusCallback);
glfwSetCursorEnterCallback(window, GlfwCursorEnterCallback);
glfwSetCursorPosCallback(window, GlfwCursorPosCallback);
glfwSetMouseButtonCallback(window, GlfwMouseButtonCallback);
glfwSetScrollCallback(window, GlfwScrollCallback);
glfwSetKeyCallback(window, GlfwKeyCallback);
glfwSetCharCallback(window, GlfwCharCallback);
}
// virtual
IWindow* GlfwWindowSystem::CreateWindow(Window* win, int width, int height, const char* title)
{
//GLFWwindow*
window = glfwCreateWindow(width, height, title, NULL, NULL);
IWindow* iwindow = new IWindow{ win, window };
glfwSetWindowUserPointer(window, (void*)iwindow);
InstallCallbacks(window);
m_windows.emplace_back(iwindow);
return iwindow;
}
// TODO: might be able to remove this shim and just call directly in code below it, however this is useful for now as can
// inject whatever for all of the glfw functions to modify this easily as the design evolves
template <typename T, typename R, typename ...A>
R ExecuteIfFindWindow(T& windowMap, IWindow* iwindow, R (*function)(GLFWwindow*, A...), A... args)
{
//if (windowMap.count(*win))
//if (iwindow->m_handle)
{
// return function(windowMap[win], args...);
return function(iwindow->m_handle, args...);
}
//return R();
}
// virtual
void GlfwWindowSystem::DestroyWindow(IWindow* iwindow)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwDestroyWindow);
delete iwindow;
}
//virtual
void GlfwWindowSystem::ShowWindow(IWindow* iwindow)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwShowWindow);
}
//virtual
void GlfwWindowSystem::CloseWindow(IWindow* iwindow)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwHideWindow);
ExecuteIfFindWindow(m_windows, iwindow, glfwSetWindowShouldClose, (int)true);
// The window will get destroyed when LastWindowClosed is next called
}
//virtual
void GlfwWindowSystem::SetWindowPosition(IWindow* iwindow, uint32_t x, uint32_t y)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwSetWindowPos, (int)x, (int)y);
}
//virtual
void GlfwWindowSystem::GetWindowPosition(IWindow* iwindow, uint32_t& x, uint32_t& y)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwGetWindowPos, (int*)&x, (int*)&y);
}
//virtual
void GlfwWindowSystem::SetWindowSize(IWindow* iwindow, uint32_t width, uint32_t height)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwSetWindowSize, (int)width, (int)height);
}
//virtual
void GlfwWindowSystem::GetWindowSize(IWindow* iwindow, uint32_t& width, uint32_t& height)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwGetWindowSize, (int*)&width, (int*)&height);
}
//virtual
void GlfwWindowSystem::SetWindowFocus(IWindow* iwindow)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwFocusWindow);
}
//virtual
bool GlfwWindowSystem::GetWindowFocus(IWindow* iwindow)
{
return ExecuteIfFindWindow(m_windows, iwindow, glfwGetWindowAttrib, GLFW_FOCUSED);
}
//virtual
bool GlfwWindowSystem::GetWindowMinimized(IWindow* iwindow)
{
return ExecuteIfFindWindow(m_windows, iwindow, glfwGetWindowAttrib, GLFW_ICONIFIED);
}
//virtual
void GlfwWindowSystem::SetWindowTitle(IWindow* iwindow, const char* str)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwSetWindowTitle, str);
}
//virtual
void GlfwWindowSystem::SetWindowAlpha(IWindow* iwindow, float alpha)
{
ExecuteIfFindWindow(m_windows, iwindow, glfwSetWindowOpacity, alpha);
}
//virtual
bool GlfwWindowSystem::IsKeyPressed(IWindow* iwindow, int key)
{
return ExecuteIfFindWindow(m_windows, iwindow, glfwGetKey, key) == GLFW_PRESS;
}
// virtual
bool GlfwWindowSystem::LastWindowClosed()
{
std::vector<IWindow*> closedWindows;
if (m_windows.size())
{
for (auto& iwindow : m_windows)
if (glfwWindowShouldClose(iwindow->m_handle))
closedWindows.emplace_back(iwindow);
for (auto& iwindow : closedWindows)
{
glfwHideWindow(iwindow->m_handle);
iwindow->m_window->Shutdown();
m_windows.erase(std::remove(m_windows.begin(), m_windows.end(), iwindow));
}
return !m_windows.size();
}
return false;
}
// virtual
void GlfwWindowSystem::Prepare()
{
// Poll and handle events (inputs, window resize, etc.)
// You can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if dear imgui wants to use your inputs.
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
glfwPollEvents();
}
// virtual
void GlfwWindowSystem::Render()
{
}
// virtual
void GlfwWindowSystem::Present()
{
}
} // ApplicationFramework namespace