taisei/src/resource/resource.h
2024-05-17 14:11:48 +02:00

180 lines
6.1 KiB
C

/*
* This software is licensed under the terms of the MIT License.
* See COPYING for further information.
* ---
* Copyright (c) 2011-2024, Lukas Weber <laochailan@web.de>.
* Copyright (c) 2012-2024, Andrei Alexeyev <akari@taisei-project.org>.
*/
#pragma once
#include "taisei.h"
#include "dynarray.h"
#include "hashtable.h"
#include "vfs/public.h"
typedef enum ResourceType {
RES_TEXTURE,
RES_ANIM,
RES_SFX,
RES_BGM,
RES_SHADER_OBJECT,
RES_SHADER_PROGRAM,
RES_MODEL,
RES_POSTPROCESS,
RES_SPRITE,
RES_FONT,
RES_MATERIAL,
RES_NUMTYPES,
} ResourceType;
typedef enum ResourceFlags {
RESF_OPTIONAL = 1,
RESF_PRELOAD = 2,
RESF_RELOAD = 4,
RESF_DEFAULT = 0,
} ResourceFlags;
typedef struct ResourceLoadState ResourceLoadState;
struct ResourceLoadState {
const char *name;
const char *path;
void *opaque;
ResourceFlags flags;
};
// Converts an abstract resource name into a vfs path from which a resource with that name could be loaded.
// The path may not actually exist or be usable. The load function (see below) shall deal with such cases.
// The returned path must be free()'d.
// May return NULL on failure, but does not have to.
typedef char *(*ResourceFindProc)(const char *name);
// Tells whether the resource handler should attempt to load a file, specified by a vfs path.
typedef bool (*ResourceCheckProc)(const char *path);
// Begins loading a resource. Called on an unspecified thread.
// Must call one of the following res_load_* functions before returning to indicate status.
typedef void (*ResourceLoadProc)(ResourceLoadState *st);
// Makes `dst` refer to the resource represented by `src`.
// `src` may no longer be a valid reference to the resource after this operation.
// Resource previously represented by `dst` is destroyed in the process.
// Called on the main thread, after a resource reload successfully completes.
//
// Returns true if the operation succeeds.
// In case of failure, `dst` must not be modified, and `src` must be destroyed.
typedef bool (*ResourceTransferProc)(void *dst, void *src);
void res_load_failed(ResourceLoadState *st) attr_nonnull(1);
void res_load_finished(ResourceLoadState *st, void *res) attr_nonnull(1, 2);
// Indicates that loading must continue on the main thread.
// Schedules callback to be called on the main thread at some point in the future.
// The callback's load state parameter will contain the opaque pointer passed to this function.
// If the resource has dependencies, callback will not be called until they finish loading.
void res_load_continue_on_main(ResourceLoadState *st, ResourceLoadProc callback, void *opaque) attr_nonnull(1, 2);
// Like res_load_continue_on_main, but may be called from a worker thread.
// Use this to wait for dependencies if nothing needs to be done on the main thread.
void res_load_continue_after_dependencies(ResourceLoadState *st, ResourceLoadProc callback, void *opaque) attr_nonnull(1, 2);
// Registers another resource as a dependency and schedules it for asynchronous loading.
// Use with res_load_continue_after_dependencies/res_load_continue_on_main to wait for dependencies.
void res_load_dependency(ResourceLoadState *st, ResourceType type, const char *name);
// Like vfs_open(), but registers the path to monitor the file for changes.
// When a change is detected, the resource will be reloaded.
// This only works if the transfer proc is implemented; otherwise it's equivalent to vfs_open().
// Note that file monitoring support is not guaranteed.
SDL_RWops *res_open_file(ResourceLoadState *st, const char *path, VFSOpenMode mode);
// Unloads a resource, freeing all allocated to it memory.
typedef void (*ResourceUnloadProc)(void *res);
// Called during resource subsystem initialization
typedef void (*ResourceInitProc)(void);
// Called after the resources and rendering subsystems have been initialized
typedef void (*ResourcePostInitProc)(void);
// Called during resource subsystem shutdown
typedef void (*ResourceShutdownProc)(void);
typedef struct ResourceHandler {
ResourceType type;
char *typename;
char *subdir;
struct {
ResourceFindProc find;
ResourceCheckProc check;
ResourceLoadProc load;
ResourceUnloadProc unload;
ResourceTransferProc transfer;
ResourceInitProc init;
ResourcePostInitProc post_init;
ResourceShutdownProc shutdown;
} procs;
struct {
ht_str2ptr_ts_t mapping;
} private;
} ResourceHandler;
typedef struct Resource {
void *data;
ResourceType type;
ResourceFlags flags;
} Resource;
typedef struct ResourceGroup {
DYNAMIC_ARRAY(void*) refs;
} ResourceGroup;
void res_init(void);
void res_post_init(void);
void res_shutdown(void);
void res_reload_all(void);
void res_purge(void);
Resource *_res_get_prehashed(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) attr_nonnull_all;
INLINE void *_res_get_data_prehashed(ResourceType type, const char *name, hash_t hash, ResourceFlags flags) {
Resource *res = _res_get_prehashed(type, name, hash, flags);
return res ? res->data : NULL;
}
attr_nonnull_all
INLINE Resource *res_get(ResourceType type, const char *name, ResourceFlags flags) {
return _res_get_prehashed(type, name, ht_str2ptr_hash(name), flags);
}
attr_nonnull_all
INLINE void *res_get_data(ResourceType type, const char *name, ResourceFlags flags) {
return _res_get_data_prehashed(type, name, ht_str2ptr_hash(name), flags);
}
void *res_for_each(ResourceType type, void *(*callback)(const char *name, Resource *res, void *arg), void *arg);
void res_group_init(ResourceGroup *rg) attr_nonnull_all;
void res_group_release(ResourceGroup *rg) attr_nonnull_all;
void res_group_preload(ResourceGroup *rg, ResourceType type, ResourceFlags flags, ...)
attr_sentinel;
void res_util_strip_ext(char *path);
char *res_util_basename(const char *prefix, const char *path);
#define DEFINE_RESOURCE_GETTER(_type, _name, _enum) \
attr_nonnull_all attr_returns_nonnull \
INLINE _type *_name(const char *resname) { \
return NOT_NULL(res_get_data(_enum, resname, RESF_DEFAULT)); \
}
#define DEFINE_OPTIONAL_RESOURCE_GETTER(_type, _name, _enum) \
attr_nonnull_all \
INLINE _type *_name(const char *resname) { \
return res_get_data(_enum, resname, RESF_OPTIONAL); \
}