MLX42 1.0
MLX42
Loading...
Searching...
No Matches
mlx_xpm42.c
Go to the documentation of this file.
1/* ************************************************************************** */
2/* */
3/* :::::::: */
4/* mlx_xpm42.c :+: :+: */
5/* +:+ */
6/* By: W2Wizard <main@w2wizard.dev> +#+ */
7/* +#+ */
8/* Created: 2021/12/28 03:42:29 by W2Wizard #+# #+# */
9/* Updated: 2022/06/27 19:58:33 by lde-la-h ######## odam.nl */
10/* */
11/* ************************************************************************** */
12
13#include "MLX42/MLX42_Int.h"
14
15/**
16 * XPM is an obscure image format which can't seem to make up its mind
17 * whether it wants to be written in C code or not.
18 *
19 * https://en.wikipedia.org/wiki/X_PixMap
20 *
21 * This might anger some but instead I decided to write my own
22 * image format, very similar to XPM2, which seems to be the better
23 * option between the 3 versions. The only difference is in the
24 * header which carries the file type, width, height, color count
25 * and finally color type aka 'c' for RGBA8 or 'm' for monochrome
26 * output.
27 *
28 * The changes, in my opinion, very much simplify the XPM format
29 * into something literally anybody can use without much guessing
30 * as to what does what.
31 *
32 * Additionally with the C style format, the idea is that you simply include
33 * it directly into the compilation of the program (since it's just C).
34 *
35 * As convenient as this is, I just find it hideous especially the XPM3 variant.
36 * By sticking to the XPM style format, conversion should be very easy and
37 * straightforward to this format however.
38 */
39
40//= Private =//
41
42/**
43 * Parses HEX color channel e.g: "0F"
44 *
45 * @param channel The 2 character string to parse.
46 * @return Int value of the channel.
47 */
49{
50 char temp_chan[] = {channel[0], channel[1], '\0'};
51 return (strtol(temp_chan, NULL, 16));
52}
53
54/**
55 * Parses the XPM color value entry e.g: ".X #00FF00FF"
56 * into the color table while also verifying the format.
57 *
58 * @param xpm The XPM.
59 * @param line The line to parse.
60 * @param ctable The color hash table.
61 * @param s Size of the hash table
62 * @return True or false depending on if it successfully parsed the line.
63 */
64static bool mlx_insert_xpm_entry(xpm_t* xpm, char* line, uint32_t* ctable, size_t s)
65{
66 // NOTE: uintptr because windows likes to complain...
67 // Verify the length of the Pixel string by checking backwards for the first
68 // occurrence of a space and then check the distance by comparing with cpp.
69 if (((uintptr_t)strrchr(line, ' ') - (uintptr_t)line) != (uint64_t)xpm->cpp)
70 return (false);
71 if (!isspace(line[xpm->cpp]) || line[xpm->cpp + 1] != '#' || !isalnum(line[xpm->cpp + 2]))
72 return (false);
73
74 uint32_t color = 0;
75 size_t start_offset = xpm->cpp + 2;
80
83 return (true);
84}
85
86/**
87 * Retrieves the pixel data line by line and then processes each pixel
88 * by hashing the characters and looking it up from the color table.
89 *
90 * @param xpm The XPM.
91 * @param file The filepath to the XPM42 file.
92 * @param ctable The color hash table.
93 * @param s Size of the hash table.
94 * @return True or false depending on if it successfully parsed the line.
95 */
96static bool mlx_read_data(xpm_t* xpm, FILE* file, uint32_t* ctable, size_t s)
97{
98 size_t line_len;
99 char* line = NULL;
100
101 for (int64_t y_xpm = 0; y_xpm < xpm->texture.height; y_xpm++)
102 {
103 if (!mlx_getline(&line, &line_len, file))
104 return (free(line), false);
105 if (line[line_len - 1] == '\n')
106 line_len--;
107 if (line_len != xpm->texture.width * xpm->cpp)
108 return (free(line), false);
109
110 // NOTE: Copy pixel by pixel as we need to retrieve the hash table.
111 for (int64_t x_xpm = 0, x_line = 0; x_xpm < xpm->texture.width; x_xpm++, x_line += xpm->cpp)
112 {
115 }
116 }
117 free(line);
118 return (true);
119}
120
121/**
122 * For quick lookups we basically create a stack allocated lookup
123 * table with every ascii character in it. This should help avoid a O(n)
124 * case and give us a O(1) for very fast look ups.
125 *
126 * Downside is we still need to iterate over each pixel to solve its color.
127 * So I hope this makes it at least a bit faster.
128 *
129 * TODO: This buffer might be way to big! Do actual collision checks,
130 * for now just straight up raw dog this.
131 */
133{
134 char* line = NULL;
135 size_t line_len;
137
138 for (int32_t i = 0; i < xpm->color_count; i++)
139 {
140 if (!mlx_getline(&line, &line_len, file))
141 return (free(line), false);
142 if (!mlx_insert_xpm_entry(xpm, line, ctable, (sizeof(ctable) / BPP)))
143 return (free(line), false);
144 }
145 free(line);
146 return (mlx_read_data(xpm, file, ctable, (sizeof(ctable) / BPP)));
147}
148
149/**
150 * Reads the XPM42 file header which usually consists of a
151 * file type declaration of "!XPM42" followed by the next line
152 * containing image information such as width, height, unique color
153 * count and finally the color mode. Which is either c for Color or
154 * m for Monochrome.
155 */
157{
159 char buffer[64] = {0};
160
161 // Check file type dec...
162 if (!fgets(buffer, sizeof(buffer), file))
163 return (false);
164 if (strncmp(buffer, "!XPM42\n", sizeof(buffer)) != 0)
165 return (false);
166
167 // Get header info ...
168 if (!fgets(buffer, sizeof(buffer), file))
169 return (false);
170 flagc = sscanf(buffer, "%i %i %i %i %c\n", &xpm->texture.width, &xpm->texture.height, &xpm->color_count, &xpm->cpp, &xpm->mode);
172 !(xpm->mode == 'c' || xpm->mode == 'm') || xpm->cpp > 10)
173 return (false);
176 return (xpm->texture.pixels != NULL ? mlx_read_table(xpm, file) : false);
177}
178
179//= Public =//
180
182{
183 FILE* file;
184 xpm_t* xpm = NULL;
185
187 if (!strstr(path, ".xpm42"))
188 return ((void*)mlx_error(MLX_INVEXT));
189 if (!(file = fopen(path, "r")))
190 return ((void*)mlx_error(MLX_INVFILE));
191 if (!(xpm = calloc(1, sizeof(xpm_t))))
192 return ((void*)mlx_error(MLX_MEMFAIL));
194 {
197 xpm = NULL;
198 }
199 fclose(file);
200 return (xpm);
201}
202
204{
207 free(xpm);
208}
@ MLX_MEMFAIL
Definition MLX42.h:383
@ MLX_INVEXT
Definition MLX42.h:373
@ MLX_INVFILE
Definition MLX42.h:374
@ MLX_INVXPM
Definition MLX42.h:376
#define MLX_NONNULL(var)
Definition MLX42_Int.h:46
bool mlx_error(mlx_errno_t val)
Definition mlx_error.c:43
void mlx_draw_pixel(uint8_t *pixel, uint32_t color)
#define BPP
Definition MLX42_Int.h:42
bool mlx_freen(int32_t count,...)
Definition mlx_utils.c:89
uint64_t mlx_fnv_hash(char *str, size_t len)
Definition mlx_utils.c:68
uint32_t mlx_rgba_to_mono(uint32_t color)
Definition mlx_utils.c:109
bool mlx_getline(char **out, size_t *out_size, FILE *file)
Definition mlx_utils.c:28
GLuint texture
Definition glad.h:2899
GLenum GLfloat * buffer
Definition glad.h:2634
GLuint index
Definition glad.h:3345
GLuint color
Definition glad.h:3749
GLuint GLsizei GLsizei * length
Definition glad.h:3372
GLdouble s
Definition glad.h:3009
static bool mlx_insert_xpm_entry(xpm_t *xpm, char *line, uint32_t *ctable, size_t s)
Definition mlx_xpm42.c:64
static bool mlx_read_xpm_header(xpm_t *xpm, FILE *file)
Definition mlx_xpm42.c:156
void mlx_delete_xpm42(xpm_t *xpm)
Definition mlx_xpm42.c:203
static bool mlx_read_table(xpm_t *xpm, FILE *file)
Definition mlx_xpm42.c:132
xpm_t * mlx_load_xpm42(const char *path)
Definition mlx_xpm42.c:181
static uint8_t mlx_parse_hex_channel(char *channel)
Definition mlx_xpm42.c:48
static bool mlx_read_data(xpm_t *xpm, FILE *file, uint32_t *ctable, size_t s)
Definition mlx_xpm42.c:96
uint32_t height
Definition MLX42.h:266
uint8_t * pixels
Definition MLX42.h:268
uint32_t width
Definition MLX42.h:265
uint8_t bytes_per_pixel
Definition MLX42.h:267
Definition MLX42.h:280
int32_t color_count
Definition MLX42.h:282
char mode
Definition MLX42.h:284
mlx_texture_t texture
Definition MLX42.h:281
int32_t cpp
Definition MLX42.h:283