raised the version
[neuro.git] / src / misc / bitmap.c
bloba35e6147c82c8163303c9cf8de4113d0aafac55b
2 /*
3 * libneuro, a light weight abstraction of high or lower libraries
4 * and toolkit for applications.
5 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 /* bitmap process module */
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <string.h>
29 #define old 0
31 #if USE_ZLIB
32 /* this is used to open the bitmaps,
33 * the beauty of this is it works
34 * for compressed and uncompressed
35 * transparently, meaning no extra code
36 * for both!
38 #include <zlib.h>
39 typedef gzFile nFILE;
40 #else /* NOT USE_ZLIB */
41 typedef FILE nFILE;
42 #endif /* USE_ZLIB */
44 #include <ebuf.h>
45 #include <other.h>
46 #include <extlib.h> /* Lib_GetDefaultDepth() */
48 #include <graphics.h> /* Neuro_PutPixel */
51 typedef struct BITMAP_HEADER
53 u16 type __attribute__((packed)); /* Magic identifier */
54 u32 size __attribute__((packed)); /* File size in bytes */
55 u16 reserved1, reserved2; /* reserved */
56 u32 offset __attribute__((packed)); /* Offset to image data, bytes */
57 }BITMAP_HEADER;
59 typedef struct BITMAP_INFOHEADER
61 u32 size; /* Header size in bytes */
62 i32 width, height; /* Width and height of image */
63 u16 planes; /* Number of colour planes */
64 u16 bits; /* Bits per pixel */
65 u32 compression; /* Compression type */
66 u32 imagesize; /* Image size in bytes */
67 i32 xresolution, yresolution; /* Pixels per meter */
68 u32 ncolors; /* Number of colours */
69 u32 importantcolours; /* Important colours */
70 }BITMAP_INFOHEADER;
72 typedef struct BITMAP_HDATA
74 BITMAP_HEADER header __attribute__((packed));
75 BITMAP_INFOHEADER infoheader __attribute__((packed));
76 }BITMAP_HDATA;
78 typedef struct BITMAP_COLOR
80 u8 r, g, b /*, a*/ ; /* red green blue */
81 u8 *symbol; /* unique symbol associated with this color */
82 }BITMAP_COLOR;
84 typedef struct BITMAP_MAP
86 BITMAP_COLOR *color;
87 }BITMAP_MAP;
89 static u32 color_key = 0; /* this is the pixel we will make it so it is transparent */
91 /* static function prototypes */
92 static void print_bitmap_infos(BITMAP_HDATA *bmap) __attribute__((unused));
93 static int fpdata8(nFILE *input, u8 *output) __attribute__((unused));
94 static int fpdata16(nFILE *input, u16 *output) __attribute__((unused));
95 static int fpdata32(nFILE *input, u32 *output) __attribute__((unused));
99 /* static functions */
101 static void
102 clean_bmap_color(void *eng)
104 BITMAP_COLOR *buf;
106 buf = (BITMAP_COLOR*)eng;
108 if (buf->symbol)
109 free(buf->symbol);
113 /* returns 0 on success and puts the data in *output
114 * 1 on error dont touch output
116 static int
117 fpdata8(nFILE *input, u8 *output)
119 if (input == NULL || output == NULL)
120 return 1;
121 #if USE_ZLIB
122 *output = gzgetc(input);
123 #else /* NOT USE_ZLIB */
124 *output = fgetc(input);
125 #endif /* NOT USE_ZLIB */
128 return 0;
131 /* returns 0 on success and puts the data in *output
132 * 1 on error dont touch output
134 static int
135 fpdata16(nFILE *input, u16 *output)
137 u8 feed[2];
138 u16 *buf;
140 if (input == NULL || output == NULL)
141 return 1;
143 #if USE_ZLIB
144 feed[0] = gzgetc(input);
145 feed[1] = gzgetc(input);
146 #else /* NOT USE_ZLIB */
147 feed[0] = fgetc(input);
148 feed[1] = fgetc(input);
149 #endif /* NOT USE_ZLIB */
151 buf = (u16*)&feed;
153 *output = *buf;
155 return 0;
158 /* returns 0 on success and puts the data in *output
159 * 1 on error dont touch output
161 static int
162 fpdata32(nFILE *input, u32 *output)
164 /* register int feed; */
165 u8 feed[4];
166 u32 *buf;
169 if (input == NULL || output == NULL)
170 return 1;
172 #if USE_ZLIB
173 feed[0] = gzgetc(input);
174 feed[1] = gzgetc(input);
175 feed[2] = gzgetc(input);
176 feed[3] = gzgetc(input);
177 #else /* NOT USE_ZLIB */
178 feed[0] = fgetc(input);
179 feed[1] = fgetc(input);
180 feed[2] = fgetc(input);
181 feed[3] = fgetc(input);
182 #endif /* NOT USE_ZLIB */
184 buf = (u32*)&feed;
186 *output = *buf;
188 return 0;
191 static BITMAP_HDATA *
192 parse_bitmap_header(nFILE *input)
194 BITMAP_HDATA *buf;
195 BITMAP_INFOHEADER *tmp;
197 if (input == NULL)
198 return NULL;
200 buf = calloc(1, sizeof(BITMAP_HDATA));
202 tmp = &buf->infoheader;
204 fpdata16(input, &buf->header.type);
205 fpdata32(input, &buf->header.size);
206 fpdata16(input, &buf->header.reserved1);
207 fpdata16(input, &buf->header.reserved2);
208 fpdata32(input, &buf->header.offset);
210 fpdata32(input, &tmp->size);
211 fpdata32(input, (u32*)&tmp->width);
212 fpdata32(input, (u32*)&tmp->height);
213 fpdata16(input, &tmp->planes);
214 fpdata16(input, &tmp->bits);
215 fpdata32(input, &tmp->compression);
216 fpdata32(input, &tmp->imagesize);
217 fpdata32(input, (u32*)&tmp->xresolution);
218 fpdata32(input, (u32*)&tmp->yresolution);
219 fpdata32(input, &tmp->ncolors);
220 fpdata32(input, &tmp->importantcolours);
222 return buf;
225 /* the magic number will probably not show correctly if big endian */
226 static void
227 print_bitmap_infos(BITMAP_HDATA *bmap)
229 printf("[%c%c] header data :\nsize %d\noffset %d\ninfoheader data :\nsize %d\nwidth %d\nheight %d\nplanes %d\nbits %d\ncompression %d\nimagesize %d\nxres %d\nyres %d\nncolors %d\nimportantcolors %d\n",
230 bmap->header.type & 0x00FF,
231 (bmap->header.type & 0xFF00) >> 8,
232 bmap->header.size,
233 bmap->header.offset,
234 bmap->infoheader.size,
235 bmap->infoheader.width,
236 bmap->infoheader.height,
237 bmap->infoheader.planes,
238 bmap->infoheader.bits,
239 bmap->infoheader.compression,
240 bmap->infoheader.imagesize,
241 bmap->infoheader.xresolution,
242 bmap->infoheader.yresolution,
243 bmap->infoheader.ncolors,
244 bmap->infoheader.importantcolours);
248 static void
249 process_palette(nFILE *input, BITMAP_HDATA *bmap, EBUF *bcolors)
251 u32 i = 0;
252 BITMAP_COLOR *buf;
254 while (i < bmap->infoheader.ncolors)
256 Neuro_AllocEBuf(bcolors, sizeof(BITMAP_COLOR*), sizeof(BITMAP_COLOR));
258 buf = Neuro_GiveCurEBuf(bcolors);
260 /*buf->r = palette[(i * 4) + 2];
261 buf->g = palette[(i * 4) + 1];
262 buf->b = palette[(i * 4)];
266 fpdata8(input, &buf->b);
267 fpdata8(input, &buf->g);
268 fpdata8(input, &buf->r);
269 fpdata8(input, &buf->a);
271 #if USE_ZLIB
272 buf->b = gzgetc(input);
273 buf->g = gzgetc(input);
274 buf->r = gzgetc(input);
276 /* I leave this just in case */
277 /* buf->a = fgetc(input); */
279 /* skip the alpha color */
280 gzgetc(input);
281 #else /* NOT USE_ZLIB */
282 buf->b = fgetc(input);
283 buf->g = fgetc(input);
284 buf->r = fgetc(input);
286 /* I leave this just in case */
287 /* buf->a = fgetc(input); */
289 /* skip the alpha color */
290 fgetc(input);
291 #endif /* NOT USE_ZLIB */
292 i++;
296 /* input the bits per pixel of the image
297 * input a 1 byte of data to process
299 static void
300 process_bitmap2(BITMAP_HDATA *bmap, v_object *image, u8 *palette, u8 *data, EBUF *bcolors, u32 *x, u32 *y, int *aux, char **buf)
303 /* we will call functions depending on the bpp of the image */
304 switch (bmap->infoheader.bits)
306 case 1:
308 /* will do a loop to get each 8 pixels from the data */
310 /* this is pretty much for little endian
311 * the minimum data size we can have for a certain width is
312 * 32 bits (4 bytes increments). Those 32 bits will be able
313 * to hold up to 32 pixels. In case the width is higher than
314 * 32 pixels, it will put 32 bits until the whole width
315 * can be fulfilled.
317 /* we will need to have the width value because we will need
318 * to know how many bits we have to read from 32 bits (4 bytes).
320 /* aux will keep how many 32 bits still need to be done in a
321 * certain width
323 u8 temp;
324 /* double calc = 0; */
326 /* u8 r, g, b; */
328 const u8 values[8] = {
329 0x80,
330 0x40,
331 0x20,
332 0x10,
333 0x08,
334 0x04,
335 0x02,
336 0x01
338 u32 i = 0;
339 u32 max = 0;
341 if (*buf == NULL)
343 *buf = calloc(1, sizeof(char));
344 **buf = 0;
345 *aux = 0;
348 /* set up aux for remaining pixels */
349 if (*aux == 0)
350 *aux = bmap->infoheader.width;
352 /* set up the number of pixels we need to process in this cycle */
353 if (*aux > 8)
355 max = 8;
356 *aux = *aux - 8;
358 else
360 max = *aux;
361 *aux = 0;
364 temp = *data;
366 while (i < max)
368 BITMAP_COLOR *cbuf = NULL;
370 if (IsLittleEndian())
371 temp = *data & values[i];
372 else
373 temp = *data & values[7 - i];
376 if (temp)
377 temp = 1;
379 cbuf = Neuro_GiveEBuf(bcolors, temp);
381 Neuro_PutPixel(image, *x, (bmap->infoheader.height - 1) - *y, Neuro_MapRGB(cbuf->r, cbuf->g, cbuf->b));
383 *x = *x + 1;
384 i++;
387 if (*x > bmap->infoheader.width - 1)
389 *x = 0;
390 *y = *y + 1;
393 break;
395 case 4:
397 /* will do a loop to get each 2 pixels from the data */
398 u8 temp;
399 /* double calc = 0; */
401 /* u8 r, g, b; */
403 const u8 values[2] = {
404 0xF0,
405 0x0F,
407 u32 i = 0;
408 u32 max = 0;
410 if (*buf == NULL)
412 *buf = calloc(1, sizeof(char));
413 **buf = 0;
414 *aux = 0;
417 /* set up aux for remaining pixels */
418 if (*aux == 0)
419 *aux = bmap->infoheader.width;
421 /* set up the number of pixels we need to process in this cycle */
422 if (*aux > 2)
424 max = 2;
425 *aux = *aux - 2;
427 else
429 max = *aux;
430 *aux = 0;
433 temp = *data;
435 while (i < max)
437 BITMAP_COLOR *cbuf = NULL;
439 if (IsLittleEndian())
441 temp = *data & values[i];
443 if (temp > values[1])
444 temp >>= 4;
446 else
448 temp = *data & values[1 - i];
450 if (temp > values[0])
451 temp <<= 4;
454 cbuf = Neuro_GiveEBuf(bcolors, temp);
456 Neuro_PutPixel(image, *x, (bmap->infoheader.height - 1) - *y, Neuro_MapRGB(cbuf->r, cbuf->g, cbuf->b));
458 *x = *x + 1;
459 i++;
462 if (*x > bmap->infoheader.width - 1)
464 *x = 0;
465 *y = *y + 1;
469 break;
471 case 8:
473 /* will get the single pixel from the data */
474 u8 temp;
475 /* double calc = 0; */
477 /* u8 r, g, b; */
479 u32 i = 0;
480 u32 max = 0;
482 if (*buf == NULL)
484 *buf = calloc(1, sizeof(char));
485 **buf = 0;
486 *aux = 0;
489 /* set up aux for remaining pixels */
490 if (*aux == 0)
491 *aux = bmap->infoheader.width;
493 /* set up the number of pixels we need to process in this cycle */
494 if (*aux > 1)
496 max = 1;
497 *aux = *aux - 1;
499 else
501 max = *aux;
502 *aux = 0;
505 temp = *data;
507 while (i < max)
509 BITMAP_COLOR *cbuf = NULL;
510 temp = *data;
513 cbuf = Neuro_GiveEBuf(bcolors, temp);
515 Neuro_PutPixel(image, *x, (bmap->infoheader.height - 1) - *y, Neuro_MapRGB(cbuf->r, cbuf->g, cbuf->b));
517 *x = *x + 1;
518 i++;
521 if (*x > bmap->infoheader.width - 1)
523 *x = 0;
524 *y = *y + 1;
528 break;
530 case 16:
532 /* we do not support 16 bit because I think they
533 * use 24 bit for those. we'll see through use.
534 * if not, I really think this depth is pointless...
537 break;
539 case 24:
541 /* will need to gather the data for 2 other bytes to get a
542 * single pixel. We will use the auxiliary variable to keep
543 * track of where we are at in the gathering.
546 if (!*buf)
548 *buf = calloc(3, sizeof(u8));
549 *aux = 0;
552 (*buf)[*aux] = *data;
553 *aux = *aux + 1;
555 if (*aux >= 3)
557 *aux = 0;
559 Neuro_PutPixel(image, *x, (bmap->infoheader.height - 1) - *y, Neuro_MapRGB((*buf)[2], (*buf)[1], (*buf)[0]));
561 *x = *x + 1;
564 if (*x > bmap->infoheader.width - 1)
566 *x = 0;
567 *y = *y + 1;
570 break;
572 case 32:
574 /* we do not support 32 bit because it is Very uncommon if it
575 * actually exist. Pretty much the same as 16 bpp.
578 break;
580 default:
582 /* an error occured */
584 break;
589 static v_object *
590 processFD_BMP(nFILE *f_bitmap)
592 /* major (buffers) */
593 EBUF *bmap_colors = NULL; /* the colors */
594 u8 *buf = NULL; /* the buffer that will contain the content of the file */
596 /* minor (mostly pointers and temporary variables) */
597 register i32 i = 0; /* incremental variable */
598 u32 skip_i = 0, x = 0, y = 0;
600 u32 psize = 0; /* the full size of the pixels data */
601 u8 *palette = NULL; /* the pointer to the palette if theres one */
602 BITMAP_HDATA *bmap; /* this is how we will get informations about the bitmap */
603 int aux_var = 0; /* auxiliary variable that can be used by external functions */
604 char *aux_buf = NULL; /* same as aux_var but a buffer */
605 double msize = 0;
606 double calc = 0;
607 double tmp = 0;
608 u32 wmult = 0;
609 double pixellen = 0;
610 u32 increm = 0;
611 u8 DATA;
612 v_object *output; /* the image into which we will load the bitmap */
614 if (f_bitmap == NULL)
615 return NULL;
617 bmap = parse_bitmap_header(f_bitmap);
619 /* TODO TODO XXX check here if the bitmap is valid or not
620 * first check for the BM word
621 * then we check for the size of the file in header and size
622 * we got when reading the file
628 /* if it is valid, we create the buffers */
629 Neuro_CreateEBuf(&bmap_colors);
630 Neuro_SetcallbEBuf(bmap_colors, &clean_bmap_color);
633 /* print_bitmap_infos(bmap); */
635 /* process the bitmap(load it in memory) */
636 i = 0;
637 psize = bmap->header.size - (sizeof(BITMAP_HEADER) + sizeof(BITMAP_INFOHEADER));
638 psize = psize - (bmap->infoheader.ncolors * 4);
639 /* printf("data size %d\n", psize); */
641 if (bmap->infoheader.ncolors)
643 process_palette(f_bitmap, bmap, bmap_colors);
646 /* we create the v_object
648 * will need to put better values for the masks to support SDL.
651 u32 rmask = 0, gmask = 0, bmask = 0, amask = 0;
653 if (IsLittleEndian())
655 switch (Lib_GetDefaultDepth())
657 case 16:
659 rmask = 0x0000f800;
660 gmask = 0x000007e0;
661 bmask = 0x0000001f;
662 amask = 0x00000000;
664 break;
666 case 24:
668 rmask = 0x00ff0000;
669 gmask = 0x0000ff00;
670 bmask = 0x000000ff;
671 amask = 0x00000000;
673 break;
676 default:
677 break;
680 else
682 switch (Lib_GetDefaultDepth())
684 case 16:
686 rmask = 0x0000001f;
687 gmask = 0x000007e0;
688 bmask = 0x0000f800;
689 amask = 0x00000000;
691 break;
693 case 24:
695 rmask = 0x0000ff00;
696 gmask = 0x00ff0000;
697 bmask = 0xff000000;
698 amask = 0x00000000;
700 break;
702 default:
703 break;
707 if (IsLittleEndian())
709 rmask = 0x0000f800;
710 gmask = 0x000007e0;
711 bmask = 0x0000001f;
712 amask = 0x00000000;
714 else
716 rmask = 0x0000001f;
717 gmask = 0x000007e0;
718 bmask = 0x0000f800;
719 amask = 0x00000000;
723 output = Neuro_CreateVObject(0, bmap->infoheader.width, bmap->infoheader.height, bmap->infoheader.bits, rmask, gmask, bmask, amask);
725 if (output == NULL)
726 return NULL;
729 /* semi static values to skip bytes that form 32 bit chunks in the data */
731 pixellen = (8 / (double)bmap->infoheader.bits);
732 msize = pixellen * 4;
734 /* we calculate the number of bytes there is per rows
735 * this is mainly so we can know how much "alignment"
736 * bytes there is (which need to be skipped)
739 wmult = (u32)bmap->infoheader.bits / 8;
741 if (wmult == 0)
742 wmult++;
744 wmult = wmult * bmap->infoheader.width;
747 increm = (u32)pixellen;
749 if (increm == 0)
750 increm++;
752 x = (u32)(bmap->infoheader.width / msize);
753 tmp = msize * x;
754 tmp = (double)bmap->infoheader.width - tmp;
755 tmp = tmp - 0.000001; /* to avoid bugs */
757 x = 0;
758 #if USE_ZLIB
759 gzseek(f_bitmap, bmap->header.offset, SEEK_SET);
760 #else /* NOT USE_ZLIB */
761 fseek(f_bitmap, bmap->header.offset, SEEK_SET);
762 #endif /* NOT USE_ZLIB */
764 Lib_LockVObject(output);
766 /* Debug_Val(0, "Image bits depth %d tmp %f\n", bmap->infoheader.bits, tmp); */
768 while (i < psize)
770 if (tmp > 0)
772 /* skip bytes that are inside the bitmap for
773 * filling purpose. (the data is purposely filled
774 * with 0 bits so the data is 32bits aligned)
776 if (skip_i >= wmult)
778 calc = tmp / pixellen;
779 skip_i = (u32)calc;
780 if (skip_i < calc)
782 skip_i++;
784 skip_i = (4 - skip_i);
785 i += skip_i;
787 #if USE_ZLIB
788 gzseek(f_bitmap, bmap->header.offset + i, SEEK_SET);
789 #else /* NOT USE_ZLIB */
790 fseek(f_bitmap, bmap->header.offset + i, SEEK_SET);
791 #endif /* NOT USE_ZLIB */
794 printf("skipping %d bytes wmult %d width %d tmp %f plen %f calc %f\n",
795 skip_i,
796 wmult,
797 bmap->infoheader.width,
798 tmp,
799 pixellen, calc);
802 skip_i = 0;
805 skip_i += increm;
807 if (i >= psize)
808 break;
812 fpdata8(f_bitmap, &DATA);
814 process_bitmap2(bmap, output, palette, &DATA,
815 bmap_colors, &x, &y, &aux_var, &aux_buf);
818 /* process_bitmap2(bmap, output, palette, &DATA,
819 bmap_colors, x, y, &aux_var, &aux_buf); */
822 /* printf("i %d psize %d\n", i, psize); */
823 /* Debug_Val(0, "current coord : %d,%d %d\n", x, y, wmult); */
825 if (tmp <= 0)
827 static u8 t = 2;
829 if (t == 0 || x > bmap->infoheader.width - 1)
831 if (x < bmap->infoheader.width - 1)
832 x++;
833 else
835 x = 0;
836 y++;
839 t = 2;
841 else
842 t--;
846 i++;
849 Lib_UnlockVObject(output);
851 if (bmap)
852 free(bmap);
853 if (buf)
854 free(buf);
855 if (aux_buf)
856 free(aux_buf);
858 Neuro_CleanEBuf(&bmap_colors);
860 #if USE_ZLIB
861 if (f_bitmap)
862 gzclose(f_bitmap);
863 #else /* NOT USE_ZLIB */
864 if (f_bitmap)
865 fclose(f_bitmap);
866 #endif /* NOT USE_ZLIB */
868 return output;
871 /* Global functions */
873 void
874 cleanPixmapEbuf(EBUF **pixmap)
876 Neuro_CleanEBuf(pixmap);
879 void
880 setBitmapColorKey(u32 key)
882 color_key = key;
885 void
886 readBitmapBufferToPixmap(char *data, EBUF **output_pixmap)
890 void
891 readBitmapFileToPixmap(const char *bitmap, EBUF **output_pixmap)
895 v_object *
896 readBitmapFile(const char *bitmap)
898 nFILE *f_bitmap;
900 #if USE_ZLIB
901 f_bitmap = gzopen(bitmap, "r"); /* can also be used for non compressed files */
902 #else /* NOT USE_ZLIB */
903 f_bitmap = fopen(bitmap, "r");
904 #endif /* NOT USE_ZLIB */
906 return processFD_BMP(f_bitmap);