/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* render.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: grobledo +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/14 14:55:05 by greg #+# #+# */ /* Updated: 2024/10/17 16:28:20 by grobledo ### ########.fr */ /* */ /* ************************************************************************** */ #include "algo.h" #include static void calculate_perpwalldist3(int x, t_point_double *deltadist) { const double ray_direction = 2 * x / (double)SCREEN_WIDTH - 1; t_point_double plane; t_point_double dir; vector_from_rotation(&dir, g_map.player.rot, 1); vector_from_rotation(&plane, g_map.player.rot + PI / 2, 1); g_ray.dir.x = dir.x + plane.x * ray_direction; g_ray.dir.y = dir.y + plane.y * ray_direction; deltadist->x = 1e30; if (g_ray.dir.x != 0) deltadist->x = fabs(1 / g_ray.dir.x); deltadist->y = 1e30; if (g_ray.dir.y != 0) deltadist->y = fabs(1 / g_ray.dir.y); } static void calculate_perpwalldist2(int x, t_point_double *sidedist, t_point_double *deltadist, t_point_int *step) { const int map_x = (int)g_map.player.pos.x; const int map_y = (int)g_map.player.pos.y; // t_point_double raydir; calculate_perpwalldist3(x, deltadist); if (g_ray.dir.x < 0) { step->x = -1; sidedist->x = (g_map.player.pos.x - map_x) * deltadist->x; } else { step->x = 1; sidedist->x = (map_x + 1.0 - g_map.player.pos.x) * deltadist->x; } if (g_ray.dir.y < 0) { step->y = -1; sidedist->y = (g_map.player.pos.y - map_y) * deltadist->y; } else { step->y = 1; sidedist->y = (map_y + 1.0 - g_map.player.pos.y) * deltadist->y; } } /// @brief Calculate the distance of the wall perpendicularly to the camera /// plane. /// /// @param x Ray direction x between 0 and 1. /// @return Result. static double calculate_perpwalldist(int x) { t_point_int map_pos; // bool side; t_point_double sidedist; t_point_double deltadist; t_point_int step; map_pos.x = (int)g_map.player.pos.x; map_pos.y = (int)g_map.player.pos.y; calculate_perpwalldist2(x, &sidedist, &deltadist, &step); while (map_get_case(&g_map, map_pos.x, map_pos.y)->wall == EMPTY) { if (sidedist.x < sidedist.y) { sidedist.x += deltadist.x; map_pos.x += step.x; g_ray.side = false; continue ; } sidedist.y += deltadist.y; map_pos.y += step.y; g_ray.side = true; } if (!g_ray.side) return (sidedist.x - deltadist.x); return (sidedist.y - deltadist.y); } static void ft_init_texture(const double perpwalldist) { if (g_ray.side == 0 && g_ray.dir.x < 0) g_tex.tex_dir = 0; if (g_ray.side == 0 && g_ray.dir.x >= 0) g_tex.tex_dir = 1; if (g_ray.side == 1 && g_ray.dir.y < 0) g_tex.tex_dir = 2; if (g_ray.side == 1 && g_ray.dir.y >= 0) g_tex.tex_dir = 3; if (g_ray.side == 0) g_ray.wallx = g_player.pos.y + perpwalldist \ * g_ray.dir.y; else g_ray.wallx = g_player.pos.x + perpwalldist \ * g_ray.dir.x; g_ray.wallx -= floor((g_ray.wallx)); } /// @brief Draw a vertical line according to the ray direction x. /// /// @param x Ray direction x between 0 and 1. static void draw_vertical_line(int x, u_int32_t *img_data) { const double perpwalldist = calculate_perpwalldist(x); const int line_height = (int)(SCREEN_HEIGHT / perpwalldist); int draw_start; int draw_end; int y; int tex_y; int tex_x; int bpp; int size_line; int endian; u_int32_t color; ft_init_texture(perpwalldist); draw_start = -line_height / 2 + SCREEN_HEIGHT / 2; if (draw_start < 0) draw_start = 0; draw_end = line_height / 2 + SCREEN_HEIGHT / 2; if (draw_end >= SCREEN_HEIGHT) draw_end = SCREEN_HEIGHT - 1; y = 0; while (y < SCREEN_HEIGHT) { if (y < draw_start) img_data[y * SCREEN_WIDTH + x] = COLOR_CEILING; else if (y < draw_end) { tex_y = ((y - draw_start) * g_tex.tex_height) / line_height; tex_x = (int)(g_ray.wallx * g_tex.tex_width); if (g_ray.side == 0 && g_ray.dir.x > 0) tex_x = g_tex.tex_width - tex_x - 1; if (g_ray.side == 1 && g_ray.dir.y < 0) tex_x = g_tex.tex_height - tex_x - 1; u_int32_t *texture_data = (u_int32_t *)mlx_get_data_addr(g_tex.textures[g_tex.tex_dir], &bpp, &size_line, &endian); color = texture_data[tex_y * g_tex.tex_width + tex_x]; img_data[y * SCREEN_WIDTH + x] = color; // img_data[y * SCREEN_WIDTH + x] = COLOR_WALL; } else img_data[y * SCREEN_WIDTH + x] = COLOR_FLOOR; y++; } } int render(u_int32_t *img_data) { int x; x = 0; while (x < SCREEN_WIDTH) { draw_vertical_line(x, img_data); x++; } return (0); }