summaryrefslogtreecommitdiff
path: root/src/platform_glfw.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/platform_glfw.c')
-rw-r--r--src/platform_glfw.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/platform_glfw.c b/src/platform_glfw.c
new file mode 100644
index 0000000..211df47
--- /dev/null
+++ b/src/platform_glfw.c
@@ -0,0 +1,232 @@
+// 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.
+// TODO: move OpenGL initialization code at some point
+
+#undef GLFW_INCLUDE_NONE
+#include <GLFW/glfw3.h>
+
+#include <daw/logging.h>
+
+#include <daw/platform.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);
+static void window_size(GLFWwindow *restrict w, ivec2 *restrict dst);
+
+
+Window* window_init_glfw(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]);
+ }
+
+ // TODO: set this to `ret` once all the garbage is moved to `struct Window`
+ glfwSetWindowUserPointer(window, (void*)ret);
+
+ 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;
+ Window* w = glfwGetWindowUserPointer(window);
+ glfwSwapBuffers(window);
+ if (w != NULL) {
+ const GladGLContext* gl = w->context;
+ gl->Finish();
+ }
+}
+
+static void framebuffer_resize_callback(GLFWwindow* window, int width, int height) {
+ (void)width; (void)height;
+ Window* w = glfwGetWindowUserPointer(window);
+ if (w != NULL) {
+ const GladGLContext* gl = w->context;
+ //TODO: Move the camera to window->renderer
+ //Camera* c = w->cam;
+ gl->Viewport(0,0, width, height);
+ w->windowsize[0] = width;
+ w->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;
+}
+
+static void window_size(GLFWwindow *restrict w, ivec2 *restrict dst) {
+ ivec2 wsize;
+ vec2 wscaling;
+ glfwGetWindowContentScale(w, &wscaling[0], &wscaling[1]);
+ glfwGetWindowSize(w, &wsize[0], &wsize[1]);
+
+ *dst[0] = (i32)((f32)wsize[0] * wscaling[0]);
+ *dst[1] = (i32)((f32)wsize[1] * wscaling[1]);
+}