diff --git a/algo.c b/algo.c index 4c40eb5..f6b4518 100644 --- a/algo.c +++ b/algo.c @@ -3,32 +3,67 @@ /* ::: :::::::: */ /* algo.c :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: greg +#+ +:+ +#+ */ +/* By: mc +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/01 16:24:58 by grobledo #+# #+# */ -/* Updated: 2024/10/11 05:16:06 by greg ### ########.fr */ +/* Updated: 2024/10/14 18:35:03 by mc ### ########.fr */ /* */ /* ************************************************************************** */ #include "algo.h" #include #include +#include +#include + +static void *g_mlx = NULL; +static void *g_win = NULL; + +static t_ray g_ray; + +// int worldMap[mapWidth][mapHeight]= +// { +// {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, +// {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1}, +// {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, +// {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} +// }; int worldMap[mapWidth][mapHeight]= { {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}, + {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,1,1,0,0,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, + {1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,1,1,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1}, + {1,0,0,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,1,1,0,0,1,1,0,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, + {1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, - {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,0,0,0,1,0,0,0,1}, - {1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,1,1,0,1,1,0,0,0,0,1,0,1,0,1,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, - {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, + {1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, {1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}, @@ -42,197 +77,244 @@ int worldMap[mapWidth][mapHeight]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1} }; - -static int initalgo(t_ray *ray) +static void vector_from_rotation( + double *vecX, double *vecY, double angle, double norm) { - ray->posX = 13; - ray->posY = 10; - ray->dirX = -1; - ray->dirY = 0; - ray->planeX = 0; - ray->planeY = 0.66; // FOV de 66 degres - ray->movespeed = 0.1; - ray->rotspeed = 0.1; + *vecX = -cos(angle) * norm; + *vecY = sin(angle) * norm; +} + +static int initalgo() +{ + // TODO from map + g_ray.posX = 14; + g_ray.posY = 6.5; + g_ray.rot = 0; return (0); } -static int render(t_ray *ray) +static int render(u_int32_t *img_data) { - int x; - double width = 640; - double height = 480; - int hit; - int side; - int *img_data = (int *)mlx_get_data_addr(ray->img_ptr, &(int){32}, &(int){width * 4}, &(int){0}); + int x; // px // clear image data - ft_bzero(img_data, width * height * sizeof(int)); + ft_bzero(img_data, SCREEN_WIDTH * SCREEN_HEIGHT * sizeof(int)); // TODO why + // 1 + double dirX, dirY, planeX, planeY; + vector_from_rotation(&dirX, &dirY, g_ray.rot, 1); + vector_from_rotation(&planeX, &planeY, g_ray.rot + PI/2, FOV); + x = 0; - while (x < width) + while (x < SCREEN_WIDTH) { - // position et direction du rayon - ray->cameraX = 2 * x / width - 1; - ray->raydirX = ray->dirX + ray->planeX * ray->cameraX; - ray->raydirY = ray->dirY + ray->planeY * ray->cameraX; + // case player on map (cases) + int mapX = (int)g_ray.posX; + // case player on map (cases) + int mapY = (int)g_ray.posY; - ray->mapX = (int)ray->posX; - ray->mapY = (int)ray->posY; - - ray->deltadistX = (ray->raydirX == 0) ? 1e30 : fabs(1 / ray->raydirX); - ray->deltadistY = (ray->raydirY == 0) ? 1e30 : fabs(1 / ray->raydirY); - - //calculate step and initial sideDist - if (ray->raydirX < 0) + // vector ray direction (1) + double raydirX, raydirY; { - ray->stepX = -1; - ray->sidedistX = (ray->posX - ray->mapX) * ray->deltadistX; + // ray direction in [-1;+1]. the highter the more to the right (1) + double ray_direction = 2 * x / (double)SCREEN_WIDTH - 1; + raydirX = dirX + planeX * ray_direction; + raydirY = dirY + planeY * ray_direction; + } + + // longueur du rayon dans une même colonne de cases (cases) + double deltadistX = (raydirX == 0) ? 1e30 : fabs(1 / raydirX); + // longueur du rayon dans une même ligne de cases (cases) + double deltadistY = (raydirY == 0) ? 1e30 : fabs(1 / raydirY); + + // longueur du rayon entre pos actuelle et pos du prochain coté ouest ou est d'une box + double sidedistX; + // longueur du rayon entre pos actuelle et pos du prochain coté nord ou sub d'une box + double sidedistY; + + // direction du rayon sur x (+1 or -1) + int stepX; + // direction du rayon sur y (+1 or -1) + int stepY; + + if (raydirX < 0) + { + stepX = -1; + sidedistX = (g_ray.posX - mapX) * deltadistX; } else { - ray->stepX = 1; - ray->sidedistX = (ray->mapX + 1.0 - ray->posX) * ray->deltadistX; + stepX = 1; + sidedistX = (mapX + 1.0 - g_ray.posX) * deltadistX; } - if (ray->raydirY < 0) + if (raydirY < 0) { - ray->stepY = -1; - ray->sidedistY = (ray->posY - ray->mapY) * ray->deltadistY; + stepY = -1; + sidedistY = (g_ray.posY - mapY) * deltadistY; } else { - ray->stepY = 1; - ray->sidedistY = (ray->mapY + 1.0 - ray->posY) * ray->deltadistY; + stepY = 1; + sidedistY = (mapY + 1.0 - g_ray.posY) * deltadistY; } - hit = 0; - while(hit == 0) + bool hit = false; + bool side; + while(!hit) { - //jump to next map square, either in x-direction, or in y-direction - if(ray->sidedistX < ray->sidedistY) + // jump to next map square, either in x-direction, or in y-direction + if(sidedistX < sidedistY) { - ray->sidedistX += ray->deltadistX; - ray->mapX += ray->stepX; - side = 0; + sidedistX += deltadistX; + mapX += stepX; + side = false; } else { - ray->sidedistY += ray->deltadistY; - ray->mapY += ray->stepY; - side = 1; + sidedistY += deltadistY; + mapY += stepY; + side = true; } - //Check if ray has hit a wall - if(worldMap[ray->mapX][ray->mapY] == 1) - hit = 1; + // check if ray has hit a wall + if(worldMap[mapX][mapY] == 1) + hit = true; } - if(side == 0) - ray->perpwalldist = (ray->sidedistX - ray->deltadistX); - else - ray->perpwalldist = (ray->sidedistY - ray->deltadistY); - //Calculate height of line to draw on screen - int lineHeight = (int)(height / ray->perpwalldist); - //calculate lowest and highest pixel to fill in current stripe - int drawStart = -lineHeight / 2 + height / 2; + // calcul lenght of ray (shortest perpendicular distance between wall and camera plane) (1) + double perpwalldist; + if(!side) + perpwalldist = (sidedistX - deltadistX); + else + perpwalldist = (sidedistY - deltadistY); + + // calculate height of line to draw on screen (px) + int lineHeight = (int)(SCREEN_HEIGHT / perpwalldist); + + // calculate lowest and highest pixel to fill in current stripe + int drawStart = -lineHeight / 2 + SCREEN_HEIGHT / 2; if(drawStart < 0) drawStart = 0; - int drawEnd = lineHeight / 2 + height / 2; - if(drawEnd >= height) - drawEnd = height - 1; + int drawEnd = lineHeight / 2 + SCREEN_HEIGHT / 2; + if(drawEnd >= SCREEN_HEIGHT) + drawEnd = SCREEN_HEIGHT - 1; // draw vertical line int y = 0; - while (y <= drawStart) + while (y < drawStart) { - img_data[y * (int)width + x] = 0x29f8ff;; + img_data[y * SCREEN_WIDTH + x] = COLOR_CEILING; y++; } - y = drawStart; - while (y <= drawEnd) + while (y < drawEnd) { - img_data[y * (int)width + x] = 0xFF0000; + img_data[y * SCREEN_WIDTH + x] = COLOR_WALL; y++; } - y++; - while (y <= height) + while (y < SCREEN_HEIGHT) { - img_data[y * (int)width + x] = 0xFF985C; + img_data[y * SCREEN_WIDTH + x] = COLOR_FLOOR; y++; } - + x++; } - // put image to window - mlx_put_image_to_window(ray->mlx_ptr, ray->win_ptr, ray->img_ptr, 0, 0); return (0); } -static int keypress(int keycode, t_ray *ray) -{ - //move forward if no wall in front of you - if (keycode == 119) +static void draw_screen() { + int bpp; + int size_line; + int endian; + + void *img_ptr = mlx_new_image(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT); + u_int32_t *img_data = (u_int32_t *)mlx_get_data_addr(img_ptr, &bpp, &size_line, &endian); + if (bpp != 32 || endian != 0) { - if (worldMap[(int)((ray->posX + ray->dirX * ray->movespeed))][(int)(ray->posY)] != 1) - ray->posX += ray->dirX * ray->movespeed; - if (worldMap[(int)(ray->posX)][(int)(ray->posY + ray->dirY * ray->movespeed)] != 1) - ray->posY += ray->dirY * ray->movespeed; + // TODO manage error better + printf("image format error (got bpp == %i, endian == %i)\n", bpp, endian); + exit(1); + } + render(img_data); + mlx_put_image_to_window(g_mlx, g_win, img_ptr, 0, 0); +} + +static int keypress(int keycode) +{ + double dirX, dirY, planeX, planeY; + vector_from_rotation(&dirX, &dirY, g_ray.rot, 1); + vector_from_rotation(&planeX, &planeY, g_ray.rot + PI/2, FOV); + + //move forward if no wall in front of you + if (keycode == XK_Up || keycode == XK_z || keycode == XK_w) + { + if (worldMap[(int)((g_ray.posX + dirX * MOVE_SPEED))][(int)(g_ray.posY)] != 1) + g_ray.posX += dirX * MOVE_SPEED; + if (worldMap[(int)(g_ray.posX)][(int)(g_ray.posY + dirY * MOVE_SPEED)] != 1) + g_ray.posY += dirY * MOVE_SPEED; } //move backwards if no wall behind you - if (keycode == 115) + if (keycode == XK_Down || keycode == XK_s) { - if (worldMap[(int)(ray->posX - ray->dirX * ray->movespeed)][(int)(ray->posY)] != 1) - ray->posX -= ray->dirX * ray->movespeed; - if (worldMap[(int)(ray->posX)][(int)(ray->posY - ray->dirY * ray->movespeed)] != 1) - ray->posY -= ray->dirY * ray->movespeed; + if (worldMap[(int)(g_ray.posX - dirX * MOVE_SPEED)][(int)(g_ray.posY)] != 1) + g_ray.posX -= dirX * MOVE_SPEED; + if (worldMap[(int)(g_ray.posX)][(int)(g_ray.posY - dirY * MOVE_SPEED)] != 1) + g_ray.posY -= dirY * MOVE_SPEED; } //rotate to the right - if (keycode == 100) + if (keycode == XK_Right || keycode == XK_d) { - //both camera direction and camera plane must be rotated - ray->oldDirX = ray->dirX; - ray->dirX = ray->dirX * cos(-ray->rotspeed) - ray->dirY * sin(-ray->rotspeed); - ray->dirY = ray->oldDirX * sin(-ray->rotspeed) + ray->dirY * cos(-ray->rotspeed); - ray->oldPlaneX = ray->planeX; - ray->planeX = ray->planeX * cos(-ray->rotspeed) - ray->planeY * sin(-ray->rotspeed); - ray->planeY = ray->oldPlaneX * sin(-ray->rotspeed) + ray->planeY * cos(-ray->rotspeed); + g_ray.rot += ROT_SPEED; + // double oldDirX; + // double oldPlaneX; + // //both camera direction and camera plane must be rotated + // oldDirX = dirX; + // dirX = dirX * cos(-ROT_SPEED) - dirY * sin(-ROT_SPEED); + // dirY = oldDirX * sin(-ROT_SPEED) + dirY * cos(-ROT_SPEED); + // oldPlaneX = planeX; + // planeX = planeX * cos(-ROT_SPEED) - planeY * sin(-ROT_SPEED); + // planeY = oldPlaneX * sin(-ROT_SPEED) + planeY * cos(-ROT_SPEED); } //rotate to the left - if (keycode == 97) + if (keycode == XK_Left || keycode == XK_q || keycode == XK_a) { - //both camera direction and camera plane must be rotated - ray->oldDirX = ray->dirX; - ray->dirX = ray->dirX * cos(ray->rotspeed) - ray->dirY * sin(ray->rotspeed); - ray->dirY = ray->oldDirX * sin(ray->rotspeed) + ray->dirY * cos(ray->rotspeed); - ray->oldPlaneX = ray->planeX; - ray->planeX = ray->planeX * cos(ray->rotspeed) - ray->planeY * sin(ray->rotspeed); - ray->planeY = ray->oldPlaneX * sin(ray->rotspeed) + ray->planeY * cos(ray->rotspeed); + g_ray.rot -= ROT_SPEED; + // double oldDirX; + // double oldPlaneX; + // //both camera direction and camera plane must be rotated + // oldDirX = dirX; + // dirX = dirX * cos(ROT_SPEED) - dirY * sin(ROT_SPEED); + // dirY = oldDirX * sin(ROT_SPEED) + dirY * cos(ROT_SPEED); + // oldPlaneX = planeX; + // planeX = planeX * cos(ROT_SPEED) - planeY * sin(ROT_SPEED); + // planeY = oldPlaneX * sin(ROT_SPEED) + planeY * cos(ROT_SPEED); } - if (keycode == 65307) + if (keycode == XK_Escape) exit(0); + + printf("x:%f y:%f\n", g_ray.posX, g_ray.posY); // render the updated frame after key press - render(ray); + draw_screen(); return (0); } int main(void) { - t_ray ray; - // Initialisation - ray.mlx_ptr = mlx_init(); - ray.win_ptr = mlx_new_window(ray.mlx_ptr, 640, 480, "cub3d"); - ray.img_ptr = mlx_new_image(ray.mlx_ptr, 640, 480); + g_mlx = mlx_init(); + g_win = mlx_new_window(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT, "cub3d"); - initalgo(&ray); + initalgo(); // hook keypress - mlx_hook(ray.win_ptr, 2, 1L<<0, keypress, &ray); + mlx_hook(g_win, 2, 1L<<0, keypress, NULL); + // render the initial frame - render(&ray); + draw_screen(); // start the mlx loop - mlx_loop(ray.mlx_ptr); + mlx_loop(g_mlx); return (0); } diff --git a/algo.h b/algo.h index 3b5585c..48207f2 100644 --- a/algo.h +++ b/algo.h @@ -3,10 +3,10 @@ /* ::: :::::::: */ /* algo.h :+: :+: :+: */ /* +:+ +:+ +:+ */ -/* By: greg +#+ +:+ +#+ */ +/* By: mc +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/09/30 15:45:59 by grobledo #+# #+# */ -/* Updated: 2024/10/11 04:32:39 by greg ### ########.fr */ +/* Updated: 2024/10/14 18:26:05 by mc ### ########.fr */ /* */ /* ************************************************************************** */ @@ -18,46 +18,26 @@ #include "Minilibx/mlx.h" #include "Minilibx/mlx_int.h" # include "Libft/libft.h" -#define mapWidth 24 -#define mapHeight 24 +#define mapWidth 24 // cases +#define mapHeight 24 // cases +#define MOVE_SPEED 0.1 // cases +#define PI 3.1415926535 +#define ROT_SPEED (PI / 16) // rad +#define COLOR_WALL 0xFF0000 // 0xRRGGBB +#define COLOR_CEILING 0x29f8ff // 0xRRGGBB +#define COLOR_FLOOR 0xFF985C // 0xRRGGBB +#define SCREEN_WIDTH 640 // px +#define SCREEN_HEIGHT 480 // px +#define FOV 0.66 // ? TODO unit typedef struct s_ray { - // pos player on map + // pos player on map (cases) double posX; + // pos player on map (cases) double posY; - // orientation player on map - double dirX; - double dirY; - // orientation cam on map - double planeX; - double planeY; - // camera pos - double cameraX; - // direction rayon - double raydirX; - double raydirY; - // longueur du rayon entre pos actuelle et pos du prochain cote d'une box - double sidedistX; - double sidedistY; - // longueur du rayon entre pos d'un cote d'une box jusqu'a pos du prochain cote d'une box - double deltadistX; - double deltadistY; - // calcul lenght of ray (shortest perpendicular distance between wall and camera plane) - double perpwalldist; - // step direction (can be -1 or +1) - int stepX; - int stepY; - double movespeed; - double rotspeed; - double oldDirX; - double oldPlaneX; - void *mlx_ptr; - void *win_ptr; - void *img_ptr; - int *img_data; - int mapX; - int mapY; + // player rotation (rad) + double rot; } t_ray; #endif