/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   cub3d.h                                            :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: ezafra-r <ezafra-r@student.42.fr>          +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2024/02/08 18:17:00 by ezafra-r          #+#    #+#             */
/*   Updated: 2024/02/08 18:43:52 by ezafra-r         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#ifndef CUB3D_H
# define CUB3D_H

/*═════════════════════════════ [  LIBS  ] ═══════════════════════════════════*/

// personal libs
# include "../lib/libft/inc/libft.h"
# include "../lib/libmlx/include/MLX42/MLX42.h"
// global libs
# include <dirent.h>
# include <errno.h>
# include <fcntl.h>
# include <libgen.h>
# include <limits.h>
# include <math.h>
# include <memory.h>
# include <signal.h>
# include <stdarg.h>
# include <stdbool.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/ioctl.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <sys/wait.h>
# include <termios.h>
# include <unistd.h>

/*═══════════════════════════ [  MACROS  ] ═══════════════════════════════════*/

// MLX - GAME

# define S_W 1900             // screen width
# define S_H 1000             // screen height
# define WALL_SIZE 30         // wall size
# define FOV 60               // field of view
# define ROTATION_SPEED 0.045 // rotation speed
# define PLAYER_SPEED 4       // player speed

// ERROR

# define ERR_INV_COP "Error: invalid argument\n"
# define ERR_INV_FILE "Error: invalid file\n"
# define ERR_EMPTY_FILE "Error: empty file\n"

# define ERR_MAP_INV "Error: invalid map element\n"
# define ERR_MAP_EMPTY "Error: empty ligne in the map\n"
# define ERR_MAP_DUP "Error: duplicate map element\n"
# define ERR_MAP_RGB "Error: invalid color map [RGB]\n"

/*══════════════════════════ [  STRUCTS  ] ═══════════════════════════════════*/

typedef struct s_tex
{
	mlx_texture_t		*no;
	mlx_texture_t		*so;
	mlx_texture_t		*we;
	mlx_texture_t		*ea;
}						t_tex;

typedef struct s_turelist
{
	char				*name;
	char				*value;
	struct s_turelist	*next;
}						t_turelist;

typedef struct s_player
{
	int		plyr_x;		// player x position in pixels
	int		plyr_y;		// player y position in pixels
	double	angle;		// player angle
	float	fov_rd;		// field of view in radians
	int		rot;		// rotation flag
	int		l_r;		// left right flag
	int		u_d;		// up down flag
}						t_player;

typedef struct s_ray
{
	int					index;
	double				ray_ngl;
	double				horiz_x;
	double				horiz_y;
	double				vert_x;
	double				vert_y;
	double				distance;
	int					flag;
}						t_ray;

typedef struct s_data
{
	int			p_x;	// player x position in the map
	int			p_y;	// player y position in the map
	int			w_map;	// map width
	int			h_map;	// map height
	int			fd;
	char		*line;
	char		*ture;
	char		**ture2d;
	char		*map;
	char		**map2d;
	char		**sq_map;
	char		**cc;
	char		**ff;
	t_turelist	*t_list;
}						t_data;

typedef struct s_mlx
{
	mlx_image_t	*img;		// the image
	mlx_t		*mlx_ptr;	// the mlx pointer
	t_ray		*ray;		// the ray structure
	t_data		*dt;		// the data structure
	t_player	*ply;		// the player structure
	t_tex		*tex;
	t_turelist	*l_ture;
}						t_mlx;

/*═════════════════════════ [  FUNCTIONS  ] ══════════════════════════════════*/
/*-------------------------- [  parsing  ] -----------------------------------*/

// p_frees.c
void					freetl(char *ture, char *line, int fd);
void					free_map(t_data *m);
void					free_m(t_mlx *mlx);
void					freelist(t_turelist **head);

// p_lst_ture.c
int						get_index(char *line, int i);
t_turelist				*new_texture(char *line);
void					lst_back_ture(t_turelist **l_ture, t_turelist *new);
int						lst_ture(t_data *m, t_turelist **l_ture);

// p_read_map_utils.c
int						check_tures_space_tab(char **ture2d, int count);
int						parse_rgb(char **ture2d);
int						check_dup(t_data *m);
int						check_first_last_line(char **map);
int						surounded_by_one(char **map);

// p_read_map.c
int						is_surrounded(char *line);
int						is_validmap(char *line, int *flag);
char					*getmap(t_data *m);
int						read_map_(t_data *m, int count);
void					process_map(t_data *map, int *count);

// p_texture_utils.c
int						is_valid_texture(char *line);
int						count_comma(char *rgb);
int						check_pos_cf(char *line);
int						line_arond_one(char *line);
char					*getlastline(char **map);

// p_texture.c
int						check_color_values(char **rgb);
void					ft_process_rgb_color(t_turelist *tmp, t_data *m);
int						color_ture(t_data *m, t_turelist *l_ture);
int						check_color_textures(char *line);
int						check_count_textures(t_data *m, int count);

// p_valid_map.c
int						h_map(char **map);
int						v_map(char **map);
char					*fixline(char *line, int maxlen);
int						getsize_line(char **map);
int						valid_map(t_data *m);

// parsing.c
int						read_map(char *av, t_data *data, int *count);
void					get_x_y_player(t_data *m);
int						parsing(int ac, char **av, t_data *data);
int						check_extension_map(char *fname);

/*------------------------ [  execution  ] -----------------------------------*/
// execfree.c
void					ft_delete_tex(t_tex *tex);
void					ft_exit(t_mlx *mlx);

// mouvement.c
void					rotate_player(t_mlx *mlx, int i);
void					move_player(t_mlx *mlx, double move_x, double move_y);
void					cub_hook(t_mlx *mlx, double move_x, double move_y);
void					ft_reset_move(mlx_key_data_t keydata, t_mlx *mlx);
void					key_press(mlx_key_data_t keydata, void *ml);

// execution.c
void					get_angle(t_mlx *mlx);
void					drow_map_pixel(void *mlxl);
int						check_load_ture(t_turelist *list);
int						load_texture(t_tex *tex, t_turelist *l_ture);
int						execution(t_data *dt);

// raycasting.c
int						inter_check(float angle, float *inter, float *step,
							int is_horizon);
int						wall_hit(float x, float y, t_mlx *mlx);
float					get_h_inter(t_mlx *mlx, float angl);
float					get_v_inter(t_mlx *mlx, float angl);
void					cast_rays(t_mlx *mlx);

// render2.c
int						get_rgba(int r, int g, int b, int a);
int						reverse_bytes(int c);
void					my_mlx_pixel_put(t_mlx *mlx, int x, int y, int color);
float					nor_angle(float angle);
int						unit_circle(float angle, char c);

// render.c
double					get_x_o(mlx_texture_t *texture, t_mlx *mlx);
void					draw_floor_ceiling(t_mlx *mlx, int ray, int t_pix,
							int b_pix);
void					draw_wall(t_mlx *mlx, int t_pix, int b_pix,
							double wall_h);
void					render_wall(t_mlx *mlx, int ray);
#endif

# **************************************************************************** #
#                                                                              #
#                                                         :::      ::::::::    #
#    e_frees.c                                            :+:      :+:    :+:    #
#                                                     +:+ +:+         +:+      #
#    By: aortigos <aortigos@student.42malaga.com    +#+  +:+       +#+         #
#                                                 +#+#+#+#+#+   +#+            #
#    Created: 2024/02/08 18:32:59 by ezafra-r          #+#    #+#              #
#    Updated: 2025/11/14 09:25:29 by aortigos         ###   ########.fr        #
#                                                                              #
# **************************************************************************** #

#include "cub3d.h"

void	ft_delete_tex(t_tex *tex)
{
	if (tex->no)
		mlx_delete_texture(tex->no);
	if (tex->so)
		mlx_delete_texture(tex->so);
	if (tex->we)
		mlx_delete_texture(tex->we);
	if (tex->ea)
		mlx_delete_texture(tex->ea);
}

void	ft_exit(t_mlx *mlx)
{
	mlx_delete_image(mlx->mlx_ptr, mlx->img);
	mlx_close_window(mlx->mlx_ptr);
	freelist(&mlx->dt->t_list);
	free_map(mlx->dt);
	ft_delete_tex(mlx->tex);
	ft_memfree(mlx->tex);
	ft_memfree(mlx->ply);
	ft_memfree(mlx->ray);
	mlx_terminate(mlx->mlx_ptr);
	ft_putstr_fd("END GAME\n", 1);
	exit(0);
}
/* ************************************************************************** */
/*   e_mouvement.c                                      :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

void	rotate_player(t_mlx *mlx, int i)
{
	if (i == 1)
	{
		mlx->ply->angle += ROTATION_SPEED;
		if (mlx->ply->angle > 2 * M_PI)
			mlx->ply->angle -= 2 * M_PI;
	}
	else
	{
		mlx->ply->angle -= ROTATION_SPEED;
		if (mlx->ply->angle < 0)
			mlx->ply->angle += 2 * M_PI;
	}
}

void	move_player(t_mlx *mlx, double move_x, double move_y)
{
	int	map_grid_y;
	int	map_grid_x;
	int	new_x;
	int	new_y;

	new_x = roundf(mlx->ply->plyr_x + move_x);
	new_y = roundf(mlx->ply->plyr_y + move_y);
	map_grid_x = (new_x / WALL_SIZE);
	map_grid_y = (new_y / WALL_SIZE);
	if (mlx->dt->sq_map[map_grid_y][map_grid_x] != '1'
		&& (mlx->dt->sq_map[map_grid_y][mlx->ply->plyr_x / WALL_SIZE] != '1'
			&& mlx->dt->sq_map[mlx->ply->plyr_y
			/ WALL_SIZE][map_grid_x] != '1'))
	{
		mlx->ply->plyr_x = new_x;
		mlx->ply->plyr_y = new_y;
	}
}

void	cub_hook(t_mlx *mlx, double move_x, double move_y)
{
	if (mlx->ply->rot == 1)
		rotate_player(mlx, 1);
	if (mlx->ply->rot == -1)
		rotate_player(mlx, 0);
	if (mlx->ply->l_r == 1)
	{
		move_x = -sin(mlx->ply->angle) * PLAYER_SPEED;
		move_y = cos(mlx->ply->angle) * PLAYER_SPEED;
	}
	if (mlx->ply->l_r == -1)
	{
		move_x = sin(mlx->ply->angle) * PLAYER_SPEED;
		move_y = -cos(mlx->ply->angle) * PLAYER_SPEED;
	}
	if (mlx->ply->u_d == 1)
	{
		move_x = cos(mlx->ply->angle) * PLAYER_SPEED;
		move_y = sin(mlx->ply->angle) * PLAYER_SPEED;
	}
	if (mlx->ply->u_d == -1)
	{
		move_x = -cos(mlx->ply->angle) * PLAYER_SPEED;
		move_y = -sin(mlx->ply->angle) * PLAYER_SPEED;
	}
	move_player(mlx, move_x, move_y);
}

void	ft_reset_move(mlx_key_data_t keydata, t_mlx *mlx)
{
	if (keydata.key == MLX_KEY_D && (keydata.action == MLX_RELEASE))
		mlx->ply->l_r = 0;
	else if (keydata.key == MLX_KEY_A && (keydata.action == MLX_RELEASE))
		mlx->ply->l_r = 0;
	else if (keydata.key == MLX_KEY_S && (keydata.action == MLX_RELEASE))
		mlx->ply->u_d = 0;
	else if (keydata.key == MLX_KEY_W && (keydata.action == MLX_RELEASE))
		mlx->ply->u_d = 0;
	else if (keydata.key == MLX_KEY_LEFT && keydata.action == MLX_RELEASE)
		mlx->ply->rot = 0;
	else if (keydata.key == MLX_KEY_RIGHT && keydata.action == MLX_RELEASE)
		mlx->ply->rot = 0;
}

void	key_press(mlx_key_data_t keydata, void *ml)
{
	t_mlx	*mlx;

	mlx = ml;
	if (keydata.key == MLX_KEY_ESCAPE && (keydata.action == MLX_PRESS
			|| keydata.action == MLX_REPEAT))
	{
		ft_exit(mlx);
	}
	else if (keydata.key == MLX_KEY_A && (keydata.action == MLX_PRESS))
		mlx->ply->l_r = -1;
	else if (keydata.key == MLX_KEY_D && (keydata.action == MLX_PRESS))
		mlx->ply->l_r = 1;
	else if (keydata.key == MLX_KEY_S && (keydata.action == MLX_PRESS))
		mlx->ply->u_d = -1;
	else if (keydata.key == MLX_KEY_W && keydata.action == MLX_PRESS)
		mlx->ply->u_d = 1;
	else if (keydata.key == MLX_KEY_LEFT && keydata.action == MLX_PRESS)
		mlx->ply->rot = -1;
	else if (keydata.key == MLX_KEY_RIGHT && keydata.action == MLX_PRESS)
		mlx->ply->rot = 1;
	ft_reset_move(keydata, mlx);
}
/* ************************************************************************** */
/*   e_raycasting.c                                     :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	inter_check(float angle, float *inter, float *step, int is_horizon)
{
	if (is_horizon)
	{
		if (angle > 0 && angle < M_PI)
		{
			*inter += WALL_SIZE;
			return (-1);
		}
		*step *= -1;
	}
	else
	{
		if (!(angle > M_PI / 2 && angle < 3 * M_PI / 2))
		{
			*inter += WALL_SIZE;
			return (-1);
		}
		*step *= -1;
	}
	return (1);
}

int	wall_hit(float x, float y, t_mlx *mlx)
{
	int	x_m;
	int	y_m;

	if (x < 0 || y < 0)
		return (0);
	x_m = floor(x / WALL_SIZE);
	y_m = floor(y / WALL_SIZE);
	if ((y_m >= mlx->dt->h_map || x_m >= mlx->dt->w_map))
		return (0);
	if (mlx->dt->map2d[y_m] && x_m <= (int)ft_strlen(mlx->dt->map2d[y_m]))
		if (mlx->dt->map2d[y_m][x_m] == '1')
			return (0);
	return (1);
}

float	get_h_inter(t_mlx *mlx, float angl)
{
	float	h_x;
	float	h_y;
	float	x_step;
	float	y_step;
	int		pixel;

	y_step = WALL_SIZE;
	x_step = WALL_SIZE / tan(angl);
	h_y = floor(mlx->ply->plyr_y / WALL_SIZE) * WALL_SIZE;
	pixel = inter_check(angl, &h_y, &y_step, 1);
	h_x = mlx->ply->plyr_x + (h_y - mlx->ply->plyr_y) / tan(angl);
	if ((unit_circle(angl, 'y') && x_step > 0) || (!unit_circle(angl, 'y')
			&& x_step < 0))
		x_step *= -1;
	while (wall_hit(h_x, h_y - pixel, mlx))
	{
		h_x += x_step;
		h_y += y_step;
	}
	mlx->ray->horiz_x = h_x;
	mlx->ray->horiz_y = h_y;
	return (sqrt(pow(h_x - mlx->ply->plyr_x, 2) + pow(h_y - mlx->ply->plyr_y,
				2)));
}

float	get_v_inter(t_mlx *mlx, float angl)
{
	float	v_x;
	float	v_y;
	float	x_step;
	float	y_step;
	int		pixel;

	x_step = WALL_SIZE;
	y_step = WALL_SIZE * tan(angl);
	v_x = floor(mlx->ply->plyr_x / WALL_SIZE) * WALL_SIZE;
	pixel = inter_check(angl, &v_x, &x_step, 0);
	v_y = mlx->ply->plyr_y + (v_x - mlx->ply->plyr_x) * tan(angl);
	if ((unit_circle(angl, 'x') && y_step < 0) || (!unit_circle(angl, 'x')
			&& y_step > 0))
		y_step *= -1;
	while (wall_hit(v_x - pixel, v_y, mlx))
	{
		v_x += x_step;
		v_y += y_step;
	}
	mlx->ray->vert_x = v_x;
	mlx->ray->vert_y = v_y;
	return (sqrt(pow(v_x - mlx->ply->plyr_x, 2) + pow(v_y - mlx->ply->plyr_y,
				2)));
}

void	cast_rays(t_mlx *mlx)
{
	double	h_inter;
	double	v_inter;
	int		ray;

	ray = 0;
	mlx->ray->ray_ngl = mlx->ply->angle - (mlx->ply->fov_rd / 2);
	while (ray < S_W)
	{
		mlx->ray->flag = 0;
		h_inter = get_h_inter(mlx, nor_angle(mlx->ray->ray_ngl));
		v_inter = get_v_inter(mlx, nor_angle(mlx->ray->ray_ngl));
		if (v_inter <= h_inter)
			mlx->ray->distance = v_inter;
		else
		{
			mlx->ray->distance = h_inter;
			mlx->ray->flag = 1;
		}
		render_wall(mlx, ray);
		ray++;
		mlx->ray->ray_ngl += (mlx->ply->fov_rd / S_W);
	}
}
/* ************************************************************************** */
/*   e_render.c                                         :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

void	draw_floor_ceiling(t_mlx *mlx, int ray, int t_pix, int b_pix)
{
	int	i;
	int	c;

	i = b_pix;
	c = get_rgba(ft_atoi(mlx->dt->ff[0]), ft_atoi(mlx->dt->ff[1]),
			ft_atoi(mlx->dt->ff[2]), 255);
	while (i < S_H)
		my_mlx_pixel_put(mlx, ray, i++, c);
	c = get_rgba(ft_atoi(mlx->dt->cc[0]), ft_atoi(mlx->dt->cc[1]),
			ft_atoi(mlx->dt->cc[2]), 255);
	i = 0;
	while (i < t_pix)
		my_mlx_pixel_put(mlx, ray, i++, c);
}

mlx_texture_t	*get_texture(t_mlx *mlx, int flag)
{
	mlx->ray->ray_ngl = nor_angle(mlx->ray->ray_ngl);
	if (flag == 0)
	{
		if (mlx->ray->ray_ngl > M_PI / 2 && mlx->ray->ray_ngl < 3 * (M_PI / 2))
			return (mlx->tex->ea);
		else
			return (mlx->tex->we);
	}
	else
	{
		if (mlx->ray->ray_ngl > 0 && mlx->ray->ray_ngl < M_PI)
			return (mlx->tex->so);
		else
			return (mlx->tex->no);
	}
}

double	get_x_o(mlx_texture_t *texture, t_mlx *mlx)
{
	double	x_o;

	if (mlx->ray->flag == 1)
		x_o = (int)fmodf((mlx->ray->horiz_x * (texture->width / WALL_SIZE)),
				texture->width);
	else
		x_o = (int)fmodf((mlx->ray->vert_y * (texture->width / WALL_SIZE)),
				texture->width);
	return (x_o);
}

void	draw_wall(t_mlx *mlx, int t_pix, int b_pix, double wall_h)
{
	double			x_o;
	double			y_o;
	mlx_texture_t	*texture;
	uint32_t		*arr;
	double			factor;

	texture = get_texture(mlx, mlx->ray->flag);
	arr = (uint32_t *)texture->pixels;
	factor = (double)texture->height / wall_h;
	x_o = get_x_o(texture, mlx);
	y_o = (t_pix - (S_H / 2) + (wall_h / 2)) * factor;
	if (y_o < 0)
		y_o = 0;
	while (t_pix < b_pix)
	{
		my_mlx_pixel_put(mlx, mlx->ray->index, t_pix, reverse_bytes(arr[(int)y_o
				* texture->width + (int)x_o]));
		y_o += factor;
		t_pix++;
	}
}

void	render_wall(t_mlx *mlx, int ray)
{
	double	wall_h;
	double	b_pix;
	double	t_pix;

	mlx->ray->distance *= cos(nor_angle(mlx->ray->ray_ngl - mlx->ply->angle));
	wall_h = (WALL_SIZE / mlx->ray->distance) * ((S_W / 2)
			/ tan(mlx->ply->fov_rd / 2));
	b_pix = (S_H / 2) + (wall_h / 2);
	t_pix = (S_H / 2) - (wall_h / 2);
	if (b_pix > S_H)
		b_pix = S_H;
	if (t_pix < 0)
		t_pix = 0;
	mlx->ray->index = ray;
	draw_wall(mlx, t_pix, b_pix, wall_h);
	draw_floor_ceiling(mlx, ray, t_pix, b_pix);
}
/* ************************************************************************** */
/*   e_render2.c                                        :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	get_rgba(int r, int g, int b, int a)
{
	return (r << 24 | g << 16 | b << 8 | a << 0);
}

int	reverse_bytes(int c)
{
	unsigned int	b;

	b = 0;
	b |= (c & 0xFF) << 24;
	b |= (c & 0xFF00) << 8;
	b |= (c & 0xFF0000) >> 8;
	b |= (c & 0xFF000000) >> 24;
	return (b);
}

void	my_mlx_pixel_put(t_mlx *mlx, int x, int y, int color)
{
	if (x < 0)
		return ;
	else if (x >= S_W)
		return ;
	if (y < 0)
		return ;
	else if (y >= S_H)
		return ;
	mlx_put_pixel(mlx->img, x, y, color);
}

float	nor_angle(float angle)
{
	if (angle < 0)
		angle += (2 * M_PI);
	if (angle > (2 * M_PI))
		angle -= (2 * M_PI);
	return (angle);
}

int	unit_circle(float angle, char c)
{
	if (c == 'x')
	{
		if (angle > 0 && angle < M_PI)
			return (1);
	}
	else if (c == 'y')
	{
		if (angle > (M_PI / 2) && angle < (3 * M_PI) / 2)
			return (1);
	}
	return (0);
}
/* ************************************************************************** */
/*   execution.c                                        :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

void	drow_map_pixel(void *mlxl)
{
	t_mlx	*mlx;

	mlx = mlxl;
	mlx_delete_image(mlx->mlx_ptr, mlx->img);
	mlx->img = mlx_new_image(mlx->mlx_ptr, S_W, S_H);
	cub_hook(mlx, 0, 0);
	cast_rays(mlx);
	mlx_image_to_window(mlx->mlx_ptr, mlx->img, 0, 0);
}

int	check_load_ture(t_turelist *list)
{
	t_turelist		*tmp;
	mlx_texture_t	*texture;

	tmp = list;
	while (tmp)
	{
		if (!ft_strncmp(tmp->name, "NO", 2) || !ft_strncmp(tmp->name, "SO", 2)
			|| !ft_strncmp(tmp->name, "WE", 2) || !ft_strncmp(tmp->name, "EA",
				2))
		{
			texture = mlx_load_png(tmp->value);
			if (!texture)
				return (0);
			mlx_delete_texture(texture);
		}
		tmp = tmp->next;
	}
	return (1);
}

int	load_texture(t_tex *tex, t_turelist *l_ture)
{
	t_turelist	*tmp;

	tmp = l_ture;
	if (!check_load_ture(l_ture))
		return (0);
	while (tmp)
	{
		if (!ft_strncmp(tmp->name, "NO", 2))
			tex->no = mlx_load_png(tmp->value);
		else if (!ft_strncmp(tmp->name, "SO", 2))
			tex->so = mlx_load_png(tmp->value);
		else if (!ft_strncmp(tmp->name, "WE", 2))
			tex->we = mlx_load_png(tmp->value);
		else if (!ft_strncmp(tmp->name, "EA", 2))
			tex->ea = mlx_load_png(tmp->value);
		tmp = tmp->next;
	}
	return (1);
}

void	get_angle(t_mlx *mlx)
{
	char	c;

	c = mlx->dt->sq_map[mlx->dt->p_y][mlx->dt->p_x];
	if (c == 'N')
		mlx->ply->angle = 3 * M_PI / 2;
	if (c == 'S')
		mlx->ply->angle = M_PI / 2;
	if (c == 'E')
		mlx->ply->angle = 0;
	if (c == 'W')
		mlx->ply->angle = M_PI;
	mlx->ply->plyr_x = (mlx->dt->p_x * WALL_SIZE) + WALL_SIZE / 2;
	mlx->ply->plyr_y = (mlx->dt->p_y * WALL_SIZE) + WALL_SIZE / 2;
	mlx->ply->fov_rd = (FOV * M_PI / 180);
}

int	execution(t_data *dt)
{
	t_mlx	mlx;

	if (S_H > 1440 || S_W > 2560 || FOV >= 180 || FOV <= 0)
		return (freelist(&dt->t_list), free_map(dt), 0);
	mlx.ply = (t_player *)ft_calloc(sizeof(t_player), 1);
	mlx.ray = (t_ray *)ft_calloc(sizeof(t_ray), 1);
	mlx.tex = (t_tex *)ft_calloc(sizeof(t_tex), 1);
	mlx.dt = dt;
	mlx.mlx_ptr = mlx_init(S_W, S_H, "cub3D", false);
	if (!mlx.mlx_ptr)
		return (ft_exit(&mlx), 0);
	if (!load_texture(mlx.tex, dt->t_list))
		return (ft_exit(&mlx), 0);
	get_angle(&mlx);
	mlx_key_hook(mlx.mlx_ptr, &key_press, &mlx);
	mlx_loop_hook(mlx.mlx_ptr, &drow_map_pixel, &mlx);
	mlx_loop(mlx.mlx_ptr);
	ft_exit(&mlx);
	return (0);
}
/* ************************************************************************** */
/*   main.c                                             :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	main(int ac, char **av)
{
	t_data	dt;

	if (!parsing(ac, av, &dt))
		return (1);
	execution(&dt);
	return (0);
}
/* ************************************************************************** */
/*   p_frees.c                                          :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

void	freetl(char *ture, char *line, int fd)
{
	if (ture)
		ft_memfree(ture);
	if (line)
		ft_memfree(line);
	if (fd >= 0)
		close(fd);
}

void	free_map(t_data *m)
{
	free2d(m->sq_map);
	free2d(m->map2d);
	free2d(m->ture2d);
	if (m->ff)
		free2d(m->ff);
	if (m->cc)
		free2d(m->cc);
}

void	free_m(t_mlx *mlx)
{
	if (mlx->dt->sq_map)
		free2d(mlx->dt->sq_map);
	if (mlx->dt->map2d)
		free2d(mlx->dt->map2d);
	if (mlx->dt->ture2d)
		free2d(mlx->dt->ture2d);
	if (mlx->dt->ff)
		free2d(mlx->dt->ff);
	if (mlx->dt->cc)
		free2d(mlx->dt->cc);
}

void	freelist(t_turelist **head)
{
	t_turelist	*tmp;

	tmp = *head;
	while (tmp)
	{
		*head = tmp->next;
		ft_memfree(tmp->name);
		ft_memfree(tmp->value);
		ft_memfree(tmp);
		tmp = *head;
	}
	ft_memfree(*head);
}
/* ************************************************************************** */
/*   p_lst_ture.c                                       :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	get_index(char *line, int i)
{
	while (ft_isspace(line[i]))
		i++;
	return (i);
}

t_turelist	*new_texture(char *line)
{
	t_turelist	*list;

	list = (t_turelist *)ft_calloc(sizeof(t_turelist), 1);
	if (!list)
		return (NULL);
	while (ft_isspace(*line))
		line++;
	if ((!ft_strncmp(line, "NO", 2) || !ft_strncmp(line, "SO", 2)
			|| !ft_strncmp(line, "WE", 2) || !ft_strncmp(line, "EA", 2)))
	{
		list->name = ft_substr(line, 0, 2);
		list->value = ft_substr(line, get_index(line, 2), ft_strlen(line));
	}
	else if ((!ft_strncmp(line, "F", 1) || !ft_strncmp(line, "C", 1)))
	{
		list->name = ft_substr(line, 0, 1);
		list->value = ft_substr(line, get_index(line, 1), ft_strlen(line));
	}
	list->next = NULL;
	return (list);
}

void	lst_back_ture(t_turelist **l_ture, t_turelist *new)
{
	t_turelist	*tmp;

	if (!*l_ture)
	{
		(*l_ture) = new;
		return ;
	}
	tmp = *l_ture;
	while (tmp->next)
		tmp = tmp->next;
	tmp->next = new;
}

int	lst_ture(t_data *m, t_turelist **l_ture)
{
	int			i;
	t_turelist	*tmp;

	i = 0;
	while (m->ture2d[i])
	{
		tmp = new_texture(m->ture2d[i++]);
		if (!tmp)
			return (0);
		lst_back_ture(l_ture, tmp);
	}
	return (1);
}
/* ************************************************************************** */
/*   p_read_map.c                                       :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	is_surrounded(char *line)
{
	while (ft_isspace(*line))
		line++;
	return (*line == '1' && line[ft_strlen(line) - 1] == '1');
}

int	is_validmap(char *line, int *flag)
{
	int	i;

	i = -1;
	while (line[++i])
	{
		if ((line[i] != '1' && line[i] != 32 && line[i] != '0'
				&& line[i] != '\n') && !(line[i] == 'W' || line[i] == 'E'
				|| line[i] == 'N' || line[i] == 'S'))
			return (0);
		else if (line[i] == 'W' || line[i] == 'E' || line[i] == 'N'
			|| line[i] == 'S')
			(*flag)++;
	}
	return (1);
}

char	*getmap(t_data *map)
{
	char	*temp;

	map->map = ft_strdup("");
	while (map->line)
	{
		if (map->line[0] == '\n')
			return (ft_putstr_fd(ERR_MAP_EMPTY, 2), freetl(map->map, map->line,
					-1), NULL);
		temp = ft_strjoin(map->map, map->line);
		ft_memfree(map->map);
		ft_memfree(map->line);
		map->map = ft_strdup(temp);
		ft_memfree(temp);
		map->line = get_next_line(map->fd);
	}
	return (map->map);
}

int	read_map_(t_data *map, int count)
{
	map->map = getmap(map);
	if (!map->map)
		return (0);
	map->map2d = ft_split(map->map, '\n');
	if (!map->map2d)
		return (ft_memfree(map->map), 0);
	ft_memfree(map->map);
	if (!check_tures_space_tab(map->ture2d, count) || !parse_rgb(map->ture2d)
		|| !check_dup(map) || !check_first_last_line(map->map2d)
		|| !surounded_by_one(map->map2d))
		return (free2d(map->map2d), 0);
	return (1);
}

void	process_map(t_data *map, int *count)
{
	char	*temp_ture;

	while (map->line && map->line[0] != '1' && map->line[0] != 32)
	{
		if (check_color_textures(map->line))
		{
			temp_ture = ft_strjoin(map->ture, map->line);
			ft_memfree(map->ture);
			map->ture = strdup(temp_ture);
			ft_memfree(temp_ture);
			(*count)++;
		}
		ft_memfree(map->line);
		map->line = get_next_line(map->fd);
	}
}
/* ************************************************************************** */
/*   p_read_map_utils.c                                 :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	check_tures_space_tab(char **ture2d, int count)
{
	int	i;

	i = -1;
	if (count != 6)
		return (0);
	while (++i < count)
		if (!is_valid_texture(ture2d[i]))
			return (ft_putstr_fd("texture mal\n", 2), 0);
	return (1);
}

int	parse_rgb(char **ture2d)
{
	int		i;
	char	*ptr;

	i = 0;
	while (ture2d[i])
	{
		ptr = ture2d[i];
		while (ft_isspace(*ptr))
			ptr++;
		if (ptr[0] == 'F' || ptr[0] == 'C')
			if (count_comma(ptr) != 2 || !check_pos_cf(ptr))
				return (ft_putstr_fd("color mal\n", 2), 0);
		i++;
	}
	return (1);
}

int	check_dup(t_data *m)
{
	int	i;
	int	j;

	i = 0;
	while (m->ture2d[i])
	{
		j = i + 1;
		while (m->ture2d[j])
		{
			if (!ft_strncmp(m->ture2d[i], m->ture2d[j], 2))
				return (ft_putstr_fd(ERR_MAP_DUP, 2), 0);
			j++;
		}
		i++;
	}
	return (1);
}

int	check_first_last_line(char **map)
{
	if (!map[0])
		return (ft_putstr_fd(ERR_MAP_INV, 2), 0);
	if (!line_arond_one(map[0]) || !line_arond_one(map[ft_arraylen(map) - 1]))
		return (ft_putstr_fd("one Y\n", 2), 0);
	return (1);
}

int	surounded_by_one(char **map)
{
	int	i;
	int	flag;

	flag = 0;
	i = -1;
	while (map[++i])
		if (!is_surrounded(map[i]) || !is_validmap(map[i], &flag) || flag > 1)
			return (ft_putstr_fd("one X\n", 2), 0);
	if (flag == 0)
		return (ft_putstr_fd("no position map\n", 2), 0);
	return (1);
}
/* ************************************************************************** */
/*   p_textures.c                                       :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	check_color_values(char **rgb)
{
	int	i;

	i = -1;
	while (rgb[++i])
		if (ft_atoi(rgb[i]) > 255 || ft_atoi(rgb[i]) < 0)
			return (free2d(rgb), 0);
	return (free2d(rgb), 1);
}

void	ft_process_rgb_color(t_turelist *tmp, t_data *m)
{
	if (!ft_strncmp(tmp->name, "F", 2))
		m->ff = ft_split(tmp->value, ',');
	else if (!ft_strncmp(tmp->name, "C", 2))
		m->cc = ft_split(tmp->value, ',');
	return ;
}

int	color_ture(t_data *m, t_turelist *l_ture)
{
	t_turelist	*tmp;

	m->cc = NULL;
	m->ff = NULL;
	tmp = l_ture;
	while (tmp)
	{
		if (!ft_strncmp(tmp->name, "F", 1) || !ft_strncmp(tmp->name, "C", 1))
		{
			if (!check_color_values(ft_split(tmp->value, ',')))
				return (ft_putstr_fd(ERR_MAP_RGB, 2), 0);
			ft_process_rgb_color(tmp, m);
		}
		tmp = tmp->next;
	}
	return (1);
}

int	check_color_textures(char *line)
{
	while (ft_isspace(*line))
		line++;
	return ((!ft_strncmp(line, "EA", 2) || !ft_strncmp(line, "NO", 2)
			|| !ft_strncmp(line, "SO", 2) || !ft_strncmp(line, "WE", 2))
		|| (!ft_strncmp(line, "F", 1) || !ft_strncmp(line, "C", 1)));
}

int	check_count_textures(t_data *m, int count)
{
	(void)m;
	if (count != 6)
		return (ft_putstr_fd(ERR_MAP_INV, 2), 0);
	return (1);
}
/* ************************************************************************** */
/*   p_textures_utils.c                                 :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	is_valid_texture(char *line)
{
	while (ft_isspace(*line))
		line++;
	if ((!ft_strncmp(line, "NO", 2) || !ft_strncmp(line, "SO", 2)
			|| !ft_strncmp(line, "WE", 2) || !ft_strncmp(line, "EA", 2))
		&& ft_isspace(line[2]))
		return (1);
	else if ((!ft_strncmp(line, "F", 1) || !ft_strncmp(line, "C", 1))
		&& ft_isspace(line[1]))
		return (1);
	return (0);
}

int	count_comma(char *rgb)
{
	int	i;
	int	count;

	i = 0;
	count = 0;
	while (rgb[i])
		if (rgb[i++] == ',')
			count++;
	return (count);
}

int	check_pos_cf(char *l)
{
	int	i;
	int	flag;

	flag = 0;
	i = 0;
	while (ft_isspace(*l) || *l == 'C' || *l == 'F')
	{
		if (*l == 'C' || *l == 'F')
			flag++;
		l++;
	}
	if (flag != 1)
		return (0);
	if (!ft_isdigit(l[i]) || !ft_isdigit(l[(ft_strlen(l) - 1)]))
		return (0);
	while (l[i])
	{
		if ((!ft_isdigit(l[i]) && l[i] != ',') || (l[i] == ',' && l[i + 1]
				&& l[i + 1] == ','))
			return (0);
		i++;
	}
	return (1);
}

int	line_arond_one(char *line)
{
	int	i;

	i = -1;
	while (line[++i])
		if (line[i] != '1' && line[i] != 32)
			return (0);
	return (1);
}

char	*getlastline(char **map)
{
	int	i;

	i = 0;
	while (map[i + 1])
		i++;
	return (map[i]);
}
/* ************************************************************************** */
/*   p_valid_map.c                                      :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	h_map(char **map)
{
	int	i;
	int	j;

	i = 0;
	while (map[i])
	{
		j = 0;
		while (map[i][j])
		{
			if (map[i][j] != '1' && map[i][j] != ' ')
				if (map[i][j - 1] == ' ' || map[i][j + 1] == ' ')
					return (ft_putstr_fd(ERR_MAP_INV, 2), 0);
			j++;
		}
		i++;
	}
	return (1);
}

int	v_map(char **map)
{
	int	i;
	int	j;

	i = 0;
	while (map[i])
	{
		j = 0;
		while (map[i][j])
		{
			if (map[i][j] != '1' && map[i][j] != ' ')
				if (map[i - 1][j] == ' ' || map[i + 1][j] == ' ')
					return (ft_putstr_fd(ERR_MAP_INV, 2), 0);
			j++;
		}
		i++;
	}
	return (1);
}

char	*fixline(char *line, int maxlen)
{
	char	*new;
	int		i;

	i = 0;
	new = ft_calloc(sizeof(char), (maxlen + 1));
	if (!new)
		return (NULL);
	while (line[i])
	{
		new[i] = line[i];
		i++;
	}
	while (i < maxlen)
	{
		new[i] = ' ';
		i++;
	}
	return (new);
}

int	getsize_line(char **map)
{
	int	i;
	int	max;

	i = -1;
	max = ft_strlen(map[0]);
	while (map[++i])
		if ((int)ft_strlen(map[i]) > max)
			max = ft_strlen(map[i]);
	return (max);
}

int	valid_map(t_data *m)
{
	int	i;
	int	maxlen;

	maxlen = getsize_line(m->map2d);
	m->sq_map = ft_calloc(sizeof(char *), (ft_arraylen(m->map2d) + 1));
	if (!m->sq_map)
		return (0);
	i = -1;
	while (m->map2d[++i])
	{
		if (maxlen == (int)ft_strlen(m->map2d[i]))
			m->sq_map[i] = ft_strdup(m->map2d[i]);
		else
			m->sq_map[i] = fixline(m->map2d[i], maxlen);
	}
	m->h_map = ft_arraylen(m->sq_map);
	m->w_map = ft_strlen(m->sq_map[0]);
	if (!h_map(m->sq_map) || !v_map(m->sq_map))
		return (free2d(m->sq_map), free2d(m->map2d), free2d(m->ture2d), 0);
	return (1);
}
/* ************************************************************************** */
/*   parsing.c                                          :+:      :+:    :+:   */
/* ************************************************************************** */

#include "cub3d.h"

int	read_map(char *av, t_data *map, int *count)
{
	map->fd = open(av, O_RDONLY);
	if (map->fd == -1)
		return (ft_putstr_fd(ERR_INV_FILE, 2), 0);
	map->line = get_next_line(map->fd);
	if (map->line == NULL)
		return (ft_putstr_fd(ERR_EMPTY_FILE, 2), 0);
	map->ture = ft_strdup("");
	process_map(map, count);
	if (!check_count_textures(map, *count))
		return (freetl(map->ture, map->line, map->fd), 0);
	map->ture2d = ft_split(map->ture, '\n');
	if (!map->ture2d)
		return (freetl(map->ture, map->line, map->fd), 0);
	if (!read_map_(map, *count))
		return (freetl(map->ture, map->line, map->fd), free2d(map->ture2d), 0);
	return (freetl(map->ture, map->line, map->fd), 1);
}

void	get_x_y_player(t_data *m)
{
	int	i;
	int	j;

	i = 0;
	while (m->sq_map[i])
	{
		j = 0;
		while (m->sq_map[i][j])
		{
			if (m->sq_map[i][j] == 'N' || m->sq_map[i][j] == 'S'
				|| m->sq_map[i][j] == 'W' || m->sq_map[i][j] == 'E')
			{
				m->p_x = j;
				m->p_y = i;
				return ;
			}
			j++;
		}
		i++;
	}
}

int	check_extension_map(char *file_name)
{
	char	*dot;

	dot = ft_strrchr(file_name, '.');
	return (dot && !ft_strcmp(dot, ".cub"));
}

int	parsing(int ac, char **av, t_data *data)
{
	int	count;

	if (ac != 2 || !check_extension_map(av[1]))
		return (ft_putstr_fd(ERR_INV_COP, 2), 0);
	count = 0;
	if (!read_map(av[1], data, &count))
		return (0);
	if (!valid_map(data))
		return (0);
	data->t_list = NULL;
	if (!lst_ture(data, &data->t_list))
		return (free_map(data), freelist(&data->t_list), 0);
	if (!color_ture(data, data->t_list))
		return (free_map(data), freelist(&data->t_list), 0);
	get_x_y_player(data);
	return (1);
}
