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
25 * bitmap process module
28 /* the package's main config file */
31 /*-------------------- Extern Headers Including --------------------*/
38 /* this is used to open the bitmaps,
39 * the beauty of this is it works
40 * for compressed and uncompressed
41 * transparently, meaning no extra code
46 #else /* NOT USE_ZLIB */
50 /*-------------------- Local Headers Including ---------------------*/
54 #include <extlib.h> /* Lib_GetDefaultDepth() */
56 #include <graphics.h> /* Neuro_PutPixel */
58 /*-------------------- Main Module Header --------------------------*/
61 /*-------------------- Other ----------------------------*/
63 NEURO_MODULE_CHANNEL("bitmap");
65 typedef struct BITMAP_HEADER
67 u16 type
__attribute__((packed
)); /* Magic identifier */
68 u32 size
__attribute__((packed
)); /* File size in bytes */
69 u16 reserved1
, reserved2
; /* reserved */
70 u32 offset
__attribute__((packed
)); /* Offset to image data, bytes */
73 typedef struct BITMAP_INFOHEADER
75 u32 size
; /* Header size in bytes */
76 i32 width
, height
; /* Width and height of image */
77 u16 planes
; /* Number of colour planes */
78 u16 bits
; /* Bits per pixel */
79 u32 compression
; /* Compression type */
80 u32 imagesize
; /* Image size in bytes */
81 i32 xresolution
, yresolution
; /* Pixels per meter */
82 u32 ncolors
; /* Number of colours */
83 u32 importantcolours
; /* Important colours */
86 typedef struct BITMAP_HDATA
88 BITMAP_HEADER header
__attribute__((packed
));
89 BITMAP_INFOHEADER infoheader
__attribute__((packed
));
92 typedef struct BITMAP_COLOR
94 u8 r
, g
, b
/*, a*/ ; /* red green blue */
97 typedef struct BITMAP_MAP
106 /* major (buffers) */
107 EBUF
*bmap_colors
; /* the colors */
108 u8
*buf
; /* the buffer that will contain the content of the file */
110 /* minor (mostly pointers and temporary variables) */
111 i32 i
; /* incremental variable */
114 u32 psize
; /* the full size of the pixels data */
115 u8
*palette
; /* the pointer to the palette if theres one */
116 BITMAP_HDATA
*bmap
; /* this is how we will get informations about the bitmap */
117 int aux_var
; /* auxiliary variable that can be used by external functions */
118 char *aux_buf
; /* same as aux_var but a buffer */
126 v_object
*output
; /* the image into which we will load the bitmap */
127 u32 cut_size
; /* amount of bytes to load per cycles */
131 /*-------------------- Global Variables ----------------------------*/
133 /*-------------------- Static Variables ----------------------------*/
135 /*-------------------- Static Prototypes ---------------------------*/
137 static void print_bitmap_infos(BITMAP_HDATA
*bmap
) __attribute__((unused
));
138 static int fpdata8(nFILE
*input
, u8
*output
) __attribute__((unused
));
139 static int fpdata16(nFILE
*input
, u16
*output
) __attribute__((unused
));
140 static int fpdata32(nFILE
*input
, u32
*output
) __attribute__((unused
));
143 /*-------------------- Static Functions ----------------------------*/
146 clean_bmap_color(void *eng
)
150 buf
= (BITMAP_COLOR
*)eng
;
154 /* returns 0 on success and puts the data in *output
155 * 1 on error dont touch output
158 fpdata8(nFILE
*input
, u8
*output
)
160 if (input
== NULL
|| output
== NULL
)
163 *output
= gzgetc(input
);
164 #else /* NOT USE_ZLIB */
165 *output
= fgetc(input
);
166 #endif /* NOT USE_ZLIB */
172 /* returns 0 on success and puts the data in *output
173 * 1 on error dont touch output
176 fpdata16(nFILE
*input
, u16
*output
)
181 if (input
== NULL
|| output
== NULL
)
184 if (IsLittleEndian())
187 feed
[0] = gzgetc(input
);
188 feed
[1] = gzgetc(input
);
189 #else /* NOT USE_ZLIB */
190 feed
[0] = fgetc(input
);
191 feed
[1] = fgetc(input
);
192 #endif /* NOT USE_ZLIB */
196 feed
[1] = gzgetc(input
);
197 feed
[0] = gzgetc(input
);
207 /* returns 0 on success and puts the data in *output
208 * 1 on error dont touch output
211 fpdata32(nFILE
*input
, u32
*output
)
213 /* register int feed; */
218 if (input
== NULL
|| output
== NULL
)
221 if (IsLittleEndian())
224 feed
[0] = gzgetc(input
);
225 feed
[1] = gzgetc(input
);
226 feed
[2] = gzgetc(input
);
227 feed
[3] = gzgetc(input
);
228 #else /* NOT USE_ZLIB */
229 feed
[0] = fgetc(input
);
230 feed
[1] = fgetc(input
);
231 feed
[2] = fgetc(input
);
232 feed
[3] = fgetc(input
);
233 #endif /* NOT USE_ZLIB */
237 feed
[3] = gzgetc(input
);
238 feed
[2] = gzgetc(input
);
239 feed
[1] = gzgetc(input
);
240 feed
[0] = gzgetc(input
);
250 static BITMAP_HDATA
*
251 parse_bitmap_header(nFILE
*input
)
254 BITMAP_INFOHEADER
*tmp
;
259 buf
= calloc(1, sizeof(BITMAP_HDATA
));
261 tmp
= &buf
->infoheader
;
263 fpdata16(input
, &buf
->header
.type
);
264 fpdata32(input
, &buf
->header
.size
);
265 fpdata16(input
, &buf
->header
.reserved1
);
266 fpdata16(input
, &buf
->header
.reserved2
);
267 fpdata32(input
, &buf
->header
.offset
);
269 fpdata32(input
, &tmp
->size
);
270 fpdata32(input
, (u32
*)&tmp
->width
);
271 fpdata32(input
, (u32
*)&tmp
->height
);
272 fpdata16(input
, &tmp
->planes
);
273 fpdata16(input
, &tmp
->bits
);
274 fpdata32(input
, &tmp
->compression
);
275 fpdata32(input
, &tmp
->imagesize
);
276 fpdata32(input
, (u32
*)&tmp
->xresolution
);
277 fpdata32(input
, (u32
*)&tmp
->yresolution
);
278 fpdata32(input
, &tmp
->ncolors
);
279 fpdata32(input
, &tmp
->importantcolours
);
284 /* the magic number will probably not show correctly if big endian */
286 print_bitmap_infos(BITMAP_HDATA
*bmap
)
288 printf("(0x%x)[%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",
290 bmap
->header
.type
& 0x00FF,
291 (bmap
->header
.type
& 0xFF00) >> 8,
294 bmap
->infoheader
.size
,
295 bmap
->infoheader
.width
,
296 bmap
->infoheader
.height
,
297 bmap
->infoheader
.planes
,
298 bmap
->infoheader
.bits
,
299 bmap
->infoheader
.compression
,
300 bmap
->infoheader
.imagesize
,
301 bmap
->infoheader
.xresolution
,
302 bmap
->infoheader
.yresolution
,
303 bmap
->infoheader
.ncolors
,
304 bmap
->infoheader
.importantcolours
);
309 process_palette(nFILE
*input
, BITMAP_HDATA
*bmap
, EBUF
*bcolors
)
314 while (i
< bmap
->infoheader
.ncolors
)
316 Neuro_AllocEBuf(bcolors
, sizeof(BITMAP_COLOR
*), sizeof(BITMAP_COLOR
));
318 buf
= Neuro_GiveCurEBuf(bcolors
);
320 /*buf->r = palette[(i * 4) + 2];
321 buf->g = palette[(i * 4) + 1];
322 buf->b = palette[(i * 4)];
326 fpdata8(input, &buf->b);
327 fpdata8(input, &buf->g);
328 fpdata8(input, &buf->r);
329 fpdata8(input, &buf->a);
332 buf
->b
= gzgetc(input
);
333 buf
->g
= gzgetc(input
);
334 buf
->r
= gzgetc(input
);
336 /* I leave this just in case */
337 /* buf->a = fgetc(input); */
339 /* skip the alpha color */
341 #else /* NOT USE_ZLIB */
342 buf
->b
= fgetc(input
);
343 buf
->g
= fgetc(input
);
344 buf
->r
= fgetc(input
);
346 /* I leave this just in case */
347 /* buf->a = fgetc(input); */
349 /* skip the alpha color */
351 #endif /* NOT USE_ZLIB */
356 /* input the bits per pixel of the image
357 * input a 1 byte of data to process
360 process_bitmap(BITMAP_HDATA
*bmap
, v_object
*image
, u8
*palette
, u8
*data
, EBUF
*bcolors
, u32
*x
, u32
*y
, int *aux
, char **buf
)
363 /* we will call functions depending on the bpp of the image */
364 switch (bmap
->infoheader
.bits
)
368 /* will do a loop to get each 8 pixels from the data */
370 /* this is pretty much for little endian
371 * the minimum data size we can have for a certain width is
372 * 32 bits (4 bytes increments). Those 32 bits will be able
373 * to hold up to 32 pixels. In case the width is higher than
374 * 32 pixels, it will put 32 bits until the whole width
377 /* we will need to have the width value because we will need
378 * to know how many bits we have to read from 32 bits (4 bytes).
380 /* aux will keep how many 32 bits still need to be done in a
384 /* double calc = 0; */
388 const u8 values
[8] = {
403 *buf
= calloc(1, sizeof(char));
408 /* set up aux for remaining pixels */
410 *aux
= bmap
->infoheader
.width
;
412 /* set up the number of pixels we need to process in this cycle */
428 BITMAP_COLOR
*cbuf
= NULL
;
430 temp
= *data
& values
[i
];
436 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
438 if (IsLittleEndian())
439 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
441 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->b
, cbuf
->g
, cbuf
->r
));
447 if (*x
> bmap
->infoheader
.width
- 1)
457 /* will do a loop to get each 2 pixels from the data */
459 /* double calc = 0; */
463 const u8 values
[2] = {
472 *buf
= calloc(1, sizeof(char));
477 /* set up aux for remaining pixels */
479 *aux
= bmap
->infoheader
.width
;
481 /* set up the number of pixels we need to process in this cycle */
497 BITMAP_COLOR
*cbuf
= NULL
;
499 temp
= *data
& values
[i
];
500 if (IsLittleEndian())
502 if (temp
> values
[1])
507 if (temp
> values
[1])
511 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
513 if (IsLittleEndian())
514 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
516 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->b
, cbuf
->g
, cbuf
->r
));
523 if (*x
> bmap
->infoheader
.width
- 1)
534 /* will get the single pixel from the data */
536 /* double calc = 0; */
545 *buf
= calloc(1, sizeof(char));
550 /* set up aux for remaining pixels */
552 *aux
= bmap
->infoheader
.width
;
554 /* set up the number of pixels we need to process in this cycle */
570 BITMAP_COLOR
*cbuf
= NULL
;
574 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
576 if (IsLittleEndian())
577 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
579 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->b
, cbuf
->g
, cbuf
->r
));
585 if (*x
> bmap
->infoheader
.width
- 1)
596 /* we do not support 16 bit because I think they
597 * use 24 bit for those. we'll see through use.
598 * if not, I really think this depth is pointless...
605 /* will need to gather the data for 2 other bytes to get a
606 * single pixel. We will use the auxiliary variable to keep
607 * track of where we are at in the gathering.
612 *buf
= calloc(3, sizeof(u8
));
616 (*buf
)[*aux
] = *data
;
623 if (bmap
->infoheader
.height
== *y
)
625 NEURO_ERROR("attempted to draw an invalid location", NULL
);
629 if (IsLittleEndian())
630 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB((*buf
)[2], (*buf
)[1], (*buf
)[0]));
632 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB((*buf
)[0], (*buf
)[1], (*buf
)[2]));
637 if (*x
> bmap
->infoheader
.width
- 1)
647 /* we do not support 32 bit because it is Very uncommon if it
648 * actually exist. Pretty much the same as 16 bpp.
655 /* an error occured */
662 /* ctx being the bitmap loading context
663 * and loops being how many times the
664 * external function wants this function
665 * to load bytes from the image file.
668 processGradual_BMP(BMP_CTX
*ctx
, u32 loops
)
672 NEURO_WARN("argument ctx is NULL", NULL
);
676 if (ctx
->f_bitmap
== NULL
)
678 NEURO_WARN("bitmap file descriptor is NULL", NULL
);
685 /* When the variable ctx->i equals 0, we
686 * initialise the buffers and prepare all the
687 * variables that will be used to load the
690 * this part of the code should only be ran
691 * once for each bitmaps.
694 ctx
->bmap
= parse_bitmap_header(ctx
->f_bitmap
);
696 /* we do consistency checks of the image to
697 * see if it is really a bitmap.
700 /* print_bitmap_infos(ctx->bmap); */
702 if (ctx
->bmap
->header
.type
!= 0x4d42)
704 NEURO_WARN("Invalid bitmap file magic %d", ctx
->bmap
->header
.type
);
709 /* if it is valid, we create the buffers */
710 Neuro_CreateEBuf(&ctx
->bmap_colors
);
711 Neuro_SetcallbEBuf(ctx
->bmap_colors
, &clean_bmap_color
);
714 /* print_bitmap_infos(bmap); */
716 /* we set the variable psize to the size that
717 * the image data is minus the actual header size.
719 * it will be used to see when the function finished
723 ctx
->psize
= ctx
->bmap
->header
.size
- (sizeof(BITMAP_HEADER
) + sizeof(BITMAP_INFOHEADER
));
724 ctx
->psize
= ctx
->psize
- (ctx
->bmap
->infoheader
.ncolors
* 4);
726 /* printf("data size %d\n", psize); */
728 /* we load the palette, if any */
729 if (ctx
->bmap
->infoheader
.ncolors
> 0)
731 process_palette(ctx
->f_bitmap
, ctx
->bmap
, ctx
->bmap_colors
);
734 /* we create the v_object which is the libneuro
735 * representation of the image.
739 /* Debug_Val(0, "image creation -- depth %d\n", ctx->bmap->infoheader.bits); */
740 /*ctx->output = Neuro_CreateVObject(0, ctx->bmap->infoheader.width, ctx->bmap->infoheader.height, ctx->bmap->infoheader.bits, rmask, gmask, bmask, amask);*/
741 ctx
->output
= Neuro_CreateVObject(0, ctx
->bmap
->infoheader
.width
, ctx
->bmap
->infoheader
.height
, ctx
->bmap
->infoheader
.bits
, 0, 0, 0, 0);
744 if (ctx
->output
== NULL
)
746 NEURO_WARN("Created output v_object is NULL", NULL
);
751 /* semi static values to skip bytes that form 32 bit chunks in the data */
753 ctx
->pixellen
= (8 / (double)ctx
->bmap
->infoheader
.bits
);
754 ctx
->msize
= ctx
->pixellen
* 4;
756 /* we calculate the number of bytes there is per rows
757 * this is mainly so we can know how much "alignment"
758 * bytes there is (which need to be skipped)
761 ctx
->wmult
= (u32
)ctx
->bmap
->infoheader
.bits
/ 8;
766 ctx
->wmult
= ctx
->wmult
* ctx
->bmap
->infoheader
.width
;
769 ctx
->increm
= (u32
)ctx
->pixellen
;
771 if (ctx
->increm
== 0)
774 ctx
->x
= (u32
)(ctx
->bmap
->infoheader
.width
/ ctx
->msize
);
775 ctx
->tmp
= ctx
->msize
* ctx
->x
;
776 ctx
->tmp
= (double)ctx
->bmap
->infoheader
.width
- ctx
->tmp
;
777 ctx
->tmp
= ctx
->tmp
- 0.000001; /* to avoid bugs */
781 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
782 #else /* NOT USE_ZLIB */
783 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
784 #endif /* NOT USE_ZLIB */
786 NEURO_WARN("Bitmap size %d", ctx
->psize
);
787 Debug_Val(0, "Bitmap size %d\n", ctx
->psize
);
789 ctx
->cut_size
= ctx
->psize
/ 30;
791 loops
= ctx
->cut_size
;
793 /* we lock the surface */
794 Lib_LockVObject(ctx
->output
);
798 /* this part of the function takes
799 * care of the actual loading of the
802 i32 initial
= ctx
->i
;
804 /* while (ctx->i < ctx->psize) */
805 while (ctx
->i
< (initial
+ loops
))
807 if (ctx
->i
> ctx
->psize
)
812 /* skip bytes that are inside the bitmap for
813 * filling purpose. (the data is purposely filled
814 * with 0 bits so the data is 32bits aligned)
816 if (ctx
->skip_i
>= ctx
->wmult
)
818 ctx
->calc
= ctx
->tmp
/ ctx
->pixellen
;
819 ctx
->skip_i
= (u32
)ctx
->calc
;
820 if (ctx
->skip_i
< ctx
->calc
)
824 ctx
->skip_i
= (4 - ctx
->skip_i
);
825 ctx
->i
+= ctx
->skip_i
;
828 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
829 #else /* NOT USE_ZLIB */
830 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
831 #endif /* NOT USE_ZLIB */
834 printf("skipping %d bytes wmult %d width %d tmp %f plen %f calc %f\n",
837 bmap->infoheader.width,
845 ctx
->skip_i
+= ctx
->increm
;
847 if (ctx
->i
>= ctx
->psize
)
851 /* we fetch 8 bits from the file stream */
852 fpdata8(ctx
->f_bitmap
, &ctx
->DATA
);
854 /* we push the 8 bits along with various other
855 * variables to the bits processor.
858 process_bitmap(ctx
->bmap
, ctx
->output
, ctx
->palette
, &ctx
->DATA
,
859 ctx
->bmap_colors
, &ctx
->x
, &ctx
->y
, &ctx
->aux_var
, &ctx
->aux_buf
);
865 if (ctx
->i
>= ctx
->psize
)
866 { /* this bitmap finished being loaded, we free everything */
868 /* to prevent further calls to be processed */
878 Neuro_CleanEBuf(&ctx
->bmap_colors
);
882 gzclose(ctx
->f_bitmap
);
883 #else /* NOT USE_ZLIB */
885 fclose(ctx
->f_bitmap
);
886 #endif /* NOT USE_ZLIB */
888 /* we return 100% done */
892 /*Debug_Val(0, "((%d * 100) / %d) == %d\n",
894 (i8)((u32)((ctx->i * 100) / ctx->psize)));*/
896 /* we return the percentage of the file that
897 * is currently loaded.
899 return (i8
)((u32
)(ctx
->i
* 100) / ctx
->psize
);
902 /* this never happens unless the image was already loaded */
903 NEURO_WARN("Useless call of the function #%d", ctx
->i
);
907 /*-------------------- Global Functions ----------------------------*/
910 readBitmapFile(const char *bitmap
)
915 ctx
= Bitmap_CreateCTX(bitmap
);
919 NEURO_WARN("Context creation failed", NULL
);
925 _err
= Bitmap_Poll(ctx
);
932 NEURO_WARN("Poll failed...", NULL
);
936 /* printf("loading progress : %d\n", _err); */
939 return Bitmap_DestroyCTX(ctx
);
942 /*-------------------- Poll ----------------------------------------*/
944 /* returns a percentage of progress */
946 Bitmap_Poll(BMP_CTX
*ctx
)
948 return processGradual_BMP(ctx
, ctx
->cut_size
);
951 /*-------------------- Constructor Destructor ----------------------*/
954 Bitmap_CreateCTX(const char *path
)
958 output
= calloc(1, sizeof(BMP_CTX
));
963 output
->f_bitmap
= gzopen(path
, "r"); /* can also be used for non compressed files */
964 #else /* NOT USE_ZLIB */
965 output
->f_bitmap
= fopen(path
, "r");
966 #endif /* NOT USE_ZLIB */
968 if (output
->f_bitmap
== NULL
)
978 Bitmap_DestroyCTX(BMP_CTX
*ctx
)
980 v_object
*output
= NULL
;
985 /* loading the image is done so we unlock */
986 Lib_UnlockVObject(ctx
->output
);
988 output
= ctx
->output
;