Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* ************************************************************************** */
- /* */
- /* ::: :::::::: */
- /* main.c :+: :+: :+: */
- /* +:+ +:+ +:+ */
- /* By: mel-haya <mel-haya@student.42.fr> +#+ +:+ +#+ */
- /* +#+#+#+#+#+ +#+ */
- /* Created: 2019/12/22 16:20:09 by mel-haya #+# #+# */
- /* Updated: 2020/01/21 15:59:35 by mel-haya ### ########.fr */
- /* */
- /* ************************************************************************** */
- #include <math.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include "GNL/get_next_line.h"
- #include "libft/libft.h"
- #include "mlx.h"
- #define TILE_SIZE 400
- #define ESC 53
- #define NO 3
- #define SO 1
- #define EA 2
- #define WE 0
- #define S 5
- #define MOV_SPEED TILE_SIZE / 10
- #define KEY_UP 126
- #define KEY_LEFT 123
- #define KEY_DOWN 125
- #define KEY_RIGHT 124
- #define FOV_ANGLE 60 * (M_PI / 180)
- #define MINI_MAP_RATIO 0.2
- typedef struct s_point
- {
- float x;
- float y;
- } t_point;
- typedef struct s_sprite
- {
- t_point pos;
- float distance;
- } t_sprite;
- typedef struct s_texture
- {
- int *data;
- int height;
- int width;
- } t_texture;
- typedef struct s_ray
- {
- float ray_angle;
- int facing_down;
- int facing_left;
- float distance;
- int hit_horz;
- int hit_vert;
- t_point horz_collision;
- t_point vert_collision;
- t_point closest_collision;
- int inv;
- int inh;
- } t_ray;
- typedef struct s_window
- {
- int width;
- int height;
- void *mlx_ptr;
- void *win_ptr;
- int **map;
- int map_rows;
- int map_cols;
- int floor;
- int ceiling;
- int sprite_index;
- t_sprite sprite[100];
- } t_window;
- typedef struct s_player
- {
- t_point pos;
- int walk_direction;
- float facing_angle;
- int move_speed;
- float rotation_speed;
- int turn_direction;
- void *win_ptr;
- void *mlx_ptr;
- int forward_key;
- int backward_key;
- } t_player;
- void draw_line(t_point p1 ,t_point p2, int color);
- void make_map();
- void draw_form(int x ,int y ,int width,int color);
- void draw_map(void *mlx_ptr, void *win_ptr);
- void render_fov(t_player *p);
- int close_win();
- void render_sprite(t_player *p);
- void *map_img;
- int *data;
- t_texture *texture;
- t_ray *rays;
- t_window window;
- void norm_angle(float *angle)
- {
- *angle = fmod(*angle , 2 * M_PI);
- if(*angle < 0)
- *angle += (M_PI * 2);
- }
- t_point make_point(float x, float y)
- {
- t_point a;
- a.x = x;
- a.y = y;
- return a;
- }
- int rgba_color(char *colors,float alpha)
- {
- char **color;
- color = ft_split(colors,',');
- int output;
- if(alpha > 1)
- alpha = 1;
- output = ft_atoi(color[0]) * alpha;
- output *= 256;
- output += ft_atoi(color[1]) * alpha;
- output *= 256;
- output += ft_atoi(color[2]) * alpha;
- free(color[0]);
- free(color[1]);
- free(color[2]);
- free(color);
- return(output);
- }
- void render_walls(t_player *p)
- {
- int i,y;
- float projection_plane_dist;
- float wall_height;
- float correct_dist;
- int color;
- int offset_x,offset_y;
- int index;
- i = 0;
- projection_plane_dist = (window.width / 2) / tan(FOV_ANGLE / 2);
- while(i < window.width)
- {
- index = 0;
- correct_dist = rays[i].distance * cos(rays[i].ray_angle - p->facing_angle);
- wall_height = (TILE_SIZE / correct_dist) * projection_plane_dist;
- y = 0;
- index = rays[i].inv;
- if(rays[i].hit_vert)
- offset_x = (int)rays[i].closest_collision.y % TILE_SIZE;
- else
- offset_x = (int)rays[i].closest_collision.x % TILE_SIZE;
- while(y < window.height)
- {
- if(y < (window.height - wall_height) / 2)
- color = window.ceiling;
- else if (y > (window.height - wall_height) / 2 && y < (window.height + wall_height) / 2)
- {
- int distanceFromTop = y + (wall_height / 2) - (window.height / 2);
- offset_y = distanceFromTop * ((float)TILE_SIZE / wall_height);
- color = texture[index].data[(texture[index].width * ((int)(offset_y * texture[index].height / TILE_SIZE))) + ((int)(offset_x * texture[index].width / TILE_SIZE))];
- }
- else
- color = window.floor;
- data[(window.width * y) + i] = color;
- y++;
- }
- i++;
- }
- }
- t_point horz_intersection(t_player *p, int column_id)
- {
- float xintercept, yintercept;
- float xstep, ystep;
- t_point output;
- rays[column_id].facing_down = (rays[column_id].ray_angle < M_PI && rays[column_id].ray_angle > 0) ? 1 : 0;
- rays[column_id].facing_left = (rays[column_id].ray_angle > M_PI / 2 && rays[column_id].ray_angle < 1.5 * M_PI) ? 1 : 0;
- yintercept = floor(p->pos.y / TILE_SIZE) * TILE_SIZE;
- yintercept += rays[column_id].facing_down * TILE_SIZE;
- xintercept = p->pos.x + (yintercept - p->pos.y) / tan(rays[column_id].ray_angle);
- ystep = rays[column_id].facing_down ? TILE_SIZE : -TILE_SIZE;
- xstep = TILE_SIZE / tan(rays[column_id].ray_angle);
- xstep *= (rays[column_id].facing_left && xstep > 0) ? -1 : 1;
- xstep *= (!rays[column_id].facing_left && xstep < 0) ? -1 : 1;
- output.x = xintercept;
- output.y = yintercept;
- while(output.x > 0 && output.y > 0 && output.y / TILE_SIZE < window.map_rows && output.x / TILE_SIZE < window.map_cols)
- {
- if(window.map[(int)(output.y - !rays[column_id].facing_down) / TILE_SIZE][(int)output.x / TILE_SIZE] == 1)
- {
- if (sin(rays[column_id].ray_angle) > 0)
- rays[column_id].inh = SO;
- else
- rays[column_id].inh = NO;
- return (output);
- }
- else
- {
- output.x += xstep;
- output.y += ystep;
- }
- }
- return (output);
- }
- t_point vert_intersection(t_player *p, int column_id)
- {
- float xintercept, yintercept;
- float xstep, ystep;
- t_point output;
- xintercept = floor(p->pos.x / TILE_SIZE) * TILE_SIZE;
- xintercept += !rays[column_id].facing_left * TILE_SIZE;
- yintercept = p->pos.y + (xintercept - p->pos.x) * tan(rays[column_id].ray_angle);
- xstep = rays[column_id].facing_left ? -TILE_SIZE : TILE_SIZE;
- ystep = TILE_SIZE * tan(rays[column_id].ray_angle);
- ystep *= (!rays[column_id].facing_down && ystep > 0) ? -1 : 1;
- ystep *= (rays[column_id].facing_down && ystep < 0) ? -1 : 1;
- output.x = xintercept;
- output.y = yintercept;
- while(output.x > 0 && output.y > 0 && output.y / TILE_SIZE < window.map_rows && output.x / TILE_SIZE < window.map_cols)
- {
- if(window.map[(int)output.y / TILE_SIZE][(int)(output.x - rays[column_id].facing_left) / TILE_SIZE] == 1)
- {
- if (cos(rays[column_id].ray_angle) > 0)
- rays[column_id].inv = EA;
- else
- rays[column_id].inv = WE;
- return (output);
- }
- else
- {
- output.x += xstep;
- output.y += ystep;
- }
- }
- return (output);
- }
- int in_canvas(t_point p)
- {
- if(p.x > 0 && p.x < window.width && p.y > 0 && p.y < window.height)
- return 1;
- return 0;
- }
- float dist_two_point(t_point p1, t_point p2)
- {
- return (sqrt( (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y)));
- }
- void cast_rays(t_player *p)
- {
- int column_id = 0;
- float horz_hit,vert_hit;
- float ray_angle = p->facing_angle - (FOV_ANGLE / 2);
- while(column_id < window.width)
- {
- norm_angle(&ray_angle);
- rays[column_id].ray_angle = ray_angle;
- rays[column_id].horz_collision = horz_intersection(p,column_id);
- rays[column_id].vert_collision = vert_intersection(p,column_id);
- horz_hit = dist_two_point(p->pos, rays[column_id].horz_collision);
- vert_hit = dist_two_point(p->pos, rays[column_id].vert_collision);
- if (horz_hit > vert_hit)
- {
- rays[column_id].closest_collision = rays[column_id].vert_collision;
- rays[column_id].hit_vert = 1;
- rays[column_id].hit_horz = 0;
- rays[column_id].distance = vert_hit;
- }
- else
- {
- rays[column_id].closest_collision = rays[column_id].horz_collision;
- rays[column_id].hit_vert = 0;
- rays[column_id].hit_horz = 1;
- rays[column_id].distance = horz_hit;
- rays[column_id].inv = rays[column_id].inh;
- }
- ray_angle += FOV_ANGLE / (window.width);
- column_id++;
- }
- }
- void draw_form(int x ,int y ,int width,int color)
- {
- int i = 0, j;
- while (i <= width)
- {
- j = 0;
- while(j <= width)
- {
- data[(y + i) * window.width + (x + j)] = color;
- j++;
- }
- i++;
- }
- }
- void get_player_pos(t_player *p,int i, int j)
- {
- p->pos.x = j * TILE_SIZE + TILE_SIZE / 2;
- p->pos.y = i * TILE_SIZE + TILE_SIZE / 2;
- if(window.map[i][j] == 'E')
- p->facing_angle = 0;
- else if(window.map[i][j] == 'S')
- p->facing_angle = M_PI / 2;
- else if(window.map[i][j] == 'W')
- p->facing_angle = M_PI;
- else if(window.map[i][j] == 'N')
- p->facing_angle = 3 * M_PI / 2;
- p->turn_direction = 0;
- p->walk_direction = 0;
- p->forward_key = 0;
- p->backward_key = 0;
- }
- void draw_line(t_point p1 ,t_point p2,int color)
- {
- float x,y,dx,dy,step,i = 0;
- dx= p2.x - p1.x;
- dy= p2.y - p1.y;
- if(fabsf(dx)>=fabsf(dy))
- step=fabsf(dx);
- else
- step=fabsf(dy);
- dx=dx/step;
- dy=dy/step;
- x = p1.x;
- y = p1.y;
- while(i <= step)
- {
- if(x > 0 && y > 0 && x < window.width && y < window.height)
- data[(int)y * window.width + (int)x] = color;
- x+=dx;
- y+=dy;
- i++;
- }
- }
- void move_player(t_player *p)
- {
- float x,y,newx,newy;
- x = p->pos.x;
- y = p->pos.y;
- if(p->walk_direction)
- {
- newx = x + cos(p->facing_angle) * (float)(MOV_SPEED * p->walk_direction);
- newy = y + sin(p->facing_angle) * (float)(MOV_SPEED * p->walk_direction);
- if(window.map[(int)y /TILE_SIZE][(int)newx / TILE_SIZE] != 1)
- p->pos.x = newx;
- if(window.map[(int)newy /TILE_SIZE][(int)x / TILE_SIZE] != 1)
- p->pos.y = newy;
- }
- if(p->turn_direction)
- p->facing_angle += p->rotation_speed * - p->turn_direction;
- norm_angle(&p->facing_angle);
- }
- int get_key(int key, t_player *p)
- {
- cast_rays(p);
- render_walls(p);
- make_map();
- render_fov(p);
- render_sprite(p);
- mlx_put_image_to_window(window.mlx_ptr,window.win_ptr, map_img, 0,0);
- if(key == ESC)
- close_win();
- if(key == KEY_UP)
- p->forward_key = 1;
- else if(key == KEY_DOWN)
- p->backward_key = 1;
- p->walk_direction = p->forward_key - p->backward_key;
- if(key == KEY_LEFT)
- p->turn_direction = 1;
- else if(key == KEY_RIGHT)
- p->turn_direction = -1;
- return(1);
- }
- int key_up(int key, t_player *p)
- {
- if(key==KEY_UP)
- {
- p->forward_key = 0;
- if(p->backward_key)
- p->walk_direction = -1;
- else
- p->walk_direction = 0;
- }
- else if(key == KEY_DOWN)
- {
- p->backward_key = 0;
- if(p->forward_key)
- p->walk_direction = 1;
- else
- p->walk_direction = 0;
- }
- if(key == KEY_LEFT)
- p->turn_direction = 0;
- else if(key == KEY_RIGHT)
- p->turn_direction = 0;
- return (1);
- }
- int ft_word_count(char const *str, char c)
- {
- int i;
- int output;
- i = 0;
- output = 0;
- while (str[i])
- {
- if (str[i] != c && (i == 0 || str[i - 1] == c))
- output++;
- i++;
- }
- return (output);
- }
- void make_map()
- {
- int x;
- int y;
- int i;
- int j;
- float ratio;
- i = 0;
- x = 0;
- y = 0;
- ratio = (float)window.width / window.map_cols * MINI_MAP_RATIO;
- while(i < window.map_rows)
- {
- j = 0;
- while(j < window.map_cols)
- {
- if(window.map[i][j] == 1)
- draw_form(j * ratio,i * ratio , ratio, 0xffff00);
- else
- draw_form(j * ratio,i * ratio , ratio, 0);
- j++;
- }
- i++;
- }
- }
- void render_fov(t_player *p)
- {
- int i = 0;
- float ratio = (float)window.width / window.map_cols * MINI_MAP_RATIO/TILE_SIZE;
- t_point player;
- t_point ray;
- player.x = p->pos.x * ratio;
- player.y = p->pos.y * ratio;
- while(i < window.width)
- {
- //printf("%f\n", ratio);
- ray.x = floor(rays[i].closest_collision.x * ratio);
- ray.y = floor(rays[i].closest_collision.y * ratio);
- draw_line(player,ray,0x0f550f);
- i+=5;
- }
- }
- void draw_sprite(int x,float distance,float height)
- {
- int i = x;
- int j;
- while (i <= x + height)
- {
- j = (window.height / 2) - (height / 2);
- if(distance < rays[i].distance && i >= 0 && i < window.width)
- {
- while(j <= (window.height / 2) + (height / 2))
- {
- if(j < window.height && j >= 0)
- data[(j) * window.width + (i)] = 0xff;
- j++;
- }
- }
- i++;
- }
- }
- void render_sprite(t_player *p)
- {
- //float ratio = (float)window.width / window.map_cols * MINI_MAP_RATIO/TILE_SIZE;
- float angle;
- float sprite_height;
- int column_index;
- float projection_plane_dist = (window.width / 2) / tan(FOV_ANGLE / 2);
- //float max_index = (2 * M_PI / (FOV_ANGLE)) * window.width;
- t_sprite *s = window.sprite;
- int i = 0;
- while(i < window.sprite_index)
- {
- angle = atan2(s[i].pos.y - p->pos.y, s[i].pos.x - p->pos.x);
- s[i].distance = dist_two_point(s[i].pos,p->pos);
- //angle = angle - rays[window.width].ray_angle;
- norm_angle(&angle);
- if (rays[0].ray_angle > rays[window.width].ray_angle && angle < rays[window.width].ray_angle)
- angle += 2 * M_PI;
- column_index = (angle - rays[0].ray_angle) / (FOV_ANGLE / window.width);
- // if(rays[0].ray_angle < angle)
- // angle -= 2 * M_PI;
- //printf("%.2f | %7.2f |%.2f\n",rays[0].ray_angle * 180 / M_PI, angle * 180 / M_PI, rays[window.width - 1].ray_angle * 180 / M_PI);
- sprite_height = (TILE_SIZE / s[i].distance) * projection_plane_dist;
- //column_index = angle * window.width / FOV_ANGLE + ((window.width / 2 )- (sprite_height / 2));
- //column_index = (angle - p->facing_angle) / FOV_ANGLE * window.width + (window.width / 2 - sprite_height / 2);
- draw_sprite(column_index - (sprite_height / 2) , s[i].distance, sprite_height);
- i++;
- }
- }
- int loop_hook(t_player *p)
- {
- cast_rays(p);
- render_walls(p);
- make_map();
- render_fov(p);
- render_sprite(p);
- mlx_put_image_to_window(window.mlx_ptr,window.win_ptr, map_img, 0,0);
- move_player(p);
- return 0;
- }
- void load_textures(char *filename,int side)
- {
- int width,height,c;
- void *img;
- img = mlx_xpm_file_to_image(window.mlx_ptr,filename,&width,&height);
- texture[side].width = width;
- texture[side].height = height;
- texture[side].data = (int *)mlx_get_data_addr(img,&c,&c,&c);
- free(img);
- return;
- }
- int ft_checkset(char c, char const *set)
- {
- int i;
- i = 0;
- while (set[i])
- {
- if (c == set[i])
- return (1);
- i++;
- }
- return (0);
- }
- char *filter(char *str, char const *set)
- {
- int count;
- int i;
- int j;
- char *output;
- count = 0;
- output = NULL;
- j = 0;
- i = 0;
- while(str[i])
- {
- if(!ft_checkset(str[i], set))
- count++;
- i++;
- }
- if(count)
- {
- output = malloc(count + 1);
- output[count] = 0;
- i = 0;
- while(str[i])
- {
- if(!ft_checkset(str[i], set))
- {
- output[j] = str[i];
- j++;
- }
- i++;
- }
- }
- return output;
- }
- int check_row(char *line)
- {
- char *copy;
- int output;
- output = 0;
- copy = filter(line,"012NSWE");
- if(copy)
- {
- output = ft_strlen(copy);
- free(copy);
- }
- return (output);
- }
- void free_array(char ***array)
- {
- int i;
- i = 0;
- while(i < window.map_rows)
- {
- free(*array[i]);
- }
- free(*array);
- }
- char *check_map(char *line,t_player *p)
- {
- char *tmp;
- char **array;
- int i;
- int j;
- int player;
- char *error;
- error = NULL;
- i = 0;
- player = 0;
- window.map = malloc(window.map_rows * sizeof(int *));
- array = ft_split(line, '\n');
- while(array[i])
- {
- tmp = array[i];
- array[i] = filter(array[i], " ");
- //printf("%s", array[i]);
- free(tmp);
- if((int)ft_strlen(array[i]) != window.map_cols)
- error = ft_strjoin("number of columns invalid at row",ft_itoa(i + 1));
- else if(array[i][window.map_cols - 1] != '1' && error)
- error = ft_strjoin("the map is not closed at row",ft_itoa(i + 1));
- else if(check_row(array[i])&& error)
- error = ft_strjoin("invalid character in the row ", ft_itoa(i + 1));
- j = 0;
- window.map[i] = malloc(window.map_cols * sizeof(int *));
- while(j < window.map_cols)
- {
- window.map[i][j] = ft_isdigit(array[i][j]) ? array[i][j] - 48 : array[i][j];
- if(ft_isalpha(array[i][j]))
- {
- get_player_pos(p,i,j);
- player++;
- }
- else if(array[i][j] == '2' && window.sprite_index < 100)
- {
- window.sprite[window.sprite_index].pos.x = (j * TILE_SIZE) + (float)(TILE_SIZE / 2);
- window.sprite[window.sprite_index].pos.y = (i * TILE_SIZE) + (float)(TILE_SIZE / 2);
- window.sprite_index++;
- }
- j++;
- }
- i++;
- }
- if(player != 1)
- error = ft_strjoin(ft_itoa(player)," player object detected");
- //free_array(&array);
- return (error);
- }
- int load_map(char **line,int fd,t_player *p)
- {
- char *buffer;
- char *tmp;
- char *error;
- window.map_cols = ft_word_count(*line,' ');
- buffer = malloc(window.map_cols * sizeof(char *));
- window.map_rows = 0;
- while(*line[0] == '1')
- {
- tmp = buffer;
- buffer = ft_strjoin(buffer, *line);
- free(tmp);
- tmp = buffer;
- buffer = ft_strjoin(buffer,"\n");
- free(tmp);
- free(*line);
- get_next_line(fd, line);
- window.map_rows++;
- }
- error = check_map(buffer,p);
- if(error)
- {
- printf("error:\n");
- printf("%s\n",error);
- free(error);
- return (1);
- }
- return (0);
- }
- int load_cub_file(char *filename,t_player *p)
- {
- char *line;
- int fd;
- char **words;
- int error;
- int a;
- error = 0;
- fd = open(filename, O_RDONLY);
- while(get_next_line(fd, &line))
- {
- words = ft_split(line, ' ');
- if(!words[0])
- continue;
- if(!ft_strncmp(words[0], "R", 1))
- {
- window.width = ft_atoi(words[1]);
- window.height = ft_atoi(words[2]);
- window.win_ptr = mlx_new_window(window.mlx_ptr,window.width,window.height,"Bruh");
- map_img = mlx_new_image(window.mlx_ptr, window.width,window.height);
- data = (int*)mlx_get_data_addr(map_img, &a,&a,&a);
- }
- else if(!ft_strncmp(words[0], "NO", 2))
- load_textures(words[1], NO);
- else if(!ft_strncmp(words[0], "SO", 2))
- load_textures(words[1], SO);
- else if(!ft_strncmp(words[0], "EA", 2))
- load_textures(words[1], EA);
- else if(!ft_strncmp(words[0], "WE", 2))
- load_textures(words[1], WE);
- else if(!ft_strncmp(words[0], "S", 2))
- load_textures(words[1], S);
- else if(!ft_strncmp(words[0], "F", 1))
- window.floor = rgba_color(words[1],1);
- else if(!ft_strncmp(words[0], "C", 1))
- window.ceiling = rgba_color(words[1],1);
- else if(words[0][0] == '1')
- load_map(&line,fd,p);
- free(words);
- }
- return (0);
- }
- int close_win()
- {
- exit(0);
- }
- int main()
- {
- t_player p;
- void *mlx_ptr = mlx_init();
- texture = malloc(sizeof(t_texture) * 8);
- window.mlx_ptr = mlx_ptr;
- load_cub_file("test.cub",&p);
- rays = malloc(sizeof(t_ray) * window.width);
- make_map();
- p.rotation_speed = 4 * (M_PI / 180);
- mlx_hook(window.win_ptr, 2, 0, get_key, &p);
- mlx_hook(window.win_ptr, 3, 0, key_up, &p);
- mlx_hook(window.win_ptr,17,0,close_win,NULL);
- mlx_loop_hook(mlx_ptr,loop_hook,&p);
- mlx_loop(mlx_ptr);
- return(0);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement