aboutsummaryrefslogtreecommitdiff
path: root/game/src/game.c
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
committer3gg <3gg@shellblade.net>2025-06-27 10:18:39 -0700
commitbd57f345ed9dbed1d81683e48199626de2ea9044 (patch)
tree4221f2f2a7ad2244d2e93052bd68187ec91b8ea9 /game/src/game.c
parent9a82ce0083437a4f9f58108b2c23b957d2249ad8 (diff)
Restructure projectHEADmain
Diffstat (limited to 'game/src/game.c')
-rw-r--r--game/src/game.c218
1 files changed, 0 insertions, 218 deletions
diff --git a/game/src/game.c b/game/src/game.c
deleted file mode 100644
index 51f5cbe..0000000
--- a/game/src/game.c
+++ /dev/null
@@ -1,218 +0,0 @@
1/*
2 * Main game module with entry point and game loop.
3 *
4 * The game module sets up the window and GL context and defers the core game
5 * logic to a plugin.
6 */
7#define _GNU_SOURCE 200112L // For readlink()
8
9#include "game.h"
10
11#include "plugins/plugin.h"
12
13#include <gfx/app.h>
14#include <gfx/core.h>
15#include <gfx/gfx.h>
16#include <gfx/renderer.h>
17
18#include <error.h>
19#include <log/log.h>
20#include <plugin.h>
21
22#include <assert.h>
23#include <stdbool.h>
24#include <stdio.h>
25#include <stdlib.h>
26
27#include <linux/limits.h>
28
29#include <unistd.h>
30
31#undef _GNU_SOURCE
32
33static const int WIDTH = 1350;
34static const int HEIGHT = 900;
35static const int MAX_FPS = 60;
36
37typedef struct GfxAppState {
38 Game game;
39} GfxAppState;
40
41/// Initialize the game's plugin.
42static bool init_plugin(Game* game) {
43 assert(game);
44 assert(game->plugin);
45 // Plugin state is allowed to be null, either when the plugin does not
46 // expose an init() or when init() does not initialize a state.
47 if (plugin_resolve(game->plugin, plugin_init, "init")) {
48 State* plugin_state = 0;
49 if (!plugin_call(game->plugin, plugin_init, "init", game, &plugin_state)) {
50 return false;
51 }
52 set_plugin_state(game->plugin, plugin_state);
53 }
54 return true; // Plugin does not need to expose an init().
55}
56
57/// Shutdown the game's plugin.
58/// The game's plugin is allowed to be null in the call to this function.
59static void shutdown_plugin(Game* game) {
60 assert(game);
61 if (game->plugin &&
62 (plugin_resolve(game->plugin, plugin_shutdown, "shutdown"))) {
63 void* plugin_state = get_plugin_state(game->plugin);
64 plugin_call(game->plugin, plugin_shutdown, "shutdown", game, plugin_state);
65 set_plugin_state(game->plugin, 0);
66 }
67}
68
69/// Boot the game's plugin.
70static bool boot_plugin(Game* game) {
71 assert(game);
72 assert(game->plugin);
73 if (plugin_resolve(game->plugin, plugin_boot, "boot")) {
74 void* plugin_state = get_plugin_state(game->plugin);
75 return plugin_call(game->plugin, plugin_boot, "boot", game, plugin_state);
76 }
77 return true; // Plugin does not need to expose a boot().
78}
79
80/// Update the plugin's state.
81static void update_plugin(Game* game, double t, double dt) {
82 assert(game);
83 assert(game->plugin);
84 if (plugin_resolve(game->plugin, plugin_update, "update")) {
85 void* plugin_state = get_plugin_state(game->plugin);
86 plugin_call(
87 game->plugin, plugin_update, "update", game, plugin_state, t, dt);
88 }
89}
90
91/// Plugin render.
92static void render_plugin(const Game* game) {
93 assert(game);
94 assert(game->plugin);
95 if (plugin_resolve(game->plugin, plugin_render, "render")) {
96 void* plugin_state = get_plugin_state(game->plugin);
97 plugin_call(game->plugin, plugin_render, "render", game, plugin_state);
98 }
99}
100
101/// Plugin resize.
102static void resize_plugin(Game* game, int width, int height) {
103 assert(game);
104 assert(game->plugin);
105 if (plugin_resolve(game->plugin, plugin_resize, "resize")) {
106 void* plugin_state = get_plugin_state(game->plugin);
107 plugin_call(
108 game->plugin, plugin_resize, "resize", game, plugin_state, width,
109 height);
110 }
111}
112
113static void Shutdown(Game* game);
114
115static bool Init(Game* game, int argc, const char** argv) {
116 assert(game);
117
118 if (argc <= 1) {
119 LOGE("Usage: %s <plugin> [plugin args]", argv[0]);
120 return false;
121 }
122
123 // Syntax: game <plugin> [plugin args]
124 //
125 // Here we consume the <plugin> arg so that plugins receive the remainder
126 // args starting from 0.
127 game->argc = argc - 1;
128 game->argv = argv + 1;
129
130 char exe_path_buf[NAME_MAX] = {0};
131 if (readlink("/proc/self/exe", exe_path_buf, sizeof(exe_path_buf)) == -1) {
132 LOGE("readlink(/proc/self/exe) failed");
133 goto cleanup;
134 }
135
136 // Replace the last / with a null terminator to remove the exe file from the
137 // path. This gets the file's parent directory.
138 *strrchr(exe_path_buf, '/') = 0;
139
140 const mstring exe_dir = mstring_make(exe_path_buf);
141 const mstring plugins_path = mstring_concat_cstr(exe_dir, "/src/plugins");
142
143 if (!(game->plugin_engine = new_plugin_engine(
144 &(PluginEngineDesc){.plugins_dir = mstring_cstr(&plugins_path)}))) {
145 goto cleanup;
146 }
147
148 const char* plugin = argv[1];
149 if (!(game->plugin = load_plugin(game->plugin_engine, plugin))) {
150 goto cleanup;
151 }
152
153 if (!(game->gfx = gfx_init())) {
154 goto cleanup;
155 }
156
157 if (!init_plugin(game)) {
158 goto cleanup;
159 }
160 if (!boot_plugin(game)) {
161 goto cleanup;
162 }
163
164 return true;
165
166cleanup:
167 LOGE("Gfx error: %s", get_error());
168 Shutdown(game);
169 return false;
170}
171
172static void Shutdown(Game* game) {
173 assert(game);
174 shutdown_plugin(game);
175 if (game->gfx) {
176 gfx_destroy(&game->gfx);
177 }
178 if (game->plugin) {
179 delete_plugin(&game->plugin);
180 }
181 if (game->plugin_engine) {
182 delete_plugin_engine(&game->plugin_engine);
183 }
184}
185
186static void Update(Game* game, double t, double dt) {
187 plugin_engine_update(game->plugin_engine);
188 if (plugin_reloaded(game->plugin)) {
189 shutdown_plugin(game);
190 const bool result = init_plugin(game);
191 assert(result); // TODO: handle error better.
192
193 // Trigger a resize just like the initial resize that occurs when the gfx
194 // application starts.
195 resize_plugin(game, game->width, game->height);
196 }
197
198 update_plugin(game, t, dt);
199}
200
201static void Render(const Game* game) {
202 GfxCore* gfxcore = gfx_get_core(game->gfx);
203 gfx_start_frame(gfxcore);
204 render_plugin(game);
205 gfx_end_frame(gfxcore);
206}
207
208static void Resize(Game* game, int width, int height) {
209 game->width = width;
210 game->height = height;
211
212 GfxCore* gfxcore = gfx_get_core(game->gfx);
213 gfx_set_viewport(gfxcore, 0, 0, width, height);
214
215 resize_plugin(game, width, height);
216}
217
218GFX_APP_MAIN(WIDTH, HEIGHT, MAX_FPS, "Game");