Compare commits

...

9 commits

Author SHA1 Message Date
1d6d97ef25
feat: enhance minimap rendering
- add heading indicator
- center of player icon is player position
- player size is independent of map tile size
- reduce minimap size
2025-08-05 15:23:31 +02:00
a46fdff49a
fix: correct error exit code when texture has error 2025-08-05 15:12:29 +02:00
a4d85c3cbb
tests: add test for detecting wrong texture size 2025-08-05 15:08:28 +02:00
c4bb3efe3e
feat: floor and ceiling colors 2025-08-05 15:01:35 +02:00
c242df5b72
feat: texture rendering 2025-08-05 13:27:34 +02:00
c09ba88d90
feat: use t_img_data to store textures insted of void ptr
This allows for easier writing of future functions, see next pr comming soon
2025-08-05 13:20:26 +02:00
121db8bd3c
norm: fix a few norm errors 2025-08-05 12:53:52 +02:00
f21e1e56fb
fix: use t_cardinal_dir instead of an int to represent direction 2025-08-05 12:50:24 +02:00
c4a867b054
feat: load and destroy wall textures 2025-08-05 12:11:06 +02:00
16 changed files with 302 additions and 103 deletions

1
.gitignore vendored
View file

@ -3,3 +3,4 @@ cub3d
*.d
libft.a
vgcore.*
cscope.*

View file

@ -0,0 +1,22 @@
NO ressources/north.xpm
SO ressources/south.xpm
WE ressources/west.xpm
EA ressources/bad_size.xpm
F 220,100,100
C 20,30,0
1111111111111111111111111
1000000000110000000000001
1011000001110000000000001
1001000000000000000000001
111111111011000001110000000000001
100000000011000001110111110111111
11110111111111011100000010001
11110111111111011101010010001
11000000110101011100000010001
10000000000000001100000010001
10000000000000001101010010001
11000001110101011111011110N0111
11110111 1110101 101111010001
11111111 1111111 111111111111

70
ressources/bad_size.xpm Normal file
View file

@ -0,0 +1,70 @@
/* XPM */
static char *dummy[]={
"65 64 3 1",
"# c #67502e",
"a c #833e4b",
". c #d6a459",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
"............................####.................................",
".........................###....##...............................",
"......................###........................................",
".....................#...........................................",
"....................#............................................",
"...................#.............................................",
"..................#..............................................",
"..................#..............................................",
"..................#..............................................",
"..................#..............................................",
"...................##............................................",
".....................##..........................................",
".......................#.........................................",
"........................##.......................................",
"..........................##.....................................",
"............................##...................................",
"..............................###................................",
".................................#...............................",
"..................................#..............................",
"..................................#..............................",
"..................................#..............................",
"..................................#..............................",
"..................................#..............................",
".................................#...............................",
"................................#................................",
"..............................##.................................",
"............................##...................................",
"....................########.....................................",
".................................................................",
".................................................................",
"........aa.......................................................",
"........aaa......................................................",
"........a.a......................................................",
".......a..a......................................................",
".......a..a.......aa.....................aaa.....................",
".......a..a.......aa....................a.......a................",
".......aaaa......a.a......aaaa..........a.......a.a..............",
".......aa........aaaa......a..a.........aaa.....a..aaa...........",
".......aa.......a...a......a..aa..........a.....a....a....aaa....",
".......a.a.....a....a......a....a........aa....a...aaa...aa......",
".......a.a.....a....a......a....a................aa......a.......",
".......a.a.....a....a......a....a................aaa.....aaa.....",
".......a.aa................a..aa....................aaa..aa......",
".......aaa.................a..a.......................a..a.......",
".......a...................aaa...........................aaa.....",
"...........................aa....................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
".................................................................",
"................................................................."};

View file

@ -3,8 +3,8 @@ SO ressources/south.xpm
WE ressources/west.xpm
EA ressources/east.xpm
F 220,100,0
C 225,30,0
F 220,100,100
C 20,30,0
1111111111111111111111111
1000000000110000000000001

View file

@ -6,7 +6,7 @@
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/17 14:54:36 by kcolin #+# #+# */
/* Updated: 2025/07/31 15:02:18 by kcolin ### ########.fr */
/* Updated: 2025/08/05 15:22:09 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -17,7 +17,8 @@
# define WIDTH 800
# define SIZE 64
# define MAP_SIZE 20
# define MAP_SIZE 10
# define PLAYER_SIZE 6
# define RESSOURCE_DIR "ressources"
# define MOVEMENT_SPEED 0.000005
# define ROTATION_SPEED 0.000002

View file

@ -6,7 +6,7 @@
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/17 14:59:37 by kcolin #+# #+# */
/* Updated: 2025/07/31 13:55:08 by tchampio ### ########.fr */
/* Updated: 2025/08/05 13:09:22 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -23,6 +23,10 @@ typedef struct s_cub3d_data
{
void *mlx;
void *mlx_win;
t_img_data *no_texture;
t_img_data *so_texture;
t_img_data *we_texture;
t_img_data *ea_texture;
t_img_data *img_data;
t_mapdata *map;
t_player player;

View file

@ -6,7 +6,7 @@
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/17 14:20:00 by kcolin #+# #+# */
/* Updated: 2025/07/29 14:16:07 by tchampio ### ########.fr */
/* Updated: 2025/08/05 15:20:47 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -14,6 +14,7 @@
#include "../player/player.h"
#include "drawutils.h"
#include "../consts.h"
#include "img_data.h"
void draw_2d_wall(unsigned int color, t_img_data *data,
int x, int y)
@ -34,6 +35,35 @@ void draw_2d_wall(unsigned int color, t_img_data *data,
}
}
void draw_player(unsigned int color, t_img_data *data,
int x, int y)
{
int i;
int j;
i = -(PLAYER_SIZE / 2);
while (i < (PLAYER_SIZE / 2))
{
j = -(PLAYER_SIZE / 2);
while (j < (PLAYER_SIZE / 2))
{
my_mlx_pixel_put(data, x + i, y + j, color);
j++;
}
i++;
}
}
void draw_heading(unsigned int color, t_img_data *data, t_player *player)
{
int x;
int y;
x = player->x * MAP_SIZE + player->dir_x * PLAYER_SIZE;
y = player->y * MAP_SIZE + player->dir_y * PLAYER_SIZE;
my_mlx_pixel_put(data, x, y, color);
}
void draw_map(t_mapdata *map, t_player *player, t_img_data *data)
{
int i;
@ -59,5 +89,6 @@ void draw_map(t_mapdata *map, t_player *player, t_img_data *data)
}
i++;
}
draw_2d_wall(0x00FF0000, data, MAP_SIZE * player->x, MAP_SIZE * player->y);
draw_player(0x00FF0000, data, MAP_SIZE * player->x, MAP_SIZE * player->y);
draw_heading(0x00FFFFFF, data, player);
}

View file

@ -6,7 +6,7 @@
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/06/21 19:35:43 by tchampio #+# #+# */
/* Updated: 2025/07/23 12:20:51 by tchampio ### ########.fr */
/* Updated: 2025/07/31 14:08:27 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -81,6 +81,7 @@ int try_set_texture(t_mapdata *map, char **texture, char *texture_name)
return (2);
}
*texture = ft_strdup(texture_name);
(*texture)[ft_strlen(*texture) - 1] = '\0';
return (0);
}

View file

@ -3,10 +3,10 @@
/* ::: :::::::: */
/* move.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tchampio <tchampio@student.42lehavre. +#+ +:+ +#+ */
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/29 13:58:00 by tchampio #+# #+# */
/* Updated: 2025/07/31 14:43:57 by tchampio ### ########.fr */
/* Created: 2025/08/05 12:53:06 by kcolin #+# #+# */
/* Updated: 2025/08/05 12:53:06 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -19,14 +19,16 @@ void move_player_forward(t_cub3d_data *data)
char **map;
double next_x;
double next_y;
float movspeed;
movspeed = MOVEMENT_SPEED * data->delta;
map = data->map->map;
next_x = data->player.x + data->player.dir_x * MOVEMENT_SPEED * data->delta;
next_y = data->player.y + data->player.dir_y * MOVEMENT_SPEED * data->delta;
next_x = data->player.x + data->player.dir_x * movspeed;
next_y = data->player.y + data->player.dir_y * movspeed;
if (map[(int)data->player.y][(int)next_x] == '0')
data->player.x += data->player.dir_x * MOVEMENT_SPEED * data->delta;
data->player.x += data->player.dir_x * movspeed;
if (map[(int)next_y][(int)data->player.x] == '0')
data->player.y += data->player.dir_y * MOVEMENT_SPEED * data->delta;
data->player.y += data->player.dir_y * movspeed;
}
void move_player_backward(t_cub3d_data *data)
@ -34,14 +36,16 @@ void move_player_backward(t_cub3d_data *data)
char **map;
double next_x;
double next_y;
float movspeed;
movspeed = MOVEMENT_SPEED * data->delta;
map = data->map->map;
next_x = data->player.x - data->player.dir_x * MOVEMENT_SPEED * data->delta;
next_y = data->player.y - data->player.dir_y * MOVEMENT_SPEED * data->delta;
next_x = data->player.x - data->player.dir_x * movspeed;
next_y = data->player.y - data->player.dir_y * movspeed;
if (map[(int)data->player.y][(int)next_x] == '0')
data->player.x -= data->player.dir_x * MOVEMENT_SPEED * data->delta;
data->player.x -= data->player.dir_x * movspeed;
if (map[(int)next_y][(int)data->player.x] == '0')
data->player.y -= data->player.dir_y * MOVEMENT_SPEED * data->delta;
data->player.y -= data->player.dir_y * movspeed;
}
void move_player_strafe_left(t_cub3d_data *data)
@ -49,14 +53,16 @@ void move_player_strafe_left(t_cub3d_data *data)
char **map;
double next_x;
double next_y;
float movspeed;
movspeed = MOVEMENT_SPEED * data->delta;
map = data->map->map;
next_x = data->player.x - data->player.plane_x * MOVEMENT_SPEED * data->delta;
next_y = data->player.y - data->player.plane_y * MOVEMENT_SPEED * data->delta;
next_x = data->player.x - data->player.plane_x * movspeed;
next_y = data->player.y - data->player.plane_y * movspeed;
if (map[(int)data->player.y][(int)next_x] == '0')
data->player.x -= data->player.plane_x * MOVEMENT_SPEED * data->delta;
data->player.x -= data->player.plane_x * movspeed;
if (map[(int)next_y][(int)data->player.x] == '0')
data->player.y -= data->player.plane_y * MOVEMENT_SPEED * data->delta;
data->player.y -= data->player.plane_y * movspeed;
}
void move_player_strafe_right(t_cub3d_data *data)
@ -64,14 +70,16 @@ void move_player_strafe_right(t_cub3d_data *data)
char **map;
double next_x;
double next_y;
float movspeed;
movspeed = MOVEMENT_SPEED * data->delta;
map = data->map->map;
next_x = data->player.x + data->player.plane_x * MOVEMENT_SPEED * data->delta;
next_y = data->player.y + data->player.plane_y * MOVEMENT_SPEED * data->delta;
next_x = data->player.x + data->player.plane_x * movspeed;
next_y = data->player.y + data->player.plane_y * movspeed;
if (map[(int)data->player.y][(int)next_x] == '0')
data->player.x += data->player.plane_x * MOVEMENT_SPEED * data->delta;
data->player.x += data->player.plane_x * movspeed;
if (map[(int)next_y][(int)data->player.x] == '0')
data->player.y += data->player.plane_y * MOVEMENT_SPEED * data->delta;
data->player.y += data->player.plane_y * movspeed;
}
void move_player(t_cub3d_data *data)

View file

@ -61,18 +61,18 @@ void calculate_wall_dist(t_ray *ray, char **map)
{
ray->side_dist_x += ray->delta_dist_x;
ray->map_x += ray->step_x;
ray->side = 0;
ray->side = NORTH;
}
else
{
ray->side_dist_y += ray->delta_dist_y;
ray->map_y += ray->step_y;
ray->side = 1;
ray->side = SOUTH;
}
if (map[ray->map_y][ray->map_x] != '0')
break ;
}
if (ray->side == 0)
if (ray->side == NORTH)
ray->wall_dist = ray->side_dist_x - ray->delta_dist_x;
else
ray->wall_dist = ray->side_dist_y - ray->delta_dist_y;
@ -89,7 +89,7 @@ void calculate_wall_height(t_ray *ray, t_player *player)
ray->draw_end = ray->wall_height / 2 + HEIGHT / 2;
if (ray->draw_end >= HEIGHT)
ray->draw_end = HEIGHT - 1;
if (ray->side == 0)
if (ray->side == NORTH)
ray->wall_x = player->y + ray->wall_dist * ray->dir_y;
else
ray->wall_x = player->x + ray->wall_dist * ray->dir_x;

View file

@ -3,16 +3,18 @@
/* ::: :::::::: */
/* ray.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tchampio <tchampio@student.42lehavre. +#+ +:+ +#+ */
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/29 11:32:20 by tchampio #+# #+# */
/* Updated: 2025/07/30 16:46:05 by tchampio ### ########.fr */
/* Created: 2025/08/05 12:49:49 by kcolin #+# #+# */
/* Updated: 2025/08/05 12:49:49 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef RAY_H
# define RAY_H
# include "../map/mapdata.h"
/*
* plane - plan de camera (vectoriel)
* dir_x - Direction (pour X)
@ -43,7 +45,7 @@ typedef struct s_ray
double delta_dist_x;
double delta_dist_y;
double wall_dist;
int side;
t_cardinal_dir side;
int wall_height;
int draw_start;
int draw_end;

View file

@ -1,12 +1,12 @@
/* ************************************************************************** */
/* */
/* ::: :::::::: */
/* render.c :+: :+: :+: */
/* walls.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/31 13:17:39 by kcolin #+# #+# */
/* Updated: 2025/07/31 13:38:07 by kcolin ### ########.fr */
/* Updated: 2025/08/05 14:59:24 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -15,69 +15,81 @@
#include "ray.h"
#include "../renderer/render.h"
int get_cardinal(t_ray *ray)
t_cardinal_dir get_cardinal(t_ray *ray)
{
if (ray->side == 0)
if (ray->side == NORTH)
{
if (ray->dir_x < 0)
return (2);
return (WEST);
else
return (3);
return (EAST);
}
else
{
if (ray->dir_y > 0)
return (1);
return (SOUTH);
else
return (0);
return (NORTH);
}
}
static int get_color(int dir)
static int my_mlx_pixel_get(t_img_data *img, int x, int y)
{
int color;
char *dst;
if (dir == 0)
color = 0x0000ff;
else if (dir == 1)
color = 0x00ff00;
else if (dir == 2)
color = 0xff0000;
else if (dir == 3)
color = 0xffeb3b;
else
color = 0xff53ff;
return (color);
dst = img->addr + (y * img->line_length + x * (img->bits_per_pixel / 8));
return (*(int *)dst);
}
static int get_color(t_cub3d_data *data, t_ray *ray, int tex_y)
{
t_cardinal_dir dir;
int tex_x;
t_img_data *texture;
tex_x = (int)(ray->wall_x * TEXTURE_SIZE);
if ((ray->side == NORTH && ray->dir_x < 0)
|| (ray->side == SOUTH && ray->dir_y > 0))
tex_x = TEXTURE_SIZE - tex_x - 1;
dir = get_cardinal(ray);
if (dir == NORTH)
texture = data->no_texture;
else if (dir == SOUTH)
texture = data->so_texture;
else if (dir == WEST)
texture = data->we_texture;
else if (dir == EAST)
texture = data->ea_texture;
else
return (0xff53ff);
return (my_mlx_pixel_get(texture, tex_x, tex_y));
}
/*
* Dir values are:
* 0: North
* 1: South
* 2: West
* 3: East
*/
void render_walls(t_cub3d_data *data, t_ray *ray, int x)
{
int dir;
int tex_x;
unsigned int color;
double step;
double pos;
double tex_y;
int y;
dir = get_cardinal(ray);
tex_x = (int)(ray->wall_x * TEXTURE_SIZE);
if ((ray->side == 0 && ray->dir_x < 0)
|| (ray->side == 1 && ray->dir_y > 0))
tex_x = TEXTURE_SIZE - tex_x - 1;
step = 1.0 * TEXTURE_SIZE / ray->wall_height;
pos = (ray->draw_start - HEIGHT / 2 + ray->wall_height / 2) * step;
while (ray->draw_start < ray->draw_end)
tex_y = (ray->draw_start - HEIGHT / 2 + ray->wall_height / 2) * step;
y = 0;
while (y < ray->draw_start)
{
pos += step;
color = get_color(dir);
(void)pos;
matrix_set(data, x, ray->draw_start, color);
ray->draw_start++;
matrix_set(data, x, y, data->map->c_color);
y++;
}
while (y < ray->draw_end - 1)
{
tex_y += step;
color = get_color(data, ray, (int)tex_y);
matrix_set(data, x, y, color);
y++;
}
while (y < HEIGHT)
{
matrix_set(data, x, y, data->map->f_color);
y++;
}
}

View file

@ -6,7 +6,7 @@
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/17 13:59:27 by kcolin #+# #+# */
/* Updated: 2025/07/31 13:26:06 by kcolin ### ########.fr */
/* Updated: 2025/07/31 14:25:10 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -58,7 +58,7 @@ void free_map(t_mapdata *map)
free(map);
}
int destroy(t_cub3d_data *data)
int destroy(t_cub3d_data *data, int exit_code)
{
free_map(data->map);
if (data->mlx_win)
@ -66,11 +66,23 @@ int destroy(t_cub3d_data *data)
if (data->img_data)
mlx_destroy_image(data->mlx, data->img_data->img);
free(data->img_data);
if (data->no_texture)
mlx_destroy_image(data->mlx, data->no_texture->img);
free(data->no_texture);
if (data->so_texture)
mlx_destroy_image(data->mlx, data->so_texture->img);
free(data->so_texture);
if (data->ea_texture)
mlx_destroy_image(data->mlx, data->ea_texture->img);
free(data->ea_texture);
if (data->we_texture)
mlx_destroy_image(data->mlx, data->we_texture->img);
free(data->we_texture);
if (data->mlx)
mlx_destroy_display(data->mlx);
free(data->mlx);
free(data->screen_matrix);
exit(0);
exit(exit_code);
return (0);
}

View file

@ -16,7 +16,7 @@
# include "../cub3d_data.h"
void gnl_exhaust(int fd);
int destroy(t_cub3d_data *data);
int destroy(t_cub3d_data *data, int exit_code);
void free_tab(char **tab);
void free_tab_length(char **tab, int length);
void free_map(t_mapdata *map);

View file

@ -22,7 +22,7 @@
int keypress_handler(int keycode, t_cub3d_data *data)
{
if (keycode == XK_Escape)
destroy(data);
destroy(data, 0);
if (keycode == XK_w)
data->keypresses.is_w_pressed = true;
if (keycode == XK_a)

View file

@ -3,10 +3,10 @@
/* ::: :::::::: */
/* inits.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: tchampio <tchampio@student.42lehavre. +#+ +:+ +#+ */
/* By: kcolin <kcolin@42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2025/07/31 13:26:53 by tchampio #+# #+# */
/* Updated: 2025/07/31 14:01:39 by tchampio ### ########.fr */
/* Created: 2025/07/31 13:43:05 by kcolin #+# #+# */
/* Updated: 2025/08/05 13:19:40 by kcolin ### ########.fr */
/* */
/* ************************************************************************** */
@ -17,6 +17,41 @@
#include "../map/map_checker.h"
#include "frees.h"
t_img_data *load_single_texture(t_cub3d_data *data, char *path)
{
int width;
int height;
void *img;
t_img_data *img_data;
img = mlx_xpm_file_to_image(data->mlx, path, &width, &height);
if (img == NULL)
{
ft_printf("Error: failed to open image at %s\n", path);
destroy(data, 1);
}
if (width != height || width != TEXTURE_SIZE)
{
ft_printf("Error: textures are not the right size\n");
destroy(data, 1);
}
ft_printf("image: %p\n", img);
img_data = ft_calloc(sizeof(t_img_data), 1);
img_data->img = img;
img_data->addr = mlx_get_data_addr(img_data->img,
&img_data->bits_per_pixel, &img_data->line_length,
&img_data->endian);
return (img_data);
}
void load_textures(t_cub3d_data *data)
{
data->no_texture = load_single_texture(data, data->map->no_texture);
data->so_texture = load_single_texture(data, data->map->so_texture);
data->we_texture = load_single_texture(data, data->map->we_texture);
data->ea_texture = load_single_texture(data, data->map->ea_texture);
}
void init_cub3d_data(t_cub3d_data *data, char **argv)
{
ft_bzero(data, sizeof(*data));
@ -36,5 +71,5 @@ void init_cub3d_data(t_cub3d_data *data, char **argv)
&data->img_data->endian);
init_player(&data->player, data->map);
data->screen_matrix = ft_calloc(sizeof(int), WIDTH * HEIGHT);
data->delta = get_milliseconds();
load_textures(data);
}