fixings and improvements

dev:
- add documentation
- main() is more readable

fix:
- unmanaged errors:
  - map parsing: error if color value is >255
  - map parsing: load_textures(): check return value of xml_xpm_file_to_image()
  - main.c: draw_screen(): check return value of mlx_new_image()

other details:
- dev: color_from_rgb(): change signature
- fix: nullize map in map_destroy
- change: change error message for read_all_text() errors
- change: change rotation speed
- change: add and use contant NOOBONUS_SPEED
This commit is contained in:
mcolonna 2024-11-21 15:18:08 +01:00
parent f3da11b105
commit 424b9aa7b2
18 changed files with 135 additions and 47 deletions

View file

@ -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

View file

@ -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.

View file

@ -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.

View file

@ -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.

View file

@ -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.
///

View file

@ -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 <map.cub>\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 <map.cub>\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);
}

View file

@ -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)

View file

@ -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

View file

@ -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)
{

View file

@ -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);

View file

@ -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)

View file

@ -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)
{

View file

@ -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

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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++;
}

View file

@ -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