Graphics Refactor Initial
This commit is contained in:
parent
87d8ce84dc
commit
bb5cbfdfe2
14 changed files with 378 additions and 555 deletions
|
|
@ -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/)
|
||||
|
|
|
|||
|
|
@ -12,31 +12,32 @@
|
|||
#include <nanovg_gl.h>
|
||||
|
||||
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);
|
||||
}
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
#include "Window.hpp"
|
||||
|
||||
#include "WindowContext.hpp"
|
||||
|
||||
#include "Graphics.hpp"
|
||||
|
||||
// -------- Debug UI -------- //
|
||||
#include <imgui.h>
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
|
@ -9,7 +10,7 @@
|
|||
#include <imgui_internal.h>
|
||||
|
||||
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());
|
||||
}
|
||||
2
Graphics/private/EventHandler.cpp
Normal file
2
Graphics/private/EventHandler.cpp
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#include "EventHandler.hpp"
|
||||
|
|
@ -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
151
Graphics/private/Window.cpp
Normal 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
|
||||
}
|
||||
14
Graphics/private/WindowContext.hpp
Normal file
14
Graphics/private/WindowContext.hpp
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "Window.hpp"
|
||||
|
||||
class GLFWwindow;
|
||||
|
||||
namespace tp {
|
||||
|
||||
class Window::Context {
|
||||
public:
|
||||
Context() = default;
|
||||
GLFWwindow* window = nullptr;
|
||||
};
|
||||
}
|
||||
|
|
@ -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(); }
|
||||
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
90
Graphics/public/EventHandler.hpp
Normal file
90
Graphics/public/EventHandler.hpp
Normal 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];
|
||||
};
|
||||
|
||||
}
|
||||
|
|
@ -1,70 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "GraphicsCommon.hpp"
|
||||
#include "Color.hpp"
|
||||
#include "Rect.hpp"
|
||||
|
||||
// TODO : ugly
|
||||
#include "Buffer.hpp"
|
||||
|
||||
namespace tp {
|
||||
class Window;
|
||||
|
||||
class Graphics {
|
||||
public:
|
||||
class GL {
|
||||
class DebugGUI {
|
||||
class Context;
|
||||
Context* mContext;
|
||||
|
||||
private:
|
||||
friend Graphics;
|
||||
friend Window;
|
||||
public:
|
||||
explicit DebugGUI(Window* window);
|
||||
~DebugGUI();
|
||||
|
||||
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();
|
||||
public:
|
||||
explicit Canvas(Window* window);
|
||||
~Canvas();
|
||||
|
||||
void init();
|
||||
void deinit();
|
||||
void proc();
|
||||
void draw();
|
||||
|
||||
|
|
@ -85,35 +48,36 @@ namespace tp {
|
|||
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&);
|
||||
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:
|
||||
halnf mWidth = 600;
|
||||
halnf mHeight = 600;
|
||||
Buffer<RectF> mScissors;
|
||||
bool mIsClamping = false;
|
||||
};
|
||||
|
||||
class Graphics {
|
||||
private:
|
||||
friend Window;
|
||||
explicit Graphics(Window* window) : mGui(window), mCanvas(window) {}
|
||||
|
||||
Graphics() = default;
|
||||
void init(Window* window);
|
||||
void deinit();
|
||||
void draw();
|
||||
void proc();
|
||||
void proc() {
|
||||
mCanvas.proc();
|
||||
mGui.proc();
|
||||
}
|
||||
|
||||
void draw() {
|
||||
mCanvas.draw();
|
||||
mGui.draw();
|
||||
}
|
||||
|
||||
private:
|
||||
GUI mGui;
|
||||
GL mGl;
|
||||
Canvas mCanvas;
|
||||
DebugGUI mGui;
|
||||
};
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "Color.hpp"
|
||||
#include "Rect.hpp"
|
||||
#include "Timing.hpp"
|
||||
|
||||
#include "Allocators.hpp"
|
||||
|
||||
namespace tp {
|
||||
extern ModuleManifest gModuleGraphics;
|
||||
}
|
||||
|
|
@ -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,
|
||||
};
|
||||
|
||||
struct KeyEvent {
|
||||
Keycode code;
|
||||
enum class EventState {
|
||||
RELEASED = 0,
|
||||
PRESSED = 1,
|
||||
REPEAT = 2,
|
||||
} event_state;
|
||||
};
|
||||
LAST_KEY_CODE = 508,
|
||||
};
|
||||
}
|
||||
|
|
@ -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<Event> 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;
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue