Graphics Refactor Initial

This commit is contained in:
IlyaShurupov 2024-03-19 11:21:58 +03:00 committed by Ilya Shurupov
parent e0f92b32dc
commit e331fc1a34
14 changed files with 378 additions and 555 deletions

View file

@ -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);
}

View file

@ -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());
}

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;
};
}