From 4212e57d06afac8a19b09fdebc24bad10b78f1ac Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Fri, 19 Jan 2024 07:21:45 -0800 Subject: Plugin refactor, moving scene from game to plugin. --- gltfview/src/plugins/gltf_view.c | 77 +++++++++++++++++++++---------- gltfview/src/plugins/gltf_view.h | 9 ---- gltfview/src/plugins/plugin.h | 59 ++++++++++++------------ gltfview/src/plugins/texture_view.c | 91 +++++++++++++++++++++++++++++++++---- gltfview/src/plugins/texture_view.h | 3 -- 5 files changed, 166 insertions(+), 73 deletions(-) delete mode 100644 gltfview/src/plugins/gltf_view.h delete mode 100644 gltfview/src/plugins/texture_view.h (limited to 'gltfview/src/plugins') diff --git a/gltfview/src/plugins/gltf_view.c b/gltfview/src/plugins/gltf_view.c index c3457a8..c19d1b8 100644 --- a/gltfview/src/plugins/gltf_view.c +++ b/gltfview/src/plugins/gltf_view.c @@ -1,6 +1,7 @@ -#include "gltf_view.h" +#include "plugin.h" #include +#include #include #include #include @@ -23,6 +24,11 @@ static const char* GIRL = #define DEFAULT_SCENE_FILE GIRL +struct State { + Scene* scene; + SceneCamera* camera; +}; + /// Load the skyquad texture. static Texture* load_environment_map(RenderBackend* render_backend) { return gfx_load_texture( @@ -57,15 +63,17 @@ static SceneNode* load_skyquad(RenderBackend* render_backend, SceneNode* root) { } /// Load the 3D scene. -static SceneNode* load_scene(Game* game, const char* scene_filepath) { +static SceneNode* load_scene( + Game* game, State* state, const char* scene_filepath) { assert(game); assert(game->gfx); - assert(game->scene); + assert(state); + assert(state->scene); - SceneNode* root = gfx_get_scene_root(game->scene); + SceneNode* root = gfx_get_scene_root(state->scene); RenderBackend* render_backend = gfx_get_render_backend(game->gfx); - Camera* camera = gfx_get_camera_camera(game->camera); + Camera* camera = gfx_get_camera_camera(state->camera); spatial3_set_position(&camera->spatial, vec3_make(0, 0, 2)); SceneNode* sky_light_node = load_skyquad(render_backend, root); @@ -85,16 +93,20 @@ static SceneNode* load_scene(Game* game, const char* scene_filepath) { return scene_node; } -State* init(Game* game) { +bool init(Game* game, State** pp_state) { assert(game); State* state = calloc(1, sizeof(State)); - return state; -} + if (!state) { + goto cleanup; + } -bool boot(State* state, Game* game) { - assert(state); - assert(game); + if (!(state->scene = gfx_make_scene())) { + goto cleanup; + } + if (!(state->camera = gfx_make_camera())) { + goto cleanup; + } const int argc = game->argc; const char** argv = game->argv; @@ -102,27 +114,44 @@ bool boot(State* state, Game* game) { // Usage: const char* scene_filepath = argc > 1 ? argv[1] : DEFAULT_SCENE_FILE; - SceneNode* node = load_scene(game, scene_filepath); + SceneNode* node = load_scene(game, state, scene_filepath); if (!node) { - return false; + goto cleanup; } Anima* anima = gfx_get_node_anima(node); gfx_play_animation( anima, &(AnimationPlaySettings){.name = "Walk", .loop = true}); + *pp_state = state; return true; + +cleanup: + shutdown(game, state); + if (state) { + free(state); + } + return false; } -void update(State* state, Game* game, double t, double dt) { - assert(state); +void shutdown(Game* game, State* state) { + assert(game); + if (state) { + gfx_destroy_camera(&state->camera); + gfx_destroy_scene(&state->scene); + // State freed by plugin engine. + } +} + +void update(Game* game, State* state, double t, double dt) { assert(game); - assert(game->scene); - assert(game->camera); + assert(state); + assert(state->scene); + assert(state->camera); - gfx_animate_scene(game->scene, (R)t); + gfx_animate_scene(state->scene, (R)t); const vec3 orbit_point = vec3_make(0, 2, 0); - Camera* camera = gfx_get_camera_camera(game->camera); + Camera* camera = gfx_get_camera_camera(state->camera); spatial3_orbit( &camera->spatial, orbit_point, /*radius=*/2.5, @@ -150,18 +179,18 @@ static void render_bounding_boxes(ImmRenderer* imm, const SceneNode* node) { } } -void render(State* state, const Game* game) { +void render(const Game* game, const State* state) { assert(state); assert(game); assert(game->gfx); - assert(game->scene); - assert(game->camera); + assert(state->scene); + assert(state->camera); ImmRenderer* imm = gfx_get_imm_renderer(game->gfx); assert(imm); gfx_imm_start(imm); - gfx_imm_set_camera(imm, gfx_get_camera_camera(game->camera)); + gfx_imm_set_camera(imm, gfx_get_camera_camera(state->camera)); gfx_imm_set_colour(imm, vec4_make(0.2, 0.2, 1.0, 0.3)); - render_bounding_boxes(imm, gfx_get_scene_root(game->scene)); + render_bounding_boxes(imm, gfx_get_scene_root(state->scene)); gfx_imm_end(imm); } diff --git a/gltfview/src/plugins/gltf_view.h b/gltfview/src/plugins/gltf_view.h deleted file mode 100644 index 670d88d..0000000 --- a/gltfview/src/plugins/gltf_view.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "plugin.h" - -#include - -typedef struct State { - int unused; -} State; diff --git a/gltfview/src/plugins/plugin.h b/gltfview/src/plugins/plugin.h index 0e0e12c..a2632cd 100644 --- a/gltfview/src/plugins/plugin.h +++ b/gltfview/src/plugins/plugin.h @@ -1,21 +1,5 @@ /* * Game plugin. - * - * A game plugin exposes three functions: - * - boot(): called once when the plugin is first loaded during the lifetime of - * the game. - * - init() -> state: creates and returns the plugin's state. - * - update(state): takes and updates the state, possibly with side effects. - * - render(): performs custom rendering. - * - * boot() is convenient for one-time initialization of the scene. - * - * init() is called every time the plugin is loaded. It is assumed that the - * plugin's state is encapsulated in the object returned. - * - * update() updates the plugin state and has side effects on the scene. It is - * assumed that update does not reference any global, mutable state outside of - * the scene and the plugin state returned by init(). */ #pragma once @@ -28,22 +12,41 @@ typedef struct State State; -/// Initialize the plugin's state. -State* init(Game*); +/// Initialize the plugin, which may optionally return a state object. +/// +/// This function is called every time the plugin is (re)loaded. +/// +/// It is assumed that the plugin's state is fully encapsulated in the returned +/// state object. The plugin should not store any (mutable) state outside of the +/// returned state object (e.g., no mutable global variables.) +bool init(Game*, State**); + +/// Shut down the plugin. +/// +/// This function is called before the plugin is unloaded. +/// +/// The plugin should perform any destruction needed, but not free the state +/// object; freeing the state object's memory is handled by the caller. +void shutdown(Game*, State*); /// Function called the first time the plugin is loaded throughout the -/// application's lifetime. Allows the plugin to do one-time initialization of -/// the game state. -bool boot(State*, Game*); +/// application's lifetime. This allows the plugin to do one-time initialization +/// of the game state. +bool boot(Game*, State*); /// Update the plugin's and the game's state. -void update(State*, Game*, double t, double dt); +void update(Game*, State*, double t, double dt); -/// Optional plugin rendering hook. -void render(State*, const Game*); +/// Render hook. +void render(const Game*, const State*); + +/// Called when the game's window is resized. +void resize(Game* game, State* state, int width, int height); // Signatures for the plugin's exposed functions. -typedef void* (*plugin_init)(Game*); -typedef bool (*plugin_boot)(State*, Game*); -typedef void (*plugin_update)(State*, Game*, double t, double dt); -typedef void (*plugin_render)(State*, const Game*); +typedef bool (*plugin_init)(Game*, State**); +typedef bool (*plugin_shutdown)(Game*, State*); +typedef bool (*plugin_boot)(Game*, State*); +typedef void (*plugin_update)(Game*, State*, double t, double dt); +typedef void (*plugin_render)(const Game*, const State*); +typedef void (*plugin_resize)(Game* game, State* state, int width, int height); diff --git a/gltfview/src/plugins/texture_view.c b/gltfview/src/plugins/texture_view.c index f16c8d1..b424158 100644 --- a/gltfview/src/plugins/texture_view.c +++ b/gltfview/src/plugins/texture_view.c @@ -1,6 +1,7 @@ -#include "texture_view.h" +#include "plugin.h" #include +#include #include #include #include @@ -9,13 +10,25 @@ #include #include +#include // Default texture to load if no texture is provided. static const char* DEFAULT_TEXTURE = "/assets/skybox/clouds1/clouds1_west.bmp"; // static const char* DEFAULT_TEXTURE = "/assets/checkerboard.jpg"; -bool boot(State* state, Game* game) { +struct State { + Scene* scene; + SceneCamera* camera; +}; + +bool init(Game* game, State** pp_state) { assert(game); + assert(pp_state); + + State* state = calloc(1, sizeof(State)); + if (!state) { + goto cleanup; + } // Usage: [texture file] const char* texture_file = game->argc > 1 ? game->argv[1] : DEFAULT_TEXTURE; @@ -30,17 +43,17 @@ bool boot(State* state, Game* game) { .mipmaps = false, .data.texture.filepath = mstring_make(texture_file)}); if (!texture) { - return false; + goto cleanup; } ShaderProgram* shader = gfx_make_view_texture_shader(render_backend); if (!shader) { - return false; + goto cleanup; } Geometry* geometry = gfx_make_quad_11(render_backend); if (!geometry) { - return false; + goto cleanup; } MaterialDesc material_desc = (MaterialDesc){.num_uniforms = 1}; @@ -50,25 +63,85 @@ bool boot(State* state, Game* game) { .name = sstring_make("Texture")}; Material* material = gfx_make_material(&material_desc); if (!material) { - return false; + goto cleanup; } const MeshDesc mesh_desc = (MeshDesc){.geometry = geometry, .material = material, .shader = shader}; Mesh* mesh = gfx_make_mesh(&mesh_desc); if (!mesh) { - return false; + goto cleanup; } SceneObject* object = gfx_make_object(); if (!object) { - return false; + goto cleanup; } gfx_add_object_mesh(object, mesh); + if (!(state->scene = gfx_make_scene())) { + goto cleanup; + } + SceneNode* node = gfx_make_object_node(object); - SceneNode* root = gfx_get_scene_root(game->scene); + if (!node) { + goto cleanup; + } + SceneNode* root = gfx_get_scene_root(state->scene); + if (!root) { + goto cleanup; + } gfx_set_node_parent(node, root); + if (!(state->camera = gfx_make_camera())) { + goto cleanup; + } + + *pp_state = state; return true; + +cleanup: + shutdown(game, state); + if (state) { + free(state); + } + return false; +} + +void shutdown(Game* game, State* state) { + assert(game); + if (state) { + gfx_destroy_camera(&state->camera); + gfx_destroy_scene(&state->scene); + // State freed by plugin engine. + } +} + +void render(const Game* game, const State* state) { + assert(game); + assert(state); + + Renderer* renderer = gfx_get_renderer(game->gfx); + gfx_render_scene( + renderer, &(RenderSceneParams){ + .mode = RenderDefault, + .scene = state->scene, + .camera = state->camera}); +} + +void resize(Game* game, State* state, int width, int height) { + assert(game); + assert(state); + + RenderBackend* render_backend = gfx_get_render_backend(game->gfx); + gfx_set_viewport(render_backend, width, height); + + const R fovy = 90 * TO_RAD; + const R aspect = (R)width / (R)height; + const R near = 0.1; + const R far = 1000; + const mat4 projection = mat4_perspective(fovy, aspect, near, far); + + Camera* camera = gfx_get_camera_camera(state->camera); + camera->projection = projection; } diff --git a/gltfview/src/plugins/texture_view.h b/gltfview/src/plugins/texture_view.h deleted file mode 100644 index 956f34a..0000000 --- a/gltfview/src/plugins/texture_view.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once - -#include "plugin.h" -- cgit v1.2.3