summaryrefslogtreecommitdiff
path: root/gltfview/src/plugins
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-06-16 09:38:15 -0700
committer3gg <3gg@shellblade.net>2023-06-16 09:38:15 -0700
commit520e4e67cd9ff53f3c3512c80d07193625e07e3e (patch)
treef2f8acfc2eb0d2aa279263d93af00beef7e93a1b /gltfview/src/plugins
parent14e6edd6bfe94089d52b5c4b6899dea23923e9be (diff)
New plugin architecture.
Diffstat (limited to 'gltfview/src/plugins')
-rw-r--r--gltfview/src/plugins/CMakeLists.txt17
-rw-r--r--gltfview/src/plugins/gltf_view.c167
-rw-r--r--gltfview/src/plugins/gltf_view.h9
-rw-r--r--gltfview/src/plugins/plugin.h49
-rw-r--r--gltfview/src/plugins/texture_view.c94
-rw-r--r--gltfview/src/plugins/texture_view.h9
6 files changed, 345 insertions, 0 deletions
diff --git a/gltfview/src/plugins/CMakeLists.txt b/gltfview/src/plugins/CMakeLists.txt
new file mode 100644
index 0000000..ecb2a45
--- /dev/null
+++ b/gltfview/src/plugins/CMakeLists.txt
@@ -0,0 +1,17 @@
1cmake_minimum_required(VERSION 3.0)
2
3project(plugins)
4
5set(LINK_LIBRARIES cstring math gfx)
6
7add_library(gltf_view SHARED
8 gltf_view.c)
9
10add_library(texture_view SHARED
11 texture_view.c)
12
13target_link_libraries(gltf_view PUBLIC
14 ${LINK_LIBRARIES})
15
16target_link_libraries(texture_view PUBLIC
17 ${LINK_LIBRARIES})
diff --git a/gltfview/src/plugins/gltf_view.c b/gltfview/src/plugins/gltf_view.c
new file mode 100644
index 0000000..511c2e8
--- /dev/null
+++ b/gltfview/src/plugins/gltf_view.c
@@ -0,0 +1,167 @@
1#include "gltf_view.h"
2
3#include <gfx/renderer.h>
4#include <gfx/util/scene.h>
5#include <gfx/util/skyquad.h>
6#include <gfx/util/texture.h>
7#include <math/camera.h>
8#include <math/spatial3.h>
9
10#include <stdlib.h>
11
12// Paths to various scene files.
13/*static const char* BOX = "/assets/models/box.gltf";
14static const char* SUZANNE = "/assets/models/suzanne.gltf";
15static const char* SPONZA =
16 "/assets/glTF-Sample-Models/2.0/Sponza/glTF/Sponza.gltf";
17static const char* FLIGHT_HELMET =
18 "/assets/glTF-Sample-Models/2.0/FlightHelmet/glTF/FlightHelmet.gltf";
19static const char* DAMAGED_HELMET =
20 "/assets/glTF-Sample-Models/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf";*/
21static const char* GIRL =
22 "/home/jeanne/Nextcloud/assets/models/girl/girl-with-ground.gltf";
23
24#define DEFAULT_SCENE_FILE GIRL
25
26/// Load the skyquad texture.
27static Texture* load_environment_map(RenderBackend* render_backend) {
28 return gfx_load_texture(
29 render_backend,
30 &(LoadTextureCmd){
31 .origin = TextureFromFile,
32 .type = LoadCubemap,
33 .colour_space = sRGB,
34 .filtering = NearestFiltering,
35 .mipmaps = false,
36 .data.cubemap.filepaths = {
37 mstring_make("/assets/skybox/clouds1/clouds1_east.bmp"),
38 mstring_make("/assets/skybox/clouds1/clouds1_west.bmp"),
39 mstring_make("/assets/skybox/clouds1/clouds1_up.bmp"),
40 mstring_make("/assets/skybox/clouds1/clouds1_down.bmp"),
41 mstring_make("/assets/skybox/clouds1/clouds1_south.bmp"),
42 mstring_make("/assets/skybox/clouds1/clouds1_north.bmp")}
43 });
44}
45
46/// Load the skyquad and return the environment light node.
47static SceneNode* load_skyquad(RenderBackend* render_backend, SceneNode* root) {
48 assert(render_backend);
49 assert(root);
50
51 Texture* environment_map = load_environment_map(render_backend);
52 if (!environment_map) {
53 return 0;
54 }
55
56 return gfx_setup_skyquad(render_backend, root, environment_map);
57}
58
59/// Load the 3D scene.
60static SceneNode* load_scene(Game* game, const char* scene_filepath) {
61 assert(game);
62 assert(game->gfx);
63 assert(game->scene);
64
65 SceneNode* root = gfx_get_scene_root(game->scene);
66 RenderBackend* render_backend = gfx_get_render_backend(game->gfx);
67
68 Camera* camera = gfx_get_camera_camera(game->camera);
69 spatial3_set_position(&camera->spatial, vec3_make(0, 0, 2));
70
71 SceneNode* sky_light_node = load_skyquad(render_backend, root);
72 if (!sky_light_node) {
73 return 0;
74 }
75
76 SceneNode* scene_node = gfx_load_scene(
77 game->gfx, sky_light_node,
78 &(LoadSceneCmd){.origin = SceneFromFile, .filepath = scene_filepath});
79 if (!scene_node) {
80 return 0;
81 }
82
83 gfx_log_node_hierarchy(root);
84
85 return scene_node;
86}
87
88State* init(Game* game) {
89 assert(game);
90
91 State* state = calloc(1, sizeof(State));
92 return state;
93}
94
95bool boot(State* state, Game* game) {
96 assert(state);
97 assert(game);
98
99 const int argc = game->argc;
100 const char** argv = game->argv;
101
102 // Usage: <scene file>
103 const char* scene_filepath = argc > 1 ? argv[1] : DEFAULT_SCENE_FILE;
104
105 SceneNode* node = load_scene(game, scene_filepath);
106 if (!node) {
107 return false;
108 }
109 Anima* anima = gfx_get_node_anima(node);
110 gfx_play_animation(
111 anima, &(AnimationPlaySettings){.name = "Walk", .loop = true});
112
113 return true;
114}
115
116void update(State* state, Game* game, double t, double dt) {
117 assert(state);
118 assert(game);
119 assert(game->scene);
120 assert(game->camera);
121
122 gfx_animate_scene(game->scene, (R)t);
123
124 const vec3 orbit_point = vec3_make(0, 2, 0);
125 Camera* camera = gfx_get_camera_camera(game->camera);
126 spatial3_orbit(
127 &camera->spatial, orbit_point,
128 /*radius=*/2.5,
129 /*azimuth=*/t * 0.5, /*zenith=*/0);
130 spatial3_lookat(&camera->spatial, orbit_point);
131}
132
133/// Render the bounding boxes of all scene objects.
134static void render_bounding_boxes(ImmRenderer* imm, const SceneNode* node) {
135 if (gfx_get_node_type(node) == ObjectNode) {
136 // TODO: Look at the scene log. The JointNodes are detached from the
137 // ObjectNodes. This is why the boxes are not being transformed as expected
138 // here. Anima needs to animate boxes? Use OOBB in addition to AABB?
139 const mat4 model = gfx_get_node_global_transform(node);
140 const SceneObject* obj = gfx_get_node_object(node);
141 const aabb3 box = gfx_calc_object_aabb(obj);
142 gfx_imm_set_model_matrix(imm, &model);
143 gfx_imm_draw_aabb(imm, box);
144 }
145
146 // Render children's boxes.
147 for (NodeIter it = gfx_get_node_child(node); it;
148 it = gfx_get_next_child(it)) {
149 render_bounding_boxes(imm, gfx_get_iter_node(it));
150 }
151}
152
153void render(State* state, const Game* game) {
154 assert(state);
155 assert(game);
156 assert(game->gfx);
157 assert(game->scene);
158 assert(game->camera);
159
160 ImmRenderer* imm = gfx_get_imm_renderer(game->gfx);
161 assert(imm);
162 gfx_imm_start(imm);
163 gfx_imm_set_camera(imm, gfx_get_camera_camera(game->camera));
164 gfx_imm_set_colour(imm, vec4_make(0.2, 0.2, 1.0, 0.3));
165 render_bounding_boxes(imm, gfx_get_scene_root(game->scene));
166 gfx_imm_end(imm);
167}
diff --git a/gltfview/src/plugins/gltf_view.h b/gltfview/src/plugins/gltf_view.h
new file mode 100644
index 0000000..670d88d
--- /dev/null
+++ b/gltfview/src/plugins/gltf_view.h
@@ -0,0 +1,9 @@
1#pragma once
2
3#include "plugin.h"
4
5#include <gfx/scene.h>
6
7typedef struct State {
8 int unused;
9} State;
diff --git a/gltfview/src/plugins/plugin.h b/gltfview/src/plugins/plugin.h
new file mode 100644
index 0000000..0e0e12c
--- /dev/null
+++ b/gltfview/src/plugins/plugin.h
@@ -0,0 +1,49 @@
1/*
2 * Game plugin.
3 *
4 * A game plugin exposes three functions:
5 * - boot(): called once when the plugin is first loaded during the lifetime of
6 * the game.
7 * - init() -> state: creates and returns the plugin's state.
8 * - update(state): takes and updates the state, possibly with side effects.
9 * - render(): performs custom rendering.
10 *
11 * boot() is convenient for one-time initialization of the scene.
12 *
13 * init() is called every time the plugin is loaded. It is assumed that the
14 * plugin's state is encapsulated in the object returned.
15 *
16 * update() updates the plugin state and has side effects on the scene. It is
17 * assumed that update does not reference any global, mutable state outside of
18 * the scene and the plugin state returned by init().
19 */
20#pragma once
21
22#include "../game.h"
23
24#include <gfx/gfx.h>
25#include <gfx/scene.h>
26
27#include <stdbool.h>
28
29typedef struct State State;
30
31/// Initialize the plugin's state.
32State* init(Game*);
33
34/// Function called the first time the plugin is loaded throughout the
35/// application's lifetime. Allows the plugin to do one-time initialization of
36/// the game state.
37bool boot(State*, Game*);
38
39/// Update the plugin's and the game's state.
40void update(State*, Game*, double t, double dt);
41
42/// Optional plugin rendering hook.
43void render(State*, const Game*);
44
45// Signatures for the plugin's exposed functions.
46typedef void* (*plugin_init)(Game*);
47typedef bool (*plugin_boot)(State*, Game*);
48typedef void (*plugin_update)(State*, Game*, double t, double dt);
49typedef void (*plugin_render)(State*, const Game*);
diff --git a/gltfview/src/plugins/texture_view.c b/gltfview/src/plugins/texture_view.c
new file mode 100644
index 0000000..f2c650f
--- /dev/null
+++ b/gltfview/src/plugins/texture_view.c
@@ -0,0 +1,94 @@
1#include "texture_view.h"
2
3#include <gfx/render_backend.h>
4#include <gfx/util/geometry.h>
5#include <gfx/util/shader.h>
6#include <gfx/util/texture.h>
7
8#include <math/camera.h>
9
10#include <assert.h>
11#include <stdlib.h>
12
13// Default texture to load if no texture is provided.
14static const char* CLOUDS1_TEXTURE = "/assets/skybox/clouds1/clouds1_west.bmp";
15
16State* init(Game* game) {
17 assert(game);
18
19 State* state = calloc(1, sizeof(State));
20 return state;
21}
22
23bool boot(State* state, Game* game) {
24 assert(state);
25 assert(game);
26
27 // Usage: [texture file]
28 const char* texture_file = game->argc > 1 ? game->argv[1] : CLOUDS1_TEXTURE;
29
30 RenderBackend* render_backend = gfx_get_render_backend(game->gfx);
31
32 Texture* texture = gfx_load_texture(
33 render_backend, &(LoadTextureCmd){
34 .origin = TextureFromFile,
35 .type = LoadTexture,
36 .filtering = LinearFiltering,
37 .mipmaps = false,
38 .data.texture.filepath = mstring_make(texture_file)});
39
40 Camera* camera = gfx_get_camera_camera(game->camera);
41 spatial3_set_position(&camera->spatial, vec3_make(0, 0, 1));
42
43 ShaderProgram* shader = gfx_make_view_texture_shader(render_backend);
44 if (!shader) {
45 return false;
46 }
47
48 Geometry* geometry = gfx_make_quad_11(render_backend);
49 if (!geometry) {
50 return false;
51 }
52
53 MaterialDesc material_desc = (MaterialDesc){0};
54 material_desc.uniforms[0] = (ShaderUniform){
55 .type = UniformTexture,
56 .value.texture = texture,
57 .name = sstring_make("Texture")};
58 material_desc.num_uniforms = 1;
59 Material* material = gfx_make_material(&material_desc);
60 if (!material) {
61 return false;
62 }
63
64 MeshDesc mesh_desc = (MeshDesc){0};
65 mesh_desc.geometry = geometry;
66 mesh_desc.material = material;
67 mesh_desc.shader = shader;
68 Mesh* mesh = gfx_make_mesh(&mesh_desc);
69 if (!mesh) {
70 return false;
71 }
72
73 SceneObject* object = gfx_make_object();
74 if (!object) {
75 return false;
76 }
77 gfx_add_object_mesh(object, mesh);
78
79 SceneNode* node = gfx_make_object_node(object);
80 SceneNode* root = gfx_get_scene_root(game->scene);
81 gfx_set_node_parent(node, root);
82
83 return true;
84}
85
86void update(State* state, Game* game, double t, double dt) {
87 assert(state);
88 assert(game);
89}
90
91void render(State* state, const Game* game) {
92 assert(state);
93 assert(game);
94}
diff --git a/gltfview/src/plugins/texture_view.h b/gltfview/src/plugins/texture_view.h
new file mode 100644
index 0000000..670d88d
--- /dev/null
+++ b/gltfview/src/plugins/texture_view.h
@@ -0,0 +1,9 @@
1#pragma once
2
3#include "plugin.h"
4
5#include <gfx/scene.h>
6
7typedef struct State {
8 int unused;
9} State;