summaryrefslogtreecommitdiff
path: root/src/rendering
diff options
context:
space:
mode:
authoronelin <oscar@nelin.dk>2025-04-10 21:44:19 +0000
committeronelin <oscar@nelin.dk>2025-04-10 21:45:54 +0000
commitf6b60693e298ca9c155be75ed2e4c687f3fa0fa5 (patch)
tree1b3b37dfda4ab5611e6a02aca44d12a6a1e8adb3 /src/rendering
parent0f12145db9f6b6856a785d33527406ae9ea35363 (diff)
Copy GLFW + OpenGL initialization code
Diffstat (limited to 'src/rendering')
-rw-r--r--src/rendering/CMakeLists.txt1
-rw-r--r--src/rendering/include/engine/rendering/platform.h57
-rw-r--r--src/rendering/include/engine/rendering/platform_glfw.h32
-rw-r--r--src/rendering/src/platform_glfw.c217
-rw-r--r--src/rendering/src/window.c2
5 files changed, 307 insertions, 2 deletions
diff --git a/src/rendering/CMakeLists.txt b/src/rendering/CMakeLists.txt
index a00f3b1..68e4f50 100644
--- a/src/rendering/CMakeLists.txt
+++ b/src/rendering/CMakeLists.txt
@@ -3,6 +3,7 @@ add_library(daw_rendering
src/rendering.c
src/text.c
src/window.c
+ src/platform_glfw.c
${GLAD_HEADER}
)
diff --git a/src/rendering/include/engine/rendering/platform.h b/src/rendering/include/engine/rendering/platform.h
new file mode 100644
index 0000000..5d2408e
--- /dev/null
+++ b/src/rendering/include/engine/rendering/platform.h
@@ -0,0 +1,57 @@
+#ifndef PLATFORM_H
+#define PLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/cglm.h>
+
+#include <engine/core/types.h>
+// TODO: We only need the window once all the garbage in Instance is cleaned up.
+#include <engine/core/platform.h>
+#include <engine/rendering/window.h>
+
+#define DAW_WINDOW_VSYNC (1 << 0)
+#define DAW_WINDOW_FULLSCREEN (1 << 1)
+#define DAW_WINDOW_RESIZEABLE (1 << 2)
+
+// Whether or not it is clever to force API consistency using a struct like this
+// can be debated, at the time of writing it seemed like a smart idea.
+
+// Platform libraries must implement a struct Platform:
+struct Platform {
+ /* Initialize a window for the given platform. The rendering backend should
+ * also be initialized here.
+ * Parameters:
+ * const char* title: window title.
+ * ivec2 windowsize: the size in pixels for the new window.
+ * const u32 flags: window flags, such as static size and fullscreen.
+ * The flags are platform agnostic and needs to be
+ * converted to the specific library
+ * Returns:
+ * A pointer to a struct Window, NULL on error.
+ */
+ Window* (*window_init)(const Instance *restrict i, const char *restrict title, ivec2 windowsize, const u32 flags);
+
+ /* Destroy, close, and free up resources related to the window and the
+ * platform library specific resources.
+ */
+ void (*window_destroy)(Window *restrict w);
+
+ /* Resize the given window. Resize callbacks are handled by the wrapper
+ * implementation.
+ */
+ void (*window_resize)(Window *restrict window, int width, int height);
+
+ /* Return true if the platform has ordered the window to exit. */
+ bool (*window_should_close)(Window *restrict w);
+
+ /* Poll events on the window from the operating system. */
+ void (*window_poll)(void);
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/src/rendering/include/engine/rendering/platform_glfw.h b/src/rendering/include/engine/rendering/platform_glfw.h
new file mode 100644
index 0000000..cbc3520
--- /dev/null
+++ b/src/rendering/include/engine/rendering/platform_glfw.h
@@ -0,0 +1,32 @@
+#ifndef PLATFORM_GLFW_H
+#define PLATFORM_GLFW_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <cglm/cglm.h>
+
+#include <engine/core/types.h>
+#include <engine/rendering/platform.h>
+#include <engine/rendering/window.h>
+
+Window* window_init_glfw(const Instance *restrict i, const char *restrict windowtitle, ivec2 windowsize, const u32 flags);
+void window_destroy_glfw(Window *restrict w);
+void window_resize_glfw(Window *restrict window, int width, int height);
+bool window_should_close_glfw(Window *restrict window);
+void window_poll_glfw(void);
+
+const struct Platform Platform_GLFW = {
+ .window_init = window_init_glfw,
+ .window_destroy = window_destroy_glfw,
+ .window_resize = window_resize_glfw,
+ .window_should_close = window_should_close_glfw,
+ .window_poll = window_poll_glfw,
+};
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/src/rendering/src/platform_glfw.c b/src/rendering/src/platform_glfw.c
new file mode 100644
index 0000000..8237593
--- /dev/null
+++ b/src/rendering/src/platform_glfw.c
@@ -0,0 +1,217 @@
+// Required for OpenGL rendering backend
+#define GLAD_GL_IMPLEMENTATION
+#include <glad/gl.h>
+#undef GLAD_GL_IMPLEMENTATION
+
+// TODO: import vulkan thingymajig once I get around to it.
+
+#undef GLFW_INCLUDE_NONE
+#include <GLFW/glfw3.h>
+
+#include <engine/core/logging.h>
+
+#include <engine/rendering/platform_glfw.h>
+
+static void window_resize_callback(GLFWwindow *restrict window, int width, int height);
+static void framebuffer_resize_callback(GLFWwindow *restrict window, int width, int height);
+static void glfw_err_callback(int code, const char* description);
+static void render_init_opengl(Window *restrict w, const u32 flags);
+
+
+Window* window_init_glfw(const Instance *restrict i, const char *restrict windowtitle, ivec2 windowsize, const u32 flags) {
+ Window* ret = NULL;
+ GLFWwindow* window = NULL;
+
+ glfwSetErrorCallback(&glfw_err_callback);
+
+ INFO_("initializing glfw...");
+ if (glfwInit() == GLFW_FALSE) {
+ const char *desc;
+ int code = glfwGetError(&desc);
+ ERROR("failed to initialize glfw [%d]: %s\n", code, *desc);
+ exit(EXIT_FAILURE);
+ } else
+ printf("ok\n");
+
+
+ INFO_("initializing window...");
+ //glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
+ if (!(flags & DAW_WINDOW_RESIZEABLE)) {
+ glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
+ }
+
+ glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);
+ glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
+
+ glfwWindowHint(GLFW_SAMPLES, 0); // Disable anti aliasing
+
+ // Use a modern opengl version
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
+
+ // Lean and mean
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+
+#ifdef __APPLE__
+ // To make MacOS happy; should not be needed
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+
+ /* "On Wayland specifically, you need to swap the buffers
+ * once of a window for it to become visible." */
+ {
+ GLFWmonitor* mon = NULL;
+ if (flags & DAW_WINDOW_FULLSCREEN) mon = glfwGetPrimaryMonitor();
+
+ window = glfwCreateWindow(windowsize[0], windowsize[1], windowtitle, mon, NULL);
+ }
+
+ if (window == NULL) {
+ ERROR("Failed to create GLFW window!\n");
+ const char *desc;
+ int code = glfwGetError(&desc);
+ ERROR("failed to initialize glfw window [%d]: %s\n", code, desc);
+ exit(EXIT_FAILURE);
+ } else
+ printf("ok\n");
+
+ // Setup callbacks
+ glfwSetFramebufferSizeCallback(window, framebuffer_resize_callback);
+ glfwSetWindowSizeCallback(window, window_resize_callback);
+ glfwSetKeyCallback(window, (GLFWkeyfun)key_callback);
+
+ // Create the window datastructure
+ ret = (Window*)calloc(1, sizeof(Window));
+ ret->framework = WINDOW_FRAMEWORK_GLFW;
+ ret->renderer = WINDOW_RENDERER_NONE;
+ ret->window = window;
+ /* Last parameter is used for the renderer */
+ ret->context = NULL;
+
+ {
+ ivec2 wsize;
+ vec2 wscaling;
+ glfwGetWindowContentScale(window, &wscaling[0], &wscaling[1]);
+ glfwGetWindowSize(window, &wsize[0], &wsize[1]);
+
+ ret->windowsize[0] = (i32)((f32)wsize[0] * wscaling[0]);
+ ret->windowsize[1] = (i32)((f32)wsize[1] * wscaling[1]);
+
+ INFO("WINDOW CONTENT SCALING: %.2f x %.2f", wscaling[0], wscaling[1]);
+ INFO("WINDOW SIZE: %d x %d -> %d x %d", wsize[0], wsize[1], ret->windowsize[0], ret->windowsize[1]);
+ }
+
+
+ render_init_opengl(ret, flags);
+
+ return ret;
+}
+
+void window_destroy_glfw(Window *restrict w) {
+ glfwDestroyWindow(w->window);
+ w->window = NULL;
+
+ // If we ever do multi-window support, we need to make sure this is the last
+ // window before terminating
+ glfwTerminate();
+
+ switch(w->renderer) {
+ case WINDOW_RENDERER_OPENGL:
+ // Missing unloader function in glad MX library
+ free(w->context);
+ w->context = NULL;
+ break;
+ default:
+ ERROR("Destroying unknown renderer type.");
+ }
+}
+
+void window_resize_glfw(Window *restrict window, int width, int height) {
+ window_resize_callback(window->window, width, height);
+ framebuffer_resize_callback(window->window, width, height);
+}
+
+bool window_should_close_glfw(Window *restrict window) {
+ return glfwWindowShouldClose(window->window);
+}
+
+void window_poll_glfw(void) {
+ glfwPollEvents();
+}
+
+// Helper function implementations
+static void window_resize_callback(GLFWwindow* window, int width, int height) {
+ (void)width; (void)height;
+ Instance* i = glfwGetWindowUserPointer(window);
+ glfwSwapBuffers(window);
+ if (i != NULL) {
+ const GladGLContext* gl = i->window->context;
+ gl->Finish();
+ }
+}
+
+static void framebuffer_resize_callback(GLFWwindow* window, int width, int height) {
+ (void)width; (void)height;
+ Instance* i = glfwGetWindowUserPointer(window);
+ if (i != NULL) {
+ const GladGLContext* gl = i->window->context;
+ Camera* c = i->cam;
+ gl->Viewport(0,0, width, height);
+ i->window->windowsize[0] = width;
+ i->window->windowsize[1] = height;
+
+ r_reset_camera(c);
+ }
+}
+
+static void glfw_err_callback(int code, const char* description) {
+ ERROR("glfw [%d]: %s\n", code, description);
+ // Terminate?
+ exit(EXIT_FAILURE);
+}
+
+static void render_init_opengl(Window *restrict w, const u32 flags) {
+ if (w->renderer != WINDOW_RENDERER_NONE || w->context != NULL) {
+ ERROR("Window already initialized with a renderer!");
+ return;
+ }
+
+ // This is GLFW specific
+ glfwMakeContextCurrent(w->window);
+
+ GladGLContext* ctx = (GladGLContext*)malloc(sizeof(GladGLContext));
+ if (!ctx) {
+ ERROR("Failed to allocate memory for context");
+ }
+
+ int version = gladLoadGLContext(ctx, glfwGetProcAddress);
+ INFO("Loaded OpenGL %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version));
+
+ if (ctx == NULL) {
+ ERROR("Failed to create glad context");
+ exit(EXIT_FAILURE);
+ }
+
+ if (flags & DAW_WINDOW_VSYNC) {
+ glfwSwapInterval(1);
+ } else {
+ glfwSwapInterval(0);
+ }
+
+
+ ctx->Viewport(0, 0, w->windowsize[0], w->windowsize[1]);
+
+#ifdef _DEBUG
+ ctx->ClearColor((float)0x10 / 255.f, (float)0x0a / 255.f, (float)0x33 / 255.f, 0.f);
+#else
+ ctx->ClearColor(0x0, 0x0, 0x0, 0.f);
+#endif
+
+ // Make sure faces closest to the camera are drawn on-top of faces that are
+ // further away
+ ctx->Enable(GL_DEPTH_TEST);
+ ctx->DepthFunc(GL_LESS);
+
+ w->context = ctx;
+ w->renderer = WINDOW_RENDERER_OPENGL;
+}
diff --git a/src/rendering/src/window.c b/src/rendering/src/window.c
index 3d163eb..4cf35f2 100644
--- a/src/rendering/src/window.c
+++ b/src/rendering/src/window.c
@@ -10,9 +10,7 @@
#define ENGINE_RENDERING_WINDOW_H_EXCLUDE_EXTERNS
#include <engine/rendering/window.h>
-#define GLAD_GL_IMPLEMENTATION
#include <glad/gl.h>
-#undef GLAD_GL_IMPLEMENTATION
#undef GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>