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) | ||
