diff --git a/dev/TODO b/dev/TODO index 1c5bd73..6632cc5 100644 --- a/dev/TODO +++ b/dev/TODO @@ -11,4 +11,3 @@ TODO: map parsing: fix segfault if bad texture TODO: map parsing: fix when color value > 255 TODO: what if the pointer goes outside of the window? TODO: fix inverted west and east textures -TODO: fix nobonus speed diff --git a/include/const.h b/include/const.h index 85da448..6accd5f 100644 --- a/include/const.h +++ b/include/const.h @@ -18,9 +18,11 @@ # define PI 3.1415926535 // it's just pi # define FPS 30 // Number of frames per second (bonus only) +# define NOBONUS_SPEED 500 // Number of calls to timedloop for one frame + // (mandatory only) # define MOVE_SPEED 0.1 // Player oves by N cases by tick -# define ROT_SPEED_DIVIDE_PI 48 // Player turns by pi/N rad by tick +# define ROT_SPEED_DIVIDE_PI 32 // Player turns by pi/N rad by tick # define MOUSE_ROTATION_SPEED 0.001 // Rotation speed from mouse: rad/px # define HITBOX 0.25 // Hitbox of N cases around player. diff --git a/include/map.h b/include/map.h index a46d578..31f5f1a 100644 --- a/include/map.h +++ b/include/map.h @@ -111,6 +111,7 @@ typedef struct s_map } t_map; /// @brief Create a t_map from the content of a .cub file. +/// If error, write an error text. /// /// @param dest Pointer to the t_map to set. /// @param file .cub file to use to create the t_map. @@ -122,12 +123,14 @@ bool map_from_file(t_map *dest, const char *file); void map_destroy(t_map *map); /// @brief Return true if the map is valid. Write an error message on stderr. +/// If error, write an error text. /// /// @param map The map to check. /// @return true if the map is valid, false if not. bool check_map(const t_map *map); /// @brief Get a case of the map from its coordinates. +/// If x or y are outside the map, undefined behaviour. /// /// @param map Map to get the case from. /// @param x x position of the case to return. diff --git a/include/stream.h b/include/stream.h index bcbe855..3992371 100644 --- a/include/stream.h +++ b/include/stream.h @@ -35,13 +35,14 @@ typedef struct s_stream void read_expected_string(const char *str, t_stream *stream, bool *err); /// @brief Read an unsigned int (which fits the pattern /[0-9]+/). +/// It must be between 0 and 255. /// Skip the potential blank space before the string. /// /// @param dest Will be set to the value of the unsigned integer. /// @param stream Stream to use. /// @param err Set to true if an error occured. /// If already true, the function won't do anything. -void read_unsigned(unsigned int *dest, t_stream *stream, bool *err); +void read_unsigned_max_255(unsigned int *dest, t_stream *stream, bool *err); /// @brief Read a string until limit char or \0. /// Skip the potential blank space before the string. diff --git a/include/utils.h b/include/utils.h index ecc5f06..0e2bedb 100644 --- a/include/utils.h +++ b/include/utils.h @@ -38,7 +38,7 @@ typedef __u32 t_color; /// @param green Level of green from 0 to 255. /// @param blue Level of blue from 0 to 255. /// @return The result. -t_color color_from_rgb(int red, int green, int blue); +t_color color_from_rgb(u_int8_t red, u_int8_t green, u_int8_t blue); /// @brief Write an error message on stderr. /// diff --git a/src/main.c b/src/main.c index 287ea7d..13ed0c0 100644 --- a/src/main.c +++ b/src/main.c @@ -21,22 +21,25 @@ static int g_return_value = 0; -static void draw_screen(void) +// If error: write the error and returns false. +static bool draw_screen(void) { void *img_ptr; u_int32_t *img_data; img_ptr = mlx_new_image(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT); + if (!img_ptr) + return (write_err("mlx_new_image() failed.\n"), false); img_data = get_data_addr(img_ptr); if (!img_data) { - g_return_value = 1; - mlx_loop_end(g_mlx); + return (false); } render(img_data); draw_minimap(img_data); mlx_put_image_to_window(g_mlx, g_win, img_ptr, 0, 0); mlx_destroy_image(g_mlx, img_ptr); + return (true); } static void loop(void) @@ -44,7 +47,11 @@ static void loop(void) move(); if (g_input_actions.quit) mlx_loop_end(g_mlx); - draw_screen(); + if (!draw_screen()) + { + g_return_value = 1; + mlx_loop_end(g_mlx); + } } static int loop_hook(void *param) @@ -54,31 +61,41 @@ static int loop_hook(void *param) return (0); } +static void destroy_g_mlx_g_win_and_map(t_map *map) +{ + if (map) + map_destroy(map); + if (g_mlx) + { + if (g_win) + { + mlx_destroy_window(g_mlx, g_win); + g_win = NULL; + } + mlx_destroy_display(g_mlx); + free(g_mlx); + g_mlx = NULL; + } +} + int main(int argc, char *argv[]) { - g_mlx = mlx_init(); + g_mlx = NULL; + g_win = NULL; if (argc != 2) - { - printf("Syntax: %s \n", argv[0]); - g_return_value = 1; - } - else - { - if (!map_from_file(&g_map, argv[1])) - g_return_value = 1; - else - { - g_win = mlx_new_window(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT, - WINDOW_NAME); - input_init(g_mlx, g_win); - mlx_loop_hook(g_mlx, loop_hook, NULL); - draw_screen(); - mlx_loop(g_mlx); - mlx_destroy_window(g_mlx, g_win); - map_destroy(&g_map); - } - } - mlx_destroy_display(g_mlx); - free(g_mlx); - return (g_return_value); + return (printf("Syntax: %s \n", argv[0]), 1); + g_mlx = mlx_init(); + if (!g_mlx) + return (write_err("mlx_init() failed.\n", NULL), 1); + if (!map_from_file(&g_map, argv[1])) + return (destroy_g_mlx_g_win_and_map(NULL), 1); + g_win = mlx_new_window(g_mlx, SCREEN_WIDTH, SCREEN_HEIGHT, WINDOW_NAME); + if (!g_win) + return (write_err("mlx_new_window() failed.\n", NULL), + destroy_g_mlx_g_win_and_map(&g_map), 1); + input_init(g_mlx, g_win); + mlx_loop_hook(g_mlx, loop_hook, NULL); + draw_screen(); + mlx_loop(g_mlx); + return (destroy_g_mlx_g_win_and_map(&g_map), g_return_value); } diff --git a/src/map1.c b/src/map1.c index 5ed80db..5f25ca5 100644 --- a/src/map1.c +++ b/src/map1.c @@ -64,7 +64,7 @@ bool map_from_file(t_map *dest, const char *file) stream.str = read_all_text(fd); if (!stream.str) { - write_err("Can't read file.\n", NULL); + write_err(strerror(errno), NULL); close(fd); return (false); } @@ -86,6 +86,7 @@ void map_destroy(t_map *map) d++; } free(map->cases); + ft_bzero(map, sizeof(t_map)); } static bool check_map2(const t_map *map, unsigned int x, unsigned int y) diff --git a/src/map_utils.h b/src/map_utils.h index 11ece40..ddb862d 100644 --- a/src/map_utils.h +++ b/src/map_utils.h @@ -18,7 +18,9 @@ # include "stream.h" /// @brief Read a parameter of the map which has a color as an argument. -/// Color format: [0-255],[0-255],[0-255] +/// Color format: [0-255],[0-255],[0-255]. +/// If redefined, write an error text. +/// /// @param name Name of the parameter. /// @param dest Will be set to the value of the parameter. /// Unchanged if error. @@ -31,6 +33,8 @@ bool read_color_parameter(const char *name, t_color *dest, t_stream *stream, bool *redefined); /// @brief Read a parameter of the map which has a string as an argument. +/// If redefined, write an error text. +/// /// @param name Name of the parameter. /// @param dest Will be set to an alloc'd pointer to the value of the parameter. /// Unchanged if error. @@ -44,12 +48,14 @@ bool read_string_parameter(const char *name, const char **dest, /// @brief Read a map-formatted string. /// If an error occurs, write an error message on stderr. +/// /// @param dest Will be set to the map. /// @param stream Stream to use. /// @return true if success, false if error. bool read_map(t_map *dest, t_stream *stream); /// @brief Get the case associated with the char. +/// If an error occurs, write an error message on stderr. /// /// @param dest Will be set to the char. /// @param name Name of the case. @@ -64,6 +70,7 @@ void fill_zeros(void *dest, size_t size); /// @brief Read the map description part of the map. /// Read until the end of the file. +/// If an error occurs, write an error message on stderr. /// /// @param map The .width, .height and .cases members will be set. /// @param stream Stream to use. @@ -71,11 +78,18 @@ void fill_zeros(void *dest, size_t size); bool read_map_description(t_map *map, t_stream *stream); /// @brief Initialize map->player. +/// If error, write an error text. +/// /// @param map Map to use. /// @return true if success, false if error /// (0 or >2 players found instead of only one). bool map_init_player(t_map *map); +/// @brief Init map->textures from map->texture_srcs. +/// If error, write an error text and destroy map. +/// +/// @param map Map to use. +/// @return true if success, false if error. bool load_textures(t_map *map); #endif diff --git a/src/map_utils1.c b/src/map_utils1.c index 46fd51a..938bc90 100644 --- a/src/map_utils1.c +++ b/src/map_utils1.c @@ -24,11 +24,11 @@ bool read_color_parameter(const char *name, t_color *dest, read_expected_string(name, stream, &err); if (!read_blank(stream)) err = true; - read_unsigned(&rgb[0], stream, &err); + read_unsigned_max_255(&rgb[0], stream, &err); read_expected_string(",", stream, &err); - read_unsigned(&rgb[1], stream, &err); + read_unsigned_max_255(&rgb[1], stream, &err); read_expected_string(",", stream, &err); - read_unsigned(&rgb[2], stream, &err); + read_unsigned_max_255(&rgb[2], stream, &err); read_expected_string("\n", stream, &err); if (!err && *dest != 0xFF000000) { diff --git a/src/map_utils2.c b/src/map_utils2.c index e2cc612..2e4f588 100644 --- a/src/map_utils2.c +++ b/src/map_utils2.c @@ -113,6 +113,13 @@ bool load_textures(t_map *map) map->textures[d].image = mlx_xpm_file_to_image(g_mlx, (char *)(map->texture_srcs[d]), &map->textures[d].width, &map->textures[d].height); + if (!map->textures[d].image) + { + write_err("The texture file '", map->texture_srcs[d], + "' can't be opened.\n", NULL); + map_destroy(map); + return (false); + } d++; } return (true); diff --git a/src/minimap_inline.h b/src/minimap_inline.h index c5f003b..e36ecdb 100644 --- a/src/minimap_inline.h +++ b/src/minimap_inline.h @@ -18,11 +18,21 @@ # include "const.h" +/// @brief Return the distance between the two points. +/// +/// @param a Point A. +/// @param b Point B. +/// @return Distance. static inline double distance_between(t_point_double a, t_point_double b) { return (sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y))); } +/// @brief Return the distance between the two points. +/// +/// @param a Point A. +/// @param b Point B. +/// @return Distance. static inline double distance_between_int(t_point_int a, t_point_int b) { return (sqrt((double)( @@ -30,6 +40,12 @@ static inline double distance_between_int(t_point_int a, t_point_int b) ))); } +/// @brief From a pixel position on the minimap relative to the window, +/// get the corresponding position on the map. +/// +/// @param pixel Position of the pixel on the minimap. +/// @param scale Scale of the map. +/// @return Position on the map. static inline t_point_double pixel_to_pos(t_point_int pixel, double scale) { return ((t_point_double){ @@ -38,12 +54,18 @@ static inline t_point_double pixel_to_pos(t_point_int pixel, double scale) }); } -static inline double get_angle(t_point_int base, t_point_int vector) +/// @brief Get the angle of the vector AB. (0, -1) is 0 rad, (1, 0) is PI/2 rad. +/// +/// @param A Point A. +/// @param B Point B. +/// @return Resulting angle in rad. +static inline double get_angle(t_point_int A, t_point_int B) { - double r; + double r; + t_point_int vector; - vector.x -= base.x; - vector.y -= base.y; + vector.x = B.x - A.x; + vector.y = B.y - A.y; if (!vector.y) { if (vector.x > 0) @@ -58,6 +80,11 @@ static inline double get_angle(t_point_int base, t_point_int vector) return (r); } +/// @brief Check if an angle is between two other angles. +/// @param angle Angle to test. +/// @param min Minimum angle. +/// @param max Maximum angle. +/// @return Either 'angle' is between 'min' and 'max'. static inline bool angle_in_between(double angle, double min, double max) { while (max < min) diff --git a/src/minimap_inline2.h b/src/minimap_inline2.h index a69f535..6eb416f 100644 --- a/src/minimap_inline2.h +++ b/src/minimap_inline2.h @@ -15,16 +15,25 @@ # include "minimap.h" +// Gamma correction. static inline double srgb_to_gamma(u_int8_t value) { return (pow((double)value / 0xFF, 2.2)); } +// Inverts the gamma correction. Inverts srgb_to_gamma. static inline u_int8_t gamma_to_srgb(double value) { return (pow((double)value, 1 / 2.2) * 0xFF); } +/// @brief Draw a color on a pixel with a specific opacity. +/// +/// @param pixel Pixel to draw on. +/// @param color Color to use. +/// @param opacity Opacity to use. If 0, 'pixel' is unchanged. If 1, 'pixel' +/// is set to 'color'. If outside of [0;1], the closest value is +/// used. static inline void draw_transparent_pixel(u_int32_t *pixel, u_int32_t color, double opacity) { diff --git a/src/move_utils.h b/src/move_utils.h index f7f69f6..f6c8cb9 100644 --- a/src/move_utils.h +++ b/src/move_utils.h @@ -13,6 +13,7 @@ #ifndef MOVE_UTILS_H # define MOVE_UTILS_H +/// @brief If the player is in a wall, move it outside of the wall. void push_from_walls(void); #endif diff --git a/src/stream.c b/src/stream.c index d1506b8..50dddf5 100644 --- a/src/stream.c +++ b/src/stream.c @@ -42,7 +42,7 @@ static bool is_digit(char c) return (c >= '0' && c <= '9'); } -void read_unsigned(unsigned int *dest, t_stream *stream, bool *err) +void read_unsigned_max_255(unsigned int *dest, t_stream *stream, bool *err) { int r; @@ -60,6 +60,11 @@ void read_unsigned(unsigned int *dest, t_stream *stream, bool *err) r = r * 10 + stream->str[stream->i] - '0'; stream->i++; } + if (r < 0 || r > 255) + { + *err = true; + return ; + } *dest = r; } diff --git a/src/utils2.c b/src/utils2.c index 960ef72..81f2649 100644 --- a/src/utils2.c +++ b/src/utils2.c @@ -29,7 +29,7 @@ u_int32_t *get_data_addr(void *img_ptr) return (r); } -t_color color_from_rgb(int red, int green, int blue) +t_color color_from_rgb(u_int8_t red, u_int8_t green, u_int8_t blue) { return (red << 16 | green << 8 | blue); } diff --git a/src/utils_timedloop_nobonus.c b/src/utils_timedloop_nobonus.c index 26d6c1e..8b3c6b3 100644 --- a/src/utils_timedloop_nobonus.c +++ b/src/utils_timedloop_nobonus.c @@ -12,11 +12,13 @@ #include "utils.h" +#include "const.h" + void timedloop(void (*f)(void)) { static int ticks; - if (ticks % 100 == 0) + if (ticks % NOBONUS_SPEED == 0) f(); ticks++; } diff --git a/testmaps/good_reallyreallyweirdblank.cub b/testmaps/err_reallyreallyweirdblank.cub similarity index 100% rename from testmaps/good_reallyreallyweirdblank.cub rename to testmaps/err_reallyreallyweirdblank.cub diff --git a/testmaps/good_reallyweirdblank.cub b/testmaps/good_reallyweirdblank.cub index cb0bdff..3c10029 100644 --- a/testmaps/good_reallyweirdblank.cub +++ b/testmaps/good_reallyweirdblank.cub @@ -1,13 +1,13 @@ -F 255, 127 ,0 +F 255, 127 ,0 C 0, 2 , 67 -EA textures/east.xpm +EA textures/east.xpm NO textures/north.xpm -SO textures/south.xpm +SO textures/south.xpm