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