/* ************************************************************************** */ /* */ /* ::: :::::::: */ /* algo.c :+: :+: :+: */ /* +:+ +:+ +:+ */ /* By: mc +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/01 16:24:58 by grobledo #+# #+# */ /* 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,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}, {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} }; static void vector_from_rotation( double *vecX, double *vecY, double angle, double norm) { *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(u_int32_t *img_data) { int x; // px // clear image data 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 < SCREEN_WIDTH) { // case player on map (cases) int mapX = (int)g_ray.posX; // case player on map (cases) int mapY = (int)g_ray.posY; // vector ray direction (1) double raydirX, raydirY; { // 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 { stepX = 1; sidedistX = (mapX + 1.0 - g_ray.posX) * deltadistX; } if (raydirY < 0) { stepY = -1; sidedistY = (g_ray.posY - mapY) * deltadistY; } else { stepY = 1; sidedistY = (mapY + 1.0 - g_ray.posY) * deltadistY; } bool hit = false; bool side; while(!hit) { // jump to next map square, either in x-direction, or in y-direction if(sidedistX < sidedistY) { sidedistX += deltadistX; mapX += stepX; side = false; } else { sidedistY += deltadistY; mapY += stepY; side = true; } // check if ray has hit a wall if(worldMap[mapX][mapY] == 1) hit = true; } // 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 + SCREEN_HEIGHT / 2; if(drawEnd >= SCREEN_HEIGHT) drawEnd = SCREEN_HEIGHT - 1; // draw vertical line int y = 0; while (y < drawStart) { img_data[y * SCREEN_WIDTH + x] = COLOR_CEILING; y++; } while (y < drawEnd) { img_data[y * SCREEN_WIDTH + x] = COLOR_WALL; y++; } while (y < SCREEN_HEIGHT) { img_data[y * SCREEN_WIDTH + x] = COLOR_FLOOR; y++; } x++; } return (0); } 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) { // 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 == XK_Down || keycode == XK_s) { 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 == XK_Right || keycode == XK_d) { 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 == XK_Left || keycode == XK_q || keycode == XK_a) { 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 == XK_Escape) exit(0); printf("x:%f y:%f\n", g_ray.posX, g_ray.posY); // render the updated frame after key press draw_screen(); return (0); } int main(void) { // Initialisation g_mlx = mlx_init(); g_win = mlx_new_window(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT, "cub3d"); initalgo(); // hook keypress mlx_hook(g_win, 2, 1L<<0, keypress, NULL); // render the initial frame draw_screen(); // start the mlx loop mlx_loop(g_mlx); return (0); } // https://github.com/iciamyplant/Cub3d-Linux // https://lodev.org/cgtutor/raycasting.html // https://www.youtube.com/watch?v=js7HW65MmNw&list=PL0H9-oZl_QOHM34HvD3DiGmwmj5X7GvTW