/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   minirt.h                                           :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: bszilas <bszilas@student.42vienna.com>     +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2024/09/08 16:34:08 by victor            #+#    #+#             */
/*   Updated: 2025/05/31 16:39:41 by victor           ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#ifndef MINIRT_H
# define MINIRT_H

#ifdef __EMSCRIPTEN__
    #include <emscripten.h>
#endif

#include <stdint.h>
#include <sys/types.h>
# include <unistd.h>
# include <math.h>
# include <stdlib.h>
# include <errno.h>
# include <fcntl.h>
# include "libft/libft.h"
# include "memory/memory.h"
# include <stdbool.h>
# ifndef __EMSCRIPTEN__
#  include <pthread.h>
# endif // !__EMSCRIPTEN__
# include <dirent.h>
# include "./raylib/src/raylib.h"
# include <string.h>
# include <time.h>

# ifdef __EMSCRIPTEN__
#  define SCENE_START_RESOLUTION_X 16
#  define SCENE_START_RESOLUTION_Y 9
# endif // __EMSCRIPTEN__

# define MAX_BODY_INIT 16
# define READ_BUFFER_SIZE 1000

# define ASPECT_RATIO 1.77777778

# ifndef ROOT_DIRECTORY
#  define ROOT_DIRECTORY "/"
# endif

# ifndef __EMSCRIPTEN__
#  ifdef VALGRIND
#   define SCENE_START_RESOLUTION_X 16
#   define SCENE_START_RESOLUTION_Y 9
#  else
#   define SCENE_START_RESOLUTION_X 1
#   define SCENE_START_RESOLUTION_Y 1
#  endif
# endif // !__EMSCRIPTEN
        //
#ifndef __EMSCRIPTEN__
# define RESOLUTION_SCALE_X ratio_x
# define RESOLUTION_SCALE_Y ratio_y
#else
# define RESOLUTION_SCALE_X ratio_x * 2
# define RESOLUTION_SCALE_Y ratio_y * 2
#endif // !__EMSCRIPTEN__

# define SCENE_START_RESOLUTION_CAP 4
# define CHECKER_GRID_SIZE 16

#ifndef __EMSCRIPTEN__

# define THREAD_COUNT 30

#else

# define THREAD_COUNT 1

#endif // !__EMSCRIPTEN__

# define MAX_DEPTH 6
# define DROPOFF_DISTANCE 6
# define MAX_LIGHTS 4

# define ANTI_ALIASING_FACTOR 9
# define SQRT_AA_FACTOR 3
# define REC_SQRT_AA_FACTOR 0.33333333333

# define SHADOW_BIAS 1e-5
# define GLOSSINESS 10
# define COS_10 0.98480775301
# define SIN_10 0.17364817766
# define RAD_TO_DEG 57.2957795131

# define INDEX_OF_SKYSPHERE_IMAGE 1
# define SKYSPHERE INDEX_OF_SKYSPHERE_IMAGE
# define SKY_COLOR 0x83E8FC

# define MAIN_MENU 0x00beef00
# define ITEM_HEIGHT 30
# define ITEM_MARGIN 5

# define CONTAINER_ITEM_COUNT 32
# define CONTAINER_TITLE_LEN 1024
# define CONTAINER_PADDING 6

# define ITEM_PADDING 8

enum    e_id_groups
{
    ID_GROUP_MENU_MAIN = 1,
    ID_GROUP_SPHERE,
    ID_GROUP_PLANE,
    ID_GROUP_CYLINDER,
    ID_GROUP_DISC,
    ID_GROUP_CONE,
    ID_GROUP_ITEM,
};

enum    e_mouse
{
    LEFT_CLICK = 1,
    RIGHT_CLICK = 3,
    SCROLL_UP = 4,
    SCROLL_DOWN = 5,
};

# define SCROLL_UP_DISTANCE -ITEM_HEIGHT
# define SCROLL_DOWN_DISTANCE ITEM_HEIGHT

typedef Image t_img;

enum    e_menu_bg
{
    MAIN_MENU_BG = 0x202020,
    MENU_ITEM_BG = 0x404040,
    HELP_MENU_BG = 0x0a0a0a,
};

enum e_menu_type
{
    MENU_MAIN,
    MENU_SPHERE,
    MENU_PLANE,
    MENU_CYLINDER,
};

typedef enum e_type
{
    BODY_END = 0,
    BODY_DELETED,
    BODY_SPHERE,
    BODY_PLANE,
    BODY_CYLINDER,
    BODY_DISK,
    BODY_CONE,
}    t_type;

typedef enum e_format
{
    CONTAINER_GRID,
    CONTAINER_LIST
}    t_format;

# define GLYPH_COUNT 82
# define GLYPH_ROW 7
# define GLYPH_COL 6
# define PATH_LENGTH 128

typedef struct s_rect
{
    uint    x;
    uint    y;
    uint    width;
    uint    height;
}    t_rect;

typedef enum e_i_type
{
    ITEM_BUTTON,
    ITEM_SLIDER,
    ITEM_DIRENT,
}    t_item_type;

typedef struct s_slider
{
    t_rect    bar;
    t_rect    cursor;
    uint8_t    max;
    uint8_t    min;
    uint8_t    *value;
}    t_slider;

typedef struct s_button
{
    uint    color;
    void    *param;
    void    (*func_ptr)(void *, void *);
}    t_button;

typedef struct s_dirent
{
    int        type;
    char    full_path[512];
    void    (*func)(void *, void *);
}    t_dirent;

typedef enum e_param_type
{
    PARAM_TEXTURE,
    PARAM_BUMP,
    PARAM_SCENE,
    PARAM_BOOL,
    PARAM_RADIUS,
    PARAM_CONE,
    PARAM_CYL,
    PARAM_U8,
    PARAM_UINT,
    PARAM_DOUBLE,
}    t_param_type;

typedef struct s_param
{
    void            *param;
    void            (*func)(void *);
    t_param_type    type;
}    t_param;

# define ITEM_TITLE_LEN 128

typedef struct s_item
{
    uint        id;
    t_item_type    type;
    t_rect        rect;
    char        description[ITEM_TITLE_LEN];
    t_param        param;
    union
    {
        t_button    button;
        t_slider    slider;
        t_dirent    dirent;
    };
}    t_item;

typedef struct s_container
{
    uint            id;
    t_rect          attr;
    t_format        format;
    t_param         param;
    char            title[CONTAINER_TITLE_LEN];
    char            buffer[1024];
    uint            item_count;
    uint            item_width;
    uint            item_height;
    struct s_data    *data;
    t_item            item[CONTAINER_ITEM_COUNT];
}   t_container;

typedef struct s_mouse
{
    bool            left_is_pressed;
    bool            right_is_pressed;
    bool            is_moving;
    struct s_body    *grabbed;
    struct s_slider    *slider;
    uint            color_store;
    int                prev_x;
    int                prev_y;
    struct s_data    *data;
}    t_mouse;

typedef struct s_vector
{
    double    x;
    double    y;
    double    z;
}    t_vector;

/* p = the visible point on the object
n = the object surface normal vector from that point
v = the normal vector towards the viewer
r = normalized perfect reflection of incoming light */
typedef struct s_hit_point
{
    t_vector    p;
    t_vector    n;
    t_vector    v;
    t_vector    r;
}    t_hit_point;

typedef struct s_pixel
{
    uint        id;
    double      dist;
    Color       *color;
    uint8_t     surface_smoothness;
}    t_pixel;

typedef struct s_line
{
    char    buffer[READ_BUFFER_SIZE + 1];
    uint    length;
    uint    count;
}    t_line;

typedef struct s_buffer
{
    char        *bytes;
    uint32_t    start;
    uint32_t    end;
    uint32_t    size;
    uint32_t    capacity;
    bool        empty;
}    t_buffer;

typedef struct s_sphere
{
    double        radius;
    t_vector    center;
}    t_sphere;

typedef struct s_plane
{
    t_vector    point;
    t_vector    normal;
    t_vector    inverse_normal;
}    t_plane;

typedef struct s_disk
{
    t_vector    point;
    t_vector    normal;
    t_vector    inverse_normal;
    double        radius;
}    t_disk;

typedef struct s_cylinder
{
    t_vector    bottom;
    t_vector    normal;
    t_vector    center;
    t_vector    top;
    t_vector    coeffs;
    double        radius;
    double        height;
    double        hit_h;
}    t_cylinder;

typedef struct s_cone
{
    t_vector    vertex;
    t_vector    normal;
    t_vector    coeffs;
    double        radius;
    double        height;
    double        hit_h;
    double        tan_a2p1;
    double        t[2];
    t_disk        bottom_cap;
}    t_cone;

# define ASSETS_PATH ROOT_DIRECTORY"/assets"
# define SCENES_PATH ASSETS_PATH"/scenes"

# ifndef TEXTURE_PATH
#  define TEXTURE_PATH ASSETS_PATH"/textures/earth.ppm"
# endif

# ifndef SKYBOX_PATH
#  define SKYBOX_PATH ASSETS_PATH"/textures/sky.ppm"
# endif


typedef struct s_texture
{
    Color       *pixel;
    char        path[255];
    int         width;
    int         height;
}    t_texture;

# ifndef BUMP_MAP_PATH
#  define BUMP_MAP_PATH ASSETS_PATH"/bump maps/earth.bump"
# endif

typedef struct s_bump_map
{
    char    path[255];
    int        *map;
    uint    width;
    uint    height;
}    t_bump_map;

typedef struct s_body
{
    uint            id;
    t_type            type;
    uint            color;
    bool            reflect;
    bool            checker_board;
    bool            textured;
    bool            bump;
    uint8_t            surface_smoothness;
    t_texture        *texture;
    t_bump_map        *map;
    union
    {
        t_sphere    sphere;
        t_plane        plane;
        t_cylinder    cylinder;
        t_disk        disk;
        t_cone        cone;
    };
}    t_body;

typedef struct s_light
{
    t_vector    position;
    t_vector    ray;
    float        phong;
    float        obj_distance;
    float        intensity;
    uint        color;
}    t_light;

typedef double    t_matrix4[4][4];

typedef struct s_camera
{
    t_vector    *ray;
    t_vector    position;
    t_vector    normal;
    t_vector    right;
    t_vector    up;
    t_matrix4    to_world;
    float        tilt;
    double        fov;
    double        fov_f;
}    t_camera;

# define MAPS_MAX 16

typedef struct s_scene
{
    uint             w;
    uint             h;
    uint            current_body_max;
    uint            body_cursor;
    uint            resolution_x;
    uint            resolution_y;
    uint            anti_aliasing;
    uint            light_count;
    t_light         light[MAX_LIGHTS];
    t_light         ambient;
    bool            ambient_was_parsed;
    t_camera        camera;
    bool            camera_was_parsed;
    uint            light_focus;
    uint            depth;
    bool            sky_sphere;
    uint            sky_color;
    t_body          *body_focus;
    t_pixel         *pixel;
    t_body          *body;
    bool            reload;
    t_texture       *texture;
    t_texture       sky;
    uint            texture_count;
    t_bump_map      *bump_map;
    uint            bump_map_count;
#ifndef __EMSCRIPTEN__
    pthread_mutex_t mutex;
#endif
}    t_scene;

typedef struct s_data
{
    Texture2D           texture;
    Color               *pixel_colors;
    t_pixel             *pixel;
    t_scene             scene;
    t_mouse             mouse;
    t_container         *menu;
    t_container         explorer;
    void                *current_menu;
    void                *func_ptr_param;
    void                (*func_ptr)(void *data, void *param);
    bool                should_rerender;
    bool                go;
#ifndef __EMSCRIPTEN__
    struct s_thread     *threads;
    int                 thread_count;
    pthread_barrier_t   barrier;
    pthread_rwlock_t    rwlock;
#endif
}    t_data;

#ifndef __EMSCRIPTEN__
typedef struct s_thread
{
    int                    id;
    pthread_t            thread;
    t_data                *data;
    t_scene                *scene;
    t_pixel                *pixel;
    pthread_rwlock_t    *rwlock;
    uint                width;
    uint                height;
    uint                startx;
    uint                starty;
}    t_thread;
#endif // !__EMSCRIPTEN__

extern t_data data;
extern uint ratio_x;
extern uint ratio_y;
extern uint max_res_x;
extern uint max_res_y;

/* ft_atod.c */
void        item_double_inc(void *value, void *null);
void        item_double_dec(void *value, void *null);

/* Utils */
void        ft_open(int *fd, const char *path, int flag, int permissons);
int            ft_close(int fd);
int            ft_read(int fd, char *character, unsigned int size_to_read);
void        glyph_print(uint begin_x, uint begin_y, \
                        char const *text, t_pixel *pixel);
void        data_destroy_func(void *data_ptr);
long        get_current_us(struct timeval start);

/* Drawing */
void        rt_draw_rect(t_rect rect, t_pixel *pixel, uint id, uint color);
void        rt_draw_rect_blend(t_rect rect, t_pixel *pixel, \
                                uint id, uint color);

# define COLLECT_MODE_NORMAL 0
# define COLLECT_MODE_END 1

/* Generics */
bool        collect_param_comma(char **entry_position, \
                                char *params[], uint count, int mode);
bool        collect_param_single(char **entry_position, \
        char *params[], int mode);
uint        id_set(uint group, int id);
uint        id_group_get(int id);
void        err(char *body_type, uint line);
bool        check_line(char *tmp);
void        swap_2_ints(uint *a, uint *b);

/* Colors */
uint        color_to_uint(Color c);
Color       uint_to_color(uint c);
Color       set_color(uint r, uint g, uint b);
void        get_color_reflect(t_vector new_center, t_vector normal, \
                                t_scene *scene, t_pixel *pixel);
/* Returns diffuse color when called with parameters
attn = dot product of surface normal and light ray,
uint obj = object color and float gloss = 1.

Returns specular reflection color when called with parameters
attn = dot product of light ray reflection and view ray
obj = 0xFFFFFF and float gloss greater than 1 */
uint        phong_reflection(uint obj, float attn, t_light l, float gloss);
void        apply_shadow_bias(t_vector *p, t_vector normal, double scale);
uint        get_color(uint obj, uint light, double attn);
uint        color_blend(uint    color1, uint color2);
/* !!! This function PRINTS a SPACE at the BEGINNING and a NEWLINE
character at the END !!! */
void        color_print(uint color, int fd);
uint        add_color(uint color1, uint color2);
uint        parse_body_color(char *params[], int *error);
void        get_background_color(t_scene *sc, t_pixel *px, t_vector v);
uint        color_brightness(uint original, float brightness);
/* Function to calculate the Euclidean distance between two colors */
float        color_distance(uint r1, uint g1, uint b1, uint r2, uint g2, uint b2);

/* Sphere */
bool        parse_sphere(char *entry, uint line_count, \
                            t_body *body, uint body_count);
void        pixel_sphere_set(t_pixel *pixel, t_vector camera_ray, \
                                t_body *body, t_scene *scene);
void        body_sphere_print(t_body *body);
void        sphere_save(t_sphere sphere, uint color, int fd);
double        sphere_hit_distance(t_vector ray, t_vector dlt_centr, \
                                t_sphere sphere, int *invert);
void        get_color_sphere(    t_body *body, \
                                t_hit_point    *hit, \
                                t_pixel *pixel);
/* Plane */
bool        parse_plane(char *entry, uint line_count, \
                        t_body *body, uint body_count);
void        body_plane_print(t_body *body);
void        trace_plane(t_pixel *pixel, t_vector camera_ray, \
                            t_body *body, t_scene *scene);
void        plane_save(t_plane plane, uint color, int fd);
bool        move_plane(int keycode, t_plane *plane);
double        plane_hit_distance(t_plane pl, t_vector cam, \
                                t_vector camera_ray, int *invert);
void        get_color_plane(t_body *body, t_hit_point *hit, t_pixel *pixel);

/* Cylinder */
void        body_cylinder_print(t_body *body);
void        cylinder_save(t_cylinder cylinder, uint color, int fd);
bool        parse_cylinder(char *entry, uint line_count, \
                            t_body *body, uint body_count);
void        calc_cyl_data(t_cylinder *cy);
/* The coefficients a, b, c in a quadratic equation f(x) = ax² + bx + c are
saved in a t_vector coeffs, so that coeffs.x = a, .y = b, .z = c */
void        cyl_equation_coefficients(t_cylinder *cy, t_vector ray, \
                                        t_vector cam_delta);
double        cyl_hit_distance(t_cylinder *cy, t_vector ray, \
                                t_vector cam, int *invert);
double        cyl_components_shadow(t_cylinder cy, t_vector ray, t_vector p);
bool        move_cylinder(int keycode, t_cylinder *cyl);
t_vector    cyl_normal(t_cylinder cy, t_vector p, int invert);
void        get_color_cylinder(t_body *body, \
                t_vector intersect, t_pixel *pixel);
void        trace_cyl_caps(t_pixel *px, t_vector ray, \
        t_body *cyl, t_scene *sc);
void        trace_cyl(t_pixel *pixel, t_vector ray, t_body *body, t_scene *sc);
bool        finite_cylinder_hit(t_cylinder *cy, t_vector hit);

/* Disk */
void        trace_disk(t_pixel *pixel, t_vector ray, \
                        t_body *body, t_scene *scene);
bool        parse_disk(char *entry, uint line_count, \
                        t_body *body, uint body_count);
double        disk_hit_distance(t_disk disk, t_vector ray, \
                        t_vector cam, int *invert);
void        print_disk(t_body *body);
bool        move_disk(int keycode, t_disk *disk);
void        disk_save(t_disk disk, uint color, int fd);
void        get_color_disk(t_body *body, t_vector intersect, t_pixel *pixel);

/* Cone */
bool        move_cone(int keycode, t_cone *cone);
bool        parse_cone(char *entry, uint line_count, t_body *body, \
uint body_count);
void        calc_cone_data(t_cone *cn);
bool        cam_inside_cone(t_cone *cn, t_vector cam, double cam_h);
/* The coefficients a, b, c in a quadratic equation f(x) = ax² + bx + c are
saved in a t_vector coeffs, so that coeffs.x = a, .y = b, .z = c */
void        cone_equation_coefficients(t_cone *cn, t_vector ray, \
t_vector cam_delta);
void        solve_cone_equation(t_cone *cn, t_vector ray, t_vector cam_delta);
double        cone_hit_distance(t_cone *cn, t_vector ray, t_vector cam, \
int *invert);
void        trace_cone(t_pixel *pixel, t_vector ray, t_body *body, \
t_scene *sc);
void        trace_cone_bottom(t_pixel *px, t_vector ray, t_body *cone, \
t_scene *sc);
double        cone_components_shadow(t_cone cn, t_vector ray, t_vector p);
void        cone_save(t_cone cone, uint color, int fd);
t_vector    cone_surface_normal(t_cone cn, t_vector p, int invert);
bool        finite_cone_hit(double cone_height, double h);

/* Vector */
void        normalize_vector(t_vector *vec);
double        dot_product(t_vector a, t_vector b);
double        vector_length(t_vector vec);
t_vector    vector_subtract(t_vector vec1, t_vector vec2);
t_vector    set_vector(double x, double y, double z);
t_vector    scale_vector(t_vector vec, double scale);
t_vector    add_vector(t_vector vec, t_vector add);
void        vector_print(t_vector vector, int fd);
t_vector    get_normal(t_vector from, t_vector to);
t_vector    cross_product(t_vector a, t_vector b);
t_vector    rot_x(t_vector vec, int dir);
t_vector    rot_y(t_vector vec, int dir);
t_vector    rot_z(t_vector vec, int dir);
t_vector    reflect_vector(t_vector incoming, t_vector axis);
void        calc_hit_point_vectors(t_hit_point *hit, t_vector ray, t_vector n);

/* Camera */
void        set_world_matrix(t_camera *camera);
/*camera->right in this function is used as cam normal projection onto the
xz plane to save one less t_vector type */
void        calc_camera_tilt(t_camera *camera);
bool        parse_camera(char *entry, uint line_count, t_camera *camera, \
        bool *reload);
void        body_camera_print(t_camera camera);
void        camera_save(t_camera *camera, int fd);
t_vector    set_ray(float x, float y, t_scene *scene, t_camera *camera);
void        calc_camera_space(t_camera *camera);

/* Pixel */
t_pixel        *pixel_plane_create(void);
void        set_pixel_distances(t_pixel *array, uint size, double dist);
void        pixels_clear(t_pixel *pixel, uint wi, uint hi);
void        trace_lights(t_scene *sc, t_pixel *px, t_hit_point hit);
void        pixel_clear_id(t_pixel *pixel);
void        set_info_to_pixel(t_pixel *pixel, t_body *body, double dist);

/* Ray Utils */
double        ray_distance_from_point_squared(t_vector ray, t_vector point);
double        smaller_non_negative(double a, double b);

/* Image */
t_img        image_create(void *mlx_ptr, uint width, uint height);
void        pixels_image_syncronize(Color *image, t_pixel *pixel);
void        save_all_lights(t_scene *scene, int fd);

/* Scene */
bool        body_distribute(char *entry, char *tmp, \
                        uint line_cursor, t_scene *scene);
void        scene_print(t_scene *scene);
void        scene_create(const char *filepath, t_scene *scene);
void        scene_create_loop(t_scene *scene, t_line line, int fd);
void        scene_replace(t_scene *scene, char *new_path);
char        *buffer_read_chunk(t_line *line, uint fd, bool *file_end_reached);
bool        body_determine(char *entry, uint line_count, t_scene *scene);
void        scene_body_add(t_body *body, t_scene *scene);
void        scene_add_cylinder(void *data_ptr, void *null);
void        scene_add_disk(void *data_ptr, void *null);
void        scene_add_sphere_func(void *scene_ptr, void *null);
void        scene_add_plane_func(void *data_ptr, void *null);
t_body        *body_get_by_id(uint id, t_scene *scene);
void        scene_save(t_scene *scene);
void        trace_reflection(t_pixel *px, t_hit_point hit, t_scene new_scene);
void        toggle_sky_sphere(t_scene *scene);

/* Rendering */
uint        rendering_loop(t_data *data);
void        pixel_fill(t_pixel *pixel, t_scene *scene);
void        ray_check_bodys(t_pixel *pixel, t_vector ray, t_scene *scene);

/* Light */
bool        parse_light(char *entry_light, uint line_count, t_light *light, \
            int count);
void        body_light_print(t_light light);
void        light_save(t_light light, int fd);
bool        parse_ambient(char *entry_light, uint line_count, t_light *light, \
        bool *relaod);
bool        shadow(t_vector p, t_light l, t_body *body, \
t_scene *scene);
void        ambient_save(t_light light, int fd);

/* Keys */
int            key_press(int keycode, void *data);
uint        key_change_res(int keycode, t_scene *scene);
bool        key_move_focused(int keycode, t_vector *focus);
bool        key_change_fov(int keycode, t_camera *camera);
bool        calc_camera_rotation(int key, t_camera *camera);
int            move_body(int keycode, t_body *body);
bool        key_move_light(int keycode, t_scene *scene);
uint        key_misc_function(int keycode, t_scene *scene, t_data *data);

/* Menu */
void        container_draw(void *data, void *menu);
void        container_item_get_by_id(t_container *container, \
        uint id, uint x, uint y);
void        help_menu_draw(void *data_ptr, void *null);
t_container    container_create(const char *title, t_rect *attr, uint format);
void        container_item_add(t_container *container, t_item *item);
t_item        container_item_button_create(const char *title, void *param, \
                                void (*func_ptr)(void *, void *));
t_item        container_item_slider_create(const char *title, uint8_t min, \
                uint8_t max, uint8_t *value);
void        container_internal_slider_config(t_item *item);

/* Slider */
bool        menu_slider_is_cursor(uint x, uint y, t_rect *slider);
void        menu_slider_value_calculate(t_slider *slider);

/* Menu Mapping And Creating */
void        disk_menu_map(t_container *menu, t_body *body, uint *color);
void        sphere_menu_map(t_container *menu, t_body *body, uint *color);
void        cylinder_menu_map(t_container *menu, t_body *body, uint *color);
void        plane_menu_map(t_container *menu, t_body *body, uint *color);
void        cone_menu_map(t_container *menu, t_body *body, uint *color);
void        menu_body_map_bool_toggle(t_item *item, bool *value);
void        menu_body_map_float(t_item *item, double *value);
void        menu_body_map_vector(t_item *item, t_vector *vector);
void        menu_body_map_color(t_item *item, uint *color);
void        menu_body_map_texture(t_item *item, t_texture **texture);
void        menu_body_map_bump(t_item *item, t_bump_map **bump);
void        menu_body_bool_add(t_container *menu, char *name);
void        menu_body_colors_add(t_container *menu);
void        menu_body_vector_position_add(t_container *menu);
void        menu_body_vector_normal_add(t_container *menu);
void        menu_body_slider_add(t_container *menu, char *name);
void        menu_body_float_add(t_container *menu, char *name_prefix);
void        menu_body_texture_add(t_container *container);
void        menu_body_bump_map_add(t_container *container);
void        menu_body_slider_add(t_container *menu, char *name);
void        menu_body_slider_map_value(t_item *item, uint8_t *value);
void        cylinder_menu_create(t_container *menu);
void        cone_menu_create(t_container *menu);
void        disc_menu_create(t_container *menu);
void        sphere_menu_create(t_container *menu);
void        plane_menu_create(t_container *menu);
void        item_normal_inc(void *null, void *value);
void        item_normal_dec(void *null, void *value);
void        item_double_inc(void *null, void *value);
void        item_double_dec(void *null, void *value);
void        item_bool_toggle(void *null, void *value);

/* Mouse */

int            mouse_press(uint x, uint y, t_data *data);
int            mouse_release(uint x, uint y, t_data *data);
int            mouse_move(uint x, uint y, t_data *data);
void        mouse_grab(t_mouse *mouse, t_body *body);

/* Parsing */
bool        check_position(char **tmp);
bool        check_end(char *entry);
char        temporary_terminate_string(char *end);
void        restore_string(char *end, char tmp);
int64_t        get_one_tenth(char *nbr);
char        get_last_char(char *str);
size_t        count_digits(int64_t n, int base);
bool        positive_overflow(int64_t max, char *str);
bool        negative_overflow(int64_t min, char *str);
bool        is_a_number(char *str);
char        *skip_whitespace(char *str);
int64_t        set_signed_int(const char *str, int64_t min, \
                            int64_t max, int *error);
void        minirt_fd_close(void *ptr);
bool        check_normal_vector(t_vector *vec);

/* PPM READER */
bool        ppm_check(int fd, int *width, int *height);
void        ppm_pixels_read(t_buffer *buffer, int fd, t_texture *texture);
int            ppm_read_number(int fd, bool *eof);
void        ppm_image_read(const char *path, t_texture *texture);

#ifndef __EMSCRIPTEN__
/* Threads */
void        data_init_threads(t_data *data);
void        threads_init(t_thread thread[], t_data *data);
void        *thread_rendering_loop(void *thread_ptr);
void        thread_define_camera_rays(    t_thread *thread, \
                                    t_pixel *pixel, \
                                    t_scene *scene, \
                                    t_camera *camera);
#else

void        define_camera_rays(t_pixel *pixel, t_camera *camera, t_scene *scene);

#endif // !__EMSCRIPTEN__

/* Read buffer */
void        buffer_move_next_whitespace(t_buffer *buffer);
void        buffer_allignment_set(t_buffer *buffer);
void        buffer_read(t_buffer *buffer, int fd);
t_buffer    buffer_init(uint capacity, void *bytes);

/* Bump Map */
void        bump_map_read(char *map_path, t_bump_map *map);
bool        contains_nan(char buffer[], uint size);
void        perturb_normal(t_vector *normal, t_bump_map *map, \
                                double u, double v);
int         close_window(void *data_ptr);

/* Mapgen */
void        map_create_from_ppm(int infile, int outfile);

/* explorer */
void        explorer_read_dir(void *data, void *path);
void        file_load(t_item *item, t_data *data);
void        explorer_entry_func(void *item_ptr, void *data);
void        container_item_swap(t_item *itema, t_item *itemb);
void        container_item_desc_sort(t_container *cont);
bool        ft_opendir(DIR **dir, char *path);

/* Phong */
uint        phong_reflection(uint obj, float attenuation, \
                                t_light l, float gloss);
void        calc_phong_vectors(t_hit_point *hit, t_light *l);
uint        diffuse_reflection(t_pixel *px, t_hit_point hit, t_light l);
uint        specular_reflection(t_pixel *px, t_hit_point hit, t_light l);
float        dropoff_factor(float distance);

#endif
