#ifndef RT_RENDERER_RENDER_RESOURCE_H
#define RT_RENDERER_RENDER_RESOURCE_H

#include <stdint.h>
#include <runtime/runtime.h>
#include <runtime/resources.h>

typedef enum {
    RT_RENDER_RESOURCE_TYPE_INVALID,
    RT_RENDER_RESOURCE_TYPE_BUFFER,
    RT_RENDER_RESOURCE_TYPE_TEXTURE2D,
    /* Max is 2**6 = 64 */
} rt_render_resource_type;

/* Handle to a render resource. 
 * The layout is:
 * | type : 6 | version : 6 | index : 20 |
 * MSB                                 LSB
 */
typedef struct {
    uint32_t value;
} rt_render_resource_handle;

/* Aliases for render_resource_handle to be able to express the type of expected resources in code. */

typedef rt_render_resource_handle rt_render_buffer_handle;
typedef rt_render_resource_handle rt_render_texture2d_handle;

#define RT_RENDER_RESOURCE_MAX_VERSION 0x3f

/* Extract the type part of a render resource handle */
static RT_INLINE rt_render_resource_type rtGetRenderResourceHandleType(rt_render_resource_handle h) {
    return (rt_render_resource_type)((h.value >> 26) & 0x3f);    
}

/* Extract the version part of a render resource handle */
static RT_INLINE uint32_t rtGetRenderResourceHandleVersion(rt_render_resource_handle h) {
    return (h.value >> 20) & 0x3f;
}

/* Extract the index part of a render resource handle */
static RT_INLINE uint32_t rtGetRenderResourceHandleIndex(rt_render_resource_handle h) {
    return h.value & 0xfffff;
}

/* Create a render resource handle. This only does the required bit-shifting, it does not actually register any resource for the handle. */
static RT_INLINE rt_render_resource_handle rtMakeRenderResourceHandle(rt_render_resource_type type, uint32_t version, uint32_t index) {
    rt_render_resource_handle h;
    h.value = ((type & 0x3f) << 26u) | ((version & 0x3f) << 20u) | (index & 0xfffff);
    return h;
}

/* Resource description structs */

typedef enum {
    RT_RENDER_BUFFER_USAGE_NONE           = 0,
    RT_RENDER_BUFFER_USAGE_VERTEX_BUFFER  = 0x01,
    RT_RENDER_BUFFER_USAGE_INDEX_BUFFER   = 0x02,
    RT_RENDER_BUFFER_USAGE_STORAGE_BUFFER = 0x04,

    /* The buffer will be used as a source to populate other resources
     * with data */
    RT_RENDER_BUFFER_USAGE_UPLOAD_BUFFER  = 0x10,
} rt_render_buffer_usage_flags;

typedef enum {
    /* The buffer can reside in memory that can only be accessed by the GPU */
    RT_RENDER_BUFFER_ACCESS_GPU_ONLY    = 0x01,

    /* The buffer needs to be in CPU accessible memory */
    RT_RENDER_BUFFER_ACCESS_CPU_AND_GPU = 0x02,

    /* The buffer is short-lived (will be destroyed at the end of the frame) */
    RT_RENDER_BUFFER_ACCESS_TRANSIENT   = 0x04,
} rt_render_buffer_access_flags;

/* Describes a gpu buffer */
typedef struct {
    /* The required size in bytes */
    size_t size;

    /* Bitmask describing the usage of the buffer */
    rt_render_buffer_usage_flags usage;

    /* Bitmask describing the access the buffer needs to support */
    rt_render_buffer_access_flags access;

    /* ResourceID of the resource that will be used to populate this buffer. */
    rt_resource_id source_resource;
} rt_render_buffer_desc;

typedef enum {
    RT_TEXTURE_FORMAT_B8G8R8A8_SRGB,

    RT_TEXTURE_FORMAT_MAX,
} rt_texture_format;

typedef enum {
    RT_TEXTURE_USAGE_NONE                     = 0x00,
    RT_TEXTURE_USAGE_COLOR_ATTACHMENT         = 0x01,
    RT_TEXTURE_USAGE_DEPTH_STENCIL_ATTACHMENT = 0x02,
    RT_TEXTURE_USAGE_SAMPLED_IMAGE            = 0x04,
    RT_TEXTURE_USAGE_STORAGE_IMAGE            = 0x10,
} rt_texture_usage_flags;

/* Describes a gpu texture */
typedef struct {
    /* Width in pixels */
    uint32_t width;

    /* Height in pixels */
    uint32_t height;

    /* Pixel format */
    rt_texture_format format;

    /* Number of samples */
    uint32_t samples;

    /* Number of mip levels */
    uint32_t mip_levels;

    /* Bitmask of usages this texture needs to support */
    rt_texture_usage_flags usage;

    /* ResourceID of the resource that will be used to populate this texture. */
    rt_resource_id source_resource;
} rt_render_texture2d_desc;

#endif

