/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   render_walls.c                                     :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: qmennen <qmennen@student.codam.nl>         +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2025/05/14 13:05:28 by whaffman          #+#    #+#             */
/*   Updated: 2025/06/04 18:17:33 by qmennen          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "cub3d.h"

t_side	get_side(t_render *render, t_vec2 ray_dir, double perp_dist)
{
	if (render->door)
		return (SIDE_DOOR);
	if (perp_dist > 0)
	{
		if (ray_dir.x > 0)
			return (SIDE_WEST);
		else
			return (SIDE_EAST);
	}
	else
	{
		if (ray_dir.y > 0)
			return (SIDE_NORTH);
		else
			return (SIDE_SOUTH);
	}
}

t_render	cast_ray(t_game *game, int x)
{
	t_vec2		ray_dir;
	t_vec2		pos;
	t_render	render;
	double		perp_dist;

	render.door = 0;
	ray_dir = add(game->player->dir,
			mul(game->player->camera,
				(2.0f * x / (double)game->screen->width - 1)));
	pos = game->player->pos;
	perp_dist = dda(&render, ray_dir, pos, game->map);
	render.perp_dist = fabs(perp_dist);
	render.side = get_side(&render, ray_dir, perp_dist);
	if (perp_dist < 0)
		render.wall_x = pos.x + ray_dir.x * render.perp_dist;
	else
		render.wall_x = pos.y + ray_dir.y * render.perp_dist;
	render.wall_x -= floor(render.wall_x);
	return (render);
}

unsigned int	get_texture_color(mlx_texture_t *texture,
	t_render render, t_vec2_int tex)
{
	int			index;
	double		dist;

	if (tex.x < 0)
		tex.x = 0;
	if (tex.y < 0)
		tex.y = 0;
	index = (tex.x + tex.y * texture->height) * texture->bytes_per_pixel;
	dist = (render.perp_dist == 0) * 1e30
		+ (render.perp_dist > 1) * render.perp_dist
		+ (render.perp_dist <= 1) * 1;
	return ((unsigned int)texture->pixels[index] << 24
		| (unsigned int)texture->pixels[index + 1] << 16
		| (unsigned int)texture->pixels[index + 2] << 8
		| (int)(1.0 / dist * 255));
}

static int	set_range(t_game *game, t_render render, t_range *range, int height)
{
	int	tex_start;

	height = game->screen->height / render.perp_dist;
	range->start = game->screen->height / 2 - height / 2;
	tex_start = range->start;
	range->start = (range->start > 0) * range->start;
	range->end = height / 2 + game->screen->height / 2;
	if (range->end >= game->screen->height)
		range->end = game->screen->height - 1;
	return (tex_start);
}

void	draw_line(t_game *game, t_render render, int x)
{
	int			color;
	int			height;
	int			tex_start;
	t_vec2_int	tex;
	t_range		range;

	height = game->screen->height / render.perp_dist;
	tex_start = set_range(game, render, &range, height);
	tex.x = render.wall_x * game->map->textures[render.side]->width;
	if (render.side == SIDE_NORTH || render.side == SIDE_EAST)
		tex.x = game->map->textures[render.side]->width - tex.x - 1;
	while (range.start < range.end)
	{
		tex.y = (range.start - tex_start);
		tex.y *= ((double)game->map->textures[render.side]->height / height);
		color = get_texture_color(game->map->textures[render.side],
				render, tex);
		if (x < 0
			|| x >= game->screen->width
			|| range.start < 0
			|| range.start >= game->screen->height)
			break ;
		mlx_put_pixel(game->screen->img, x, range.start, color);
		range.start++;
	}
}
