added scr_lvled, a bunch of libraries, and improved framework code
[raydungeon] / libs / imago / src / conv.c
1 /*
2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2021 John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <string.h>
19 #include "imago2.h"
20 #include "byteord.h"
21
22 /* pixel-format conversions are sub-optimal at the moment to avoid
23  * writing a lot of code. optimize at some point ?
24  */
25
26 #define CLAMP(x, a, b)  ((x) < (a) ? (a) : ((x) > (b) ? (b) : (x)))
27
28 struct pixel {
29         float r, g, b, a;
30 };
31
32 static void unpack_grey8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
33 static void unpack_rgb24(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
34 static void unpack_rgba32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
35 static void unpack_bgra32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
36 static void unpack_greyf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
37 static void unpack_rgbf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
38 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
39 static void unpack_rgb565(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
40 static void unpack_idx8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap);
41
42 static void pack_grey8(void *pptr, struct pixel *unp, int count);
43 static void pack_rgb24(void *pptr, struct pixel *unp, int count);
44 static void pack_rgba32(void *pptr, struct pixel *unp, int count);
45 static void pack_bgra32(void *pptr, struct pixel *unp, int count);
46 static void pack_greyf(void *pptr, struct pixel *unp, int count);
47 static void pack_rgbf(void *pptr, struct pixel *unp, int count);
48 static void pack_rgbaf(void *pptr, struct pixel *unp, int count);
49 static void pack_rgb565(void *pptr, struct pixel *unp, int count);
50
51 /* XXX keep in sync with enum img_fmt at imago2.h */
52 static void (*unpack[])(struct pixel*, void*, int, struct img_colormap*) = {
53         unpack_grey8,
54         unpack_rgb24,
55         unpack_rgba32,
56         unpack_greyf,
57         unpack_rgbf,
58         unpack_rgbaf,
59         unpack_bgra32,
60         unpack_rgb565,
61         unpack_idx8
62 };
63
64 /* XXX keep in sync with enum img_fmt at imago2.h */
65 static void (*pack[])(void*, struct pixel*, int) = {
66         pack_grey8,
67         pack_rgb24,
68         pack_rgba32,
69         pack_greyf,
70         pack_rgbf,
71         pack_rgbaf,
72         pack_bgra32,
73         pack_rgb565,
74         0
75 };
76
77
78 int img_convert(struct img_pixmap *img, enum img_fmt tofmt)
79 {
80         struct pixel pbuf[8];
81         int bufsz = (img->width & 7) == 0 ? 8 : ((img->width & 3) == 0 ? 4 : 1);
82         int i, num_pix = img->width * img->height;
83         int num_iter = num_pix / bufsz;
84         char *sptr, *dptr;
85         struct img_pixmap nimg;
86         struct img_colormap *cmap = img_colormap(img);
87
88         if(img->fmt == tofmt) {
89                 return 0;       /* nothing to do */
90         }
91
92         if(tofmt == IMG_FMT_IDX8) {
93                 /* TODO */
94                 fprintf(stderr, "imago: conversions to indexed not implemented yet\n");
95                 return 0;
96         }
97
98         img_init(&nimg);
99         if(img_set_pixels(&nimg, img->width, img->height, tofmt, 0) == -1) {
100                 img_destroy(&nimg);
101                 return -1;
102         }
103
104         sptr = img->pixels;
105         dptr = nimg.pixels;
106
107         for(i=0; i<num_iter; i++) {
108                 unpack[img->fmt](pbuf, sptr, bufsz, cmap);
109                 pack[tofmt](dptr, pbuf, bufsz);
110
111                 sptr += bufsz * img->pixelsz;
112                 dptr += bufsz * nimg.pixelsz;
113         }
114
115         img_copy(img, &nimg);
116         img_destroy(&nimg);
117         return 0;
118 }
119
120 /* the following functions *could* benefit from SIMD */
121
122 static void unpack_grey8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
123 {
124         int i;
125         unsigned char *pix = pptr;
126
127         for(i=0; i<count; i++) {
128                 unp->r = unp->g = unp->b = (float)*pix++ / 255.0;
129                 unp->a = 1.0;
130                 unp++;
131         }
132 }
133
134 static void unpack_rgb24(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
135 {
136         int i;
137         unsigned char *pix = pptr;
138
139         for(i=0; i<count; i++) {
140                 unp->r = (float)*pix++ / 255.0;
141                 unp->g = (float)*pix++ / 255.0;
142                 unp->b = (float)*pix++ / 255.0;
143                 unp->a = 1.0;
144                 unp++;
145         }
146 }
147
148 static void unpack_rgba32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
149 {
150         int i;
151         unsigned char *pix = pptr;
152
153         for(i=0; i<count; i++) {
154                 unp->r = (float)*pix++ / 255.0;
155                 unp->g = (float)*pix++ / 255.0;
156                 unp->b = (float)*pix++ / 255.0;
157                 unp->a = (float)*pix++ / 255.0;
158                 unp++;
159         }
160 }
161
162 static void unpack_bgra32(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
163 {
164         int i;
165         unsigned char *pix = pptr;
166
167         for(i=0; i<count; i++) {
168                 unp->a = (float)*pix++ / 255.0;
169                 unp->r = (float)*pix++ / 255.0;
170                 unp->g = (float)*pix++ / 255.0;
171                 unp->b = (float)*pix++ / 255.0;
172                 unp++;
173         }
174 }
175
176 static void unpack_greyf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
177 {
178         int i;
179         float *pix = pptr;
180
181         for(i=0; i<count; i++) {
182                 unp->r = unp->g = unp->b = *pix++;
183                 unp->a = 1.0;
184                 unp++;
185         }
186 }
187
188 static void unpack_rgbf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
189 {
190         int i;
191         float *pix = pptr;
192
193         for(i=0; i<count; i++) {
194                 unp->r = *pix++;
195                 unp->g = *pix++;
196                 unp->b = *pix++;
197                 unp->a = 1.0;
198                 unp++;
199         }
200 }
201
202 static void unpack_rgbaf(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
203 {
204         int i;
205         float *pix = pptr;
206
207         for(i=0; i<count; i++) {
208                 unp->r = *pix++;
209                 unp->g = *pix++;
210                 unp->b = *pix++;
211                 unp->a = *pix++;
212                 unp++;
213         }
214 }
215
216 static void unpack_rgb565(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
217 {
218         int i;
219         uint16_t *pix = pptr;
220
221         for(i=0; i<count; i++) {
222                 uint16_t r, g, b, p = *pix++;
223                 b = (p & 0x1f) << 3;
224                 if(b & 8) b |= 7;       /* fill LSbits with whatever bit 0 was */
225                 g = (p >> 2) & 0xfc;
226                 if(g & 4) g |= 3;       /* ditto */
227                 r = (p >> 8) & 0xf8;
228                 if(r & 8) r |= 7;       /* same */
229
230                 unp->r = (float)r / 255.0f;
231                 unp->g = (float)g / 255.0f;
232                 unp->b = (float)b / 255.0f;
233                 unp->a = 1.0f;
234                 unp++;
235         }
236 }
237
238 static void unpack_idx8(struct pixel *unp, void *pptr, int count, struct img_colormap *cmap)
239 {
240         int i, idx;
241         unsigned char *pix = pptr;
242
243         for(i=0; i<count; i++) {
244                 idx = *pix++;
245                 if(idx >= cmap->ncolors) {
246                         unp->r = unp->g = unp->b = 0;
247                 } else {
248                         unp->r = (float)cmap->color[idx].r / 255.0f;
249                         unp->g = (float)cmap->color[idx].g / 255.0f;
250                         unp->b = (float)cmap->color[idx].b / 255.0f;
251                 }
252                 unp->a = 1.0f;
253                 unp++;
254         }
255 }
256
257
258 static void pack_grey8(void *pptr, struct pixel *unp, int count)
259 {
260         int i;
261         unsigned char *pix = pptr;
262
263         for(i=0; i<count; i++) {
264                 int lum = (int)(255.0 * (unp->r + unp->g + unp->b) / 3.0);
265                 *pix++ = CLAMP(lum, 0, 255);
266                 unp++;
267         }
268 }
269
270 static void pack_rgb24(void *pptr, struct pixel *unp, int count)
271 {
272         int i;
273         unsigned char *pix = pptr;
274
275         for(i=0; i<count; i++) {
276                 int r = (int)(unp->r * 255.0);
277                 int g = (int)(unp->g * 255.0);
278                 int b = (int)(unp->b * 255.0);
279
280                 *pix++ = CLAMP(r, 0, 255);
281                 *pix++ = CLAMP(g, 0, 255);
282                 *pix++ = CLAMP(b, 0, 255);
283                 unp++;
284         }
285 }
286
287 static void pack_rgba32(void *pptr, struct pixel *unp, int count)
288 {
289         int i;
290         unsigned char *pix = pptr;
291
292         for(i=0; i<count; i++) {
293                 int r = (int)(unp->r * 255.0);
294                 int g = (int)(unp->g * 255.0);
295                 int b = (int)(unp->b * 255.0);
296                 int a = (int)(unp->a * 255.0);
297
298                 *pix++ = CLAMP(r, 0, 255);
299                 *pix++ = CLAMP(g, 0, 255);
300                 *pix++ = CLAMP(b, 0, 255);
301                 *pix++ = CLAMP(a, 0, 255);
302                 unp++;
303         }
304 }
305
306 static void pack_bgra32(void *pptr, struct pixel *unp, int count)
307 {
308         int i;
309         unsigned char *pix = pptr;
310
311         for(i=0; i<count; i++) {
312                 int r = (int)(unp->r * 255.0);
313                 int g = (int)(unp->g * 255.0);
314                 int b = (int)(unp->b * 255.0);
315                 int a = (int)(unp->a * 255.0);
316
317                 *pix++ = CLAMP(b, 0, 255);
318                 *pix++ = CLAMP(g, 0, 255);
319                 *pix++ = CLAMP(r, 0, 255);
320                 *pix++ = CLAMP(a, 0, 255);
321                 unp++;
322         }
323 }
324
325 static void pack_greyf(void *pptr, struct pixel *unp, int count)
326 {
327         int i;
328         float *pix = pptr;
329
330         for(i=0; i<count; i++) {
331                 *pix++ = (unp->r + unp->g + unp->b) / 3.0;
332                 unp++;
333         }
334 }
335
336 static void pack_rgbf(void *pptr, struct pixel *unp, int count)
337 {
338         int i;
339         float *pix = pptr;
340
341         for(i=0; i<count; i++) {
342                 *pix++ = unp->r;
343                 *pix++ = unp->g;
344                 *pix++ = unp->b;
345                 unp++;
346         }
347 }
348
349 static void pack_rgbaf(void *pptr, struct pixel *unp, int count)
350 {
351         memcpy(pptr, unp, count * sizeof *unp);
352 }
353
354
355 static void pack_rgb565(void *pptr, struct pixel *unp, int count)
356 {
357         int i;
358         uint16_t *pix = pptr;
359
360         for(i=0; i<count; i++) {
361                 uint16_t r = (uint16_t)(unp->r * 31.0f);
362                 uint16_t g = (uint16_t)(unp->g * 63.0f);
363                 uint16_t b = (uint16_t)(unp->b * 31.0f);
364                 if(r > 31) r = 31;
365                 if(g > 63) g = 63;
366                 if(b > 31) b = 31;
367                 *pix++ = (r << 11) | (g << 5) | b;
368                 unp++;
369         }
370 }