#ifndef RT_RESOURCES_H
#define RT_RESOURCES_H

/* Resource system interface
 *
 * To differentiate the two ideas, we call processed assets "resources"
 * and the source files "assets".
 *
 * For example a .pipeline file is an asset, while a compiled pipeline in
 * a binary file is a resource.
 *
 * Furthermore, a single asset file might contain multiple resources,
 * i.e. a single texture file might be turned into multiple resources for the different mip-levels.
 */

#include <stdint.h>

#include "runtime.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Identifies a single resource
 *
 * This is a hash of the resource name. */
typedef uint64_t rt_resource_id;

#define RT_INVALID_RESOURCE_ID 0u

typedef enum {
    /* Compiled shader code */
    RT_RESOURCE_SHADER,

    /* A pipeline state object */
    RT_RESOURCE_PIPELINE,

    RT_RESOURCE_FRAMEGRAPH,

    RT_RESOURCE_EFFECT,

    RT_RESOURCE_MESH,

    RT_RESOURCE_MESHLET,

    RT_RESOURCE_TYPE_count,
} rt_resource_type;

#define RT_MAX_SUBRESOURCES          32
#define RT_MAX_RESOURCE_DEPENDENCIES 32

typedef struct {
    /* Points to the resource data. The size of which is determined by the type. */
    void *data;
    rt_resource_type type;

    /* Subresources are necessary to complete the resource.
     * For example, a texture might contain different mip-levels as sub-resources. */
    uint32_t subresource_count;
    rt_resource_id subresources[RT_MAX_SUBRESOURCES];

    /* Dependencies reference distinct resources that are necessary to use this resource.
     * For example, a model file might depend on its materials */
    uint32_t dependency_count;
    rt_resource_id dependencies[RT_MAX_RESOURCE_DEPENDENCIES];
} rt_resource;

/* Retrieves a resource.
 *
 * This function will also attempt to pre-cache resources that are likely to be accessed
 * in the future. Namely subresources and dependencies of the accessed resource. 
 *
 * The passed destination must point to a buffer large enough to hold the resource.
 * You can query the resources size with rtGetResourceSize().
 */
RT_DLLEXPORT rt_result rtGetResource(rt_resource_id id, void *dest);

/* Notifies the system that a resource might be accessed soon.
 * Starts a asynchronous prefetch of that resource. */
RT_DLLEXPORT void rtPrefetchResources(const rt_resource_id *ids, uint32_t count);

/* Returns the size of a resource in bytes, or 0 if the resource id is invalid. */
RT_DLLEXPORT size_t rtGetResourceSize(rt_resource_id id);

/* Returns the resource id that maps to a given name.
 * Does not check if a resource with that id does exist. */
RT_DLLEXPORT rt_resource_id rtGetResourceID(const char *name);

/* Logs information about a resource. Useful for debugging */
RT_DLLEXPORT void rDebugLogResource(rt_resource_id id, const rt_resource *resource);

RT_DLLEXPORT void rtSaveResourceNamespace(void);

/* Registers resources with the resource manager, making them available to the system.
 * 
 * The runtime will create a standalone file for each resource in the resource directory.
 * To package them, you will need to use a separate tool.
 */
RT_DLLEXPORT rt_result rtCreateResources(uint32_t count,
                                         const char **names,
                                         const rt_resource *resources,
                                         rt_resource_id *ids);

#ifdef __cplusplus
}
#endif

#endif
