Graphics Refactor Initial

This commit is contained in:
IlyaShurupov 2024-03-19 11:21:58 +03:00
parent 87d8ce84dc
commit bb5cbfdfe2
14 changed files with 378 additions and 555 deletions

View file

@ -5,7 +5,7 @@ set(BINDINGS_INCLUDE ../Externals/glfw/include ${GLEW_INCLUDE_DIR})
set(BINDINGS_LIBS glfw Imgui Nanovg ${GLEW_LIB}) set(BINDINGS_LIBS glfw Imgui Nanovg ${GLEW_LIB})
### ---------------------- Static Library --------------------- ### ### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp") file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp") file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS}) add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/) target_include_directories(${PROJECT_NAME} PUBLIC ./public/)

View file

@ -12,31 +12,32 @@
#include <nanovg_gl.h> #include <nanovg_gl.h>
namespace tp { namespace tp {
class Graphics::Canvas::Context { class Canvas::Context {
public: public:
NVGcontext* vg; NVGcontext* vg {};
Window* window {};
}; };
} }
using namespace tp; 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); mContext->vg = nvgCreateGL3(NVG_ANTIALIAS | NVG_STENCIL_STROKES);
if (nvgCreateFont(mContext->vg, "default", "Font.ttf") == -1) { 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 Canvas::rect(const RectF& rec, const RGBA& col, halnf round) {
void Graphics::Canvas::rect(const RectF& rec, const RGBA& col, halnf round) {
nvgBeginPath(mContext->vg); nvgBeginPath(mContext->vg);
if (round == 0) { if (round == 0) {
@ -49,7 +50,7 @@ void Graphics::Canvas::rect(const RectF& rec, const RGBA& col, halnf round) {
nvgFill(mContext->vg); nvgFill(mContext->vg);
} }
void Graphics::Canvas::pushClamp(const RectF& rec) { void Canvas::pushClamp(const RectF& rec) {
RectF intersection = rec; RectF intersection = rec;
if (mScissors.size()) { if (mScissors.size()) {
mScissors.last().calcIntersection(rec, intersection); mScissors.last().calcIntersection(rec, intersection);
@ -58,7 +59,7 @@ void Graphics::Canvas::pushClamp(const RectF& rec) {
mScissors.append(rec); mScissors.append(rec);
} }
void Graphics::Canvas::popClamp() { void Canvas::popClamp() {
DEBUG_ASSERT(mScissors.size()); DEBUG_ASSERT(mScissors.size());
mIsClamping = false; mIsClamping = false;
mScissors.pop(); 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 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 }; 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(); 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); auto imgPaint = nvgImagePattern(mContext->vg, rec.x, rec.y, rec.z, rec.w, angle, image->id, alpha);
nvgBeginPath(mContext->vg); nvgBeginPath(mContext->vg);
nvgRoundedRect(mContext->vg, rec.x, rec.y, rec.z, rec.w, rounding); 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); 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 #ifdef ENV_OS_ANDROID
return { (ualni) nvglCreateImageFromHandleGLES3(mContext->vg, id, size.x, size.y, 0) }; return { (ualni) nvglCreateImageFromHandleGLES3(mContext->vg, id, size.x, size.y, 0) };
#else #else
@ -128,12 +129,17 @@ void Graphics::Canvas::drawImage(const RectF& rec, ImageHandle* image, halnf ang
#endif #endif
} }
void Graphics::Canvas::deleteImageHandle(ImageHandle image) { void Canvas::deleteImageHandle(ImageHandle image) {
if (image.id) { if (image.id) {
nvgDeleteImage(mContext->vg, 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);
}

View file

@ -1,7 +1,8 @@
#include "Window.hpp" #include "Window.hpp"
#include "WindowContext.hpp" #include "WindowContext.hpp"
#include "Graphics.hpp"
// -------- Debug UI -------- // // -------- Debug UI -------- //
#include <imgui.h> #include <imgui.h>
#include <imgui_impl_glfw.h> #include <imgui_impl_glfw.h>
@ -9,7 +10,7 @@
#include <imgui_internal.h> #include <imgui_internal.h>
namespace tp { namespace tp {
class Graphics::GUI::Context { class DebugGUI::Context {
public: public:
ImGuiIO* io{}; ImGuiIO* io{};
ImGuiContext* ctx{}; ImGuiContext* ctx{};
@ -18,11 +19,9 @@ namespace tp {
using 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(); IMGUI_CHECKVERSION();
mContext->ctx = ImGui::CreateContext(); mContext->ctx = ImGui::CreateContext();
mContext->io = &ImGui::GetIO(); mContext->io = &ImGui::GetIO();
@ -38,13 +37,15 @@ void Graphics::GUI::init(Window* window) {
io.Fonts->AddFontFromFileTTF("Font.ttf", 20.f); io.Fonts->AddFontFromFileTTF("Font.ttf", 20.f);
} }
void Graphics::GUI::deinit() { DebugGUI::~DebugGUI() {
ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplOpenGL3_Shutdown();
ImGui_ImplGlfw_Shutdown(); ImGui_ImplGlfw_Shutdown();
ImGui::DestroyContext(); ImGui::DestroyContext();
delete mContext;
} }
void Graphics::GUI::proc() { void DebugGUI::proc() {
tp::HeapAllocGlobal::startIgnore(); tp::HeapAllocGlobal::startIgnore();
ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplOpenGL3_NewFrame();
@ -54,7 +55,7 @@ void Graphics::GUI::proc() {
tp::HeapAllocGlobal::stopIgnore(); tp::HeapAllocGlobal::stopIgnore();
} }
void Graphics::GUI::draw() { void DebugGUI::draw() {
ImGui::Render(); ImGui::Render();
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
} }

View file

@ -0,0 +1,2 @@
#include "EventHandler.hpp"

View file

@ -1,7 +0,0 @@
#include "GraphicsCommon.hpp"
#include "MathCommon.hpp"
namespace tp {
static ModuleManifest* deps[] = { &gModuleAllocators, nullptr };
ModuleManifest gModuleGraphics = ModuleManifest("Graphics", nullptr, nullptr, deps);
}

151
Graphics/private/Window.cpp Normal file
View file

@ -0,0 +1,151 @@
#include "Window.hpp"
#include "WindowContext.hpp"
// -------- OpenGL -------- //
#include <GL/glew.h>
// -------- Window Context -------- //
#include <GLFW/glfw3.h>
#ifdef ENV_OS_WINDOWS
#define GLFW_EXPOSE_NATIVE_WIN32
#endif
#ifdef ENV_OS_LINUX
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include <GLFW/glfw3native.h>
#include <array>
#include <cstdio>
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<Window*>(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<Window*>(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
}

View file

@ -0,0 +1,14 @@
#pragma once
#include "Window.hpp"
class GLFWwindow;
namespace tp {
class Window::Context {
public:
Context() = default;
GLFWwindow* window = nullptr;
};
}

View file

@ -1,215 +0,0 @@
#include "Window.hpp"
// -------- OpenGL -------- //
#include <GL/glew.h>
#include "WindowContext.hpp"
#include <cstdio>
// #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(); }

View file

@ -1,130 +0,0 @@
#pragma once
#include "Environment.hpp"
// -------- Window Context -------- //
#include <GLFW/glfw3.h>
#ifdef ENV_OS_WINDOWS
#define GLFW_EXPOSE_NATIVE_WIN32
#endif
#ifdef ENV_OS_LINUX
#define GLFW_EXPOSE_NATIVE_WAYLAND
#endif
#include <GLFW/glfw3native.h>
#include <array>
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<InputManager*>(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<InputManager*>(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<InputManager*>(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<int, GLFW_KEY_LAST + 1> keyStates = { GLFW_RELEASE };
std::array<int, GLFW_MOUSE_BUTTON_LAST + 1> mouseButtonStates = { GLFW_RELEASE };
};
class Window::Context {
friend Graphics::GL;
friend Graphics::GUI;
friend Graphics::Canvas;
public:
GLFWwindow* window;
InputManager inputManager;
};
}

View file

@ -0,0 +1,90 @@
#pragma once
#include "InputCodes.hpp"
#include "Vec.hpp"
#include "List.hpp"
#include "Map.hpp"
#include <mutex>
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<InputEvent> mEventQueue;
// input states
Vec2F mPointer;
halnf pressure = 0;
InputState mInputStates[(int) InputID::LAST_KEY_CODE];
};
}

View file

@ -1,70 +1,33 @@
#pragma once #pragma once
#include "GraphicsCommon.hpp" #include "Color.hpp"
#include "Rect.hpp"
// TODO : ugly #include "Buffer.hpp"
namespace tp { namespace tp {
class Window; class Window;
class Graphics { class DebugGUI {
public:
class GL {
class Context; class Context;
Context* mContext; Context* mContext;
private: public:
friend Graphics; explicit DebugGUI(Window* window);
friend Window; ~DebugGUI();
GL();
~GL();
void init();
void deinit();
void proc(); void proc();
void draw(); 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 Canvas {
class Context; class Context;
Context* mContext; Context* mContext;
private: public:
friend Graphics; explicit Canvas(Window* window);
friend Window;
Canvas();
~Canvas(); ~Canvas();
void init();
void deinit();
void proc(); void proc();
void draw(); void draw();
@ -85,35 +48,36 @@ namespace tp {
ualni id = 0; ualni id = 0;
}; };
RectF getAvaliableArea();
void pushClamp(const RectF& rec); void pushClamp(const RectF& rec);
void popClamp(); void popClamp();
void rect(const RectF& rec, const RGBA& col, halnf round = 0); void rect(const RectF& rec, const RGBA& col, halnf round = 0);
void text(const char*, const RectF&, halnf size, Align, halnf marging, const RGBA&); void text(const char*, const RectF&, halnf size, Align, halnf padding, const RGBA&);
ImageHandle createImageFromTextId(ualni id, Vec2F size); ImageHandle createImageFromTextId(ualni id, Vec2F size);
void deleteImageHandle(ImageHandle image); void deleteImageHandle(ImageHandle image);
void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding); void drawImage(const RectF& rec, ImageHandle* image, halnf angle, halnf alpha, halnf rounding);
private: private:
halnf mWidth = 600;
halnf mHeight = 600;
Buffer<RectF> mScissors; Buffer<RectF> mScissors;
bool mIsClamping = false; bool mIsClamping = false;
}; };
class Graphics {
private: private:
friend Window; explicit Graphics(Window* window) : mGui(window), mCanvas(window) {}
Graphics() = default; void proc() {
void init(Window* window); mCanvas.proc();
void deinit(); mGui.proc();
void draw(); }
void proc();
void draw() {
mCanvas.draw();
mGui.draw();
}
private: private:
GUI mGui;
GL mGl;
Canvas mCanvas; Canvas mCanvas;
DebugGUI mGui;
}; };
} }

View file

@ -1,11 +0,0 @@
#pragma once
#include "Color.hpp"
#include "Rect.hpp"
#include "Timing.hpp"
#include "Allocators.hpp"
namespace tp {
extern ModuleManifest gModuleGraphics;
}

View file

@ -2,10 +2,7 @@
#pragma once #pragma once
namespace tp { namespace tp {
enum class InputID : ualni {
// basically copy of glfw keys
enum class Keycode {
/* Printable keys */ /* Printable keys */
SPACE = 32, SPACE = 32,
APOSTROPHE = 39, /* ' */ APOSTROPHE = 39, /* ' */
@ -145,22 +142,7 @@ namespace tp {
MOUSE5 = 505, MOUSE5 = 505,
MOUSE_UP = 506, MOUSE_UP = 506,
MOUSE_DOWN = 507, MOUSE_DOWN = 507,
};
enum class KeyState { LAST_KEY_CODE = 508,
PRESSED,
RELEASED,
HOLD,
REPEAT,
NONE,
};
struct KeyEvent {
Keycode code;
enum class EventState {
RELEASED = 0,
PRESSED = 1,
REPEAT = 2,
} event_state;
};
}; };
}

View file

@ -1,62 +1,38 @@
#pragma once #pragma once
// TODO : fix this ugly shit
#include "Buffer.hpp" #include "Buffer.hpp"
#include "Graphics.hpp" #include "EventHandler.hpp"
#include "Keycodes.hpp" #include "Strings.hpp"
namespace tp { namespace tp {
extern ModuleManifest gModuleGraphics;
class Window { class Window {
class Context; 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: private:
friend Window; Window(Vec2F size, const String& title);
Buffer<Event> mQueu;
Context* mContext;
};
private:
Window(int width, int height, const char* title);
~Window(); ~Window();
public: 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); static void destroyWindow(Window* window);
public: public:
void draw(); void draw();
void processEvents(); void processEvents();
void setEventHandler(EventHandler* eventHandler);
[[nodiscard]] EventHandler* getEventHandler();
Context* getContext();
[[nodiscard]] bool shouldClose() const; [[nodiscard]] bool shouldClose() const;
[[nodiscard]] const Vec2F& getSize() const;
auto getContext() -> Context*;
Graphics::Canvas& getCanvas();
const Events& getEvents();
private: private:
Vec2F mSize;
Context* mContext; Context* mContext;
Graphics mGraphics; EventHandler* mEventHandler = nullptr;
Events mEvents;
}; };
} }