This commit is contained in:
mcolonna 2024-10-14 18:35:50 +02:00
parent f89c74cd68
commit 8c0d63300d
2 changed files with 227 additions and 165 deletions

338
algo.c
View file

@ -3,32 +3,67 @@
/* ::: :::::::: */
/* algo.c :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: greg <greg@student.42.fr> +#+ +:+ +#+ */
/* By: mc <mc@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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 <math.h>
#include <stdio.h>
#include <X11/X.h>
#include <stdbool.h>
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);
}

54
algo.h
View file

@ -3,10 +3,10 @@
/* ::: :::::::: */
/* algo.h :+: :+: :+: */
/* +:+ +:+ +:+ */
/* By: greg <greg@student.42.fr> +#+ +:+ +#+ */
/* By: mc <mc@student.42.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* 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