From c593c24b62b274fbc1d465f0386a0c5d32423f4f Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Mon, 12 Feb 2024 17:42:57 -0800 Subject: Initial implementation for an asset cache. --- game/src/plugins/viewer.c | 69 ++++++++++------ gfx/CMakeLists.txt | 1 + gfx/include/gfx/asset.h | 98 ++++++++++++++++++++++ gfx/include/gfx/gfx.h | 6 +- gfx/include/gfx/sizes.h | 4 + gfx/include/gfx/util/scene.h | 24 +----- gfx/include/gfx/util/texture.h | 62 +------------- gfx/src/asset/asset_cache.c | 183 +++++++++++++++++++++++++++++++++++++++++ gfx/src/asset/asset_cache.h | 31 +++++++ gfx/src/gfx.c | 10 ++- gfx/src/util/scene.c | 74 ++++++++--------- gfx/src/util/texture.c | 8 +- 12 files changed, 419 insertions(+), 151 deletions(-) create mode 100644 gfx/include/gfx/asset.h create mode 100644 gfx/src/asset/asset_cache.c create mode 100644 gfx/src/asset/asset_cache.h diff --git a/game/src/plugins/viewer.c b/game/src/plugins/viewer.c index 83fc8ed..1ed3b9d 100644 --- a/game/src/plugins/viewer.c +++ b/game/src/plugins/viewer.c @@ -30,31 +30,33 @@ struct State { }; /// Load the skyquad texture. -static Texture* load_environment_map(RenderBackend* render_backend) { +static Texture* load_environment_map(Gfx* gfx) { + assert(gfx); return gfx_load_texture( - render_backend, - &(LoadTextureCmd){ - .origin = TextureFromFile, - .type = LoadCubemap, - .colour_space = sRGB, - .filtering = NearestFiltering, - .mipmaps = false, - .data.cubemap.filepaths = { - mstring_make("/assets/skybox/clouds1/clouds1_east.bmp"), - mstring_make("/assets/skybox/clouds1/clouds1_west.bmp"), - mstring_make("/assets/skybox/clouds1/clouds1_up.bmp"), - mstring_make("/assets/skybox/clouds1/clouds1_down.bmp"), - mstring_make("/assets/skybox/clouds1/clouds1_south.bmp"), - mstring_make("/assets/skybox/clouds1/clouds1_north.bmp")} + gfx, &(LoadTextureCmd){ + .origin = AssetFromFile, + .type = LoadCubemap, + .colour_space = sRGB, + .filtering = NearestFiltering, + .mipmaps = false, + .data.cubemap.filepaths = { + mstring_make("/assets/skybox/clouds1/clouds1_east.bmp"), + mstring_make("/assets/skybox/clouds1/clouds1_west.bmp"), + mstring_make("/assets/skybox/clouds1/clouds1_up.bmp"), + mstring_make("/assets/skybox/clouds1/clouds1_down.bmp"), + mstring_make("/assets/skybox/clouds1/clouds1_south.bmp"), + mstring_make("/assets/skybox/clouds1/clouds1_north.bmp")} }); } /// Load the skyquad and return the environment light node. -static SceneNode* load_skyquad(RenderBackend* render_backend, SceneNode* root) { - assert(render_backend); +static SceneNode* load_skyquad(Gfx* gfx, SceneNode* root) { + assert(gfx); assert(root); - Texture* environment_map = load_environment_map(render_backend); + RenderBackend* render_backend = gfx_get_render_backend(gfx); + + Texture* environment_map = load_environment_map(gfx); if (!environment_map) { return 0; } @@ -70,20 +72,19 @@ static SceneNode* load_scene( assert(state); assert(state->scene); - SceneNode* root = gfx_get_scene_root(state->scene); - RenderBackend* render_backend = gfx_get_render_backend(game->gfx); - Camera* camera = gfx_get_camera_camera(state->camera); spatial3_set_position(&camera->spatial, vec3_make(0, 0, 2)); - SceneNode* sky_light_node = load_skyquad(render_backend, root); + SceneNode* root = gfx_get_scene_root(state->scene); + SceneNode* sky_light_node = load_skyquad(game->gfx, root); if (!sky_light_node) { - return 0; + return 0; // test } SceneNode* scene_node = gfx_load_scene( game->gfx, sky_light_node, - &(LoadSceneCmd){.origin = SceneFromFile, .filepath = scene_filepath}); + &(LoadSceneCmd){ + .origin = AssetFromFile, .filepath = mstring_make(scene_filepath)}); if (!scene_node) { return 0; } @@ -136,6 +137,10 @@ cleanup: void shutdown(Game* game, State* state) { assert(game); if (state) { + // TODO: Destroying the scene here currently does not play well with asset + // reloading. The issue is that we expect to mutate the scene/model during + // animation. This needs to change if we want to be able to cache assets + // in memory. gfx_destroy_camera(&state->camera); gfx_destroy_scene(&state->scene); // State freed by plugin engine. @@ -165,8 +170,20 @@ static void render_bounding_boxes_rec(ImmRenderer* imm, const SceneNode* node) { assert(node); if (gfx_get_node_type(node) == ObjectNode) { // TODO: Look at the scene log. The JointNodes are detached from the - // ObjectNodes. This is why the boxes are not being transformed as expected - // here. Anima needs to animate boxes? Use OOBB in addition to AABB? + // ObjectNodes. This is why the boxes are not being transformed as expected + // here. Anima needs to animate boxes? Use OOBB in addition to AABB? + // + // TODO: Idea: when a model is loaded, compute an OOBB per joint using the + // vertices that are affected by the joint. Then transform this OOBB when + // animating the skeleton. Start with AABB for simplicity. The AABB/OOBB + // in the skeleton should be const. The transform AABB/OOBB is derived + // on demand. Stack allocator would be best for this kind of per-frame + // data. + // + // TODO: After computing joint AABB/OOBBs, check here whether the node has + // a skeleton, and if so, render the skeleton's boxes instead of the + // node's (the node's boxes are not animated, but computer from the rest + // pose). const mat4 model = gfx_get_node_global_transform(node); const SceneObject* obj = gfx_get_node_object(node); const aabb3 box = gfx_calc_object_aabb(obj); diff --git a/gfx/CMakeLists.txt b/gfx/CMakeLists.txt index 3aa3312..e5c965e 100644 --- a/gfx/CMakeLists.txt +++ b/gfx/CMakeLists.txt @@ -33,6 +33,7 @@ add_shader_library(shaders shaders/view_texture.vert) add_library(gfx SHARED + src/asset/asset_cache.c src/render/buffer.c src/render/framebuffer.c src/render/geometry.c diff --git a/gfx/include/gfx/asset.h b/gfx/include/gfx/asset.h new file mode 100644 index 0000000..28b8557 --- /dev/null +++ b/gfx/include/gfx/asset.h @@ -0,0 +1,98 @@ +/* Asset Management */ +#pragma once + +#include + +#include + +typedef struct Gfx Gfx; +typedef struct SceneNode SceneNode; +typedef struct ShaderProgram ShaderProgram; +typedef struct Texture Texture; + +/// Describes where the asset comes from. +typedef enum AssetOrigin { + AssetFromMemory, + AssetFromFile, +} AssetOrigin; + +/// Describes a texture's colour space. +typedef enum TextureColourSpace { + sRGB, // The most likely default. + LinearColourSpace, +} TextureColourSpace; + +/// Describes a command to load a texture. +typedef struct LoadTextureCmd { + AssetOrigin origin; + enum { LoadTexture, LoadCubemap } type; + TextureColourSpace colour_space; + TextureFiltering filtering; + TextureWrapping wrap; + bool mipmaps; + union { + // A single texture. + struct { + union { + struct { + mstring filepath; + }; + struct { + const void* data; + size_t size_bytes; + }; + }; + } texture; + // Cubemap texture. + struct { + union { + struct { + mstring filepath_pos_x; + mstring filepath_neg_x; + mstring filepath_pos_y; + mstring filepath_neg_y; + mstring filepath_pos_z; + mstring filepath_neg_z; + } filepaths; + struct { + const void* data_pos_x; + const void* data_neg_x; + const void* data_pos_y; + const void* data_neg_y; + const void* data_pos_z; + const void* data_neg_z; + } buffers; + }; + } cubemap; + } data; +} LoadTextureCmd; + +/// Describes a command to load a scene. +typedef struct LoadSceneCmd { + AssetOrigin origin; + union { + struct { + mstring filepath; + }; + struct { + const void* data; + size_t size_bytes; + }; + }; + ShaderProgram* shader; +} LoadSceneCmd; + +/// Load a scene. +/// +/// Return a top-level node under which scene elements are rooted. |root_node| +/// is made the parent of this top-level node. +/// +/// |shader| is an optional shader program assigned to the loaded scene objects. +/// If no shader is given, a Cook-Torrance shader based on the object's +/// characteristics (presence of normals, tangents, etc) is assigned. +/// +/// Currently only supports the GLTF format. +SceneNode* gfx_load_scene(Gfx*, SceneNode* root_node, const LoadSceneCmd*); + +/// Load a texture. +Texture* gfx_load_texture(Gfx*, const LoadTextureCmd*); diff --git a/gfx/include/gfx/gfx.h b/gfx/include/gfx/gfx.h index b8f2595..bfc457f 100644 --- a/gfx/include/gfx/gfx.h +++ b/gfx/include/gfx/gfx.h @@ -1,10 +1,9 @@ #pragma once +typedef struct AssetCache AssetCache; typedef struct ImmRenderer ImmRenderer; typedef struct RenderBackend RenderBackend; typedef struct Renderer Renderer; -typedef struct Scene Scene; -typedef struct SceneCamera SceneCamera; typedef struct Gfx Gfx; @@ -23,6 +22,9 @@ Renderer* gfx_get_renderer(Gfx*); /// Get the immediate mode renderer. ImmRenderer* gfx_get_imm_renderer(Gfx*); +/// Get the asset cache. +AssetCache* gfx_get_asset_cache(Gfx*); + /// Remove unused resources from the scene (meshes, materials). /// TODO: need to think about the interface for scene_purge(). Maybe this /// should be gfx_purge() and take a list of Scenes? diff --git a/gfx/include/gfx/sizes.h b/gfx/include/gfx/sizes.h index f2ace8a..b6f47ef 100644 --- a/gfx/include/gfx/sizes.h +++ b/gfx/include/gfx/sizes.h @@ -83,6 +83,10 @@ /// Maximum number of matrices in the immediate-mode renderer's matrix stack. #define IMM_MAX_NUM_MATRICES 32 +// Asset Manager. + +#define GFX_MAX_NUM_ASSETS 1024 + // Gfx. #define GFX_MAX_NUM_SCENES 4 diff --git a/gfx/include/gfx/util/scene.h b/gfx/include/gfx/util/scene.h index fa9304b..c03e2cb 100644 --- a/gfx/include/gfx/util/scene.h +++ b/gfx/include/gfx/util/scene.h @@ -1,26 +1,10 @@ /// Load scene files. #pragma once -#include -#include +#include -typedef struct Gfx Gfx; -typedef struct SceneNode SceneNode; -typedef struct ShaderProgram ShaderProgram; - -typedef struct LoadSceneCmd { - enum { SceneFromMemory, SceneFromFile } origin; - union { - struct { - const char* filepath; - }; - struct { - const void* data; - size_t size_bytes; - }; - }; - ShaderProgram* shader; -} LoadSceneCmd; +typedef struct Gfx Gfx; +typedef struct SceneNode SceneNode; /// Load a scene. /// @@ -32,4 +16,4 @@ typedef struct LoadSceneCmd { /// characteristics (presence of normals, tangents, etc) is assigned. /// /// Currently only supports the GLTF format. -SceneNode* gfx_load_scene(Gfx*, SceneNode* root_node, const LoadSceneCmd*); +SceneNode* gfx_scene_load(Gfx*, SceneNode* root_node, const LoadSceneCmd*); diff --git a/gfx/include/gfx/util/texture.h b/gfx/include/gfx/util/texture.h index cdc582b..a3239fe 100644 --- a/gfx/include/gfx/util/texture.h +++ b/gfx/include/gfx/util/texture.h @@ -1,63 +1,7 @@ /// Load textures from images. #pragma once -#include +#include -#include - -#include -#include - -/// Describes a texture's colour space. -typedef enum TextureColourSpace { - sRGB, // The most likely default. - LinearColourSpace, -} TextureColourSpace; - -/// Describes a command to load a texture. -typedef struct LoadTextureCmd { - enum { TextureFromMemory, TextureFromFile } origin; - enum { LoadTexture, LoadCubemap } type; - TextureColourSpace colour_space; - TextureFiltering filtering; - TextureWrapping wrap; - bool mipmaps; - union { - // A single texture. - struct { - union { - struct { - mstring filepath; - }; - struct { - const void* data; - size_t size_bytes; - }; - }; - } texture; - // Cubemap texture. - struct { - union { - struct { - mstring filepath_pos_x; - mstring filepath_neg_x; - mstring filepath_pos_y; - mstring filepath_neg_y; - mstring filepath_pos_z; - mstring filepath_neg_z; - } filepaths; - struct { - const void* data_pos_x; - const void* data_neg_x; - const void* data_pos_y; - const void* data_neg_y; - const void* data_pos_z; - const void* data_neg_z; - } buffers; - }; - } cubemap; - } data; -} LoadTextureCmd; - -/// Load a cubemap texture. -Texture* gfx_load_texture(RenderBackend*, const LoadTextureCmd*); +/// Load a texture. +Texture* gfx_texture_load(RenderBackend*, const LoadTextureCmd*); diff --git a/gfx/src/asset/asset_cache.c b/gfx/src/asset/asset_cache.c new file mode 100644 index 0000000..0c6a8dc --- /dev/null +++ b/gfx/src/asset/asset_cache.c @@ -0,0 +1,183 @@ +#include "asset_cache.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include + +static Hash calc_scene_hash(const LoadSceneCmd* cmd) { + assert(cmd); + switch (cmd->origin) { + case AssetFromFile: + return cstring_hash(mstring_cstr(&cmd->filepath)); + case AssetFromMemory: + return (Hash)cmd->data; + } + assert(false); + return 0; +} + +static Hash calc_texture_hash(const LoadTextureCmd* cmd) { + assert(cmd); + switch (cmd->origin) { + case AssetFromFile: + switch (cmd->type) { + case LoadTexture: + return cstring_hash(mstring_cstr(&cmd->data.texture.filepath)); + case LoadCubemap: + return cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_x)) ^ + cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_x)) ^ + cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_y)) ^ + cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_y)) ^ + cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_pos_z)) ^ + cstring_hash( + mstring_cstr(&cmd->data.cubemap.filepaths.filepath_neg_z)); + } + break; + case AssetFromMemory: + switch (cmd->type) { + case LoadTexture: + return (Hash)cmd->data.texture.data; + case LoadCubemap: + return (Hash)cmd->data.cubemap.buffers.data_pos_x ^ + (Hash)cmd->data.cubemap.buffers.data_neg_x ^ + (Hash)cmd->data.cubemap.buffers.data_pos_y ^ + (Hash)cmd->data.cubemap.buffers.data_neg_y ^ + (Hash)cmd->data.cubemap.buffers.data_pos_z ^ + (Hash)cmd->data.cubemap.buffers.data_neg_z; + } + break; + } + assert(false); + return 0; +} + +static Asset* lookup_cache(AssetCache* cache, Hash hash) { + assert(cache); + mempool_foreach(&cache->assets, asset, { + if (asset->hash == hash) { + return asset; + } + }); + return 0; +} + +// TODO: questionable function. Make mempool_alloc() fail when out of memory. +static void insert_into_cache(AssetCache* cache, const Asset* asset) { + assert(cache); + assert(asset); + Asset* poolAsset = mempool_alloc(&cache->assets); + assert(asset); + *poolAsset = *asset; +} + +static void log_scene_cache_hit(const LoadSceneCmd* cmd, Hash hash) { + assert(cmd); + switch (cmd->origin) { + case AssetFromFile: + LOGI( + "Found asset [%s] in cache with hash [%lu]", + mstring_cstr(&cmd->filepath), hash); + break; + case AssetFromMemory: + LOGI("Found asset [%p] in cache with hash [%lu]", cmd->data, hash); + break; + } +} + +static void log_scene_loaded(const LoadSceneCmd* cmd) { + assert(cmd); + switch (cmd->origin) { + case AssetFromFile: + LOGI("Loaded asset from file: [%s]", mstring_cstr(&cmd->filepath)); + break; + case AssetFromMemory: + LOGI("Loaded asset from memory: [%p]", cmd->data); + break; + } +} + +void gfx_init_asset_cache(AssetCache* cache) { + assert(cache); + mempool_make(&cache->assets); + + // Allocate a dummy asset at index 0 to guarantee that no assets allocated by + // the caller map to index 0. + const Asset* dummy = mempool_alloc(&cache->assets); + assert(mempool_get_block_index(&cache->assets, dummy) == 0); +} + +void gfx_destroy_asset_cache(AssetCache* cache) { + assert(cache); + mempool_del(&cache->assets); +} + +SceneNode* gfx_load_scene( + Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { + assert(gfx); + + AssetCache* cache = gfx_get_asset_cache(gfx); + + // First search for the asset in the cache. + // TODO: Animated models are currently mutated in place, so sharing them is + // not really valid. + const uint64_t hash = calc_scene_hash(cmd); + Asset* asset = lookup_cache(cache, hash); + if (asset) { + log_scene_cache_hit(cmd, hash); + return (SceneNode*)asset; + } + + // Asset not found in the cache. + // Load it, insert it into the cache, and return it. + SceneNode* node = gfx_scene_load(gfx, root_node, cmd); + if (node) { + insert_into_cache( + cache, &(Asset){ + .type = SceneAsset, + .hash = hash, + .data = node, + }); + log_scene_loaded(cmd); + } + return node; +} + +Texture* gfx_load_texture(Gfx* gfx, const LoadTextureCmd* cmd) { + assert(gfx); + assert(cmd); + + AssetCache* cache = gfx_get_asset_cache(gfx); + + // First search for the asset in the cache. + const uint64_t hash = calc_texture_hash(cmd); + Asset* asset = lookup_cache(cache, hash); + if (asset) { + return (Texture*)asset; + } + + // Asset not found in the cache. + // Load it, insert it into the cache, and return it. + RenderBackend* render_backend = gfx_get_render_backend(gfx); + Texture* texture = gfx_texture_load(render_backend, cmd); + if (texture) { + insert_into_cache( + cache, &(Asset){ + .type = TextureAsset, + .hash = hash, + .data = texture, + }); + } + return texture; +} diff --git a/gfx/src/asset/asset_cache.h b/gfx/src/asset/asset_cache.h new file mode 100644 index 0000000..04baa51 --- /dev/null +++ b/gfx/src/asset/asset_cache.h @@ -0,0 +1,31 @@ +#pragma once + +#include + +#include +#include + +typedef uint64_t Hash; + +typedef enum AssetType { + SceneAsset, + TextureAsset, +} AssetType; + +typedef struct Asset { + AssetType type; + Hash hash; + void* data; +} Asset; + +DEF_MEMPOOL(asset_pool, Asset, GFX_MAX_NUM_ASSETS) + +typedef struct AssetCache { + asset_pool assets; +} AssetCache; + +/// Create a new asset cache. +void gfx_init_asset_cache(AssetCache*); + +/// Destroy the asset cache. +void gfx_destroy_asset_cache(AssetCache*); diff --git a/gfx/src/gfx.c b/gfx/src/gfx.c index fc720ed..7095ea1 100644 --- a/gfx/src/gfx.c +++ b/gfx/src/gfx.c @@ -1,5 +1,6 @@ #include +#include "asset/asset_cache.h" #include "render/render_backend_impl.h" #include "renderer/imm_renderer_impl.h" #include "renderer/renderer_impl.h" @@ -14,6 +15,7 @@ #include typedef struct Gfx { + AssetCache asset_cache; RenderBackend render_backend; Renderer renderer; ImmRenderer imm_renderer; @@ -40,16 +42,17 @@ Gfx* gfx_init(void) { gfx_destroy(&gfx); return 0; } + gfx_init_asset_cache(&gfx->asset_cache); scene_mem_init(); return gfx; } void gfx_destroy(Gfx** gfx) { - assert(gfx); if (!gfx) { return; } scene_mem_destroy(); + gfx_destroy_asset_cache(&(*gfx)->asset_cache); renderer_destroy(&(*gfx)->renderer); imm_renderer_destroy(&(*gfx)->imm_renderer); gfx_del_render_backend(&(*gfx)->render_backend); @@ -71,3 +74,8 @@ ImmRenderer* gfx_get_imm_renderer(Gfx* gfx) { assert(gfx); return &gfx->imm_renderer; } + +AssetCache* gfx_get_asset_cache(Gfx* gfx) { + assert(gfx); + return &gfx->asset_cache; +} diff --git a/gfx/src/util/scene.c b/gfx/src/util/scene.c index 5d79cf2..5bf45aa 100644 --- a/gfx/src/util/scene.c +++ b/gfx/src/util/scene.c @@ -655,7 +655,7 @@ static void load_textures_lazy( mstring_concat_path(mstring_make(directory), mstring_make(image->uri)); load_texture_cmds[i] = (LoadTextureCmd){ - .origin = TextureFromFile, + .origin = AssetFromFile, .type = LoadTexture, .colour_space = sRGB, .filtering = filtering, @@ -670,12 +670,11 @@ static void load_textures_lazy( /// This determines a texture's colour space based on its intended use, loads /// the texture, and then defines the sampler shader uniform. static bool load_texture_and_uniform( - const cgltf_data* data, RenderBackend* render_backend, - const cgltf_texture_view* texture_view, TextureType texture_type, - Texture** textures, LoadTextureCmd* load_texture_cmds, int* next_uniform, - MaterialDesc* desc) { + const cgltf_data* data, Gfx* gfx, const cgltf_texture_view* texture_view, + TextureType texture_type, Texture** textures, + LoadTextureCmd* load_texture_cmds, int* next_uniform, MaterialDesc* desc) { assert(data); - assert(render_backend); + assert(gfx); assert(texture_view); assert(textures); assert(next_uniform); @@ -700,7 +699,7 @@ static bool load_texture_and_uniform( mstring_cstr(&cmd->data.texture.filepath), cmd->mipmaps, cmd->filtering); - textures[texture_index] = gfx_load_texture(render_backend, cmd); + textures[texture_index] = gfx_load_texture(gfx, cmd); if (!textures[texture_index]) { prepend_error( "Failed to load texture: %s", @@ -724,11 +723,10 @@ static bool load_texture_and_uniform( /// the index of each glTF material in the scene. Also return the number of /// materials and the textures used by them. static bool load_materials( - const cgltf_data* data, RenderBackend* render_backend, - LoadTextureCmd* load_texture_cmds, Texture** textures, - Material** materials) { + const cgltf_data* data, Gfx* gfx, LoadTextureCmd* load_texture_cmds, + Texture** textures, Material** materials) { assert(data); - assert(render_backend); + assert(gfx); assert(materials); if (data->textures_count > 0) { assert(load_texture_cmds); @@ -771,16 +769,15 @@ static bool load_materials( if (pbr->base_color_texture.texture) { if (!load_texture_and_uniform( - data, render_backend, &pbr->base_color_texture, - BaseColorTexture, textures, load_texture_cmds, &next_uniform, - &desc)) { + data, gfx, &pbr->base_color_texture, BaseColorTexture, textures, + load_texture_cmds, &next_uniform, &desc)) { return false; } } if (pbr->metallic_roughness_texture.texture) { if (!load_texture_and_uniform( - data, render_backend, &pbr->metallic_roughness_texture, + data, gfx, &pbr->metallic_roughness_texture, MetallicRoughnessTexture, textures, load_texture_cmds, &next_uniform, &desc)) { return false; @@ -790,24 +787,23 @@ static bool load_materials( if (mat->emissive_texture.texture) { if (!load_texture_and_uniform( - data, render_backend, &mat->emissive_texture, EmissiveTexture, - textures, load_texture_cmds, &next_uniform, &desc)) { + data, gfx, &mat->emissive_texture, EmissiveTexture, textures, + load_texture_cmds, &next_uniform, &desc)) { return false; } } if (mat->occlusion_texture.texture) { if (!load_texture_and_uniform( - data, render_backend, &mat->occlusion_texture, - AmbientOcclusionTexture, textures, load_texture_cmds, - &next_uniform, &desc)) { + data, gfx, &mat->occlusion_texture, AmbientOcclusionTexture, + textures, load_texture_cmds, &next_uniform, &desc)) { return false; } } if (mat->normal_texture.texture) { if (!load_texture_and_uniform( - data, render_backend, &mat->normal_texture, NormalMap, textures, + data, gfx, &mat->normal_texture, NormalMap, textures, load_texture_cmds, &next_uniform, &desc)) { return false; } @@ -878,7 +874,7 @@ aabb3 compute_aabb(const cgltf_accessor* accessor, int dim) { /// Load all meshes from the glTF scene. static bool load_meshes( - const cgltf_data* data, Gfx* gfx, Buffer** buffers, + const cgltf_data* data, RenderBackend* render_backend, Buffer** buffers, Buffer** tangent_buffers, const cgltfTangentBuffer* cgltf_tangent_buffers, cgltf_size num_tangent_buffers, Material** materials, ShaderProgram* const shader, size_t primitive_count, Geometry** geometries, @@ -894,7 +890,7 @@ static bool load_meshes( // Accessor + buffer view BufferView // Buffer Buffer assert(data); - assert(gfx); + assert(render_backend); assert(buffers); assert(materials); assert(geometries); @@ -905,9 +901,6 @@ static bool load_meshes( assert(cgltf_tangent_buffers); } - // TODO: pass render_backend as argument instead of gfx. - RenderBackend* render_backend = gfx_get_render_backend(gfx); - // Points to the next available Mesh and also the next available Geometry. // There is one (Mesh, Geometry) pair per glTF mesh primitive. size_t next_mesh = 0; @@ -1331,6 +1324,10 @@ static void load_nodes( assert(skin_index < data->skins_count); const Skeleton* skeleton = gfx_get_anima_skeleton(anima, skin_index); gfx_set_object_skeleton(object, skeleton); + + // TODO: Compute AABBs/OOBBs for the skeleton's joints here. Iterate + // over the mesh's primitives, its vertices, their joint indices, and + // add the vertex to the AABB/OOBB. } } else if (node->camera) { assert(next_camera < data->cameras_count); @@ -1409,7 +1406,7 @@ static void load_nodes( /// This function ignores the many scenes and default scene of the glTF spec /// and instead just loads all scenes into a single gfx Scene. static SceneNode* load_scene( - cgltf_data* data, Gfx* gfx, SceneNode* root_node, const char* filepath, + cgltf_data* data, Gfx* gfx, SceneNode* root_node, const mstring* filepath, ShaderProgram* shader, const cgltfTangentBuffer* cgltf_tangent_buffers, cgltf_size num_tangent_buffers) { // In a GLTF scene, buffers can be shared among meshes, meshes among nodes, @@ -1437,8 +1434,8 @@ static SceneNode* load_scene( RenderBackend* render_backend = gfx_get_render_backend(gfx); const size_t primitive_count = get_total_primitives(data); - const mstring directory = mstring_dirname(mstring_make(filepath)); - LOGD("Filepath: %s", filepath); + const mstring directory = mstring_dirname(*filepath); + LOGD("Filepath: %s", mstring_cstr(filepath)); LOGD("Directory: %s", mstring_cstr(&directory)); Buffer** tangent_buffers = 0; @@ -1494,13 +1491,12 @@ static SceneNode* load_scene( data, render_backend, mstring_cstr(&directory), load_texture_cmds); } - if (!load_materials( - data, render_backend, load_texture_cmds, textures, materials)) { + if (!load_materials(data, gfx, load_texture_cmds, textures, materials)) { goto cleanup; } if (!load_meshes( - data, gfx, buffers, tangent_buffers, cgltf_tangent_buffers, + data, render_backend, buffers, tangent_buffers, cgltf_tangent_buffers, num_tangent_buffers, materials, shader, primitive_count, geometries, meshes, scene_objects)) { goto cleanup; @@ -1639,7 +1635,7 @@ cleanup: return anima_node; } -SceneNode* gfx_load_scene( +SceneNode* gfx_scene_load( Gfx* gfx, SceneNode* root_node, const LoadSceneCmd* cmd) { assert(gfx); assert(root_node); @@ -1653,10 +1649,10 @@ SceneNode* gfx_load_scene( cgltf_result result; switch (cmd->origin) { - case SceneFromFile: - result = cgltf_parse_file(&options, cmd->filepath, &data); + case AssetFromFile: + result = cgltf_parse_file(&options, mstring_cstr(&cmd->filepath), &data); break; - case SceneFromMemory: + case AssetFromMemory: result = cgltf_parse(&options, cmd->data, cmd->size_bytes, &data); break; } @@ -1664,9 +1660,9 @@ SceneNode* gfx_load_scene( goto cleanup; } - if (cmd->origin == SceneFromFile) { + if (cmd->origin == AssetFromFile) { // Must call cgltf_load_buffers() to load buffer data. - result = cgltf_load_buffers(&options, data, cmd->filepath); + result = cgltf_load_buffers(&options, data, mstring_cstr(&cmd->filepath)); if (result != cgltf_result_success) { goto cleanup; } @@ -1678,7 +1674,7 @@ SceneNode* gfx_load_scene( &options, data, &tangent_buffers, &num_tangent_buffers); scene_node = load_scene( - data, gfx, root_node, cmd->filepath, cmd->shader, tangent_buffers, + data, gfx, root_node, &cmd->filepath, cmd->shader, tangent_buffers, num_tangent_buffers); cleanup: diff --git a/gfx/src/util/texture.c b/gfx/src/util/texture.c index 23f15f0..0d2e4b8 100644 --- a/gfx/src/util/texture.c +++ b/gfx/src/util/texture.c @@ -43,18 +43,18 @@ static void flip_horizontally( // For this reason, we do X and Y flips when doing cubemap textures so that we // can sample cubemaps as if they were given in the usual OpenGL coordinate // system. -Texture* gfx_load_texture( +Texture* gfx_texture_load( RenderBackend* render_backend, const LoadTextureCmd* cmd) { assert(render_backend); assert(cmd); - assert(cmd->origin == TextureFromFile || cmd->origin == TextureFromMemory); + assert(cmd->origin == AssetFromFile || cmd->origin == AssetFromMemory); assert(cmd->type == LoadTexture || cmd->type == LoadCubemap); int width, height, components, old_components; unsigned char* pixels[6] = {0}; switch (cmd->origin) { - case TextureFromFile: + case AssetFromFile: switch (cmd->type) { case LoadTexture: { const char* filepath = mstring_cstr(&cmd->data.texture.filepath); @@ -91,7 +91,7 @@ Texture* gfx_load_texture( break; } break; - case TextureFromMemory: + case AssetFromMemory: // TODO: Load textures from memory. set_error("Loading textures from memory is not yet implemented"); return 0; -- cgit v1.2.3