/* ************************************************************************** */
/*                                                                            */
/*                                                        :::      ::::::::   */
/*   render_sprite.c                                    :+:      :+:    :+:   */
/*                                                    +:+ +:+         +:+     */
/*   By: qmennen <qmennen@student.codam.nl>         +#+  +:+       +#+        */
/*                                                +#+#+#+#+#+   +#+           */
/*   Created: 2025/05/08 12:23:17 by qmennen           #+#    #+#             */
/*   Updated: 2025/06/03 22:15:19 by qmennen          ###   ########.fr       */
/*                                                                            */
/* ************************************************************************** */

#include "render.h"

static void	get_start_end(t_game *game,
	t_sprite *sprite, t_vec2_int *start, t_vec2_int *end)
{
	double			sprite_scale;

	sprite_scale = game->screen->height / sprite->dist
		/ sprite->texture->height;
	start->x = 0.5 * (game->screen->width * (1.0 + sprite->cam_frac)
			- sprite->texture->width / sprite->n_frames * sprite_scale);
	start->y = 0.5 * (game->screen->height
			- sprite->texture->height * sprite_scale);
	end->x = start->x;
	end->x += sprite->texture->width / sprite->n_frames * sprite_scale;
	end->y = start->y + sprite->texture->height * sprite_scale;
}

static int	sprite_visible(t_game *game,
		t_sprite *sprite, t_render *render, int x)
{
	return (!isnan(sprite->cam_frac)
		&& sprite->dist > MIN_SPRITE_DIST
		&& x > 0
		&& x < game->screen->width
		&& sprite->dist <= render[x].perp_dist);
}

static void	draw_sprite_column(
	t_game *game, t_sprite *sprite, t_render *render,
	t_sprite_column column)
{
	t_vec2_int		tex;
	t_vec2			inv_range;
	int				y;
	unsigned int	color;
	int				frame;

	frame = (mlx_get_time() * sprite->animation_speed);
	frame %= sprite->n_frames;
	inv_range.y = 1.0 / (column.end.y - column.start.y);
	inv_range.x = 1.0 / (column.end.x - column.start.x);
	sprite->alpha = calculate_alpha(column.start.x,
			column.start.y, sprite->dist);
	tex.x = column.x - column.start.x;
	tex.x *= sprite->texture->width / sprite->n_frames;
	tex.x *= inv_range.x;
	y = column.start.y;
	while (y < column.end.y)
	{
		tex.y = (y - column.start.y) * sprite->texture->height;
		tex.y *= inv_range.y;
		color = sample_texture_color(sprite, tex, frame);
		if (y > 0 && y < game->screen->height && (color & 0xFF) != 0)
			mlx_put_pixel(game->screen->img, column.x, y, color);
		y++;
	}
}

void	draw_sprite(t_game *game, t_sprite *sprite, t_render *render)
{
	t_vec2_int		start;
	t_vec2_int		end;
	t_sprite_column	column;
	int				x;

	if (isnan(sprite->cam_frac) || sprite->dist <= MIN_SPRITE_DIST)
		return ;
	get_start_end(game, sprite, &start, &end);
	x = start.x;
	while (x < end.x)
	{
		if (sprite_visible(game, sprite, render, x))
		{
			handle_flash(sprite, game);
			column.start = start;
			column.end = end;
			column.x = x;
			draw_sprite_column(game, sprite, render, column);
		}
		x++;
	}
}

void	render_sprites(t_render *render, t_game *game)
{
	int		i;

	calculate_sprite_dist(game);
	sort_sprites(game);
	i = 0;
	while (i < game->map->n_sprites)
	{
		if (game->map->sprites[i].type == SPRITE_TYPE_DISABLED
			|| game->map->sprites[i].type == SPRITE_TYPE_COLLECTED)
		{
			i++;
			continue ;
		}
		cam_fraction(game, &game->map->sprites[i]);
		draw_sprite(game, &game->map->sprites[i], render);
		i++;
	}
}
