diff options
Diffstat (limited to 'src/rendering')
| -rw-r--r-- | src/rendering/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/platform.h | 57 | ||||
| -rw-r--r-- | src/rendering/include/engine/rendering/platform_glfw.h | 32 | ||||
| -rw-r--r-- | src/rendering/src/platform_glfw.c | 217 | ||||
| -rw-r--r-- | src/rendering/src/window.c | 2 |
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> |
