diff --git a/Graphics/CMakeLists.txt b/Graphics/CMakeLists.txt index 47a1788..25ddd02 100644 --- a/Graphics/CMakeLists.txt +++ b/Graphics/CMakeLists.txt @@ -5,7 +5,7 @@ set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR}) set(BINDINGS_LIBS glfw Imgui Nanovg ${GLEW_LIB}) ### ---------------------- Static Library --------------------- ### -file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") +file(GLOB SOURCES "./private/*.cpp") file(GLOB HEADERS "./public/*.hpp") add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) target_include_directories(${PROJECT_NAME} PUBLIC ./public/) diff --git a/Graphics/private/bindings/Canvas.cpp b/Graphics/private/Canvas.cpp similarity index 74% rename from Graphics/private/bindings/Canvas.cpp rename to Graphics/private/Canvas.cpp index a46c977..b502bfb 100644 --- a/Graphics/private/bindings/Canvas.cpp +++ b/Graphics/private/Canvas.cpp @@ -12,31 +12,32 @@ #include namespace tp { - class Graphics::Canvas::Context { + class Canvas::Context { public: - NVGcontext* vg; + NVGcontext* vg {}; + Window* window {}; }; } using namespace tp; -Graphics::Canvas::Canvas() { mContext = new Context(); } +Canvas::Canvas(Window* window) { + mContext = new Context(); + mContext->window = window; -Graphics::Canvas::~Canvas() { delete mContext; } - -void Graphics::Canvas::init() { mContext->vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES); if (nvgCreateFont(mContext->vg, "default", "Font.ttf") == -1) { - // TODO + ASSERT(!"Cant create NVG font") } } -void Graphics::Canvas::deinit() { nvgDeleteGL3(mContext->vg); } +Canvas::~Canvas() { + nvgDeleteGL3(mContext->vg); + delete mContext; +} -RectF Graphics::Canvas::getAvaliableArea() { return { (halnf) 0, (halnf) 0, mWidth, mHeight }; } - -void Graphics::Canvas::rect(const RectF& rec, const RGBA& col, halnf round) { +void Canvas::rect(const RectF& rec, const RGBA& col, halnf round) { nvgBeginPath(mContext->vg); if (round == 0) { @@ -49,7 +50,7 @@ void Graphics::Canvas::rect(const RectF& rec, const RGBA& col, halnf round) { nvgFill(mContext->vg); } -void Graphics::Canvas::pushClamp(const RectF& rec) { +void Canvas::pushClamp(const RectF& rec) { RectF intersection = rec; if (mScissors.size()) { mScissors.last().calcIntersection(rec, intersection); @@ -58,7 +59,7 @@ void Graphics::Canvas::pushClamp(const RectF& rec) { mScissors.append(rec); } -void Graphics::Canvas::popClamp() { +void Canvas::popClamp() { DEBUG_ASSERT(mScissors.size()); mIsClamping = false; mScissors.pop(); @@ -70,7 +71,7 @@ void Graphics::Canvas::popClamp() { } } -void Graphics::Canvas::text( +void Canvas::text( const char* string, const RectF& aRec, halnf size, Align align, halnf marging, const RGBA& col ) { RectF rec = { aRec.x + marging, aRec.y + marging, aRec.z - marging * 2, aRec.w - marging * 2 }; @@ -112,7 +113,7 @@ void Graphics::Canvas::text( popClamp(); } -void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) { +void Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding) { auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha); nvgBeginPath(mContext->vg); nvgRoundedRect(mContext->vg, rec.x, rec.y, rec.z, rec.w, rounding); @@ -120,7 +121,7 @@ void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf ang nvgFill(mContext->vg); } - Graphics::Canvas::ImageHandle Graphics::Canvas::createImageFromTextId(ualni id, Vec2F size) { + Canvas::ImageHandle Canvas::createImageFromTextId(ualni id, Vec2F size) { #ifdef ENV_OS_ANDROID return { (ualni) nvglCreateImageFromHandleGLES3(mContext->vg, id, size.x, size.y, 0) }; #else @@ -128,12 +129,17 @@ void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf ang #endif } -void Graphics::Canvas::deleteImageHandle(ImageHandle image) { +void Canvas::deleteImageHandle(ImageHandle image) { if (image.id) { nvgDeleteImage(mContext->vg, image.id); } } -void Graphics::Canvas::proc() { nvgBeginFrame(mContext->vg, mWidth, mHeight, 1.0); } +void Canvas::proc() { + const auto size = mContext->window->getSize(); + nvgBeginFrame(mContext->vg, size.x, size.y, 1.0); +} -void Graphics::Canvas::draw() { nvgEndFrame(mContext->vg); } +void Canvas::draw() { + nvgEndFrame(mContext->vg); +} diff --git a/Graphics/private/bindings/DebugGUI.cpp b/Graphics/private/DebugGUI.cpp similarity index 79% rename from Graphics/private/bindings/DebugGUI.cpp rename to Graphics/private/DebugGUI.cpp index 376d79b..9142784 100644 --- a/Graphics/private/bindings/DebugGUI.cpp +++ b/Graphics/private/DebugGUI.cpp @@ -1,7 +1,8 @@ #include "Window.hpp" - #include "WindowContext.hpp" +#include "Graphics.hpp" + // -------- Debug UI -------- // #include #include @@ -9,7 +10,7 @@ #include namespace tp { - class Graphics::GUI::Context { + class DebugGUI::Context { public: ImGuiIO* io{}; ImGuiContext* ctx{}; @@ -18,11 +19,9 @@ namespace tp { using namespace tp; -Graphics::GUI::GUI() { mContext = new Context(); } +DebugGUI::DebugGUI(Window* window) { + mContext = new Context(); -Graphics::GUI::~GUI() { delete mContext; } - -void Graphics::GUI::init(Window* window) { IMGUI_CHECKVERSION(); mContext->ctx = ImGui::CreateContext(); mContext->io = &ImGui::GetIO(); @@ -38,13 +37,15 @@ void Graphics::GUI::init(Window* window) { io.Fonts->AddFontFromFileTTF("Font.ttf", 20.f); } -void Graphics::GUI::deinit() { +DebugGUI::~DebugGUI() { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); + + delete mContext; } -void Graphics::GUI::proc() { +void DebugGUI::proc() { tp::HeapAllocGlobal::startIgnore(); ImGui_ImplOpenGL3_NewFrame(); @@ -54,7 +55,7 @@ void Graphics::GUI::proc() { tp::HeapAllocGlobal::stopIgnore(); } -void Graphics::GUI::draw() { +void DebugGUI::draw() { ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); } \ No newline at end of file diff --git a/Graphics/private/EventHandler.cpp b/Graphics/private/EventHandler.cpp new file mode 100644 index 0000000..6bf8d5c --- /dev/null +++ b/Graphics/private/EventHandler.cpp @@ -0,0 +1,2 @@ + +#include "EventHandler.hpp" diff --git a/Graphics/private/GraphicsCommon.cpp b/Graphics/private/GraphicsCommon.cpp deleted file mode 100644 index c6161f1..0000000 --- a/Graphics/private/GraphicsCommon.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "GraphicsCommon.hpp" -#include "MathCommon.hpp" - -namespace tp { - static ModuleManifest* deps[] = { &gModuleAllocators, nullptr }; - ModuleManifest gModuleGraphics = ModuleManifest("Graphics", nullptr, nullptr, deps); -} \ No newline at end of file diff --git a/Graphics/private/Window.cpp b/Graphics/private/Window.cpp new file mode 100644 index 0000000..f52efda --- /dev/null +++ b/Graphics/private/Window.cpp @@ -0,0 +1,151 @@ +#include "Window.hpp" +#include "WindowContext.hpp" + +// -------- OpenGL -------- // +#include + +// -------- Window Context -------- // +#include + +#ifdef ENV_OS_WINDOWS +#define GLFW_EXPOSE_NATIVE_WIN32 +#endif + +#ifdef ENV_OS_LINUX +#define GLFW_EXPOSE_NATIVE_WAYLAND +#endif + +#include + +#include +#include + +namespace tp { + static ModuleManifest* deps[] = { &gModuleAllocators, nullptr }; + ModuleManifest gModuleGraphics = ModuleManifest("Graphics", nullptr, nullptr, deps); +} + +using namespace tp; + +static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); +static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); +static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset); + +Window::Window(Vec2F size, const String& title) { + mContext = new Context(); + + glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1); + + // Create a window and OpenGL context + mContext->window = glfwCreateWindow((int) size.x, (int) size.y, title.read(), nullptr, nullptr); + if (!mContext->window) { + printf("Failed to create GLFW window\n"); + return; + } + + glfwMakeContextCurrent(mContext->window); + + // Initialize GLEW + if (glewInit() != GLEW_OK) { + printf("Failed to initialize GLEW\n"); + return; + } + + // set event bindings + glfwSetWindowUserPointer(mContext->window, this); + glfwSetKeyCallback(mContext->window, keyCallback); + glfwSetMouseButtonCallback(mContext->window, mouseButtonCallback); + glfwSetScrollCallback(mContext->window, scrollCallback); +} + +Window::~Window() { + glfwDestroyWindow(mContext->window); + delete mContext; +} + +Window* Window::createWindow(Vec2F size, const String& title) { + HeapAllocGlobal::startIgnore(); + + static int count = 1; + if (!count) { + printf("Window class is a singleton\n"); + return nullptr; + } + count--; + + // Initialize GLFW + if (!glfwInit()) { + printf("Failed to initialize GLFW\n"); + return nullptr; + } + + // Set the GLFW error callback + glfwSetErrorCallback([](int error, const char* description) { printf("GLFW Error: %i %s\n", error, description); }); + + auto out = new Window(size, title); + + HeapAllocGlobal::stopIgnore(); + return out; +} + +void Window::destroyWindow(Window* window) { + delete window; + glfwTerminate(); +} + +bool Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } + +void Window::processEvents() { + glfwPollEvents(); + + int w, h; + glfwGetWindowSize(mContext->window, &w, &h); + mSize = { (halnf) w, (halnf) h }; +} + +void Window::draw() { + glfwSwapBuffers(mContext->window); +} + +const Vec2F& Window::getSize() const { return mSize; } + +Window::Context* Window::getContext() { return mContext; } + +void Window::setEventHandler(EventHandler* eventHandler) { mEventHandler = eventHandler; } +EventHandler* Window::getEventHandler() { return mEventHandler; } + + +static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { + + auto* self = static_cast(glfwGetWindowUserPointer(window)); + if (!self) return; + + EventHandler* eventHandler = self->getEventHandler(); + if (!eventHandler) return; + + // post key event + /* + if (action == GLFW_PRESS) { + inputManager->keyStates[key] = GLFW_PRESS; + } else if (action == GLFW_RELEASE) { + inputManager->keyStates[key] = GLFW_RELEASE; + } + inputManager->isEvent = true; + */ +} + +static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { + auto* self = static_cast(glfwGetWindowUserPointer(window)); + if (!self) return; + + EventHandler* eventHandler = self->getEventHandler(); + if (!eventHandler) return; + + // post mouse button event + // inputManager->mouseButtonStates[button] = action; + // inputManager->isEvent = true; +} + +static void scrollCallback(GLFWwindow* window, double xOffset, double yOffset) { + // ignore for now +} \ No newline at end of file diff --git a/Graphics/private/WindowContext.hpp b/Graphics/private/WindowContext.hpp new file mode 100644 index 0000000..02fdd40 --- /dev/null +++ b/Graphics/private/WindowContext.hpp @@ -0,0 +1,14 @@ +#pragma once + +#include "Window.hpp" + +class GLFWwindow; + +namespace tp { + + class Window::Context { + public: + Context() = default; + GLFWwindow* window = nullptr; + }; +} \ No newline at end of file diff --git a/Graphics/private/bindings/Window.cpp b/Graphics/private/bindings/Window.cpp deleted file mode 100644 index 516066d..0000000 --- a/Graphics/private/bindings/Window.cpp +++ /dev/null @@ -1,215 +0,0 @@ -#include "Window.hpp" - -// -------- OpenGL -------- // -#include - -#include "WindowContext.hpp" - -#include - -// #define EASYTAB_IMPLEMENTATION -// #include "easytab.h" - -namespace tp { - class Graphics::GL::Context { - public: - // Showoff data - GLuint vao{}; - GLuint vbo{}; - GLfloat vertices[9] = { - -0.0f, -0.0f, 0.0f, // Left vertex - 1.0f, 0.0f, 0.0f, // Right vertex - 0.5f, 1.0f, 0.0f // Top vertex - }; - }; -} - -using namespace tp; - -Graphics::GL::GL() { mContext = new Context(); } - -Graphics::GL::~GL() { delete mContext; } - -void Graphics::GL::init() { - // Create a Vertex Array Object (VAO) - glGenVertexArrays(1, &mContext->vao); - glBindVertexArray(mContext->vao); - - // Create a Vertex Buffer Object (VBO) - glGenBuffers(1, &mContext->vbo); - glBindBuffer(GL_ARRAY_BUFFER, mContext->vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(mContext->vertices), mContext->vertices, GL_STATIC_DRAW); - - // Set up vertex attributes - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*) nullptr); - glEnableVertexAttribArray(0); -} - -void Graphics::GL::deinit() { - glDeleteBuffers(1, &mContext->vbo); - glDeleteVertexArrays(1, &mContext->vao); -} - -void Graphics::GL::proc() {} - -void Graphics::GL::draw() { - glClearColor(0.f, 0.f, 0.f, 0.f); - glClear(GL_COLOR_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - glViewport(0, 0, mWidth, mHeight); - // glDrawArrays(GL_TRIANGLES, 0, 3); -} - -void Graphics::init(Window* window) { - mGl.init(); - mGui.init(window); - mCanvas.init(); -} - -void Graphics::deinit() { - mCanvas.deinit(); - mGui.deinit(); - mGl.deinit(); -} - -void Graphics::proc() { - mGl.proc(); - mCanvas.proc(); - mGui.proc(); -} - -void Graphics::draw() { - mGl.draw(); - mCanvas.draw(); - mGui.draw(); -} - -tp::Window::Window(int width, int height, const char* title) { - mContext = new Context(); - - glfwWindowHint(GLFW_TRANSPARENT_FRAMEBUFFER, 1); - - // Create a window and OpenGL context - mContext->window = glfwCreateWindow(width, height, title, nullptr, nullptr); - if (!mContext->window) { - printf("Failed to create GLFW window\n"); - return; - } - - glfwMakeContextCurrent(mContext->window); - - // Initialize GLEW - if (glewInit() != GLEW_OK) { - printf("Failed to initialize GLEW\n"); - return; - } - - mContext->inputManager.init(mContext->window); - - mGraphics.init(this); - - mEvents.mContext = mContext; - - #ifdef ENV_OS_WINDOWS - // EasyTab_Load(glfwGetWin32Window(mContext->window)); - #endif -} - -tp::Window::~Window() { - #ifdef ENV_OS_WINDOWS - // EasyTab_Unload(); - #endif - - mGraphics.deinit(); - glfwDestroyWindow(mContext->window); - delete mContext; -} - -tp::Window* tp::Window::createWindow(int width, int height, const char* title) { - tp::HeapAllocGlobal::startIgnore(); - - static int count = 1; - if (!count) { - printf("Window class is a singleton\n"); - return nullptr; - } - count--; - - // Initialize GLFW - if (!glfwInit()) { - printf("Failed to initialize GLFW\n"); - return nullptr; - } - - // Set the GLFW error callback - glfwSetErrorCallback([](int error, const char* description) { printf("GLFW Error: %i %s\n", error, description); }); - - auto out = new Window(width, height, title); - - tp::HeapAllocGlobal::stopIgnore(); - return out; -} - -void tp::Window::destroyWindow(Window* window) { - delete window; - glfwTerminate(); -} - -bool tp::Window::shouldClose() const { return glfwWindowShouldClose(mContext->window); } - -void tp::Window::processEvents() { - mContext->inputManager.isEvent = false; - - #ifdef ENV_OS_WINDOWS - // HWND w32window = glfwGetWin32Window(mContext->window); - // MSG msg; - // if (PeekMessageW(&msg, NULL, 0, 0, PM_NOREMOVE)) { - // if (EasyTab_HandleEvent(msg.hwnd, msg.message, msg.lParam, msg.wParam) == EASYTAB_OK) - // mEvents.pressure = EasyTab->Pressure; - // } - #endif - - glfwPollEvents(); - - int w, h; - glfwGetWindowSize(mContext->window, &w, &h); - - mGraphics.mCanvas.mWidth = w; - mGraphics.mCanvas.mHeight = h; - - mGraphics.mGl.mWidth = w; - mGraphics.mGl.mHeight = h; - - mGraphics.proc(); - - mContext->inputManager.update(); - - if (mEvents.isPressed()) { - mEvents.pressure = 1.f; - } else if (mEvents.isReleased()) { - mEvents.pressure = 0.f; - } - - get_time(); -} - -void tp::Window::draw() { - mGraphics.draw(); - glfwSwapBuffers(mContext->window); - mContext->inputManager.resetScroll(); -} - -auto tp::Window::getContext() -> Context* { return mContext; } -Graphics::Canvas& tp::Window::getCanvas() { return mGraphics.mCanvas; } -const tp::Window::Events& tp::Window::getEvents() { return mEvents; } - -const Vec2F& tp::Window::Events::getPos() const { return mContext->inputManager.getPos(); } - -bool tp::Window::Events::isPressed() const { return mContext->inputManager.isPressed(); } - -bool tp::Window::Events::isReleased() const { return mContext->inputManager.isReleased(); } - -bool tp::Window::Events::isDown() const { return mContext->inputManager.isDown(); } - -halnf tp::Window::Events::getScrollY() const { return mContext->inputManager.getScrollY(); } - -bool tp::Window::Events::isEvent() const { return mContext->inputManager.isEvents(); } diff --git a/Graphics/private/bindings/WindowContext.hpp b/Graphics/private/bindings/WindowContext.hpp deleted file mode 100644 index fd35566..0000000 --- a/Graphics/private/bindings/WindowContext.hpp +++ /dev/null @@ -1,130 +0,0 @@ -#pragma once - -#include "Environment.hpp" - -// -------- Window Context -------- // -#include - -#ifdef ENV_OS_WINDOWS -#define GLFW_EXPOSE_NATIVE_WIN32 -#endif - -#ifdef ENV_OS_LINUX -#define GLFW_EXPOSE_NATIVE_WAYLAND -#endif - -#include - -#include - -namespace tp { - - class Window; - - class InputManager { - public: - InputManager() = default; - - void init(GLFWwindow* aWindow) { - window = aWindow; - // Set up key and mouse button callbacks - - glfwSetWindowUserPointer(window, this); - glfwSetKeyCallback(window, keyCallback); - glfwSetMouseButtonCallback(window, mouseButtonCallback); - glfwSetScrollCallback(window, scrollCallback); - } - - const Vec2F& getPos() const { return mousePos; } - - bool isKeyPressed(int key) const { return keyStates[key] == GLFW_PRESS; } - - bool isKeyDown(int key) const { return keyStates[key] == GLFW_REPEAT || keyStates[key] == GLFW_PRESS; } - - bool isPressed() const { return mouseButtonStates[GLFW_MOUSE_BUTTON_LEFT] == GLFW_PRESS; } - - bool isReleased() const { return mouseButtonStates[GLFW_MOUSE_BUTTON_LEFT] == GLFW_RELEASE; } - - bool isDown() const { return mouseButtonStates[GLFW_MOUSE_BUTTON_LEFT] == GLFW_REPEAT || mouseButtonStates[GLFW_MOUSE_BUTTON_LEFT] == GLFW_PRESS; } - - bool isEvents() const { return isEvent; } - - double getScrollY() const { return scrollY; } - - // bool isScrollDown() const { return scrollY < 0.0; } - - private: - friend Window; - - static void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { - InputManager* inputManager = static_cast(glfwGetWindowUserPointer(window)); - - if (!inputManager) { - // Update key state - if (action == GLFW_PRESS) { - inputManager->keyStates[key] = GLFW_PRESS; - } else if (action == GLFW_RELEASE) { - inputManager->keyStates[key] = GLFW_RELEASE; - } - inputManager->isEvent = true; - } - } - - static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) { - InputManager* inputManager = static_cast(glfwGetWindowUserPointer(window)); - - if (inputManager) { - // Update mouse button state - inputManager->mouseButtonStates[button] = action; - inputManager->isEvent = true; - } - } - - static void scrollCallback(GLFWwindow* window, double xoffset, double yoffset) { - InputManager* inputManager = static_cast(glfwGetWindowUserPointer(window)); - - if (inputManager) { - // Update scroll state - inputManager->scrollX = xoffset; - inputManager->scrollY = yoffset; - inputManager->isEvent = true; - } - } - - void update() { - double x, y; - glfwGetCursorPos(window, &x, &y); - mousePosPrev = mousePos; - mousePos = { x, y }; - - if ((mousePosPrev - mousePos).length2()) { - isEvent = true; - } - } - - void resetScroll() { - scrollX = 0.0; - scrollY = 0.0; - mouseButtonStates[GLFW_MOUSE_BUTTON_LEFT] = GLFW_REPEAT; - } - - bool isEvent = false; - double scrollX = 0.0; - double scrollY = 0.0; - GLFWwindow* window; - Vec2F mousePos; - Vec2F mousePosPrev; - std::array keyStates = { GLFW_RELEASE }; - std::array mouseButtonStates = { GLFW_RELEASE }; - }; - - class Window::Context { - friend Graphics::GL; - friend Graphics::GUI; - friend Graphics::Canvas; - - public: - GLFWwindow* window; - InputManager inputManager; - }; -} \ No newline at end of file diff --git a/Graphics/public/EventHandler.hpp b/Graphics/public/EventHandler.hpp new file mode 100644 index 0000000..8de9853 --- /dev/null +++ b/Graphics/public/EventHandler.hpp @@ -0,0 +1,90 @@ +#pragma once + +#include "InputCodes.hpp" +#include "Vec.hpp" +#include "List.hpp" +#include "Map.hpp" + +#include + +namespace tp { + + struct InputEvent { + enum class Type { + NONE, + BUTTON_ACTION, + MOUSE_DELTA, + MOUSE_POS, + } type = Type::NONE; + + enum class ButtonAction { + NONE, + PRESS, + RELEASE, + REPEAT, + } buttonAction = ButtonAction::NONE; + + Vec2F mouseEvent = { 0, 0 }; + }; + + class InputState { + // Transitions from state to state is strict and defined by state order in the enum + // If posted event conflicts with that automata, we need to emulate intermediate states + enum State { + NONE, // Button is inactive + PRESSED, // Button is pressed + HOLD, // Button is still pressed + RELEASED, // Button is released + }; + + State mCurrentState; + State mPreviousState; + + public: + InputState() = default; + + void handleEvent(const InputEvent& event); + + bool isStateChanged(); + + // true if event is no longer needed and false if we need to emulate some transitions further + bool isHandled(); + }; + + // Assumes that user and event poster use different threads + // User can add own states for each input and decide how this state changes on specific events + // Event posters has no access to any custom state and only report any changes in any way + class EventHandler { + public: + EventHandler() = default; + ~EventHandler(); + + public: // Event Poster Interface + void postEvent(InputID inputID, InputEvent inputEvent); // Record event + + public: // User interface + bool isEvents(); + void processEvent(); + + const Vec2F& getPointer() const; + + bool isPressed(InputID id) const; + bool isReleased(InputID id) const; + bool isDown(InputID id) const; + + halnf getScrollY() const; + + private: + std::mutex mMutex = {}; + + // Store thread protected queue of posted events + List mEventQueue; + + // input states + Vec2F mPointer; + halnf pressure = 0; + + InputState mInputStates[(int) InputID::LAST_KEY_CODE]; + }; + +} \ No newline at end of file diff --git a/Graphics/public/Graphics.hpp b/Graphics/public/Graphics.hpp index 148eec5..ab96873 100644 --- a/Graphics/public/Graphics.hpp +++ b/Graphics/public/Graphics.hpp @@ -1,119 +1,83 @@ #pragma once -#include "GraphicsCommon.hpp" +#include "Color.hpp" +#include "Rect.hpp" -// TODO : ugly +#include "Buffer.hpp" namespace tp { class Window; - class Graphics { + class DebugGUI { + class Context; + Context* mContext; + public: - class GL { - class Context; - Context* mContext; + explicit DebugGUI(Window* window); + ~DebugGUI(); - private: - friend Graphics; - friend Window; - - GL(); - ~GL(); - - void init(); - void deinit(); - void proc(); - void draw(); - - public: - // TODO : API - - private: - halnf mWidth = 100; - halnf mHeight = 100; - }; - - class GUI { - class Context; - Context* mContext; - - private: - friend Graphics; - - GUI(); - ~GUI(); - - void init(Window* window); - void deinit(); - void proc(); - void draw(); - - public: - // TODO : API - }; - - class Canvas { - class Context; - Context* mContext; - - private: - friend Graphics; - friend Window; - - Canvas(); - ~Canvas(); - - void init(); - void deinit(); - void proc(); - void draw(); - - public: - enum Align : int2 { - CC = 0x0000, - CT = 0x0001, - CB = 0x0002, - LC = 0x0100, - LT = 0x0101, - LB = 0x0102, - RC = 0x0200, - RT = 0x0201, - RB = 0x0202, - }; - - struct ImageHandle { - ualni id = 0; - }; - - RectF getAvaliableArea(); - void pushClamp(const RectF& rec); - void popClamp(); - void rect(const RectF& rec, const RGBA& col, halnf round = 0); - void text(const char*, const RectF&, halnf size, Align, halnf marging, const RGBA&); - - ImageHandle createImageFromTextId(ualni id, Vec2F size); - void deleteImageHandle(ImageHandle image); - void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding); - - private: - halnf mWidth = 600; - halnf mHeight = 600; - Buffer mScissors; - bool mIsClamping = false; - }; - - private: - friend Window; - - Graphics() = default; - void init(Window* window); - void deinit(); - void draw(); void proc(); + void draw(); + }; + + class Canvas { + class Context; + Context* mContext; + + public: + explicit Canvas(Window* window); + ~Canvas(); + + void proc(); + void draw(); + + public: + enum Align : int2 { + CC = 0x0000, + CT = 0x0001, + CB = 0x0002, + LC = 0x0100, + LT = 0x0101, + LB = 0x0102, + RC = 0x0200, + RT = 0x0201, + RB = 0x0202, + }; + + struct ImageHandle { + ualni id = 0; + }; + + void pushClamp(const RectF& rec); + void popClamp(); + void rect(const RectF& rec, const RGBA& col, halnf round = 0); + void text(const char*, const RectF&, halnf size, Align, halnf padding, const RGBA&); + + ImageHandle createImageFromTextId(ualni id, Vec2F size); + void deleteImageHandle(ImageHandle image); + void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding); + + private: + Buffer mScissors; + bool mIsClamping = false; + }; + + class Graphics { + private: + explicit Graphics(Window* window) : mGui(window), mCanvas(window) {} + + void proc() { + mCanvas.proc(); + mGui.proc(); + } + + void draw() { + mCanvas.draw(); + mGui.draw(); + } private: - GUI mGui; - GL mGl; Canvas mCanvas; + DebugGUI mGui; }; } \ No newline at end of file diff --git a/Graphics/public/GraphicsCommon.hpp b/Graphics/public/GraphicsCommon.hpp deleted file mode 100644 index df31c8f..0000000 --- a/Graphics/public/GraphicsCommon.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include "Color.hpp" -#include "Rect.hpp" -#include "Timing.hpp" - -#include "Allocators.hpp" - -namespace tp { - extern ModuleManifest gModuleGraphics; -} \ No newline at end of file diff --git a/Graphics/public/Keycodes.hpp b/Graphics/public/InputCodes.hpp similarity index 88% rename from Graphics/public/Keycodes.hpp rename to Graphics/public/InputCodes.hpp index 6e9a39e..a0fd296 100644 --- a/Graphics/public/Keycodes.hpp +++ b/Graphics/public/InputCodes.hpp @@ -2,10 +2,7 @@ #pragma once namespace tp { - - // basically copy of glfw keys - enum class Keycode { - + enum class InputID : ualni { /* Printable keys */ SPACE = 32, APOSTROPHE = 39, /* ' */ @@ -145,22 +142,7 @@ namespace tp { MOUSE5 = 505, MOUSE_UP = 506, MOUSE_DOWN = 507, - }; - enum class KeyState { - PRESSED, - RELEASED, - HOLD, - REPEAT, - NONE, + LAST_KEY_CODE = 508, }; - - struct KeyEvent { - Keycode code; - enum class EventState { - RELEASED = 0, - PRESSED = 1, - REPEAT = 2, - } event_state; - }; -}; \ No newline at end of file +} \ No newline at end of file diff --git a/Graphics/public/Window.hpp b/Graphics/public/Window.hpp index e7351eb..6b6bd01 100644 --- a/Graphics/public/Window.hpp +++ b/Graphics/public/Window.hpp @@ -1,62 +1,38 @@ #pragma once -// TODO : fix this ugly shit - #include "Buffer.hpp" -#include "Graphics.hpp" -#include "Keycodes.hpp" +#include "EventHandler.hpp" +#include "Strings.hpp" namespace tp { + extern ModuleManifest gModuleGraphics; + class Window { class Context; - public: - struct Event { - enum Type { - KEY, - MOUSE, - }; - }; - - struct Events { - Vec2F mPointer; - halnf pressure = 0; - - const Vec2F& getPos() const; - bool isPressed() const; - bool isReleased() const; - bool isDown() const; - halnf getScrollY() const; - bool isEvent() const; - - private: - friend Window; - Buffer mQueu; - Context* mContext; - }; - private: - Window(int width, int height, const char* title); + Window(Vec2F size, const String& title); ~Window(); public: - static Window* createWindow(int width, int height, const char* title); + static Window* createWindow(Vec2F size = { 1000.f, 900.f }, const String& title = "Window"); static void destroyWindow(Window* window); public: void draw(); void processEvents(); + + void setEventHandler(EventHandler* eventHandler); + [[nodiscard]] EventHandler* getEventHandler(); + + Context* getContext(); [[nodiscard]] bool shouldClose() const; - - auto getContext() -> Context*; - - Graphics::Canvas& getCanvas(); - const Events& getEvents(); + [[nodiscard]] const Vec2F& getSize() const; private: + Vec2F mSize; Context* mContext; - Graphics mGraphics; - Events mEvents; + EventHandler* mEventHandler = nullptr; }; } \ No newline at end of file