diff options
Diffstat (limited to 'gfx/src/scene')
-rw-r--r-- | gfx/src/scene/camera.c | 42 | ||||
-rw-r--r-- | gfx/src/scene/camera_impl.h | 12 | ||||
-rw-r--r-- | gfx/src/scene/light.c | 45 | ||||
-rw-r--r-- | gfx/src/scene/light_impl.h | 25 | ||||
-rw-r--r-- | gfx/src/scene/material.c | 57 | ||||
-rw-r--r-- | gfx/src/scene/material_impl.h | 17 | ||||
-rw-r--r-- | gfx/src/scene/mesh.c | 25 | ||||
-rw-r--r-- | gfx/src/scene/mesh_impl.h | 11 | ||||
-rw-r--r-- | gfx/src/scene/node.c | 115 | ||||
-rw-r--r-- | gfx/src/scene/node_impl.h | 38 | ||||
-rw-r--r-- | gfx/src/scene/object.c | 71 | ||||
-rw-r--r-- | gfx/src/scene/object_impl.h | 25 | ||||
-rw-r--r-- | gfx/src/scene/scene.c | 43 | ||||
-rw-r--r-- | gfx/src/scene/scene_graph.h | 67 | ||||
-rw-r--r-- | gfx/src/scene/scene_impl.h | 17 | ||||
-rw-r--r-- | gfx/src/scene/scene_memory.c | 148 | ||||
-rw-r--r-- | gfx/src/scene/scene_memory.h | 130 | ||||
-rw-r--r-- | gfx/src/scene/types.h | 21 |
18 files changed, 909 insertions, 0 deletions
diff --git a/gfx/src/scene/camera.c b/gfx/src/scene/camera.c new file mode 100644 index 0000000..df161c2 --- /dev/null +++ b/gfx/src/scene/camera.c | |||
@@ -0,0 +1,42 @@ | |||
1 | #include "camera_impl.h" | ||
2 | |||
3 | #include "node_impl.h" | ||
4 | #include "scene_memory.h" | ||
5 | |||
6 | #include <assert.h> | ||
7 | |||
8 | static void scene_camera_make(SceneCamera* camera) { | ||
9 | assert(camera); | ||
10 | camera->camera = | ||
11 | camera_perspective(/*fovy=*/90.0 * TO_RAD, /*aspect=*/16.0 / 9.0, | ||
12 | /*near=*/0.1, /*far=*/1000); | ||
13 | } | ||
14 | |||
15 | SceneCamera* gfx_make_camera() { | ||
16 | SceneCamera* camera = mem_alloc_camera(); | ||
17 | if (!camera) { | ||
18 | return 0; | ||
19 | } | ||
20 | scene_camera_make(camera); | ||
21 | return camera; | ||
22 | } | ||
23 | |||
24 | void gfx_destroy_camera(SceneCamera** camera) { | ||
25 | assert(camera); | ||
26 | assert(*camera); | ||
27 | if ((*camera)->parent.val) { | ||
28 | gfx_del_node((*camera)->parent); | ||
29 | } | ||
30 | mem_free_camera(camera); | ||
31 | } | ||
32 | |||
33 | void gfx_set_camera_camera(SceneCamera* scene_camera, Camera* camera) { | ||
34 | assert(scene_camera); | ||
35 | assert(camera); | ||
36 | scene_camera->camera = *camera; | ||
37 | } | ||
38 | |||
39 | Camera* gfx_get_camera_camera(SceneCamera* camera) { | ||
40 | assert(camera); | ||
41 | return &camera->camera; | ||
42 | } | ||
diff --git a/gfx/src/scene/camera_impl.h b/gfx/src/scene/camera_impl.h new file mode 100644 index 0000000..20c3890 --- /dev/null +++ b/gfx/src/scene/camera_impl.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/camera.h> | ||
4 | |||
5 | #include "types.h" | ||
6 | |||
7 | #include <math/camera.h> | ||
8 | |||
9 | typedef struct SceneCamera { | ||
10 | Camera camera; | ||
11 | node_idx parent; // Parent SceneNode. | ||
12 | } SceneCamera; | ||
diff --git a/gfx/src/scene/light.c b/gfx/src/scene/light.c new file mode 100644 index 0000000..2ca1a01 --- /dev/null +++ b/gfx/src/scene/light.c | |||
@@ -0,0 +1,45 @@ | |||
1 | #include "light_impl.h" | ||
2 | |||
3 | #include "node_impl.h" | ||
4 | #include "scene_memory.h" | ||
5 | |||
6 | #include <gfx/error.h> | ||
7 | |||
8 | static void make_environment_light(Light* light, | ||
9 | const EnvironmentLightDesc* desc) { | ||
10 | assert(light); | ||
11 | assert(desc); | ||
12 | |||
13 | light->type = EnvironmentLightType; | ||
14 | light->environment.environment_map = desc->environment_map; | ||
15 | } | ||
16 | |||
17 | Light* gfx_make_light(const LightDesc* desc) { | ||
18 | assert(desc); | ||
19 | |||
20 | Light* light = mem_alloc_light(); | ||
21 | if (!light) { | ||
22 | return 0; | ||
23 | } | ||
24 | |||
25 | switch (desc->type) { | ||
26 | case EnvironmentLightType: | ||
27 | make_environment_light(light, &desc->light.environment); | ||
28 | break; | ||
29 | default: | ||
30 | gfx_set_error("Unhandled light type"); | ||
31 | gfx_destroy_light(&light); | ||
32 | return 0; | ||
33 | } | ||
34 | |||
35 | return light; | ||
36 | } | ||
37 | |||
38 | void gfx_destroy_light(Light** light) { | ||
39 | assert(light); | ||
40 | assert(*light); | ||
41 | if ((*light)->parent.val) { | ||
42 | gfx_del_node((*light)->parent); | ||
43 | } | ||
44 | mem_free_light(light); | ||
45 | } | ||
diff --git a/gfx/src/scene/light_impl.h b/gfx/src/scene/light_impl.h new file mode 100644 index 0000000..1aa0bb4 --- /dev/null +++ b/gfx/src/scene/light_impl.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/light.h> | ||
4 | |||
5 | #include "types.h" | ||
6 | |||
7 | typedef struct Texture Texture; | ||
8 | |||
9 | /// An environment light. | ||
10 | typedef struct EnvironmentLight { | ||
11 | const Texture* environment_map; | ||
12 | const Texture* irradiance_map; // Renderer implementation. | ||
13 | const Texture* prefiltered_environment_map; // Renderer implementation. | ||
14 | int max_reflection_lod; // Mandatory when prefiltered_environment_map is | ||
15 | // given. | ||
16 | } EnvironmentLight; | ||
17 | |||
18 | /// A scene light. | ||
19 | typedef struct Light { | ||
20 | LightType type; | ||
21 | union { | ||
22 | EnvironmentLight environment; | ||
23 | }; | ||
24 | node_idx parent; // Parent SceneNode. | ||
25 | } Light; | ||
diff --git a/gfx/src/scene/material.c b/gfx/src/scene/material.c new file mode 100644 index 0000000..d44746a --- /dev/null +++ b/gfx/src/scene/material.c | |||
@@ -0,0 +1,57 @@ | |||
1 | #include "material_impl.h" | ||
2 | |||
3 | #include "scene_memory.h" | ||
4 | |||
5 | #include <gfx/render_backend.h> | ||
6 | |||
7 | static void material_make(Material* material, const MaterialDesc* desc) { | ||
8 | assert(material); | ||
9 | assert(desc); | ||
10 | assert(desc->num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); | ||
11 | material->shader = desc->shader; | ||
12 | material->num_uniforms = desc->num_uniforms; | ||
13 | for (int i = 0; i < desc->num_uniforms; ++i) { | ||
14 | material->uniforms[i] = desc->uniforms[i]; | ||
15 | } | ||
16 | } | ||
17 | |||
18 | Material* gfx_make_material(const MaterialDesc* desc) { | ||
19 | assert(desc); | ||
20 | Material* material = mem_alloc_material(); | ||
21 | if (!material) { | ||
22 | return 0; | ||
23 | } | ||
24 | material_make(material, desc); | ||
25 | return material; | ||
26 | } | ||
27 | |||
28 | void gfx_destroy_material(Material** material) { mem_free_material(material); } | ||
29 | |||
30 | static void set_uniform(ShaderProgram* prog, const ShaderUniform* uniform) { | ||
31 | switch (uniform->type) { | ||
32 | case UniformTexture: | ||
33 | gfx_set_texture_uniform(prog, uniform->name.str, uniform->value.texture); | ||
34 | break; | ||
35 | case UniformMat4: | ||
36 | gfx_set_mat4_uniform(prog, uniform->name.str, &uniform->value.mat4); | ||
37 | break; | ||
38 | case UniformVec3: | ||
39 | gfx_set_vec3_uniform(prog, uniform->name.str, uniform->value.vec3); | ||
40 | break; | ||
41 | case UniformVec4: | ||
42 | gfx_set_vec4_uniform(prog, uniform->name.str, uniform->value.vec4); | ||
43 | break; | ||
44 | case UniformFloat: | ||
45 | gfx_set_float_uniform(prog, uniform->name.str, uniform->value.scalar); | ||
46 | break; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | void material_activate(const Material* material) { | ||
51 | assert(material); | ||
52 | gfx_activate_shader_program(material->shader); | ||
53 | for (int i = 0; i < material->num_uniforms; ++i) { | ||
54 | const ShaderUniform* uniform = &material->uniforms[i]; | ||
55 | set_uniform(material->shader, uniform); | ||
56 | } | ||
57 | } | ||
diff --git a/gfx/src/scene/material_impl.h b/gfx/src/scene/material_impl.h new file mode 100644 index 0000000..c680ccf --- /dev/null +++ b/gfx/src/scene/material_impl.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/material.h> | ||
4 | |||
5 | typedef struct ShaderProgram ShaderProgram; | ||
6 | |||
7 | typedef struct Material { | ||
8 | ShaderProgram* shader; | ||
9 | ShaderUniform uniforms[GFX_MAX_UNIFORMS_PER_MATERIAL]; | ||
10 | int num_uniforms; | ||
11 | } Material; | ||
12 | |||
13 | /// Activate the material. | ||
14 | /// | ||
15 | /// This activates the material's shader and configures the shader uniforms that | ||
16 | /// are specific to the material. | ||
17 | void material_activate(const Material* material); | ||
diff --git a/gfx/src/scene/mesh.c b/gfx/src/scene/mesh.c new file mode 100644 index 0000000..722eae7 --- /dev/null +++ b/gfx/src/scene/mesh.c | |||
@@ -0,0 +1,25 @@ | |||
1 | #include "mesh_impl.h" | ||
2 | |||
3 | #include "scene_memory.h" | ||
4 | |||
5 | #include <assert.h> | ||
6 | |||
7 | static void mesh_make(Mesh* mesh, const MeshDesc* desc) { | ||
8 | assert(mesh); | ||
9 | assert(desc); | ||
10 | assert(desc->geometry); | ||
11 | assert(desc->material); | ||
12 | mesh->geometry = desc->geometry; | ||
13 | mesh->material = desc->material; | ||
14 | } | ||
15 | |||
16 | Mesh* gfx_make_mesh(const MeshDesc* desc) { | ||
17 | Mesh* mesh = mem_alloc_mesh(); | ||
18 | if (!mesh) { | ||
19 | return 0; | ||
20 | } | ||
21 | mesh_make(mesh, desc); | ||
22 | return mesh; | ||
23 | } | ||
24 | |||
25 | void gfx_destroy_mesh(Mesh** mesh) { mem_free_mesh(mesh); } | ||
diff --git a/gfx/src/scene/mesh_impl.h b/gfx/src/scene/mesh_impl.h new file mode 100644 index 0000000..858b147 --- /dev/null +++ b/gfx/src/scene/mesh_impl.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/mesh.h> | ||
4 | |||
5 | typedef struct Mesh { | ||
6 | const Geometry* geometry; | ||
7 | const Material* material; | ||
8 | } Mesh; | ||
9 | |||
10 | // TODO: a mesh_render() that takes a transform, applies the material and the | ||
11 | // transform, and then renders the geometry. | ||
diff --git a/gfx/src/scene/node.c b/gfx/src/scene/node.c new file mode 100644 index 0000000..7d7f69f --- /dev/null +++ b/gfx/src/scene/node.c | |||
@@ -0,0 +1,115 @@ | |||
1 | #include "node_impl.h" | ||
2 | |||
3 | #include "camera_impl.h" | ||
4 | #include "light_impl.h" | ||
5 | #include "object_impl.h" | ||
6 | #include "scene_graph.h" | ||
7 | #include "scene_memory.h" | ||
8 | |||
9 | #include <assert.h> | ||
10 | |||
11 | static void scene_node_make(SceneNode* node) { | ||
12 | assert(node); | ||
13 | node->type = LogicalNode; | ||
14 | node->transform = mat4_id(); | ||
15 | } | ||
16 | |||
17 | SceneNode* gfx_make_node() { | ||
18 | SceneNode* node = mem_alloc_node(); | ||
19 | if (!node) { | ||
20 | return 0; | ||
21 | } | ||
22 | scene_node_make(node); | ||
23 | return node; | ||
24 | } | ||
25 | |||
26 | SceneNode* gfx_make_camera_node(SceneCamera* camera) { | ||
27 | assert(camera); | ||
28 | SceneNode* node = gfx_make_node(); | ||
29 | if (!node) { | ||
30 | return 0; | ||
31 | } | ||
32 | node->type = CameraNode; | ||
33 | node->camera = mem_get_camera_index(camera); | ||
34 | camera->parent = mem_get_node_index(node); | ||
35 | return node; | ||
36 | } | ||
37 | |||
38 | SceneNode* gfx_make_light_node(Light* light) { | ||
39 | assert(light); | ||
40 | SceneNode* node = gfx_make_node(); | ||
41 | if (!node) { | ||
42 | return 0; | ||
43 | } | ||
44 | node->type = LightNode; | ||
45 | node->light = mem_get_light_index(light); | ||
46 | light->parent = mem_get_node_index(node); | ||
47 | return node; | ||
48 | } | ||
49 | |||
50 | SceneNode* gfx_make_object_node(SceneObject* object) { | ||
51 | assert(object); | ||
52 | SceneNode* node = gfx_make_node(); | ||
53 | if (!node) { | ||
54 | return 0; | ||
55 | } | ||
56 | node->type = ObjectNode; | ||
57 | node->object = mem_get_object_index(object); | ||
58 | object->parent = mem_get_node_index(node); | ||
59 | return node; | ||
60 | } | ||
61 | |||
62 | void gfx_destroy_node(SceneNode** node) { | ||
63 | assert(node); | ||
64 | assert(*node); | ||
65 | |||
66 | // Destroy the node's resources. | ||
67 | // Camera. | ||
68 | if ((*node)->type == CameraNode) { | ||
69 | SceneCamera* camera = mem_get_camera((*node)->camera); | ||
70 | camera->parent.val = 0; // Avoid recursive call into gfx_destroy_node(). | ||
71 | gfx_destroy_camera(&camera); | ||
72 | } | ||
73 | // TODO: free light. | ||
74 | // Object. | ||
75 | if ((*node)->type == ObjectNode) { | ||
76 | SceneObject* object = mem_get_object((*node)->object); | ||
77 | object->parent.val = 0; // Avoid recursive call into gfx_destroy_node(). | ||
78 | gfx_destroy_object(&object); | ||
79 | } | ||
80 | |||
81 | TREE_REMOVE(*node); | ||
82 | mem_free_node(node); | ||
83 | } | ||
84 | |||
85 | void gfx_del_node(node_idx index) { | ||
86 | assert(index.val); | ||
87 | SceneNode* node = mem_get_node(index); | ||
88 | assert(node); | ||
89 | TREE_REMOVE(node); | ||
90 | mem_free_node(&node); | ||
91 | } | ||
92 | |||
93 | void gfx_set_node_parent(SceneNode* child, SceneNode* parent) { | ||
94 | assert(child); | ||
95 | assert(parent); | ||
96 | SET_PARENT(child, parent); | ||
97 | } | ||
98 | |||
99 | void gfx_set_node_transform(SceneNode* node, const mat4* transform) { | ||
100 | assert(node); | ||
101 | assert(transform); | ||
102 | node->transform = *transform; | ||
103 | } | ||
104 | |||
105 | void gfx_set_node_position(SceneNode* node, const vec3* position) { | ||
106 | assert(node); | ||
107 | assert(position); | ||
108 | mat4_set_v3(&node->transform, *position); | ||
109 | } | ||
110 | |||
111 | void gfx_set_node_rotation(SceneNode* node, const mat4* rotation) { | ||
112 | assert(node); | ||
113 | assert(rotation); | ||
114 | mat4_set_3x3(&node->transform, *rotation); | ||
115 | } | ||
diff --git a/gfx/src/scene/node_impl.h b/gfx/src/scene/node_impl.h new file mode 100644 index 0000000..ce3b769 --- /dev/null +++ b/gfx/src/scene/node_impl.h | |||
@@ -0,0 +1,38 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/node.h> | ||
4 | |||
5 | #include "types.h" | ||
6 | |||
7 | #include <math/mat4.h> | ||
8 | |||
9 | /// Scene node type. | ||
10 | typedef enum NodeType { | ||
11 | CameraNode, | ||
12 | LightNode, | ||
13 | LogicalNode, | ||
14 | ObjectNode | ||
15 | } NodeType; | ||
16 | |||
17 | /// Scene node. | ||
18 | /// | ||
19 | /// The SceneNode owns its cameras, objects, lights and child nodes. These | ||
20 | /// together form a strict tree hierarchy and not a more general DAG. | ||
21 | typedef struct SceneNode { | ||
22 | NodeType type; | ||
23 | union { | ||
24 | camera_idx camera; | ||
25 | light_idx light; | ||
26 | object_idx object; | ||
27 | }; | ||
28 | mat4 transform; // Transformation for this node and its children. | ||
29 | node_idx parent; // Parent SceneNode. | ||
30 | node_idx child; // First child SceneNode. | ||
31 | node_idx next; // Next sibling SceneNode. | ||
32 | node_idx prev; // Previous sibling SceneNode. | ||
33 | } SceneNode; | ||
34 | |||
35 | /// Destroy a node given its index. | ||
36 | /// | ||
37 | /// The node is conveniently removed from the scene graph. | ||
38 | void gfx_del_node(node_idx); | ||
diff --git a/gfx/src/scene/object.c b/gfx/src/scene/object.c new file mode 100644 index 0000000..7f23e92 --- /dev/null +++ b/gfx/src/scene/object.c | |||
@@ -0,0 +1,71 @@ | |||
1 | #include "object_impl.h" | ||
2 | |||
3 | #include "node_impl.h" | ||
4 | #include "scene_memory.h" | ||
5 | |||
6 | #include <assert.h> | ||
7 | |||
8 | static void scene_object_make(SceneObject* object) { | ||
9 | assert(object); | ||
10 | object->transform = mat4_id(); | ||
11 | } | ||
12 | |||
13 | SceneObject* gfx_make_object() { | ||
14 | SceneObject* object = mem_alloc_object(); | ||
15 | if (!object) { | ||
16 | return 0; | ||
17 | } | ||
18 | scene_object_make(object); | ||
19 | return object; | ||
20 | } | ||
21 | |||
22 | void gfx_destroy_object(SceneObject** object) { | ||
23 | assert(object); | ||
24 | assert(*object); | ||
25 | if ((*object)->parent.val) { | ||
26 | gfx_del_node((*object)->parent); | ||
27 | } | ||
28 | mem_free_object(object); | ||
29 | } | ||
30 | |||
31 | void gfx_set_object_transform(SceneObject* object, const mat4* transform) { | ||
32 | assert(object); | ||
33 | assert(transform); | ||
34 | object->transform = *transform; | ||
35 | } | ||
36 | |||
37 | void gfx_add_object_mesh(SceneObject* object, Mesh* mesh) { | ||
38 | assert(object); | ||
39 | assert(mesh); | ||
40 | |||
41 | MeshLink* link = mem_alloc_mesh_link(); | ||
42 | assert(link); | ||
43 | link->mesh = mem_get_mesh_index(mesh); | ||
44 | link->next = object->mesh_link; | ||
45 | object->mesh_link = mem_get_mesh_link_index(link); | ||
46 | } | ||
47 | |||
48 | void gfx_remove_object_mesh(SceneObject* object, Mesh* mesh) { | ||
49 | assert(object); | ||
50 | assert(mesh); | ||
51 | |||
52 | MeshLink* prev = 0; | ||
53 | const mesh_idx mesh_index = mem_get_mesh_index(mesh); | ||
54 | |||
55 | // Find the MeshLink in the object that contains the given mesh. | ||
56 | for (mesh_link_idx mesh_link_index = object->mesh_link; | ||
57 | mesh_link_index.val;) { | ||
58 | MeshLink* mesh_link = mem_get_mesh_link(mesh_link_index); | ||
59 | if (mesh_link->mesh.val == mesh_index.val) { | ||
60 | if (prev) { | ||
61 | prev->next = mesh_link->next; | ||
62 | } else { | ||
63 | object->mesh_link = mesh_link->next; | ||
64 | } | ||
65 | mem_free_mesh_link(&mesh_link); | ||
66 | break; | ||
67 | } | ||
68 | prev = mesh_link; | ||
69 | mesh_link_index = mesh_link->next; | ||
70 | } | ||
71 | } | ||
diff --git a/gfx/src/scene/object_impl.h b/gfx/src/scene/object_impl.h new file mode 100644 index 0000000..bd3fdbc --- /dev/null +++ b/gfx/src/scene/object_impl.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/object.h> | ||
4 | |||
5 | #include "types.h" | ||
6 | |||
7 | #include <math/mat4.h> | ||
8 | |||
9 | typedef struct MeshLink { | ||
10 | mesh_idx mesh; | ||
11 | mesh_link_idx next; // Next MeshLink in the list. | ||
12 | } MeshLink; | ||
13 | |||
14 | /// Scene object. | ||
15 | /// | ||
16 | /// A SceneObject does not own its Meshes, and they are instead shared for | ||
17 | /// re-use. The SceneObject consequently embeds a list of MeshLinks as opposed | ||
18 | /// to a list of Meshes. The MeshLinks define a list of Meshes, which can be | ||
19 | /// different for each SceneObject. Each SceneObject may then have a unique list | ||
20 | /// of Meshes, and the Meshes are re-used. | ||
21 | typedef struct SceneObject { | ||
22 | mat4 transform; | ||
23 | mesh_link_idx mesh_link; // First MeshLink in the list. | ||
24 | node_idx parent; // Parent SceneNode. | ||
25 | } SceneObject; | ||
diff --git a/gfx/src/scene/scene.c b/gfx/src/scene/scene.c new file mode 100644 index 0000000..9e974de --- /dev/null +++ b/gfx/src/scene/scene.c | |||
@@ -0,0 +1,43 @@ | |||
1 | #include "scene_impl.h" | ||
2 | |||
3 | #include "camera_impl.h" | ||
4 | #include "node_impl.h" | ||
5 | #include "object_impl.h" | ||
6 | #include "scene_graph.h" | ||
7 | #include "scene_memory.h" | ||
8 | |||
9 | static void scene_destroy_rec(node_idx node_index) { | ||
10 | assert(node_index.val); | ||
11 | |||
12 | SceneNode* node = mem_get_node(node_index); | ||
13 | assert(node); | ||
14 | |||
15 | // First child. | ||
16 | if (node->child.val) { | ||
17 | scene_destroy_rec(node->child); | ||
18 | } | ||
19 | |||
20 | // Right sibling. | ||
21 | if (node->next.val) { | ||
22 | scene_destroy_rec(node->next); | ||
23 | } | ||
24 | |||
25 | gfx_destroy_node(&node); | ||
26 | } | ||
27 | |||
28 | void scene_make(Scene* scene) { | ||
29 | assert(scene); | ||
30 | SceneNode* root = gfx_make_node(); | ||
31 | assert(root); | ||
32 | scene->root = mem_get_node_index(root); | ||
33 | } | ||
34 | |||
35 | void scene_destroy(Scene* scene) { | ||
36 | assert(scene); | ||
37 | scene_destroy_rec(scene->root); | ||
38 | } | ||
39 | |||
40 | SceneNode* gfx_get_scene_root(Scene* scene) { | ||
41 | assert(scene); | ||
42 | return mem_get_node(scene->root); | ||
43 | } | ||
diff --git a/gfx/src/scene/scene_graph.h b/gfx/src/scene/scene_graph.h new file mode 100644 index 0000000..b9b3a14 --- /dev/null +++ b/gfx/src/scene/scene_graph.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /// Functions for list manipulation. | ||
2 | #pragma once | ||
3 | |||
4 | #include "scene_memory.h" | ||
5 | |||
6 | // Note that SceneMemory guarantees that index 0 can be regarded as an invalid | ||
7 | // index. | ||
8 | |||
9 | #define MEM_GET(INDEX) \ | ||
10 | _Generic((INDEX), camera_idx \ | ||
11 | : mem_get_camera, material_idx \ | ||
12 | : mem_get_material, mesh_idx \ | ||
13 | : mem_get_mesh, mesh_link_idx \ | ||
14 | : mem_get_mesh_link, node_idx \ | ||
15 | : mem_get_node, object_idx \ | ||
16 | : mem_get_object, scene_idx \ | ||
17 | : mem_get_scene)(INDEX) | ||
18 | |||
19 | #define MEM_GET_INDEX(ITEM) \ | ||
20 | _Generic((ITEM), SceneCamera * \ | ||
21 | : mem_get_camera_index, Material * \ | ||
22 | : mem_get_material_index, Mesh * \ | ||
23 | : mem_get_mesh_index, MeshLink * \ | ||
24 | : mem_get_mesh_link_index, SceneNode * \ | ||
25 | : mem_get_node_index, SceneObject * \ | ||
26 | : mem_get_object_index, Scene * \ | ||
27 | : mem_get_scene_index)(ITEM) | ||
28 | |||
29 | #define LIST_PREPEND(HEAD_INDEX, ITEM) \ | ||
30 | ITEM->next = HEAD_INDEX; \ | ||
31 | if (HEAD_INDEX.val) { \ | ||
32 | typeof(ITEM) old_head = MEM_GET(HEAD_INDEX); \ | ||
33 | old_head->prev = MEM_GET_INDEX(ITEM); \ | ||
34 | } \ | ||
35 | HEAD_INDEX = MEM_GET_INDEX(ITEM); | ||
36 | |||
37 | #define LIST_REMOVE(ITEM) \ | ||
38 | if ((ITEM)->prev.val) { \ | ||
39 | typeof(ITEM) prev_sibling = MEM_GET((ITEM)->prev); \ | ||
40 | prev_sibling->next = (ITEM)->next; \ | ||
41 | } \ | ||
42 | if ((ITEM)->next.val) { \ | ||
43 | typeof(ITEM) next_sibling = MEM_GET((ITEM)->next); \ | ||
44 | next_sibling->prev = (ITEM)->prev; \ | ||
45 | } | ||
46 | |||
47 | #define SET_PARENT(CHILD, PARENT) \ | ||
48 | assert(CHILD); \ | ||
49 | if (CHILD->parent.val) { \ | ||
50 | LIST_REMOVE(CHILD); \ | ||
51 | } \ | ||
52 | if (parent) { \ | ||
53 | LIST_PREPEND(PARENT->CHILD, CHILD); \ | ||
54 | } | ||
55 | |||
56 | #define TREE_REMOVE(ITEM) \ | ||
57 | if ((ITEM)->prev.val) { \ | ||
58 | typeof(ITEM) prev_sibling = MEM_GET((ITEM)->prev); \ | ||
59 | prev_sibling->next = (ITEM)->next; \ | ||
60 | } \ | ||
61 | if ((ITEM)->next.val) { \ | ||
62 | typeof(ITEM) next_sibling = MEM_GET((ITEM)->next); \ | ||
63 | next_sibling->prev = (ITEM)->prev; \ | ||
64 | } \ | ||
65 | if ((ITEM)->parent.val) { \ | ||
66 | MEM_GET((ITEM)->parent)->child.val = 0; \ | ||
67 | } | ||
diff --git a/gfx/src/scene/scene_impl.h b/gfx/src/scene/scene_impl.h new file mode 100644 index 0000000..e0c25bf --- /dev/null +++ b/gfx/src/scene/scene_impl.h | |||
@@ -0,0 +1,17 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <gfx/scene/scene.h> | ||
4 | |||
5 | #include "types.h" | ||
6 | |||
7 | typedef struct Scene { | ||
8 | node_idx root; | ||
9 | scene_idx next; | ||
10 | scene_idx prev; | ||
11 | } Scene; | ||
12 | |||
13 | /// Create a new scene. | ||
14 | void scene_make(Scene*); | ||
15 | |||
16 | /// Destroy the scene. | ||
17 | void scene_destroy(Scene*); | ||
diff --git a/gfx/src/scene/scene_memory.c b/gfx/src/scene/scene_memory.c new file mode 100644 index 0000000..cd4a79c --- /dev/null +++ b/gfx/src/scene/scene_memory.c | |||
@@ -0,0 +1,148 @@ | |||
1 | #include "scene_memory.h" | ||
2 | |||
3 | #include <gfx/sizes.h> | ||
4 | |||
5 | #include "camera_impl.h" | ||
6 | #include "light_impl.h" | ||
7 | #include "material_impl.h" | ||
8 | #include "mesh_impl.h" | ||
9 | #include "node_impl.h" | ||
10 | #include "object_impl.h" | ||
11 | #include "scene_impl.h" | ||
12 | #include "types.h" | ||
13 | |||
14 | #include <mempool.h> | ||
15 | |||
16 | DEF_MEMPOOL(camera_pool, SceneCamera, GFX_MAX_NUM_CAMERAS) | ||
17 | DEF_MEMPOOL(light_pool, Light, GFX_MAX_NUM_LIGHTS) | ||
18 | DEF_MEMPOOL(material_pool, Material, GFX_MAX_NUM_MATERIALS) | ||
19 | DEF_MEMPOOL(mesh_pool, Mesh, GFX_MAX_NUM_MESHES) | ||
20 | DEF_MEMPOOL(mesh_link_pool, MeshLink, GFX_MAX_NUM_MESH_LINKS) | ||
21 | DEF_MEMPOOL(node_pool, SceneNode, GFX_MAX_NUM_NODES) | ||
22 | DEF_MEMPOOL(object_pool, SceneObject, GFX_MAX_NUM_OBJECTS) | ||
23 | DEF_MEMPOOL(scene_pool, Scene, GFX_MAX_NUM_SCENES) | ||
24 | |||
25 | /// Scene memory. | ||
26 | /// | ||
27 | /// Holds memory pools for every type of scene object. | ||
28 | typedef struct SceneMemory { | ||
29 | camera_pool cameras; | ||
30 | light_pool lights; | ||
31 | material_pool materials; | ||
32 | mesh_pool meshes; | ||
33 | mesh_link_pool mesh_links; | ||
34 | node_pool nodes; | ||
35 | object_pool objects; | ||
36 | scene_pool scenes; | ||
37 | } SceneMemory; | ||
38 | |||
39 | static SceneMemory mem; | ||
40 | |||
41 | #define ALLOC_DUMMY(POOL) \ | ||
42 | assert(mempool_get_block_index(POOL, mempool_alloc(POOL)) == 0) | ||
43 | |||
44 | void scene_mem_init() { | ||
45 | mempool_make(&mem.cameras); | ||
46 | mempool_make(&mem.lights); | ||
47 | mempool_make(&mem.materials); | ||
48 | mempool_make(&mem.meshes); | ||
49 | mempool_make(&mem.mesh_links); | ||
50 | mempool_make(&mem.nodes); | ||
51 | mempool_make(&mem.objects); | ||
52 | mempool_make(&mem.scenes); | ||
53 | |||
54 | // Allocate dummy objects at index 0 to guarantee that no objects allocated by | ||
55 | // the caller map to index 0. | ||
56 | ALLOC_DUMMY(&mem.cameras); | ||
57 | ALLOC_DUMMY(&mem.lights); | ||
58 | ALLOC_DUMMY(&mem.materials); | ||
59 | ALLOC_DUMMY(&mem.meshes); | ||
60 | ALLOC_DUMMY(&mem.mesh_links); | ||
61 | ALLOC_DUMMY(&mem.nodes); | ||
62 | ALLOC_DUMMY(&mem.objects); | ||
63 | ALLOC_DUMMY(&mem.scenes); | ||
64 | } | ||
65 | |||
66 | void scene_mem_destroy() {} | ||
67 | |||
68 | // Memory allocation. | ||
69 | SceneCamera* mem_alloc_camera() { return mempool_alloc(&mem.cameras); } | ||
70 | Light* mem_alloc_light() { return mempool_alloc(&mem.lights); } | ||
71 | Material* mem_alloc_material() { return mempool_alloc(&mem.materials); } | ||
72 | Mesh* mem_alloc_mesh() { return mempool_alloc(&mem.meshes); } | ||
73 | MeshLink* mem_alloc_mesh_link() { return mempool_alloc(&mem.mesh_links); } | ||
74 | SceneNode* mem_alloc_node() { return mempool_alloc(&mem.nodes); } | ||
75 | SceneObject* mem_alloc_object() { return mempool_alloc(&mem.objects); } | ||
76 | Scene* mem_alloc_scene() { return mempool_alloc(&mem.scenes); } | ||
77 | |||
78 | // Memory free. | ||
79 | void mem_free_camera(SceneCamera** camera) { | ||
80 | mempool_free(&mem.cameras, camera); | ||
81 | } | ||
82 | void mem_free_light(Light** light) { mempool_free(&mem.lights, light); } | ||
83 | void mem_free_material(Material** material) { | ||
84 | mempool_free(&mem.materials, material); | ||
85 | } | ||
86 | void mem_free_mesh(Mesh** mesh) { mempool_free(&mem.meshes, mesh); } | ||
87 | void mem_free_mesh_link(MeshLink** mesh_link) { | ||
88 | mempool_free(&mem.mesh_links, mesh_link); | ||
89 | } | ||
90 | void mem_free_node(SceneNode** node) { mempool_free(&mem.nodes, node); } | ||
91 | void mem_free_object(SceneObject** object) { | ||
92 | mempool_free(&mem.objects, object); | ||
93 | } | ||
94 | void mem_free_scene(Scene** scene) { mempool_free(&mem.scenes, scene); } | ||
95 | |||
96 | // Query by index. | ||
97 | SceneCamera* mem_get_camera(camera_idx index) { | ||
98 | return mempool_get_block(&mem.cameras, index.val); | ||
99 | } | ||
100 | Light* mem_get_light(light_idx index) { | ||
101 | return mempool_get_block(&mem.lights, index.val); | ||
102 | } | ||
103 | Material* mem_get_material(material_idx index) { | ||
104 | return mempool_get_block(&mem.materials, index.val); | ||
105 | } | ||
106 | Mesh* mem_get_mesh(mesh_idx index) { | ||
107 | return mempool_get_block(&mem.meshes, index.val); | ||
108 | } | ||
109 | MeshLink* mem_get_mesh_link(mesh_link_idx index) { | ||
110 | return mempool_get_block(&mem.mesh_links, index.val); | ||
111 | } | ||
112 | SceneNode* mem_get_node(node_idx index) { | ||
113 | return mempool_get_block(&mem.nodes, index.val); | ||
114 | } | ||
115 | SceneObject* mem_get_object(object_idx index) { | ||
116 | return mempool_get_block(&mem.objects, index.val); | ||
117 | } | ||
118 | Scene* mem_get_scene(scene_idx index) { | ||
119 | return mempool_get_block(&mem.scenes, index.val); | ||
120 | } | ||
121 | |||
122 | // Map object to index. | ||
123 | camera_idx mem_get_camera_index(const SceneCamera* camera) { | ||
124 | return (camera_idx){.val = mempool_get_block_index(&mem.cameras, camera)}; | ||
125 | } | ||
126 | light_idx mem_get_light_index(const Light* light) { | ||
127 | return (light_idx){.val = mempool_get_block_index(&mem.lights, light)}; | ||
128 | } | ||
129 | material_idx mem_get_material_index(const Material* material) { | ||
130 | return (material_idx){.val = | ||
131 | mempool_get_block_index(&mem.materials, material)}; | ||
132 | } | ||
133 | mesh_idx mem_get_mesh_index(const Mesh* mesh) { | ||
134 | return (mesh_idx){.val = mempool_get_block_index(&mem.meshes, mesh)}; | ||
135 | } | ||
136 | mesh_link_idx mem_get_mesh_link_index(const MeshLink* mesh_link) { | ||
137 | return (mesh_link_idx){ | ||
138 | .val = mempool_get_block_index(&mem.mesh_links, mesh_link)}; | ||
139 | } | ||
140 | node_idx mem_get_node_index(const SceneNode* node) { | ||
141 | return (node_idx){.val = mempool_get_block_index(&mem.nodes, node)}; | ||
142 | } | ||
143 | object_idx mem_get_object_index(const SceneObject* object) { | ||
144 | return (object_idx){.val = mempool_get_block_index(&mem.objects, object)}; | ||
145 | } | ||
146 | scene_idx mem_get_scene_index(const Scene* scene) { | ||
147 | return (scene_idx){.val = mempool_get_block_index(&mem.scenes, scene)}; | ||
148 | } | ||
diff --git a/gfx/src/scene/scene_memory.h b/gfx/src/scene/scene_memory.h new file mode 100644 index 0000000..dff5bd8 --- /dev/null +++ b/gfx/src/scene/scene_memory.h | |||
@@ -0,0 +1,130 @@ | |||
1 | /// Memory management of scene objects. | ||
2 | #pragma once | ||
3 | |||
4 | #include "types.h" | ||
5 | |||
6 | typedef struct Light Light; | ||
7 | typedef struct Material Material; | ||
8 | typedef struct Mesh Mesh; | ||
9 | typedef struct MeshLink MeshLink; | ||
10 | typedef struct SceneCamera SceneCamera; | ||
11 | typedef struct SceneNode SceneNode; | ||
12 | typedef struct SceneObject SceneObject; | ||
13 | typedef struct Scene Scene; | ||
14 | |||
15 | /// Initialize scene memory. | ||
16 | /// | ||
17 | /// The scene memory guarantees that every object maps to an index different | ||
18 | /// than 0. In this way, 0 can be used as a special index to denote "no value". | ||
19 | void scene_mem_init(); | ||
20 | |||
21 | /// Destroy the scene memory. | ||
22 | void scene_mem_destroy(); | ||
23 | |||
24 | /// ---------------------------------------------------------------------------- | ||
25 | /// Memory allocation. | ||
26 | /// ---------------------------------------------------------------------------- | ||
27 | |||
28 | /// Allocate space for a camera. | ||
29 | SceneCamera* mem_alloc_camera(); | ||
30 | |||
31 | /// Allocate space for a light. | ||
32 | Light* mem_alloc_light(); | ||
33 | |||
34 | /// Allocate space for a material. | ||
35 | Material* mem_alloc_material(); | ||
36 | |||
37 | /// Allocate space for a mesh. | ||
38 | Mesh* mem_alloc_mesh(); | ||
39 | |||
40 | /// Allocate space for a mesh link. | ||
41 | MeshLink* mem_alloc_mesh_link(); | ||
42 | |||
43 | /// Allocate space for a scene node. | ||
44 | SceneNode* mem_alloc_node(); | ||
45 | |||
46 | /// Allocate space for a scene object. | ||
47 | SceneObject* mem_alloc_object(); | ||
48 | |||
49 | /// Allocate space for a scene. | ||
50 | Scene* mem_alloc_scene(); | ||
51 | |||
52 | /// Free the camera. | ||
53 | void mem_free_camera(SceneCamera**); | ||
54 | |||
55 | /// Free the light. | ||
56 | void mem_free_light(Light**); | ||
57 | |||
58 | /// Free the material. | ||
59 | void mem_free_material(Material**); | ||
60 | |||
61 | /// Free the mesh. | ||
62 | void mem_free_mesh(Mesh**); | ||
63 | |||
64 | /// Free the mesh link. | ||
65 | void mem_free_mesh_link(MeshLink**); | ||
66 | |||
67 | /// Free the scene node. | ||
68 | void mem_free_node(SceneNode**); | ||
69 | |||
70 | /// Free the scene object. | ||
71 | void mem_free_object(SceneObject**); | ||
72 | |||
73 | /// Free the scene. | ||
74 | void mem_free_scene(Scene**); | ||
75 | |||
76 | /// ---------------------------------------------------------------------------- | ||
77 | /// Query objects by index. | ||
78 | /// ---------------------------------------------------------------------------- | ||
79 | |||
80 | /// Get a camera by index. | ||
81 | SceneCamera* mem_get_camera(camera_idx); | ||
82 | |||
83 | /// Get a light by index. | ||
84 | Light* mem_get_light(light_idx); | ||
85 | |||
86 | /// Get a material by index. | ||
87 | Material* mem_get_material(material_idx); | ||
88 | |||
89 | /// Get a mesh by index. | ||
90 | Mesh* mem_get_mesh(mesh_idx); | ||
91 | |||
92 | /// Get a mesh link by index. | ||
93 | MeshLink* mem_get_mesh_link(mesh_link_idx); | ||
94 | |||
95 | /// Get a node by index. | ||
96 | SceneNode* mem_get_node(node_idx); | ||
97 | |||
98 | /// Get an object by index. | ||
99 | SceneObject* mem_get_object(object_idx); | ||
100 | |||
101 | /// Get a scene by index. | ||
102 | Scene* mem_get_scene(scene_idx); | ||
103 | |||
104 | /// ---------------------------------------------------------------------------- | ||
105 | /// Map objects to indices. | ||
106 | /// ---------------------------------------------------------------------------- | ||
107 | |||
108 | /// Get the camera's index. | ||
109 | camera_idx mem_get_camera_index(const SceneCamera*); | ||
110 | |||
111 | /// Get the light's index. | ||
112 | light_idx mem_get_light_index(const Light*); | ||
113 | |||
114 | /// Get the material's index. | ||
115 | material_idx mem_get_material_index(const Material*); | ||
116 | |||
117 | /// Get the mesh's index. | ||
118 | mesh_idx mem_get_mesh_index(const Mesh*); | ||
119 | |||
120 | /// Get the mesh link's index. | ||
121 | mesh_link_idx mem_get_mesh_link_index(const MeshLink*); | ||
122 | |||
123 | /// Get the node's index. | ||
124 | node_idx mem_get_node_index(const SceneNode*); | ||
125 | |||
126 | /// Get the object's index. | ||
127 | object_idx mem_get_object_index(const SceneObject*); | ||
128 | |||
129 | /// Get the scene's index. | ||
130 | scene_idx mem_get_scene_index(const Scene*); | ||
diff --git a/gfx/src/scene/types.h b/gfx/src/scene/types.h new file mode 100644 index 0000000..2863ac7 --- /dev/null +++ b/gfx/src/scene/types.h | |||
@@ -0,0 +1,21 @@ | |||
1 | #pragma once | ||
2 | |||
3 | #include <stdint.h> | ||
4 | |||
5 | typedef uint16_t gfx_idx; | ||
6 | |||
7 | // Strongly-typed indices. | ||
8 | |||
9 | #define DEF_STRONG_INDEX(TYPE_NAME) \ | ||
10 | typedef struct TYPE_NAME##_idx { \ | ||
11 | gfx_idx val; \ | ||
12 | } TYPE_NAME##_idx; | ||
13 | |||
14 | DEF_STRONG_INDEX(camera) | ||
15 | DEF_STRONG_INDEX(light) | ||
16 | DEF_STRONG_INDEX(material) | ||
17 | DEF_STRONG_INDEX(mesh) | ||
18 | DEF_STRONG_INDEX(mesh_link) | ||
19 | DEF_STRONG_INDEX(node) | ||
20 | DEF_STRONG_INDEX(object) | ||
21 | DEF_STRONG_INDEX(scene) | ||