/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   dda.c                                              :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: erey-bet <marvin@42.fr>                    +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2023/05/02 15:49:00 by erey-bet          #+#    #+#             */
/*   Updated: 2023/05/04 14:37:21 by erey-bet         ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "game.h"

double	ft_abs(double nb)
{
	if (nb < 0)
		return (-nb);
	return (nb);
}

void	init_dda(t_game *game, t_dda *dda)
{
	t_ray	*ray;
	t_ply	*ply;

	ray = &game->ray;
	ply = &game->ply;
	dda->map_x = (int)ply->pos_x;
	dda->map_y = (int)ply->pos_y;
	if (ray->dir_x == 0)
		dda->delta_dist_x = 1e30;
	else
		dda->delta_dist_x = ft_abs(1 / ray->dir_x);
	if (ray->dir_y == 0)
		dda->delta_dist_y = 1e30;
	else
		dda->delta_dist_y = ft_abs(1 / ray->dir_y);
	dda->step_x = 1;
	dda->step_y = 1;
	if (ray->dir_x < 0)
	{
		dda->step_x = -1;
		dda->side_dist_x = (ply->pos_x - dda->map_x) * dda->delta_dist_x;
	}
	else
		dda->side_dist_x = (dda->map_x + 1.0 - ply->pos_x) * dda->delta_dist_x;
	if (ray->dir_y < 0)
	{
		dda->step_y = -1;
		dda->side_dist_y = (ply->pos_y - dda->map_y) * dda->delta_dist_y;
	}
	else
		dda->side_dist_y = (dda->map_y + 1.0 - ply->pos_y) * dda->delta_dist_y;
	dda->hit = 0;
}

void loop_dda(t_game *game, t_dda *dda)
{
	while (dda->hit == 0)
	{
		if (dda->side_dist_x < dda->side_dist_y)
		{
			dda->side_dist_x += dda->delta_dist_x;
			dda->map_x += dda->step_x;
			dda->side = 0;
		}
		else
		{
			dda->side_dist_y += dda->delta_dist_y;
			dda->map_y += dda->step_y;
			dda->side = 1;
		}
		if (dda->map_x < 0 || dda->map_y < 0
			|| dda->map_x >= (int)game->map.size_x || dda->map_y >= (int)game->map.size_y)
		{
			dda->perp_wall_dist = 1e30;
			return ;
		}
		if (game->map.map[dda->map_y][dda->map_x] == '1') 
			dda->hit = 1;
	} 
	if(dda->side == 0)
		dda->perp_wall_dist = dda->side_dist_x - dda->delta_dist_x;
	else
		dda->perp_wall_dist = dda->side_dist_y - dda->delta_dist_y;
}

void	ray_dda(t_dda *dda)
{
	if (dda->perp_wall_dist == 0)
		dda->perp_wall_dist = 1e30;
	dda->line_height = (int)(HEIGHT / dda->perp_wall_dist);
	dda->draw_start = -(dda->line_height) / 2 + HEIGHT / 2;
	if(dda->draw_start < 0)
		dda->draw_start = 0;
	dda->draw_end = dda->line_height / 2 + HEIGHT / 2;
	if(dda->draw_end >= HEIGHT)
		dda->draw_end = HEIGHT - 1;
}

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

void	draw_line(t_game *game, t_dda *dda, unsigned int color, int x)
{
	int	y;
	unsigned int	white;

	white = 0xFFFFFFFF;
	y = 0;
	while (y < HEIGHT)
	{
		if (y < dda->draw_start)
		{
			mlx_put_pixel(game->window, x, y, white);
		}
		else if (y >= dda->draw_start && y <= dda->draw_end)
		{
			mlx_put_pixel(game->window, x, y, color);
		}
		else if (y > dda->draw_end)
		{
			mlx_put_pixel(game->window, x, y, white);
		}
		y++;
	}
}


void	draw_dda(t_game *game, t_dda *dda, int x)
{
	unsigned int color;

	if (dda->step_x < 0 && dda->side == 0) // NORTH
		color = get_rgba(0, 0, 200, 255);
	else if (dda->step_x > 0 && dda->side == 0) // SOUTH
		color = get_rgba(200, 0, 0, 255);
	else if (dda->step_y < 0 && dda->side == 1) // EAST
		color = get_rgba(0, 200, 0, 255);
	else if (dda->step_y > 0 && dda->side == 1) // WEST
		color = get_rgba(50, 100, 50, 255);
	else
		color = get_rgba(0, 0, 0, 255);

	draw_line(game, dda, color, x);
}

void	dda(t_game *game, int x)
{
	t_dda dda;

	init_dda(game, &dda);
	loop_dda(game, &dda);
	ray_dda(&dda);
	draw_dda(game, &dda, x);
}
