diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/capture.c | 25 | ||||
| -rw-r--r-- | src/error.c | 48 | ||||
| -rw-r--r-- | src/event.c | 45 | ||||
| -rw-r--r-- | src/helper.c | 60 | ||||
| -rw-r--r-- | src/main.c | 77 | ||||
| -rw-r--r-- | src/parse/parse.c | 142 | ||||
| -rw-r--r-- | src/parse/parse_check.c | 46 | ||||
| -rw-r--r-- | src/parse/parse_color.c | 55 | ||||
| -rw-r--r-- | src/parse/parse_resolution.c | 24 | ||||
| -rw-r--r-- | src/parse/parse_textures.c | 48 | ||||
| -rw-r--r-- | src/render.c | 107 | ||||
| -rw-r--r-- | src/render_state.c | 205 | ||||
| -rw-r--r-- | src/state.c | 128 | ||||
| -rw-r--r-- | src/vector.c | 62 |
14 files changed, 1072 insertions, 0 deletions
diff --git a/src/capture.c b/src/capture.c new file mode 100644 index 0000000..521774a --- /dev/null +++ b/src/capture.c @@ -0,0 +1,25 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* capture.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 13:15:11 by cacharle #+# #+# */ +/* Updated: 2020/01/16 07:49:17 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +int capture(t_state *state) +{ + printf("capture\n"); + /* render_update_window(state); */ + /* write_bmp(&state->window); */ + return (0); +} + +void write_bmp(t_image *image) +{ +} diff --git a/src/error.c b/src/error.c new file mode 100644 index 0000000..eb94c9f --- /dev/null +++ b/src/error.c @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* error.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 13:33:14 by cacharle #+# #+# */ +/* Updated: 2020/01/11 13:34:18 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +void error_put_usage_exit(char *name) +{ + ft_putstr_fd(name, STDERR_FILENO); + ft_putendl_fd(": missing file operand", STDERR_FILENO); + ft_putstr_fd("Usage: ", STDERR_FILENO); + ft_putstr_fd(name, STDERR_FILENO); + ft_putendl_fd(" [.cub file] [--save]", STDERR_FILENO); + exit(EXIT_FAILURE); +} + +void error_put(char *message) +{ + ft_putstr("Error\nCouldnt "); + ft_putendl(message); +} + +void *error_put_return(char *message) +{ + error_put(message); + return (NULL); +} + +void *error_put_return_state_destroy(char *message, t_state *state) +{ + state_destroy(state); + return (error_put_return(message)); +} + +void *error_put_return_lines_state_destroy( + char *message, t_state *state, char **lines) +{ + helper_free_splited(lines); + return (error_put_return_state_destroy(message, state)); +} diff --git a/src/event.c b/src/event.c new file mode 100644 index 0000000..9dcaa75 --- /dev/null +++ b/src/event.c @@ -0,0 +1,45 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* event.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/15 06:39:37 by cacharle #+# #+# */ +/* Updated: 2020/01/30 15:20:18 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +#define ROTATE_STEP (M_PI / 40.0) +#define MOVE_SPEED 0.25 + +int event_keydown(int key, t_state *state) +{ + if (key == MLXK_ESC) + state->running = FALSE; + else if (key == MLXK_A) + state->pos = vector_add(state->pos, + vector_scale(vector_rotate(state->dir, -M_PI_2), MOVE_SPEED)); + else if (key == MLXK_D) + state->pos = vector_add(state->pos, + vector_scale(vector_rotate(state->dir, M_PI_2), MOVE_SPEED)); + else if (key == MLXK_W) + state->pos = vector_add(state->pos, + vector_scale(state->dir, MOVE_SPEED)); + else if (key == MLXK_S) + state->pos = vector_add(state->pos, + vector_scale(state->dir, -MOVE_SPEED)); + else if (key == MLXK_LEFT) + helper_rotate_player(state, -ROTATE_STEP); + else if (key == MLXK_RIGHT) + helper_rotate_player(state, ROTATE_STEP); + return (0); +} + +int event_quit(t_state *state) +{ + state->running = FALSE; + return (0); +} diff --git a/src/helper.c b/src/helper.c new file mode 100644 index 0000000..9940848 --- /dev/null +++ b/src/helper.c @@ -0,0 +1,60 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* helper.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 07:32:20 by cacharle #+# #+# */ +/* Updated: 2020/01/16 08:57:01 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_bool helper_is_player_cell(t_cell cell) +{ + return (cell == CELL_LOOK_NORTH || cell == CELL_LOOK_SOUTH || + cell == CELL_LOOK_WEST || cell == CELL_LOOK_EAST); +} + +void helper_free_splited(char **splited) +{ + int i; + + if (splited == NULL) + return ; + i = -1; + while (splited[++i] != NULL) + free(splited[i]); + free(splited); +} + +void helper_rotate_player(t_state *state, double rotation) +{ + state->dir = vector_rotate(state->dir, rotation); + state->plane = vector_rotate(state->plane, rotation); +} + +/* +** Initial player direction vector +** Since the map [0 0] is in the top left corner the north/south direction are slipped. +** The camera plane has to stay perpendicular to the direction and +** create a camera with a 66 degree angle (which is a recommended angle for fps) +*/ + +void helper_init_dir_plane(t_state *state, int y, int x) +{ + if (state->map[y][x] == CELL_LOOK_NORTH) + state->dir.y = -1.0; + else if (state->map[y][x] == CELL_LOOK_SOUTH) + state->dir.y = 1.0; + else if (state->map[y][x] == CELL_LOOK_WEST) + state->dir.x = -1.0; + else if (state->map[y][x] == CELL_LOOK_EAST) + state->dir.x = 1.0; + state->plane = vector_rotate(state->dir, M_PI_2); + state->plane = vector_scale(state->plane, 1.0 / vector_norm(state->plane)); + state->plane = vector_scale(state->plane, 0.66); + state->plane = vector_apply(state->plane, &fabs); +} diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..00a041d --- /dev/null +++ b/src/main.c @@ -0,0 +1,77 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* main.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/15 06:39:39 by cacharle #+# #+# */ +/* Updated: 2020/01/30 14:02:58 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +int main(int argc, char **argv) +{ + t_state *state; + + if (argc != 2 && !(argc == 3 && ft_strcmp(argv[2], "--save") == 0)) + error_put_usage_exit(argv[0]); + if ((state = state_new(parse_check(parse(argv[1])))) == NULL) + return (1); + if (argc == 3) + return (capture(state)); + /* printf("%d\n", state->window.size_line); */ + mlx_hook(state->window_ptr, 2, (1L << 1), event_keydown, (void*)state); + mlx_hook(state->window_ptr, 17L, 0, event_quit, (void*)state); + mlx_loop_hook(state->mlx_ptr, render_update, (void*)state); + mlx_loop(state->mlx_ptr); + /* while (1) */ + /* render_update(state); */ + return (0); +} + +/* +int main(int argc, char **argv) +{ + (void)argc; + t_state *s = parse_check(parse(argv[1])); + if (s == NULL) + return (1); + printf("R %d %d\n", s->window.width, s->window.height); + printf("NO %s\n", s->textures_path[TEX_NORTH]); + printf("SO %s\n", s->textures_path[TEX_SOUTH]); + printf("WE %s\n", s->textures_path[TEX_WEST]); + printf("EA %s\n\n", s->textures_path[TEX_EAST]); + printf("S %s\n", s->textures_path[TEX_SPRITE]); + printf("F %d,%d,%d\n", s->floor_color.rgb.r, s->floor_color.rgb.g, s->floor_color.rgb.b); + printf("C %d,%d,%d\n\n", s->ceilling_color.rgb.r, s->ceilling_color.rgb.g, s->ceilling_color.rgb.b); + + printf("%dx%d\n", s->map_height, s->map_width); + for (int i = 0; i < s->map_height; i++) + { + for (int j = 0; j < s->map_width; j++) + { + if (s->map[i][j] == CELL_WALL) + printf("#"); + else if (s->map[i][j] == CELL_EMPTY) + printf(" "); + else + printf("%d", s->map[i][j]); + if (j != s->map_width - 1) + printf(" "); + } + printf("\n"); + } + printf("post state_new\n"); + if ((s = state_new(s)) == NULL) + { + printf("Error: state new"); + return 1; + } + printf("state->pos [%f %f]\n", s->pos.x, s->pos.y); + state_destroy(s); + return 0; +} +*/ diff --git a/src/parse/parse.c b/src/parse/parse.c new file mode 100644 index 0000000..f4b5b66 --- /dev/null +++ b/src/parse/parse.c @@ -0,0 +1,142 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parse.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/15 09:29:21 by cacharle #+# #+# */ +/* Updated: 2020/01/30 12:03:54 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_state *parse(char *filename) +{ + int i; + char **lines; + t_state *state; + + if ((state = state_new_empty()) == NULL) + return (error_put_return("create empty state")); + if ((lines = get_file_lines(filename)) == NULL) + return (error_put_return_state_destroy("read .cub file", state)); + i = -1; + while (lines[++i] != NULL) + { + if (*lines[i] == '1') + break ; + if (!parse_line(state, lines[i])) + return (error_put_return_lines_state_destroy( + "parse configuration", state, lines)); + } + if ((state = parse_map(state, lines + i)) == NULL) + return (error_put_return_lines_state_destroy( + "parse map", state, lines)); + helper_free_splited(lines); + return (state); +} + +char **get_file_lines(char *filename) +{ + int fd; + int ret; + char buf[CUB3D_BUFFER_SIZE + 1]; + char *file; + + if ((fd = open(filename, O_RDONLY)) < 0) + return (NULL); + if ((file = ft_strdup("")) == NULL) + return (NULL); + while ((ret = read(fd, buf, CUB3D_BUFFER_SIZE)) > 0) + { + buf[ret] = '\0'; + if ((file = ft_strjoin(file, buf)) == NULL) + return (NULL); + } + if (ret == -1) + return (NULL); + close(fd); + return (ft_split(file, '\n')); +} + +static t_option_parser g_option_parsers[] = +{ + {"R", parse_resolution}, + {"NO", parse_north_texture}, + {"SO", parse_south_texture}, + {"WE", parse_west_texture}, + {"EA", parse_east_texture}, + {"S", parse_sprite_texture}, + {"F", parse_floor_color}, + {"C", parse_ceilling_color} +}; + +#define OPTIONS_PARSERS_SIZE (sizeof(g_option_parsers) / sizeof(t_option_parser)) + +t_bool parse_line(t_state *state, char *line) +{ + int i; + + if (!*line) + return (TRUE); + i = -1; + while (++i < (int)OPTIONS_PARSERS_SIZE) + if (ft_strncmp(g_option_parsers[i].id, line, + ft_strlen(g_option_parsers[i].id)) == 0) + return (g_option_parsers[i].func( + state, line + ft_strlen(g_option_parsers[i].id) + 1)); + return (FALSE); +} + +t_state *parse_map(t_state *state, char **lines) +{ + int i; + + i = -1; + while (lines[++i] != NULL) + if (*lines[i] != '1') + return (NULL); + state->map_height = i; + if ((state->map = (t_map)malloc(sizeof(t_cell*) * i)) == NULL) + return (NULL); + state->map_width = ft_strcount(*lines, '1'); + i = -1; + while (lines[++i] != NULL) + if ((state->map[i] = create_map_row(lines[i])) == NULL) + return (NULL); + return (state); +} + +t_cell *create_map_row(char *line) +{ + int i; + t_cell *row; + + if ((row = (t_cell*)malloc(sizeof(t_cell) * ft_strlen(line))) == NULL) + return (NULL); + i = 0; + while (*line) + { + if (*line == '0' || *line == '1' || *line == '2') + row[i++] = *line - '0'; + else if (*line == 'N') + row[i++] = CELL_LOOK_NORTH; + else if (*line == 'S') + row[i++] = CELL_LOOK_SOUTH; + else if (*line == 'W') + row[i++] = CELL_LOOK_WEST; + else if (*line == 'E') + row[i++] = CELL_LOOK_EAST; + else + { + free(row); + return (NULL); + } + line++; + while (*line == ' ') + line++; + } + return (row); +} diff --git a/src/parse/parse_check.c b/src/parse/parse_check.c new file mode 100644 index 0000000..a65d74a --- /dev/null +++ b/src/parse/parse_check.c @@ -0,0 +1,46 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* check.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 10:59:15 by cacharle #+# #+# */ +/* Updated: 2020/01/11 13:03:33 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_state *parse_check(t_state *state) +{ + int i; + /* int j; */ + /* int player_count; */ + + i = -1; + while (++i < state->map_width) + if (state->map[0][i] != CELL_WALL + || state->map[state->map_height - 1][i] != CELL_WALL) + return (error_put_return_state_destroy( + "validate map without borders", state)); + i = -1; + while (++i < state->map_height) + if (state->map[i][0] != CELL_WALL + || state->map[i][state->map_width - 1] != CELL_WALL) + return (error_put_return_state_destroy( + "validate map without borders", state)); + // maybe not necessary + /* player_count = 0; */ + /* i = -1; */ + /* while (++i < state->map_height) */ + /* { */ + /* j = -1; */ + /* while (++j < state->map_width) */ + /* if (helper_is_player_cell(state->map[i][j])) */ + /* player_count++; */ + /* } */ + /* if (player_count != 1) */ + /* return (state_destroy(state)); */ + return (state); +} diff --git a/src/parse/parse_color.c b/src/parse/parse_color.c new file mode 100644 index 0000000..fd482e5 --- /dev/null +++ b/src/parse/parse_color.c @@ -0,0 +1,55 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parse_color.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 09:52:34 by cacharle #+# #+# */ +/* Updated: 2020/01/30 14:17:37 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_bool parse_ceilling_color(t_state *state, char *line) +{ + int tmp; + + state->ceilling_color.hexcode = 0x0; + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) // cant do atoi due to overflow stuff, use ft_strtol + return (FALSE); + state->ceilling_color.rgb.r = (t_byte)tmp; + if ((line = ft_strchr(line, ',') + 1) == NULL) + return (FALSE); + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) + return (FALSE); + state->ceilling_color.rgb.g = (t_byte)tmp; + if ((line = ft_strchr(line, ',') + 1) == NULL) + return (FALSE); + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) + return (FALSE); + state->ceilling_color.rgb.b = (t_byte)tmp; + return (TRUE); +} + +t_bool parse_floor_color(t_state *state, char *line) +{ + int tmp; + + state->floor_color.hexcode = 0x0; + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) + return (FALSE); + state->floor_color.rgb.r = (t_byte)tmp; + if ((line = ft_strchr(line, ',') + 1) == NULL) + return (FALSE); + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) + return (FALSE); + state->floor_color.rgb.g = (t_byte)tmp; + if ((line = ft_strchr(line, ',') + 1) == NULL) + return (FALSE); + if ((tmp = ft_atoi(line)) > 255 || tmp < 0) + return (FALSE); + state->floor_color.rgb.b = (t_byte)tmp; + return (TRUE); +} diff --git a/src/parse/parse_resolution.c b/src/parse/parse_resolution.c new file mode 100644 index 0000000..d6c5759 --- /dev/null +++ b/src/parse/parse_resolution.c @@ -0,0 +1,24 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parse_resolution.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/15 09:29:27 by cacharle #+# #+# */ +/* Updated: 2020/01/11 09:44:18 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_bool parse_resolution(t_state *state, char *line) +{ + if ((state->window.width = ft_atoi(line)) < 0) + return (FALSE); + if ((line = ft_strrchr(line, ' ') + 1) == NULL) + return (FALSE); + if ((state->window.height = ft_atoi(line)) < 0) + return (FALSE); + return (TRUE); +} diff --git a/src/parse/parse_textures.c b/src/parse/parse_textures.c new file mode 100644 index 0000000..a0fb8f6 --- /dev/null +++ b/src/parse/parse_textures.c @@ -0,0 +1,48 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* parse_textures.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 09:47:53 by cacharle #+# #+# */ +/* Updated: 2020/01/11 09:51:03 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_bool parse_north_texture(t_state *state, char *line) +{ + if ((state->textures_path[TEX_NORTH] = ft_strdup(line)) == NULL) + return (FALSE); + return (TRUE); +} + +t_bool parse_south_texture(t_state *state, char *line) +{ + if ((state->textures_path[TEX_SOUTH] = ft_strdup(line)) == NULL) + return (FALSE); + return (TRUE); +} + +t_bool parse_west_texture(t_state *state, char *line) +{ + if ((state->textures_path[TEX_WEST] = ft_strdup(line)) == NULL) + return (FALSE); + return (TRUE); +} + +t_bool parse_east_texture(t_state *state, char *line) +{ + if ((state->textures_path[TEX_EAST] = ft_strdup(line)) == NULL) + return (FALSE); + return (TRUE); +} + +t_bool parse_sprite_texture(t_state *state, char *line) +{ + if ((state->textures_path[TEX_SPRITE] = ft_strdup(line)) == NULL) + return (FALSE); + return (TRUE); +} diff --git a/src/render.c b/src/render.c new file mode 100644 index 0000000..88b0cae --- /dev/null +++ b/src/render.c @@ -0,0 +1,107 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* render.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/11 13:37:17 by cacharle #+# #+# */ +/* Updated: 2020/01/30 15:17:49 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +int render_update(void *param) +{ + t_state *state; + + state = param; + if (!state->running) + { + state_destroy(state); + exit(EXIT_SUCCESS); + return (0); + } + render_update_window(state); + mlx_put_image_to_window(state->mlx_ptr, state->window_ptr, state->window.id, 0, 0); + return (0); +} + +void render_update_window(t_state *state) +{ + int x; + + x = -1; + while (++x < state->window.width) + render_column(state, x); +} + +void render_column(t_state *state, int x) +{ + t_render_state rstate; + + rstate.x = x; + rstate_ray(state, &rstate); + rstate.map_pos = vector_new((double)((int)state->pos.x), (double)((int)state->pos.y)); //floor? + rstate_delta(&rstate); + rstate_init_probe(state, &rstate); + rstate.map_step = vector_new(rstate.ray.x < 0.0 ? -1.0 : 1.0, rstate.ray.y < 0.0 ? -1.0 : 1.0); + while (TRUE) + { + rstate.side = rstate.probe.x < rstate.probe.y ? SIDE_WE : SIDE_NS; + rstate_next_probe(&rstate); + if (state->map[(int)rstate.map_pos.y][(int)rstate.map_pos.x] == CELL_WALL) + break ; + } + rstate_perp_dist(state, &rstate); + rstate_line_height(state, &rstate); + rstate.draw_start = state->window.height / 2 - rstate.line_height / 2; + rstate.draw_end = state->window.height / 2 + rstate.line_height / 2; + if (rstate.draw_start < 0) + rstate.draw_start = 0; + if (rstate.draw_end > state->window.height - 1) + rstate.draw_end = state->window.height - 1; + render_window_column(state, &rstate); +} + +void render_window_column(t_state *state, t_render_state *rstate) +{ + int i; + t_color white; + + white.hexcode = 0x00ffffff; + i = 0; + while (i < rstate->draw_start) + ((t_color*)state->window.data)[i++ * state->window.width + rstate->x] = state->ceilling_color; + while (i < rstate->draw_end) + ((t_color*)state->window.data)[i++ * state->window.width + rstate->x] = white; + render_texture(state, rstate); + i = rstate->draw_end; + while (i < state->window.height) + ((t_color*)state->window.data)[i++ * state->window.width + rstate->x] = state->floor_color; + +} + +void render_texture(t_state *state, t_render_state *rstate) +{ + int i; + double step; + double tex_pos; + int tex_y; + int tex_x; + t_image *texture; + + texture = get_tex(state, rstate); + tex_x = get_tex_x(state, rstate, texture); + step = 1.0 * texture->height / rstate->line_height; + tex_pos = (rstate->draw_start - state->window.height / 2 + rstate->line_height / 2) * step; + i = rstate->draw_start - 1; + while (++i < rstate->draw_end) + { + tex_y = (int)tex_pos & (texture->height - 1); + tex_pos += step; + ((t_color*)state->window.data)[i * state->window.width + rstate->x] = + ((t_color*)texture->data)[texture->height * tex_y + tex_x]; + } +} diff --git a/src/render_state.c b/src/render_state.c new file mode 100644 index 0000000..46fc7c5 --- /dev/null +++ b/src/render_state.c @@ -0,0 +1,205 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* render_state.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2020/01/15 14:40:14 by cacharle #+# #+# */ +/* Updated: 2020/01/30 15:50:48 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +/* +** -1 0 1 <-- camera_x +** v v v +** ################ +** # | # <-- screen +** # | # +** ################ +** +** camera_x is the x column from the camera percpective +** scaling the plane vector and adding it to the direction vector +** to create a vector in the *direction* of the column x. +*/ + +void rstate_ray(t_state *state, t_render_state *rstate) +{ + double camera_x; + + camera_x = 2.0 * (double)rstate->x / (double)state->window.width - 1.0; + rstate->ray = vector_add(state->dir, vector_scale(state->plane, camera_x)); +} + +/* +** delta between each grid unit form the vector percpective +** +** if we have a vector v = [2 3]: +** dx = |v| / v_1 +** = sqrt(v_1^2 + v_2^2) / v_1 +** = (v_1^2 + v_2^2) / v_1^2 +** = 1 + v_2^2 / v_1^2 +** Same thing for dy +** dy = |v| / v_2 +** = sqrt(v_1^2 + v_2^2) / v_1 +** = (v_1^2 + v_2^2) / v_2^2 +** = v_1^2 / v_2^2 + 1 +** +** This can be simplified (for some obscure reason): +** dx = |1 / v_1| +** dy = |1 / v_2| +*/ + +void rstate_delta(t_render_state *rstate) +{ + rstate->delta.x = fabs(1 / rstate->ray.x); //vector_norm(rstate->ray) / rstate->ray.x; + rstate->delta.y = fabs(1 / rstate->ray.y); // vector_norm(rstate->ray) / rstate->ray.y; +} + +/* +** first delta between player position and first grid unit +** +** current x and y are the perpendicular distance to the nearest wall, +** we multiply them by their corresponding delta. +** 0 <= perpendicular distance <= 1 is a ratio, how much of the full delta we need to take. +** +** if (rstate->ray.x < 0) +** rstate->probe.x = state->pos.x - rstate->map_pos.x; +** else +** rstate->probe.x = fabs(state->pos.x - rstate->map_pos.x + 1.0); +** if (rstate->ray.y < 0) +** rstate->probe.y = state->pos.y - rstate->map_pos.y; +** else +** rstate->probe.y = fabs(state->pos.y - rstate->map_pos.y + 1.0); +** rstate->probe.x *= rstate->delta.x; +** rstate->probe.y *= rstate->delta.y; +*/ + +void rstate_init_probe(t_state *state, t_render_state *rstate) +{ + if (rstate->ray.x < 0) + rstate->probe.x = (state->pos.x - rstate->map_pos.x) * rstate->delta.x; + else + rstate->probe.x = (rstate->map_pos.x + 1.0 - state->pos.x) * rstate->delta.x; + if (rstate->ray.y < 0) + rstate->probe.y = (state->pos.y - rstate->map_pos.y) * rstate->delta.y; + else + rstate->probe.y = (rstate->map_pos.y + 1.0 - state->pos.y) * rstate->delta.y; + /* rstate->probe = VECTOR_SUB(state->pos, rstate->map_pos); */ + /* if (rstate->ray.x > 0) */ + /* rstate->probe.x += 1.0; */ + /* if (rstate->ray.y > 0) */ + /* rstate->probe.y += 1.0; */ + /* rstate->probe.x *= rstate->delta.x; */ + /* rstate->probe.y *= rstate->delta.y; */ +} + +/* +** Move the probe to it's next iteration by advancing to the nearest square unit +** in the x or y direction. +** This advance is represented both with the +** player/ray percpective and the map pecpective. +*/ + +void rstate_next_probe(t_render_state *rstate) +{ + if (rstate->probe.x < rstate->probe.y) + { + rstate->probe.x += rstate->delta.x; + rstate->map_pos.x += rstate->map_step.x; + } + else + { + rstate->probe.y += rstate->delta.y; + rstate->map_pos.y += rstate->map_step.y; + } +} + +/* +** perpendicular distance between the wall hit and the camera plane. +** We don't use euclidean distance because it would cause a fisheye effect. +** +** ====================X========== wall +** | /| +** | <------ / | -----+ +** | / | | +** plane | / | <- perpendicular distance +** | | / | +** v | / | +** <-------^----/----------------- camera plane +** | / +** dir -> | / +** | / <- euclidean distance +** |/ +** x <- pos +** +** In this case the perpendicular distance (p) is the difference +** of the y-coord of the hit point and the y-coord of the pos + dir vector. +** We use the y component because we hit the wall +** from a south/north percepective, +** if we had hit it form west/east, we would use the x component instead. +*/ + +void rstate_perp_dist(t_state *state, t_render_state *rstate) +{ + if (rstate->side == SIDE_WE) + rstate->perp_dist = (rstate->map_pos.x - state->pos.x + (1 - rstate->map_step.x) / 2) / rstate->ray.x; + else + rstate->perp_dist = (rstate->map_pos.y - state->pos.y + (1 - rstate->map_step.y) / 2) / rstate->ray.y; +} + +/* +** 0 <= 1 / perp_dist <= 1 +** height * (1 / perp_dist) is how much of the screen height do we take +*/ + +void rstate_line_height(t_state *state, t_render_state *rstate) +{ + rstate->line_height = (int)((double)state->window.height / rstate->perp_dist); +} + +t_image *get_tex(t_state *state, t_render_state *rstate) +{ + if (rstate->side == SIDE_NS) + { + if (rstate->probe.y < state->pos.y) + return (state->textures + TEX_NORTH); + else + return (state->textures + TEX_SOUTH); + } + else if (rstate->side == SIDE_WE) + { + if (rstate->probe.x > state->pos.x) + return (state->textures + TEX_WEST); + else + return (state->textures + TEX_EAST); + } + return (NULL); +} + +/* +** Since we're drawing each column, all the texels we want to draw on the window +** are on a single column of the texture. +** First we find the x-coord relative to the wall we hit +*/ + +int get_tex_x(t_state *state, t_render_state *rstate, t_image *texture) +{ + int tex_x; + double wall_x; + + if (rstate->side == SIDE_WE) + wall_x = state->pos.y + rstate->perp_dist * rstate->ray.y; + else + wall_x = state->pos.x + rstate->perp_dist * rstate->ray.x; + wall_x -= floor(wall_x); + + tex_x = (int)(wall_x * (double)texture->width); + if (rstate->side == 0 && rstate->ray.x > 0) + tex_x = texture->width - tex_x - 1; + if (rstate->side == 1 && rstate->ray.y < 0) + tex_x = texture->width - tex_x - 1; + return (tex_x); +} diff --git a/src/state.c b/src/state.c new file mode 100644 index 0000000..11e1c65 --- /dev/null +++ b/src/state.c @@ -0,0 +1,128 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* graphics.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/19 16:39:57 by cacharle #+# #+# */ +/* Updated: 2020/01/30 15:13:42 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +/* +** Initialize the state attributes that weren't already filled by the parsing +*/ + +t_state *state_new(t_state *state) +{ + int i; + + state->running = TRUE; + if ((state->mlx_ptr = mlx_init()) == NULL) + return (state_destroy(state)); + if ((state->window_ptr = mlx_new_window(state->mlx_ptr, + state->window.width, state->window.height, WINDOW_TITLE)) == NULL) + return (state_destroy(state)); + printf("init mlx and mlx window\n"); + i = -1; + while (++i < TEXTURES_NUM) + { + load_texture(state->mlx_ptr, &state->textures[i], + state->textures_path[i]); + if (state->textures[i].id == NULL) + return (error_put_return_state_destroy("load texture", state)); + } + if ((state->window.id = mlx_new_image(state->mlx_ptr, + state->window.width, state->window.height)) == NULL) + return (state_destroy(state)); + state->window.data = mlx_get_data_addr(state->window.id, + &state->window.depth, &state->window.size_line, + &state->window.endian); + printf("init mlx window image\n"); + state_init_player(state); + printf("init player\n"); + return (state); +} + +void state_init_player(t_state *state) +{ + int i; + int j; + + i = -1; + while (++i < state->map_height) + { + j = -1; + while (++j < state->map_width) + if (helper_is_player_cell(state->map[i][j])) + { + state->pos.x = (double)j + 0.5; + state->pos.y = (double)i + 0.5; + } + } + helper_init_dir_plane(state, (int)state->pos.y, (int)state->pos.x); +} + +t_state *state_new_empty(void) +{ + int i; + t_state *state; + + if ((state = (t_state*)malloc(sizeof(t_state))) == NULL) + return (NULL); + state->mlx_ptr = NULL; + state->window_ptr = NULL; + i = -1; + while (++i < TEXTURES_NUM) + { + state->textures_path[i] = NULL; + state->textures[i].id = NULL; + } + state->dir.x = 0.0; + state->dir.y = 0.0; + state->map = NULL; + state->ceilling_color.hexcode = 0x0; + state->floor_color.hexcode = 0x0; + return (state); +} + +void *state_destroy(t_state *state) +{ + int i; + + if (state == NULL) + return (NULL); + i = -1; + while (++i < TEXTURES_NUM) + { + free(state->textures_path[i]); + if (state->mlx_ptr != NULL && state->textures[i].id != NULL) + mlx_destroy_image(state->mlx_ptr, state->textures[i].id); + } + printf("free window image\n"); + if (state->mlx_ptr != NULL && state->window.id != NULL) + mlx_destroy_image(state->mlx_ptr, state->window.id); + printf("free window\n"); + if (state->mlx_ptr && state->window_ptr) + mlx_destroy_window(state->mlx_ptr, state->window_ptr); + printf("free map\n"); + if (state->map != NULL) + while (state->map_height-- > 0 && state->map[state->map_height] != NULL) + free(state->map[state->map_height]); + free(state->map); + printf("free state\n"); + free(state); + return (NULL); +} + +void load_texture(void *mlx_ptr, t_image *image, char *path) +{ + if ((image->id = mlx_xpm_file_to_image( + mlx_ptr, path, &image->width, &image->height)) == NULL) + return ; + image->data = mlx_get_data_addr(image->id, &image->depth, + &image->size_line, &image->endian); +} diff --git a/src/vector.c b/src/vector.c new file mode 100644 index 0000000..44f784b --- /dev/null +++ b/src/vector.c @@ -0,0 +1,62 @@ +/* ************************************************************************** */ +/* */ +/* ::: :::::::: */ +/* linear_algebra.c :+: :+: :+: */ +/* +:+ +:+ +:+ */ +/* By: cacharle <marvin@42.fr> +#+ +:+ +#+ */ +/* +#+#+#+#+#+ +#+ */ +/* Created: 2019/11/18 01:28:01 by cacharle #+# #+# */ +/* Updated: 2020/01/16 08:43:09 by cacharle ### ########.fr */ +/* */ +/* ************************************************************************** */ + +#include "cub3d.h" + +t_vector vector_add(t_vector a, t_vector b) +{ + a.x += b.x; + a.y += b.y; + return (a); +} + +t_vector vector_scale(t_vector v, double scalar) +{ + v.x *= scalar; + v.y *= scalar; + return (v); +} + +/* +** rotate counter clockwise +*/ + +t_vector vector_rotate(t_vector v, double angle) +{ + t_vector rotated; + + rotated.x = cos(angle) * v.x - sin(angle) * v.y; + rotated.y = sin(angle) * v.x + cos(angle) * v.y; + return (rotated); +} + +double vector_norm(t_vector v) +{ + /* return (sqrt(SQUARE(v.x) + SQUARE(v.y))); */ + return (hypot(v.x, v.y)); +} + +t_vector vector_new(double x, double y) +{ + t_vector v; + + v.x = x; + v.y = y; + return (v); +} + +t_vector vector_apply(t_vector v, double (*f)(double)) +{ + v.x = f(v.x); + v.y = f(v.y); + return (v); +} |
