From c1e17997ffe3a8e26e650aa5b1d6f26c7b185245 Mon Sep 17 00:00:00 2001 From: ReverseSky Date: Thu, 10 Oct 2024 18:38:37 +0200 Subject: [PATCH] render termine manque textures --- algo.c | 242 ++++++++++++++++++++++++++++----------------------------- algo.h | 7 +- cub3d | Bin 0 -> 39080 bytes 3 files changed, 125 insertions(+), 124 deletions(-) create mode 100755 cub3d diff --git a/algo.c b/algo.c index 62414a9..569e103 100644 --- a/algo.c +++ b/algo.c @@ -6,7 +6,7 @@ /* By: greg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/10/01 16:24:58 by grobledo #+# #+# */ -/* Updated: 2024/10/09 03:30:08 by greg ### ########.fr */ +/* Updated: 2024/10/10 18:22:08 by greg ### ########.fr */ /* */ /* ************************************************************************** */ @@ -45,8 +45,8 @@ int worldMap[mapWidth][mapHeight]= static int initalgo(t_ray *ray) { - ray->posX = 2; - ray->posY = 2; + ray->posX = 13; + ray->posY = 10; ray->dirX = -1; ray->dirY = 0; ray->planeX = 0; @@ -56,123 +56,67 @@ static int initalgo(t_ray *ray) return (0); } -static int keypress(int keycode, t_ray *ray, int **worldMap) +static int render(t_ray *ray) { - //move forward if no wall in front of you - if (keycode == 119) - { - if(worldMap[(int)(ray->posX + ray->dirX * ray->movespeed)][(int)(ray->posY)] == 0) - ray->posX += ray->dirX * ray->movespeed; - if(worldMap[(int)(ray->posX)][((int)ray->posY + (int)ray->dirY * (int)ray->movespeed)] == 0) - ray->posY += ray->dirY * ray->movespeed; - } - //move backwards if no wall behind you - if (keycode == 115) - { - if(worldMap[(int)(ray->posX - ray->dirX * ray->movespeed)][(int)(ray->posY)] == 0) - ray->posX -= ray->dirX * ray->movespeed; - if(worldMap[(int)(ray->posX)][((int)ray->posY - (int)ray->dirY * (int)ray->movespeed)] == 0) - ray->posY -= ray->dirY * ray->movespeed; - } - //rotate to the right - if (keycode == 100) - { - //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); - } - //rotate to the left - if (keycode == 97) - { - //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); - } - return (0); -} - -int main(int /*argc*/, char */*argv*/[]) -{ - t_ray ray; - int x; - double width; - double height; - // quelle box sur la map on est - int mapX; - int mapY; - // wall hit and if yes in wich direction - int hit; - int side; - - initalgo(&ray); - + int x; + double width = 640; + double height = 480; + int mapX, mapY, hit, side; + int *img_data = (int *)mlx_get_data_addr(ray->img_ptr, &(int){32}, &(int){width * 4}, &(int){0}); + + // clear image data + ft_bzero(img_data, width * height * sizeof(int)); + x = 0; - width = 640; - height = 480; - - void *mlx_ptr; - void *win_ptr; - - mlx_ptr = mlx_init(); // Initialise la connexion à la MLX - win_ptr = mlx_new_window(mlx_ptr, width, height, "cub3d"); - while (x < 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; + ray->cameraX = 2 * x / width - 1; + ray->raydirX = ray->dirX + ray->planeX * ray->cameraX; + ray->raydirY = ray->dirY + ray->planeY * ray->cameraX; - mapX = (int)ray.posX; - mapY = (int)ray.posY; + mapX = (int)ray->posX; + mapY = (int)ray->posY; - ray.deltadistX = (ray.raydirX == 0) ? 1e30 : fabs(1 / ray.raydirX); - ray.deltadistY = (ray.raydirY == 0) ? 1e30 : fabs(1 / ray.raydirY); + 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) + { + ray->stepX = -1; + ray->sidedistX = (ray->posX - mapX) * ray->deltadistX; + } + else + { + ray->stepX = 1; + ray->sidedistX = (mapX + 1.0 - ray->posX) * ray->deltadistX; + } + if (ray->raydirY < 0) + { + ray->stepY = -1; + ray->sidedistY = (ray->posY - mapY) * ray->deltadistY; + } + else + { + ray->stepY = 1; + ray->sidedistY = (mapY + 1.0 - ray->posY) * ray->deltadistY; + } hit = 0; - - //calculate step and initial sideDist - if (ray.raydirX < 0) - { - ray.stepX = -1; - ray.sidedistX = (ray.posX - mapX) * ray.deltadistX; - } - else - { - ray.stepX = 1; - ray.sidedistX = (mapX + 1.0 - ray.posX) * ray.deltadistX; - } - if (ray.raydirY < 0) - { - ray.stepY = -1; - ray.sidedistY = (ray.posY - mapY) * ray.deltadistY; - } - else - { - ray.stepY = 1; - ray.sidedistY = (mapY + 1.0 - ray.posY) * ray.deltadistY; - } while(hit == 0) { //jump to next map square, either in x-direction, or in y-direction - if(ray.sidedistX < ray.sidedistY) + if(ray->sidedistX < ray->sidedistY) { - ray.sidedistX += ray.deltadistX; - mapX += ray.stepX; + ray->sidedistX += ray->deltadistX; + mapX += ray->stepX; side = 0; } else { - ray.sidedistY += ray.deltadistY; - mapY += ray.stepY; + ray->sidedistY += ray->deltadistY; + mapY += ray->stepY; side = 1; } //Check if ray has hit a wall @@ -180,45 +124,97 @@ int main(int /*argc*/, char */*argv*/[]) hit = 1; } if(side == 0) - ray.perpwalldist = (ray.sidedistX - ray.deltadistX); + ray->perpwalldist = (ray->sidedistX - ray->deltadistX); else - ray.perpwalldist = (ray.sidedistY - ray.deltadistY); + ray->perpwalldist = (ray->sidedistY - ray->deltadistY); //Calculate height of line to draw on screen - int lineHeight = (int)(height / ray.perpwalldist); - lineHeight = (int)(height / ray.perpwalldist); + int lineHeight = (int)(height / ray->perpwalldist); //calculate lowest and highest pixel to fill in current stripe - int drawStart; - drawStart = -lineHeight / 2 + height / 2; + int drawStart = -lineHeight / 2 + height / 2; if(drawStart < 0) drawStart = 0; - int drawEnd; - drawEnd = lineHeight / 2 + height / 2; + int drawEnd = lineHeight / 2 + height / 2; if(drawEnd >= height) drawEnd = height - 1; + + // draw vertical line int y = drawStart; while (y <= drawEnd) { - mlx_pixel_put(mlx_ptr, win_ptr, x, y, 0xFF0000); + img_data[y * (int)width + x] = 0xFF0000; y++; } x++; } - //draw the pixels of the stripe as a vertical line - //verLine(x, drawStart, drawEnd, color); */ - - - // put image to window - // destroy old image - - - mlx_hook(win_ptr, 2, 1L<<0, keypress, &ray); - + // 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) + { + ray->posX += ray->dirX * ray->movespeed; + ray->posY += ray->dirY * ray->movespeed; + } + //move backwards if no wall behind you + if (keycode == 115) + { + ray->posX -= ray->dirX * ray->movespeed; + ray->posY -= ray->dirY * ray->movespeed; + } + //rotate to the right + if (keycode == 100) + { + //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); + } + //rotate to the left + if (keycode == 97) + { + //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); + } + // render the updated frame after key press + render(ray); + 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); + + initalgo(&ray); + + // hook keypress + mlx_hook(ray.win_ptr, 2, 1L<<0, keypress, &ray); + // render the initial frame + render(&ray); + + // start the mlx loop + mlx_loop(ray.mlx_ptr); + + return (0); +} diff --git a/algo.h b/algo.h index 47a1836..bae8383 100644 --- a/algo.h +++ b/algo.h @@ -6,7 +6,7 @@ /* By: greg +#+ +:+ +#+ */ /* +#+#+#+#+#+ +#+ */ /* Created: 2024/09/30 15:45:59 by grobledo #+# #+# */ -/* Updated: 2024/10/09 02:51:53 by greg ### ########.fr */ +/* Updated: 2024/10/10 17:53:01 by greg ### ########.fr */ /* */ /* ************************************************************************** */ @@ -17,6 +17,7 @@ #include #include "Minilibx/mlx.h" #include "Minilibx/mlx_int.h" +# include "Libft/libft.h" #define mapWidth 24 #define mapHeight 24 @@ -51,6 +52,10 @@ typedef struct s_ray double rotspeed; double oldDirX; double oldPlaneX; + void *mlx_ptr; + void *win_ptr; + void *img_ptr; + int *img_data; } t_ray; #endif diff --git a/cub3d b/cub3d new file mode 100755 index 0000000000000000000000000000000000000000..e95c3fcd32b6daebfd0908341c01b025f9618055 GIT binary patch literal 39080 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