fix: render *

fix:
- fix texture for each direction (north texture is in north etc)
- fix mirror textures (the left of each texture is at its left)
- fix dimensions (walls are 1x1 for any window dimensions or FOV)
- optimize render()

dev:
- add testmaps/good_directions_test.cub
- add textures/test/*.xpm
This commit is contained in:
mcolonna 2024-11-12 13:07:09 +01:00
parent 184c8a60af
commit 6007f27510
14 changed files with 488 additions and 164 deletions

View file

@ -3,21 +3,21 @@
/* ::: :::::::: */
/* render.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: mc <mc@student.42.fr> +#+ +:+ +#+ */
/* By: Zy <frzysk@proton.me> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/10/14 14:55:05 by greg #+# #+# */
/* Updated: 2024/11/07 19:27:54 by mc ### ########.fr */
/* Updated: 2024/11/13 17:53:57 by Zy ### ########.fr */
/* */
/* ************************************************************************** */
#include "render.h"
#include "render_utils.h"
static void calculate_perpwalldist3(int x,
t_point_double *deltadist,
t_ray *ray)
// needs ray->x to be defined.
static void calculate_dir_and_deltadist(t_ray *ray)
{
const double ray_direction = 2 * x / (double)SCREEN_WIDTH - 1;
const double ray_direction
= FOV * 2 * ray->x / (double)SCREEN_WIDTH - FOV;
t_point_double plane;
t_point_double dir;
@ -25,129 +25,111 @@ static void calculate_perpwalldist3(int x,
vector_from_rotation(&plane, g_map.player.rot + PI / 2, 1);
ray->dir.x = dir.x + plane.x * ray_direction;
ray->dir.y = dir.y + plane.y * ray_direction;
deltadist->x = 1e30;
ray->deltadist.x = 1e30;
if (ray->dir.x != 0)
deltadist->x = fabs(1 / ray->dir.x);
deltadist->y = 1e30;
ray->deltadist.x = fabs(1 / ray->dir.x);
ray->deltadist.y = 1e30;
if (ray->dir.y != 0)
deltadist->y = fabs(1 / ray->dir.y);
ray->deltadist.y = fabs(1 / ray->dir.y);
}
static void calculate_perpwalldist2(int x,
t_point_double *sidedist,
t_point_double *deltadist,
t_point_int *step,
t_ray *ray)
// needs ray->x to be defined.
// also defines ->dir and ->deltadist.
static void calculate_step_and_sidedist(t_ray *ray)
{
const int map_x = (int)g_map.player.pos.x;
const int map_y = (int)g_map.player.pos.y;
calculate_perpwalldist3(x, deltadist, ray);
calculate_dir_and_deltadist(ray);
if (ray->dir.x < 0)
{
step->x = -1;
sidedist->x = (g_map.player.pos.x - map_x) * deltadist->x;
ray->step.x = -1;
ray->sidedist.x = (g_map.player.pos.x - map_x) * ray->deltadist.x;
}
else
{
step->x = 1;
sidedist->x = (map_x + 1.0 - g_map.player.pos.x) * deltadist->x;
ray->step.x = +1;
ray->sidedist.x = (map_x + 1.0 - g_map.player.pos.x) * ray->deltadist.x;
}
if (ray->dir.y < 0)
{
step->y = -1;
sidedist->y = (g_map.player.pos.y - map_y) * deltadist->y;
ray->step.y = -1;
ray->sidedist.y = (g_map.player.pos.y - map_y) * ray->deltadist.y;
}
else
{
step->y = 1;
sidedist->y = (map_y + 1.0 - g_map.player.pos.y) * deltadist->y;
ray->step.y = +1;
ray->sidedist.y = (map_y + 1.0 - g_map.player.pos.y) * ray->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_ray *ray)
// needs ray->x to be defined.
// also defines ->dir, ->deltadist, ->step and ->sidedist.
static void calculate_side_and_perpwalldist(t_ray *ray)
{
t_point_int map_pos;
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, ray);
calculate_step_and_sidedist(ray);
while (map_get_case(&g_map, map_pos.x, map_pos.y)->wall == EMPTY)
{
if (sidedist.x < sidedist.y)
if (ray->sidedist.x < ray->sidedist.y)
{
sidedist.x += deltadist.x;
map_pos.x += step.x;
ray->sidedist.x += ray->deltadist.x;
map_pos.x += ray->step.x;
ray->side = false;
continue ;
}
sidedist.y += deltadist.y;
map_pos.y += step.y;
ray->sidedist.y += ray->deltadist.y;
map_pos.y += ray->step.y;
ray->side = true;
}
if (!ray->side)
return (sidedist.x - deltadist.x);
return (sidedist.y - deltadist.y);
ray->perpwalldist = ray->sidedist.x - ray->deltadist.x;
else
ray->perpwalldist = ray->sidedist.y - ray->deltadist.y;
}
/// @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,
t_ray *ray, t_tex *tex)
static void draw_vertical_line(u_int32_t *img_data, t_ray *ray)
{
const double perpwalldist = calculate_perpwalldist(x, ray);
const int line_height = (int)(SCREEN_HEIGHT / perpwalldist);
int draw_start;
int draw_end;
int y;
int line_height;
int draw_start;
int draw_end;
ft_init_texture(perpwalldist, ray, tex);
calculate_side_and_perpwalldist(ray);
calculate_texdir_and_wallx(ray);
line_height = (int)(SCREEN_WIDTH / FOV / 2 / ray->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)
ray->y = 0;
while (ray->y++ < SCREEN_HEIGHT)
{
if (y < draw_start)
img_data[y * SCREEN_WIDTH + x] = g_map.color_ceiling;
else if (y < draw_end)
{
draw_wall(tex, ray, line_height, x, y, img_data);
}
if (ray->y < draw_start)
img_data[ray->y * SCREEN_WIDTH + ray->x] = g_map.color_ceiling;
else if (ray->y < draw_end)
draw_wall(ray, line_height, img_data);
else
img_data[y * SCREEN_WIDTH + x] = g_map.color_floor;
img_data[ray->y * SCREEN_WIDTH + ray->x] = g_map.color_floor;
}
}
int render(u_int32_t *img_data)
{
int x;
t_ray ray;
t_tex tex;
tex.tex_width = 64; // TODO fix
tex.tex_height = 64; // TODO fix
tex.textures[NORTH] = g_map.textures[NORTH].image;
tex.textures[SOUTH] = g_map.textures[SOUTH].image;
tex.textures[WEST] = g_map.textures[WEST].image;
tex.textures[EAST] = g_map.textures[EAST].image;
x = 0;
while (x < SCREEN_WIDTH)
ray.x = 0;
while (ray.x < SCREEN_WIDTH)
{
draw_vertical_line(x, img_data, &ray, &tex);
x++;
draw_vertical_line(img_data, &ray);
ray.x++;
}
return (0);
}

View file

@ -3,10 +3,10 @@
/* ::: :::::::: */
/* render_utils.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: mcolonna <mcolonna@student.42.fr> +#+ +:+ +#+ */
/* By: Zy <frzysk@proton.me> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/10/24 14:26:22 by grobledo #+# #+# */
/* Updated: 2024/11/04 14:00:25 by mcolonna ### ########.fr */
/* Updated: 2024/11/13 18:11:14 by Zy ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,42 +15,39 @@
#include "const.h"
#include "global.h"
void ft_init_texture(const double perpwalldist, t_ray *ray, t_tex *tex)
void calculate_texdir_and_wallx(t_ray *ray)
{
if (ray->side == 0 && ray->dir.x < 0)
tex->tex_dir = 0;
if (ray->side == 0 && ray->dir.x >= 0)
tex->tex_dir = 1;
if (ray->side == 1 && ray->dir.y < 0)
tex->tex_dir = 2;
if (ray->side == 1 && ray->dir.y >= 0)
tex->tex_dir = 3;
if (ray->side == 0)
ray->wallx = g_map.player.pos.y + perpwalldist \
if (ray->side && ray->dir.y < 0)
ray->texdir = NORTH;
if (ray->side && ray->dir.y >= 0)
ray->texdir = SOUTH;
if (!ray->side && ray->dir.x < 0)
ray->texdir = EAST;
if (!ray->side && ray->dir.x >= 0)
ray->texdir = WEST;
if (!ray->side)
ray->wallx = g_map.player.pos.y + ray->perpwalldist \
* ray->dir.y;
else
ray->wallx = g_map.player.pos.x + perpwalldist \
ray->wallx = g_map.player.pos.x + ray->perpwalldist \
* ray->dir.x;
if (ray->texdir == SOUTH || ray->texdir == EAST)
ray->wallx = -ray->wallx;
ray->wallx -= floor((ray->wallx));
}
void draw_wall(t_tex *tex, t_ray *ray, const int line_height, int x,
int y, u_int32_t *img_data)
void draw_wall(t_ray *ray, const int line_height, u_int32_t *img_data)
{
u_int32_t color;
u_int32_t *texture_data;
int texx;
int texy;
u_int32_t color;
u_int32_t *texture_data;
int texx;
int texy;
const t_texture texture = g_map.textures[ray->texdir];
texy = ((y - (-line_height / 2 + SCREEN_HEIGHT / 2)) \
* tex->tex_height) / line_height;
texx = (int)(ray->wallx * (double)tex->tex_width);
if (ray->side == 0 && ray->dir.x > 0)
texx = tex->tex_width - texx - 1;
if (ray->side == 1 && ray->dir.y < 0)
texx = tex->tex_height - texx - 1;
texture_data = (u_int32_t *)mlx_get_data_addr(tex->textures[tex->tex_dir],
&tex->bpp, &tex->size_line, &tex->endian);
color = texture_data[texx * tex->tex_width + texy];
img_data[y * SCREEN_WIDTH + x] = color;
texy = ((ray->y - (-line_height / 2 + SCREEN_HEIGHT / 2))
* texture.height) / line_height;
texx = (int)(ray->wallx * (double)texture.width);
texture_data = get_data_addr(texture.image);
color = texture_data[texy * texture.width + texx];
img_data[ray->y * SCREEN_WIDTH + ray->x] = color;
}

View file

@ -6,7 +6,7 @@
/* By: mcolonna <mcolonna@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2024/10/24 14:26:22 by grobledo #+# #+# */
/* Updated: 2024/11/04 13:07:42 by mcolonna ### ########.fr */
/* Updated: 2024/11/12 17:38:08 by mcolonna ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,9 +15,39 @@
# include "render.h"
void ft_init_texture(const double perpwalldist, t_ray *ray, t_tex *tex);
typedef struct s_ray
{
// Column of pixels currently drawing.
// Define the angle of the projected ray.
int x;
// With x, pixel to draw.
int y;
// Let the plane 1 case in front of the camera, of size FOV:
// point at which the ray projected touches the plane, relative to
// the camera position.
t_point_double dir;
// Transversal distance between two cases horizontally (for x) /
// vertically (for y), following the ray angle.
t_point_double deltadist;
// Direction of the ray, each component is either -1 or +1.
t_point_int step;
// Iterating perpwalldist for both north/south walls and east/west walls.
t_point_double sidedist;
// If true, the texture touched by the ray is facing north or south.
bool side;
// Distance between the wall touched by the ray and the camera plane.
double perpwalldist;
// x position of the point at which the ray touches the wall
// on the wall texture.
// Is in [0, 1[: 0 is the left side, 1 is the right side.
double wallx;
// Direction of the wall that the ray touches.
t_direction texdir;
} t_ray;
void draw_wall(t_tex *tex, t_ray *ray, const int line_height, int x,
int y, u_int32_t *img_data);
// needs ray->x, ->side and ->dir to be defined.
void calculate_texdir_and_wallx(t_ray *ray);
void draw_wall(t_ray *ray, const int line_height, u_int32_t *img_data);
#endif