#ifndef RT_RENCOM_RENDER_MESH_H
#define RT_RENCOM_RENDER_MESH_H

/* Meshes
 * A mesh is a tree of small meshlets: Chunks of up to 64 vertices/126 triangles.
 * Each tree node contains the meshlet data and (optionally) children.
 * A node is a simplified version of all its children.
 * 
 * A meshlet contains a primitive index buffer that references the meshes
 */

#include <stdint.h>

#include "runtime/resources.h"

#ifdef __cplusplus
extern "C" {
#endif

#define RT_MAX_MESHLET_CHILDREN 8

/* These numbers match the ones for nvidias turing mesh-shaders 
 * See: https://developer.nvidia.com/blog/introduction-turing-mesh-shaders/ */
#define RT_MESHLET_MAX_VERTICES   64
#define RT_MESHLET_MAX_PRIMITIVES 126
#define RT_MESHLET_MAX_INDICES    (RT_MESHLET_MAX_PRIMITIVES * 3)

typedef struct {
    uint16_t position[3];
    uint16_t normal[3];
    uint16_t tangent[3];
    uint16_t texcoord[2];
} rt_vertex;

/* Meshlet data as passed to the GPU */
typedef struct {
    /* Offset into the shared index buffer */
    uint32_t base_index : 21;
    uint32_t triangle_count : 8;
    uint32_t child_count : 3;

    /* Bounding sphere for culling */
    float center[3];
    float radius;

    /* Indices of the child nodes in the meshlet buffer */
    uint32_t children[8];
} rt_gpu_meshlet;

/* Static data stored in the meshlet resource */
typedef struct {
    /* Bounding sphere for culling */
    float center[3];
    float radius;

    /* Number of triangles = index_count / 3 */
    uint32_t triangle_count;
    uint32_t vertex_count;

    uint32_t child_count;
    rt_resource_id child_resources[RT_MAX_MESHLET_CHILDREN];
} rt_render_meshlet_static_data;

typedef enum {
    RT_RENDER_MESHLET_STATE_INVALID,
    RT_RENDER_MESHLET_STATE_LOADING,
    RT_RENDER_MESHLET_STATE_LOADED,
    RT_RENDER_MESHLET_STATE_LOAD_FAILED,
} rt_render_meshlet_state;

typedef struct rt_render_meshlet {
    rt_render_meshlet_static_data static_data;

    /* Non-null for loaded children */
    struct rt_render_meshlet *children[RT_MAX_MESHLET_CHILDREN];

    /* Meshlet index buffer. */
    uint32_t *indices;

    /* Meshlet vertex buffer. */
    rt_vertex *vertices;

    rt_render_meshlet_state state;
} rt_render_meshlet;

/* Static data stored in the mesh resource */
typedef struct {
    uint32_t meshlet_count;
    uint32_t total_index_count;
    uint32_t total_vertex_count;
    rt_resource_id root_resource;
} rt_render_mesh_static_data;

typedef struct {
    rt_render_mesh_static_data static_data;
    rt_render_meshlet *root;
} rt_render_mesh;

rt_result rtInitMeshStreaming(void);
void rtShutdownMeshStreaming(void);
void rtMeshStreamingNewFrame(unsigned int frame_id);

/* Loads a mesh from a resource file.
 * Allocates storage for the mesh data and loads the root meshlet,
 * to make a (much) simplified version available for rendering immediately.
 *
 * If the mesh is already loaded, a shared reference count is incremented instead.
 */
rt_render_mesh *rtGetRenderMesh(rt_resource_id mesh_id);

/* Decrement a meshes reference counter */
void rtReleaseRenderMesh(rt_resource_id mesh_id);

void rtMeshStreamingNewFrame(unsigned int frame_id);

#ifdef __cplusplus
}
#endif

#endif
