From f9e38bf24e1874d773083d06ca443cce9bd92d56 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 9 Mar 2024 08:55:46 -0800 Subject: Rename gfx_app -> app. --- CMakeLists.txt | 2 +- app/CMakeLists.txt | 14 +++ app/README.md | 3 + app/include/gfx/app.h | 95 ++++++++++++++++++++ app/src/app.c | 205 ++++++++++++++++++++++++++++++++++++++++++ game/src/game.c | 2 +- game/src/plugins/pong.c | 2 +- gfx-app/CMakeLists.txt | 14 --- gfx-app/README.md | 3 - gfx-app/include/gfx/gfx_app.h | 95 -------------------- gfx-app/src/gfx_app.c | 205 ------------------------------------------ gfx-iso/include/isogfx/app.h | 2 +- gfx-iso/src/app.c | 2 +- 13 files changed, 322 insertions(+), 322 deletions(-) create mode 100644 app/CMakeLists.txt create mode 100644 app/README.md create mode 100644 app/include/gfx/app.h create mode 100644 app/src/app.c delete mode 100644 gfx-app/CMakeLists.txt delete mode 100644 gfx-app/README.md delete mode 100644 gfx-app/include/gfx/gfx_app.h delete mode 100644 gfx-app/src/gfx_app.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 27e4bd6..25c7560 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.0) project(gfx-all) +add_subdirectory(app) add_subdirectory(gfx) -add_subdirectory(gfx-app) add_subdirectory(gfx-iso) add_subdirectory(game) diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt new file mode 100644 index 0000000..7e60351 --- /dev/null +++ b/app/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0) + +project(gfx-app) + +add_library(gfx-app + src/app.c) + +target_include_directories(gfx-app PUBLIC + include/) + +target_link_libraries(gfx-app PUBLIC + glfw + log + timer) diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000..b21d1aa --- /dev/null +++ b/app/README.md @@ -0,0 +1,3 @@ +# Gfx App + +A small library to more conveniently create a window and run a game loop. diff --git a/app/include/gfx/app.h b/app/include/gfx/app.h new file mode 100644 index 0000000..ffff4bc --- /dev/null +++ b/app/include/gfx/app.h @@ -0,0 +1,95 @@ +#pragma once + +#include + +typedef struct GfxAppState GfxAppState; + +/// Application settings. +typedef struct GfxAppDesc { + int argc; // Number of application arguments. + const char** argv; // Application arguments. + int width; // Window width. + int height; // Window height. + int max_fps; // Desired maximum display framerate. 0 to disable. + double update_delta_time; // Desired delta time between frame updates. + const char* title; // Window title. + GfxAppState* app_state; +} GfxAppDesc; + +typedef bool (*GfxAppInit)(GfxAppState*, int argc, const char** argv); +typedef void (*GfxAppShutdown)(GfxAppState*); +typedef void (*GfxAppUpdate)(GfxAppState*, double t, double dt); +typedef void (*GfxAppRender)(GfxAppState*); +typedef void (*GfxAppResize)(GfxAppState*, int width, int height); + +/// Application callback functions. +typedef struct GfxAppCallbacks { + GfxAppInit init; + GfxAppShutdown shutdown; + GfxAppUpdate update; + GfxAppRender render; + GfxAppResize resize; +} GfxAppCallbacks; + +typedef enum Key { + KeyA = 'a', + KeyB, + KeyC, + KeyD, + KeyE, + KeyF, + KeyG, + KeyH, + KeyI, + KeyJ, + KeyK, + KeyL, + KeyM, + KeyN, + KeyO, + KeyP, + KeyQ, + KeyR, + KeyS, + KeyT, + KeyU, + KeyV, + KeyW, + KeyX, + KeyY, + KeyZ, +} Key; + +/// Create a window with an OpenGL context and run the main loop. +bool gfx_app_run(const GfxAppDesc*, const GfxAppCallbacks*); + +/// Get the mouse coordinates relative to the app's window. +void gfx_app_get_mouse_position(double* x, double* y); + +/// Return true if the given key is pressed. +bool gfx_is_key_pressed(Key); + +/// Define a main function that initializes and puts the application in a loop. +/// See also: gfx_app_run(). +#define GFX_APP_MAIN(WIDTH, HEIGHT, MAX_FPS, TITLE) \ + int main(int argc, const char** argv) { \ + GfxAppState app_state = {0}; \ + gfx_app_run( \ + &(GfxAppDesc){ \ + .argc = argc, \ + .argv = argv, \ + .width = WIDTH, \ + .height = HEIGHT, \ + .max_fps = MAX_FPS, \ + .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0, \ + .title = TITLE, \ + .app_state = &app_state, \ + }, \ + &(GfxAppCallbacks){ \ + .init = (GfxAppInit)app_init, \ + .update = (GfxAppUpdate)app_update, \ + .render = (GfxAppRender)app_render, \ + .resize = (GfxAppResize)app_resize, \ + .shutdown = (GfxAppShutdown)app_end}); \ + return 0; \ + } diff --git a/app/src/app.c b/app/src/app.c new file mode 100644 index 0000000..b6d10ca --- /dev/null +++ b/app/src/app.c @@ -0,0 +1,205 @@ +#include + +#include +#include +#include + +#include +#include + +/// Application state. +typedef struct GfxApp { + GfxAppState* app_state; + GfxAppCallbacks callbacks; + int max_fps; + double update_delta_time; + GLFWwindow* window; +} GfxApp; + +/// Storing the application state in a global variable so that we can call the +/// application's callbacks from GLFW callbacks. +static GfxApp g_gfx_app; + +/// Called by GLFW when the window is resized. +static void on_resize(GLFWwindow* window, int width, int height) { + (*g_gfx_app.callbacks.resize)(g_gfx_app.app_state, width, height); +} + +/// Run the application's main loop. +static void loop(GfxApp* app) { + assert(app); + assert(app->window); + + const time_delta min_frame_time = + app->max_fps > 0 ? sec_to_time_delta(1.0 / (double)(app->max_fps)) : 0; + const time_delta update_dt = sec_to_time_delta(app->update_delta_time); + time_delta time = 0; + time_delta time_budget = 0; + Timer timer = timer_make(); + + // Warm up the update to initialize the application's state. + (*app->callbacks.update)( + app->app_state, time_delta_to_sec(time), time_delta_to_sec(update_dt)); + + // Warm up the rendering before entering the main loop. A renderer can + // compile shaders and do other initialization the first time it renders a + // scene. + (*app->callbacks.render)(app->app_state); + glfwSwapBuffers(app->window); + + timer_start(&timer); + while (!glfwWindowShouldClose(app->window)) { + timer_tick(&timer); + time_budget += timer.delta_time; + + while (time_budget >= update_dt) { + (*app->callbacks.update)( + app->app_state, time_delta_to_sec(time), + time_delta_to_sec(update_dt)); + + time += update_dt; + time_budget -= update_dt; + } + + (*app->callbacks.render)(app->app_state); + glfwSwapBuffers(app->window); + glfwPollEvents(); + + const time_point frame_end = time_now(); + const time_delta frame_time = time_diff(timer.last_tick, frame_end); + if ((min_frame_time > 0) && (frame_time < min_frame_time)) { + time_sleep(min_frame_time - frame_time); + } + } +} + +bool gfx_app_run(const GfxAppDesc* desc, const GfxAppCallbacks* callbacks) { + assert(desc); + assert(callbacks); + + bool success = false; + + g_gfx_app.app_state = desc->app_state; + g_gfx_app.callbacks = *callbacks; + g_gfx_app.max_fps = desc->max_fps; + g_gfx_app.update_delta_time = desc->update_delta_time; + g_gfx_app.window = 0; + + if (!glfwInit()) { + LOGE("glfwInit() failed"); + return false; + } + + const int major = 4; + const int minor = 4; + glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); + // TODO: Test antialiasing later on. + // glfwWindowHint(GLFW_SAMPLES, 4); + + const char* title = desc->title ? desc->title : "Gfx Application"; + + g_gfx_app.window = + glfwCreateWindow(desc->width, desc->height, title, NULL, NULL); + if (!g_gfx_app.window) { + LOGE("glfwCreateWindow() failed"); + goto cleanup; + } + glfwMakeContextCurrent(g_gfx_app.window); + + // Initialize the application's state before setting any callbacks. + if (!(*g_gfx_app.callbacks.init)( + g_gfx_app.app_state, desc->argc, desc->argv)) { + LOGE("Failed to initialize application"); + goto cleanup; + } + + // Trigger an initial resize for convenience. + (*g_gfx_app.callbacks.resize)(g_gfx_app.app_state, desc->width, desc->height); + + // Set GLFW callbacks now that the application has been initialized. + glfwSetWindowSizeCallback(g_gfx_app.window, on_resize); + + loop(&g_gfx_app); + + (*g_gfx_app.callbacks.shutdown)(g_gfx_app.app_state); + + success = true; + +cleanup: + if (g_gfx_app.window) { + glfwDestroyWindow(g_gfx_app.window); + } + glfwTerminate(); + return success; +} + +void gfx_app_get_mouse_position(double* x, double* y) { + glfwGetCursorPos(g_gfx_app.window, x, y); +} + +static int to_glfw_key(Key key); + +bool gfx_is_key_pressed(Key key) { + return glfwGetKey(g_gfx_app.window, to_glfw_key(key)) == GLFW_PRESS; +} + +static int to_glfw_key(Key key) { + switch (key) { + case KeyA: + return GLFW_KEY_A; + case KeyB: + return GLFW_KEY_B; + case KeyC: + return GLFW_KEY_C; + case KeyD: + return GLFW_KEY_D; + case KeyE: + return GLFW_KEY_E; + case KeyF: + return GLFW_KEY_F; + case KeyG: + return GLFW_KEY_G; + case KeyH: + return GLFW_KEY_H; + case KeyI: + return GLFW_KEY_I; + case KeyJ: + return GLFW_KEY_J; + case KeyK: + return GLFW_KEY_K; + case KeyL: + return GLFW_KEY_L; + case KeyM: + return GLFW_KEY_M; + case KeyN: + return GLFW_KEY_N; + case KeyO: + return GLFW_KEY_O; + case KeyP: + return GLFW_KEY_P; + case KeyQ: + return GLFW_KEY_Q; + case KeyR: + return GLFW_KEY_R; + case KeyS: + return GLFW_KEY_S; + case KeyT: + return GLFW_KEY_T; + case KeyU: + return GLFW_KEY_U; + case KeyV: + return GLFW_KEY_V; + case KeyW: + return GLFW_KEY_W; + case KeyX: + return GLFW_KEY_X; + case KeyY: + return GLFW_KEY_Y; + case KeyZ: + return GLFW_KEY_Z; + } +} diff --git a/game/src/game.c b/game/src/game.c index dc4ab84..bc85691 100644 --- a/game/src/game.c +++ b/game/src/game.c @@ -10,8 +10,8 @@ #include "plugins/plugin.h" +#include #include -#include #include #include #include diff --git a/game/src/plugins/pong.c b/game/src/plugins/pong.c index 3a0b825..070cc6f 100644 --- a/game/src/plugins/pong.c +++ b/game/src/plugins/pong.c @@ -1,7 +1,7 @@ #include "plugin.h" +#include #include -#include #include #include diff --git a/gfx-app/CMakeLists.txt b/gfx-app/CMakeLists.txt deleted file mode 100644 index d9cb80f..0000000 --- a/gfx-app/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -cmake_minimum_required(VERSION 3.0) - -project(gfx-app) - -add_library(gfx-app - src/gfx_app.c) - -target_include_directories(gfx-app PUBLIC - include/) - -target_link_libraries(gfx-app PUBLIC - glfw - log - timer) diff --git a/gfx-app/README.md b/gfx-app/README.md deleted file mode 100644 index b21d1aa..0000000 --- a/gfx-app/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Gfx App - -A small library to more conveniently create a window and run a game loop. diff --git a/gfx-app/include/gfx/gfx_app.h b/gfx-app/include/gfx/gfx_app.h deleted file mode 100644 index ffff4bc..0000000 --- a/gfx-app/include/gfx/gfx_app.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once - -#include - -typedef struct GfxAppState GfxAppState; - -/// Application settings. -typedef struct GfxAppDesc { - int argc; // Number of application arguments. - const char** argv; // Application arguments. - int width; // Window width. - int height; // Window height. - int max_fps; // Desired maximum display framerate. 0 to disable. - double update_delta_time; // Desired delta time between frame updates. - const char* title; // Window title. - GfxAppState* app_state; -} GfxAppDesc; - -typedef bool (*GfxAppInit)(GfxAppState*, int argc, const char** argv); -typedef void (*GfxAppShutdown)(GfxAppState*); -typedef void (*GfxAppUpdate)(GfxAppState*, double t, double dt); -typedef void (*GfxAppRender)(GfxAppState*); -typedef void (*GfxAppResize)(GfxAppState*, int width, int height); - -/// Application callback functions. -typedef struct GfxAppCallbacks { - GfxAppInit init; - GfxAppShutdown shutdown; - GfxAppUpdate update; - GfxAppRender render; - GfxAppResize resize; -} GfxAppCallbacks; - -typedef enum Key { - KeyA = 'a', - KeyB, - KeyC, - KeyD, - KeyE, - KeyF, - KeyG, - KeyH, - KeyI, - KeyJ, - KeyK, - KeyL, - KeyM, - KeyN, - KeyO, - KeyP, - KeyQ, - KeyR, - KeyS, - KeyT, - KeyU, - KeyV, - KeyW, - KeyX, - KeyY, - KeyZ, -} Key; - -/// Create a window with an OpenGL context and run the main loop. -bool gfx_app_run(const GfxAppDesc*, const GfxAppCallbacks*); - -/// Get the mouse coordinates relative to the app's window. -void gfx_app_get_mouse_position(double* x, double* y); - -/// Return true if the given key is pressed. -bool gfx_is_key_pressed(Key); - -/// Define a main function that initializes and puts the application in a loop. -/// See also: gfx_app_run(). -#define GFX_APP_MAIN(WIDTH, HEIGHT, MAX_FPS, TITLE) \ - int main(int argc, const char** argv) { \ - GfxAppState app_state = {0}; \ - gfx_app_run( \ - &(GfxAppDesc){ \ - .argc = argc, \ - .argv = argv, \ - .width = WIDTH, \ - .height = HEIGHT, \ - .max_fps = MAX_FPS, \ - .update_delta_time = MAX_FPS > 0 ? 1.0 / (double)MAX_FPS : 0.0, \ - .title = TITLE, \ - .app_state = &app_state, \ - }, \ - &(GfxAppCallbacks){ \ - .init = (GfxAppInit)app_init, \ - .update = (GfxAppUpdate)app_update, \ - .render = (GfxAppRender)app_render, \ - .resize = (GfxAppResize)app_resize, \ - .shutdown = (GfxAppShutdown)app_end}); \ - return 0; \ - } diff --git a/gfx-app/src/gfx_app.c b/gfx-app/src/gfx_app.c deleted file mode 100644 index a93756c..0000000 --- a/gfx-app/src/gfx_app.c +++ /dev/null @@ -1,205 +0,0 @@ -#include - -#include -#include -#include - -#include -#include - -/// Application state. -typedef struct GfxApp { - GfxAppState* app_state; - GfxAppCallbacks callbacks; - int max_fps; - double update_delta_time; - GLFWwindow* window; -} GfxApp; - -/// Storing the application state in a global variable so that we can call the -/// application's callbacks from GLFW callbacks. -static GfxApp g_gfx_app; - -/// Called by GLFW when the window is resized. -static void on_resize(GLFWwindow* window, int width, int height) { - (*g_gfx_app.callbacks.resize)(g_gfx_app.app_state, width, height); -} - -/// Run the application's main loop. -static void loop(GfxApp* app) { - assert(app); - assert(app->window); - - const time_delta min_frame_time = - app->max_fps > 0 ? sec_to_time_delta(1.0 / (double)(app->max_fps)) : 0; - const time_delta update_dt = sec_to_time_delta(app->update_delta_time); - time_delta time = 0; - time_delta time_budget = 0; - Timer timer = timer_make(); - - // Warm up the update to initialize the application's state. - (*app->callbacks.update)( - app->app_state, time_delta_to_sec(time), time_delta_to_sec(update_dt)); - - // Warm up the rendering before entering the main loop. A renderer can - // compile shaders and do other initialization the first time it renders a - // scene. - (*app->callbacks.render)(app->app_state); - glfwSwapBuffers(app->window); - - timer_start(&timer); - while (!glfwWindowShouldClose(app->window)) { - timer_tick(&timer); - time_budget += timer.delta_time; - - while (time_budget >= update_dt) { - (*app->callbacks.update)( - app->app_state, time_delta_to_sec(time), - time_delta_to_sec(update_dt)); - - time += update_dt; - time_budget -= update_dt; - } - - (*app->callbacks.render)(app->app_state); - glfwSwapBuffers(app->window); - glfwPollEvents(); - - const time_point frame_end = time_now(); - const time_delta frame_time = time_diff(timer.last_tick, frame_end); - if ((min_frame_time > 0) && (frame_time < min_frame_time)) { - time_sleep(min_frame_time - frame_time); - } - } -} - -bool gfx_app_run(const GfxAppDesc* desc, const GfxAppCallbacks* callbacks) { - assert(desc); - assert(callbacks); - - bool success = false; - - g_gfx_app.app_state = desc->app_state; - g_gfx_app.callbacks = *callbacks; - g_gfx_app.max_fps = desc->max_fps; - g_gfx_app.update_delta_time = desc->update_delta_time; - g_gfx_app.window = 0; - - if (!glfwInit()) { - LOGE("glfwInit() failed"); - return false; - } - - const int major = 4; - const int minor = 4; - glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, major); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, minor); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); - // TODO: Test antialiasing later on. - // glfwWindowHint(GLFW_SAMPLES, 4); - - const char* title = desc->title ? desc->title : "Gfx Application"; - - g_gfx_app.window = - glfwCreateWindow(desc->width, desc->height, title, NULL, NULL); - if (!g_gfx_app.window) { - LOGE("glfwCreateWindow() failed"); - goto cleanup; - } - glfwMakeContextCurrent(g_gfx_app.window); - - // Initialize the application's state before setting any callbacks. - if (!(*g_gfx_app.callbacks.init)( - g_gfx_app.app_state, desc->argc, desc->argv)) { - LOGE("Failed to initialize application"); - goto cleanup; - } - - // Trigger an initial resize for convenience. - (*g_gfx_app.callbacks.resize)(g_gfx_app.app_state, desc->width, desc->height); - - // Set GLFW callbacks now that the application has been initialized. - glfwSetWindowSizeCallback(g_gfx_app.window, on_resize); - - loop(&g_gfx_app); - - (*g_gfx_app.callbacks.shutdown)(g_gfx_app.app_state); - - success = true; - -cleanup: - if (g_gfx_app.window) { - glfwDestroyWindow(g_gfx_app.window); - } - glfwTerminate(); - return success; -} - -void gfx_app_get_mouse_position(double* x, double* y) { - glfwGetCursorPos(g_gfx_app.window, x, y); -} - -static int to_glfw_key(Key key); - -bool gfx_is_key_pressed(Key key) { - return glfwGetKey(g_gfx_app.window, to_glfw_key(key)) == GLFW_PRESS; -} - -static int to_glfw_key(Key key) { - switch (key) { - case KeyA: - return GLFW_KEY_A; - case KeyB: - return GLFW_KEY_B; - case KeyC: - return GLFW_KEY_C; - case KeyD: - return GLFW_KEY_D; - case KeyE: - return GLFW_KEY_E; - case KeyF: - return GLFW_KEY_F; - case KeyG: - return GLFW_KEY_G; - case KeyH: - return GLFW_KEY_H; - case KeyI: - return GLFW_KEY_I; - case KeyJ: - return GLFW_KEY_J; - case KeyK: - return GLFW_KEY_K; - case KeyL: - return GLFW_KEY_L; - case KeyM: - return GLFW_KEY_M; - case KeyN: - return GLFW_KEY_N; - case KeyO: - return GLFW_KEY_O; - case KeyP: - return GLFW_KEY_P; - case KeyQ: - return GLFW_KEY_Q; - case KeyR: - return GLFW_KEY_R; - case KeyS: - return GLFW_KEY_S; - case KeyT: - return GLFW_KEY_T; - case KeyU: - return GLFW_KEY_U; - case KeyV: - return GLFW_KEY_V; - case KeyW: - return GLFW_KEY_W; - case KeyX: - return GLFW_KEY_X; - case KeyY: - return GLFW_KEY_Y; - case KeyZ: - return GLFW_KEY_Z; - } -} diff --git a/gfx-iso/include/isogfx/app.h b/gfx-iso/include/isogfx/app.h index 0a0fcc1..769af6d 100644 --- a/gfx-iso/include/isogfx/app.h +++ b/gfx-iso/include/isogfx/app.h @@ -1,6 +1,6 @@ #pragma once -#include +#include #include diff --git a/gfx-iso/src/app.c b/gfx-iso/src/app.c index 079ac96..8e0a45a 100644 --- a/gfx-iso/src/app.c +++ b/gfx-iso/src/app.c @@ -1,8 +1,8 @@ #include #include +#include #include -#include #include #include #include -- cgit v1.2.3