aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asset/model.c111
-rw-r--r--src/asset/texture.c32
-rw-r--r--src/core/texture.c10
-rw-r--r--src/scene/scene_graph.h42
-rw-r--r--src/scene/scene_memory.c59
5 files changed, 161 insertions, 93 deletions
diff --git a/src/asset/model.c b/src/asset/model.c
index 25f2780..402b2e1 100644
--- a/src/asset/model.c
+++ b/src/asset/model.c
@@ -578,11 +578,10 @@ static bool load_buffers(
578 const cgltf_buffer* buffer = &data->buffers[i]; 578 const cgltf_buffer* buffer = &data->buffers[i];
579 assert(buffer->data); 579 assert(buffer->data);
580 buffers[i] = gfx_make_buffer( 580 buffers[i] = gfx_make_buffer(
581 gfxcore, &(BufferDesc){ 581 gfxcore, &(BufferDesc){.usage = BufferStatic,
582 .usage = BufferStatic, 582 .type = BufferUntyped,
583 .type = BufferUntyped, 583 .data.data = buffer->data,
584 .data.data = buffer->data, 584 .data.count = buffer->size});
585 .data.count = buffer->size});
586 if (!buffers[i]) { 585 if (!buffers[i]) {
587 return false; 586 return false;
588 } 587 }
@@ -604,11 +603,10 @@ static bool load_tangent_buffers(
604 const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i]; 603 const cgltfTangentBuffer* buffer = &cgltf_tangent_buffers[i];
605 assert(buffer->data); 604 assert(buffer->data);
606 tangent_buffers[i] = gfx_make_buffer( 605 tangent_buffers[i] = gfx_make_buffer(
607 gfxcore, &(BufferDesc){ 606 gfxcore, &(BufferDesc){.usage = BufferStatic,
608 .usage = BufferStatic, 607 .type = BufferUntyped,
609 .type = BufferUntyped, 608 .data.data = buffer->data,
610 .data.data = buffer->data, 609 .data.count = buffer->size_bytes});
611 .data.count = buffer->size_bytes});
612 if (!tangent_buffers[i]) { 610 if (!tangent_buffers[i]) {
613 return false; 611 return false;
614 } 612 }
@@ -682,14 +680,13 @@ static void load_textures_lazy(
682 mstring fullpath = 680 mstring fullpath =
683 mstring_concat_path(mstring_make(directory), mstring_make(image->uri)); 681 mstring_concat_path(mstring_make(directory), mstring_make(image->uri));
684 682
685 load_texture_cmds[i] = (LoadTextureCmd){ 683 load_texture_cmds[i] = (LoadTextureCmd){.origin = AssetFromFile,
686 .origin = AssetFromFile, 684 .type = LoadTexture,
687 .type = LoadTexture, 685 .colour_space = LinearColourSpace,
688 .colour_space = sRGB, 686 .filtering = filtering,
689 .filtering = filtering, 687 .wrap = wrap,
690 .wrap = wrap, 688 .mipmaps = mipmaps,
691 .mipmaps = mipmaps, 689 .data.texture.filepath = fullpath};
692 .data.texture.filepath = fullpath};
693 } 690 }
694} 691}
695 692
@@ -717,8 +714,12 @@ static bool load_texture_and_uniform(
717 // not be used as albedo and vice versa. 714 // not be used as albedo and vice versa.
718 if (!textures[texture_index]) { 715 if (!textures[texture_index]) {
719 LoadTextureCmd* cmd = &load_texture_cmds[texture_index]; 716 LoadTextureCmd* cmd = &load_texture_cmds[texture_index];
720 // TODO: Check for colour textures and default to LinearColourSpace instead. 717 // Albedo and emissive use sRGB. Other textures use a linear colour space.
721 if (texture_type == NormalMap) { 718 // See the notes on the spec.
719 if ((texture_type == BaseColorTexture) ||
720 (texture_type == EmissiveTexture)) {
721 cmd->colour_space = sRGB;
722 } else {
722 cmd->colour_space = LinearColourSpace; 723 cmd->colour_space = LinearColourSpace;
723 } 724 }
724 725
@@ -778,22 +779,22 @@ static bool load_materials(
778 .value.vec4 = vec4_from_array(pbr->base_color_factor)}; 779 .value.vec4 = vec4_from_array(pbr->base_color_factor)};
779 780
780 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 781 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
781 desc.uniforms[next_uniform++] = (ShaderUniform){ 782 desc.uniforms[next_uniform++] =
782 .name = sstring_make(UNIFORM_METALLIC_FACTOR), 783 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR),
783 .type = UniformFloat, 784 .type = UniformFloat,
784 .value.scalar = pbr->metallic_factor}; 785 .value.scalar = pbr->metallic_factor};
785 786
786 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 787 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
787 desc.uniforms[next_uniform++] = (ShaderUniform){ 788 desc.uniforms[next_uniform++] =
788 .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), 789 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR),
789 .type = UniformFloat, 790 .type = UniformFloat,
790 .value.scalar = pbr->roughness_factor}; 791 .value.scalar = pbr->roughness_factor};
791 792
792 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL); 793 assert(next_uniform < GFX_MAX_UNIFORMS_PER_MATERIAL);
793 desc.uniforms[next_uniform++] = (ShaderUniform){ 794 desc.uniforms[next_uniform++] =
794 .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), 795 (ShaderUniform){.name = sstring_make(UNIFORM_EMISSIVE_FACTOR),
795 .type = UniformVec3, 796 .type = UniformVec3,
796 .value.vec3 = vec3_from_array(mat->emissive_factor)}; 797 .value.vec3 = vec3_from_array(mat->emissive_factor)};
797 798
798 if (pbr->base_color_texture.texture) { 799 if (pbr->base_color_texture.texture) {
799 if (!load_texture_and_uniform( 800 if (!load_texture_and_uniform(
@@ -854,28 +855,28 @@ static Material* make_default_material() {
854 MaterialDesc desc = (MaterialDesc){0}; 855 MaterialDesc desc = (MaterialDesc){0};
855 856
856 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 857 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
857 desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ 858 desc.uniforms[desc.num_uniforms++] =
858 .name = sstring_make(UNIFORM_BASE_COLOR_FACTOR), 859 (ShaderUniform){.name = sstring_make(UNIFORM_BASE_COLOR_FACTOR),
859 .type = UniformVec4, 860 .type = UniformVec4,
860 .value.vec4 = vec4_make(1, 1, 1, 1)}; 861 .value.vec4 = vec4_make(1, 1, 1, 1)};
861 862
862 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 863 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
863 desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ 864 desc.uniforms[desc.num_uniforms++] =
864 .name = sstring_make(UNIFORM_METALLIC_FACTOR), 865 (ShaderUniform){.name = sstring_make(UNIFORM_METALLIC_FACTOR),
865 .type = UniformFloat, 866 .type = UniformFloat,
866 .value.scalar = 0}; 867 .value.scalar = 0};
867 868
868 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 869 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
869 desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ 870 desc.uniforms[desc.num_uniforms++] =
870 .name = sstring_make(UNIFORM_ROUGHNESS_FACTOR), 871 (ShaderUniform){.name = sstring_make(UNIFORM_ROUGHNESS_FACTOR),
871 .type = UniformFloat, 872 .type = UniformFloat,
872 .value.scalar = 1}; 873 .value.scalar = 1};
873 874
874 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL); 875 assert(desc.num_uniforms < GFX_MAX_UNIFORMS_PER_MATERIAL);
875 desc.uniforms[desc.num_uniforms++] = (ShaderUniform){ 876 desc.uniforms[desc.num_uniforms++] =
876 .name = sstring_make(UNIFORM_EMISSIVE_FACTOR), 877 (ShaderUniform){.name = sstring_make(UNIFORM_EMISSIVE_FACTOR),
877 .type = UniformVec3, 878 .type = UniformVec3,
878 .value.vec3 = vec3_make(0, 0, 0)}; 879 .value.vec3 = vec3_make(0, 0, 0)};
879 880
880 return gfx_make_material(&desc); 881 return gfx_make_material(&desc);
881} 882}
@@ -1192,10 +1193,10 @@ static bool load_meshes(
1192 shader ? shader : make_shader_permutation(gfxcore, perm); 1193 shader ? shader : make_shader_permutation(gfxcore, perm);
1193 assert(mesh_shader); 1194 assert(mesh_shader);
1194 1195
1195 meshes[next_mesh] = gfx_make_mesh(&(MeshDesc){ 1196 meshes[next_mesh] =
1196 .geometry = geometries[next_mesh], 1197 gfx_make_mesh(&(MeshDesc){.geometry = geometries[next_mesh],
1197 .material = material, 1198 .material = material,
1198 .shader = mesh_shader}); 1199 .shader = mesh_shader});
1199 1200
1200 if (!meshes[next_mesh]) { 1201 if (!meshes[next_mesh]) {
1201 return false; 1202 return false;
@@ -1432,9 +1433,9 @@ static void load_animations(
1432 const cgltf_animation* animation = &data->animations[a]; 1433 const cgltf_animation* animation = &data->animations[a];
1433 AnimationDesc* animation_desc = &anima_desc->animations[a]; 1434 AnimationDesc* animation_desc = &anima_desc->animations[a];
1434 1435
1435 *animation_desc = (AnimationDesc){ 1436 *animation_desc =
1436 .name = sstring_make(animation->name), 1437 (AnimationDesc){.name = sstring_make(animation->name),
1437 .num_channels = animation->channels_count}; 1438 .num_channels = animation->channels_count};
1438 1439
1439 assert(animation->channels_count <= GFX_MAX_NUM_CHANNELS); 1440 assert(animation->channels_count <= GFX_MAX_NUM_CHANNELS);
1440 for (cgltf_size c = 0; c < animation->channels_count; ++c) { 1441 for (cgltf_size c = 0; c < animation->channels_count; ++c) {
diff --git a/src/asset/texture.c b/src/asset/texture.c
index c790394..fb423cc 100644
--- a/src/asset/texture.c
+++ b/src/asset/texture.c
@@ -49,7 +49,7 @@ Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) {
49 assert(cmd->origin == AssetFromFile || cmd->origin == AssetFromMemory); 49 assert(cmd->origin == AssetFromFile || cmd->origin == AssetFromMemory);
50 assert(cmd->type == LoadTexture || cmd->type == LoadCubemap); 50 assert(cmd->type == LoadTexture || cmd->type == LoadCubemap);
51 51
52 int width, height, components, old_components; 52 int width, height, components;
53 unsigned char* pixels[6] = {0}; 53 unsigned char* pixels[6] = {0};
54 54
55 switch (cmd->origin) { 55 switch (cmd->origin) {
@@ -64,7 +64,8 @@ Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) {
64 } 64 }
65 break; 65 break;
66 } 66 }
67 case LoadCubemap: 67 case LoadCubemap: {
68 int old_components = 0;
68 for (int i = 0; i < 6; ++i) { 69 for (int i = 0; i < 6; ++i) {
69 // Flip +Y and -Y textures vertically. 70 // Flip +Y and -Y textures vertically.
70 stbi_set_flip_vertically_on_load(((i == 2) || (i == 3)) ? 1 : 0); 71 stbi_set_flip_vertically_on_load(((i == 2) || (i == 3)) ? 1 : 0);
@@ -76,9 +77,10 @@ Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) {
76 log_error("Failed to load texture file: %s", filepath); 77 log_error("Failed to load texture file: %s", filepath);
77 break; 78 break;
78 } 79 }
79 if (i > 0 && components != old_components) { 80 if ((i > 0) && (components != old_components)) {
80 log_error("All textures in a cubemap must have the same number of " 81 log_error(
81 "components"); 82 "All textures in a cubemap must have the same number of "
83 "components");
82 break; 84 break;
83 } 85 }
84 if ((i != 2) && (i != 3)) { 86 if ((i != 2) && (i != 3)) {
@@ -89,6 +91,7 @@ Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) {
89 } 91 }
90 break; 92 break;
91 } 93 }
94 }
92 break; 95 break;
93 case AssetFromMemory: 96 case AssetFromMemory:
94 // TODO: Load textures from memory. 97 // TODO: Load textures from memory.
@@ -122,6 +125,25 @@ Texture* gfx_texture_load(GfxCore* gfxcore, const LoadTextureCmd* cmd) {
122 } 125 }
123 126
124 switch (components) { 127 switch (components) {
128 case 1:
129 switch (cmd->colour_space) {
130 case LinearColourSpace:
131 desc.format = TextureR8;
132 break;
133 case sRGB:
134 // TODO: Gamma single-channel textures are not implemented yet.
135 // The caller should convert the single-channel to RGB and pass it down
136 // as sRGB. This is why the ChronographWatch currently appears red on the
137 // back.
138 log_error("Gamma colour space is not supported for 1-channel textures");
139 // return 0;
140 desc.format = TextureR8;
141 break;
142 default:
143 log_error("Unsupported texture colour space: %d", cmd->colour_space);
144 return 0;
145 }
146 break;
125 case 3: 147 case 3:
126 switch (cmd->colour_space) { 148 switch (cmd->colour_space) {
127 case LinearColourSpace: 149 case LinearColourSpace:
diff --git a/src/core/texture.c b/src/core/texture.c
index 89f7ec0..372f9e6 100644
--- a/src/core/texture.c
+++ b/src/core/texture.c
@@ -37,6 +37,7 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) {
37 gfx_del_texture(texture); 37 gfx_del_texture(texture);
38 return false; 38 return false;
39 } 39 }
40 ASSERT_GL;
40 41
41 texture->format = to_GL_format(desc->format); 42 texture->format = to_GL_format(desc->format);
42 texture->type = to_GL_type(desc->format); 43 texture->type = to_GL_type(desc->format);
@@ -50,6 +51,7 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) {
50 // Mipmaps. 51 // Mipmaps.
51 if (desc->mipmaps) { 52 if (desc->mipmaps) {
52 glGenerateMipmap(texture->target); 53 glGenerateMipmap(texture->target);
54 ASSERT_GL;
53 } 55 }
54 56
55 // Texture filtering. 57 // Texture filtering.
@@ -60,6 +62,7 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) {
60 GLenum mag = linear ? GL_LINEAR : GL_NEAREST; 62 GLenum mag = linear ? GL_LINEAR : GL_NEAREST;
61 glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min); 63 glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, min);
62 glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag); 64 glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, mag);
65 ASSERT_GL;
63 66
64 // Texture wrapping. 67 // Texture wrapping.
65 GLenum wrap = GL_INVALID_ENUM; 68 GLenum wrap = GL_INVALID_ENUM;
@@ -74,6 +77,7 @@ bool gfx_init_texture(Texture* texture, const TextureDesc* desc) {
74 glTexParameteri(texture->target, GL_TEXTURE_WRAP_R, wrap); 77 glTexParameteri(texture->target, GL_TEXTURE_WRAP_R, wrap);
75 glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, wrap); 78 glTexParameteri(texture->target, GL_TEXTURE_WRAP_S, wrap);
76 glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, wrap); 79 glTexParameteri(texture->target, GL_TEXTURE_WRAP_T, wrap);
80 ASSERT_GL;
77 81
78 glBindTexture(texture->target, 0); 82 glBindTexture(texture->target, 0);
79 return true; 83 return true;
@@ -119,6 +123,7 @@ void gfx_update_texture(Texture* texture, const TextureDataDesc* desc) {
119 FAIL("Unhandled texture dimension"); 123 FAIL("Unhandled texture dimension");
120 break; 124 break;
121 } 125 }
126 ASSERT_GL;
122 127
123 glBindTexture(texture->target, 0); 128 glBindTexture(texture->target, 0);
124} 129}
@@ -139,6 +144,8 @@ GLenum to_GL_internal_format(TextureFormat format) {
139 switch (format) { 144 switch (format) {
140 case TextureDepth: 145 case TextureDepth:
141 return GL_DEPTH_COMPONENT; 146 return GL_DEPTH_COMPONENT;
147 case TextureR8:
148 return GL_R8;
142 case TextureRG16: 149 case TextureRG16:
143 return GL_RG16; 150 return GL_RG16;
144 case TextureRG16F: 151 case TextureRG16F:
@@ -163,6 +170,8 @@ GLenum to_GL_format(TextureFormat format) {
163 switch (format) { 170 switch (format) {
164 case TextureDepth: 171 case TextureDepth:
165 return GL_DEPTH_COMPONENT; 172 return GL_DEPTH_COMPONENT;
173 case TextureR8:
174 return GL_RED;
166 case TextureRG16: 175 case TextureRG16:
167 case TextureRG16F: 176 case TextureRG16F:
168 return GL_RG; 177 return GL_RG;
@@ -185,6 +194,7 @@ GLenum to_GL_type(TextureFormat format) {
185 case TextureRG16F: 194 case TextureRG16F:
186 case TextureR11G11B10F: 195 case TextureR11G11B10F:
187 return GL_FLOAT; 196 return GL_FLOAT;
197 case TextureR8:
188 case TextureRG16: 198 case TextureRG16:
189 case TextureRGB8: 199 case TextureRGB8:
190 case TextureRGBA8: 200 case TextureRGBA8:
diff --git a/src/scene/scene_graph.h b/src/scene/scene_graph.h
index a26f828..0b1f7d0 100644
--- a/src/scene/scene_graph.h
+++ b/src/scene/scene_graph.h
@@ -6,35 +6,41 @@
6// NOTE: SceneMemory guarantees that index 0 can be regarded as an invalid 6// NOTE: SceneMemory guarantees that index 0 can be regarded as an invalid
7// index. 7// index.
8 8
9#define MEM_GET(INDEX) \ 9#define MEM_GET(INDEX) \
10 _Generic((INDEX), camera_idx \ 10 _Generic( \
11 : mem_get_camera, material_idx \ 11 (INDEX), \
12 : mem_get_material, mesh_idx \ 12 camera_idx: mem_get_camera, \
13 : mem_get_mesh, mesh_link_idx \ 13 material_idx: mem_get_material, \
14 : mem_get_mesh_link, node_idx \ 14 mesh_idx: mem_get_mesh, \
15 : mem_get_node, object_idx \ 15 mesh_link_idx: mem_get_mesh_link, \
16 : mem_get_object, scene_idx \ 16 node_idx: mem_get_node, \
17 : mem_get_scene)(INDEX) 17 object_idx: mem_get_object, \
18 scene_idx: mem_get_scene)(INDEX)
18 19
19#define MEM_GET_INDEX(ITEM) \ 20#define MEM_GET_INDEX(ITEM) \
20 _Generic((ITEM), SceneCamera * \ 21 _Generic( \
21 : mem_get_camera_index, Material * \ 22 (ITEM), \
22 : mem_get_material_index, Mesh * \ 23 SceneCamera *: mem_get_camera_index, \
23 : mem_get_mesh_index, MeshLink * \ 24 Material *: mem_get_material_index, \
24 : mem_get_mesh_link_index, SceneNode * \ 25 Mesh *: mem_get_mesh_index, \
25 : mem_get_node_index, SceneObject * \ 26 MeshLink *: mem_get_mesh_link_index, \
26 : mem_get_object_index, Scene * \ 27 SceneNode *: mem_get_node_index, \
27 : mem_get_scene_index)(ITEM) 28 SceneObject *: mem_get_object_index, \
29 Scene *: mem_get_scene_index)(ITEM)
28 30
29/// Assert the list node invariant. 31/// Assert the list node invariant.
30/// 32///
31/// - A node does not point to itself. 33/// - A node does not point to itself.
34#if NDEBUG
35#define ASSERT_LIST_NODE_INVARIANT(ITEM)
36#else
32#define ASSERT_LIST_NODE_INVARIANT(ITEM) \ 37#define ASSERT_LIST_NODE_INVARIANT(ITEM) \
33 { \ 38 { \
34 const gfx_idx item_idx = MEM_GET_INDEX(ITEM).val; \ 39 const gfx_idx item_idx = MEM_GET_INDEX(ITEM).val; \
35 assert((ITEM)->prev.val != item_idx); \ 40 assert((ITEM)->prev.val != item_idx); \
36 assert((ITEM)->next.val != item_idx); \ 41 assert((ITEM)->next.val != item_idx); \
37 } 42 }
43#endif
38 44
39/// Assert the tree node invariant. 45/// Assert the tree node invariant.
40/// 46///
diff --git a/src/scene/scene_memory.c b/src/scene/scene_memory.c
index 85c27e7..d1d81a9 100644
--- a/src/scene/scene_memory.c
+++ b/src/scene/scene_memory.c
@@ -12,6 +12,7 @@
12#include "object_impl.h" 12#include "object_impl.h"
13#include "scene_impl.h" 13#include "scene_impl.h"
14 14
15#include <log/log.h>
15#include <mempool.h> 16#include <mempool.h>
16 17
17DEF_MEMPOOL(anima_pool, Anima, GFX_MAX_NUM_ANIMAS) 18DEF_MEMPOOL(anima_pool, Anima, GFX_MAX_NUM_ANIMAS)
@@ -47,10 +48,11 @@ typedef struct SceneMemory {
47 48
48static SceneMemory mem; 49static SceneMemory mem;
49 50
50#define ALLOC_DUMMY(POOL) \ 51#define ALLOC_DUMMY(POOL) \
51 { \ 52 { \
52 const void* object = mempool_alloc(POOL); \ 53 const void* object = mempool_alloc(POOL); \
53 assert(mempool_get_block_index(POOL, object) == 0); \ 54 (void)object; /* Silence warning in release builds. */ \
55 assert(mempool_get_block_index(POOL, object) == 0); \
54 } 56 }
55 57
56#define PLURAL(name) name##s 58#define PLURAL(name) name##s
@@ -90,13 +92,40 @@ void scene_mem_destroy() {
90 // NOTE: the dummy objects are not constructed, so the destruction code below 92 // NOTE: the dummy objects are not constructed, so the destruction code below
91 // always skips index 0. (I don't really like the conditional inside the loop, 93 // always skips index 0. (I don't really like the conditional inside the loop,
92 // but this gets the job done without having to specialize the loop macro.) 94 // but this gets the job done without having to specialize the loop macro.)
93#define DESTROY(name) \ 95#define DESTROY(NAME) \
94 mempool_foreach(&MEM_FIELD(name), obj, { \ 96 mempool_foreach(&MEM_FIELD(NAME), obj, { \
95 if (i > 0) { \ 97 if (i > 0) { \
96 gfx_destroy_##name(&obj); \ 98 gfx_destroy_##NAME(&obj); \
97 } \ 99 } \
98 }) 100 })
99 101
102 // Print memory diagnostics.
103#define PRINT_POOL(POOL_NAME, POOL) \
104 { \
105 const size_t capacity = mempool_capacity(POOL); \
106 const size_t size = mempool_size(POOL); \
107 const size_t block_size_bytes = mempool_block_size_bytes(POOL); \
108 const size_t size_bytes = size * block_size_bytes; \
109 const size_t capacity_bytes = capacity * block_size_bytes; \
110 LOGI( \
111 "%s pool: %lu/%lu (%lu/%lu bytes)", POOL_NAME, size, capacity, \
112 size_bytes, capacity_bytes); \
113 }
114
115 LOGI("Pool diagnostics:");
116 PRINT_POOL("Animas", &mem.animas);
117 PRINT_POOL("Animations", &mem.animations);
118 PRINT_POOL("Cameras", &mem.cameras);
119 PRINT_POOL("Lights", &mem.lights);
120 PRINT_POOL("Materials", &mem.materials);
121 PRINT_POOL("Meshes", &mem.meshs);
122 PRINT_POOL("Mesh links", &mem.mesh_links);
123 PRINT_POOL("Models", &mem.models);
124 PRINT_POOL("Nodes", &mem.nodes);
125 PRINT_POOL("Objects", &mem.objects);
126 PRINT_POOL("Scenes", &mem.scenes);
127 PRINT_POOL("Skeletons", &mem.skeletons);
128
100 // Models contain scene elements. Destruction is handled by the remainder of 129 // Models contain scene elements. Destruction is handled by the remainder of
101 // scene destructionb elow. 130 // scene destructionb elow.
102 // 131 //
@@ -119,20 +148,20 @@ void scene_mem_destroy() {
119 // Skeletons are owned by animas and do not have a destructor. 148 // Skeletons are owned by animas and do not have a destructor.
120} 149}
121 150
122#define DEF_MEMORY(name, type) \ 151#define DEF_MEMORY(NAME, TYPE) \
123 /* xyz* mem_alloc_xyz(); */ \ 152 /* xyz* mem_alloc_xyz(); */ \
124 type* mem_alloc_##name() { return mempool_alloc(&MEM_FIELD(name)); } \ 153 TYPE* mem_alloc_##NAME() { return mempool_alloc(&MEM_FIELD(NAME)); } \
125 /* void mem_free_xyz(xyz**); */ \ 154 /* void mem_free_xyz(xyz**); */ \
126 void mem_free_##name(type** obj) { mempool_free(&MEM_FIELD(name), obj); } \ 155 void mem_free_##NAME(TYPE** obj) { mempool_free(&MEM_FIELD(NAME), obj); } \
127 /* xyz* mem_get_xyz(xyz_idx); */ \ 156 /* xyz* mem_get_xyz(xyz_idx); */ \
128 type* mem_get_##name(NAMED_INDEX(name) index) { \ 157 TYPE* mem_get_##NAME(NAMED_INDEX(NAME) index) { \
129 assert(index.val != 0); /* 0 is the dummy allocation. */ \ 158 assert(index.val != 0); /* 0 is the dummy allocation. */ \
130 return mempool_get_block(&MEM_FIELD(name), index.val); \ 159 return mempool_get_block(&MEM_FIELD(NAME), index.val); \
131 } \ 160 } \
132 /* xyz_idx mem_get_xyz_index(const xyz*); */ \ 161 /* xyz_idx mem_get_xyz_index(const xyz*); */ \
133 NAMED_INDEX(name) mem_get_##name##_index(const type* obj) { \ 162 NAMED_INDEX(NAME) mem_get_##NAME##_index(const TYPE* obj) { \
134 return (NAMED_INDEX(name)){ \ 163 return (NAMED_INDEX(NAME)){ \
135 .val = mempool_get_block_index(&MEM_FIELD(name), obj)}; \ 164 .val = mempool_get_block_index(&MEM_FIELD(NAME), obj)}; \
136 } 165 }
137 166
138DEF_MEMORY(anima, Anima) 167DEF_MEMORY(anima, Anima)