diff options
Diffstat (limited to 'src/platform_glfw.c')
| -rw-r--r-- | src/platform_glfw.c | 232 |
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]); +} |
