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 ---------------------*/
53 #include <extlib.h> /* Lib_GetDefaultDepth() */
55 #include <graphics.h> /* Neuro_PutPixel */
57 /*-------------------- Main Module Header --------------------------*/
60 /*-------------------- Other ----------------------------*/
62 NEURO_MODULE_CHANNEL("bitmap");
64 typedef struct BITMAP_HEADER
66 u16 type
__attribute__((packed
)); /* Magic identifier */
67 u32 size
__attribute__((packed
)); /* File size in bytes */
68 u16 reserved1
, reserved2
; /* reserved */
69 u32 offset
__attribute__((packed
)); /* Offset to image data, bytes */
72 typedef struct BITMAP_INFOHEADER
74 u32 size
; /* Header size in bytes */
75 i32 width
, height
; /* Width and height of image */
76 u16 planes
; /* Number of colour planes */
77 u16 bits
; /* Bits per pixel */
78 u32 compression
; /* Compression type */
79 u32 imagesize
; /* Image size in bytes */
80 i32 xresolution
, yresolution
; /* Pixels per meter */
81 u32 ncolors
; /* Number of colours */
82 u32 importantcolours
; /* Important colours */
85 typedef struct BITMAP_HDATA
87 BITMAP_HEADER header
__attribute__((packed
));
88 BITMAP_INFOHEADER infoheader
__attribute__((packed
));
91 typedef struct BITMAP_COLOR
93 u8 r
, g
, b
/*, a*/ ; /* red green blue */
96 typedef struct BITMAP_MAP
105 /* major (buffers) */
106 EBUF
*bmap_colors
; /* the colors */
107 u8
*buf
; /* the buffer that will contain the content of the file */
109 /* minor (mostly pointers and temporary variables) */
110 i32 i
; /* incremental variable */
113 u32 psize
; /* the full size of the pixels data */
114 u8
*palette
; /* the pointer to the palette if theres one */
115 BITMAP_HDATA
*bmap
; /* this is how we will get informations about the bitmap */
116 int aux_var
; /* auxiliary variable that can be used by external functions */
117 char *aux_buf
; /* same as aux_var but a buffer */
125 v_object
*output
; /* the image into which we will load the bitmap */
129 /*-------------------- Global Variables ----------------------------*/
131 /*-------------------- Static Variables ----------------------------*/
133 /*-------------------- Static Prototypes ---------------------------*/
135 static void print_bitmap_infos(BITMAP_HDATA
*bmap
) __attribute__((unused
));
136 static int fpdata8(nFILE
*input
, u8
*output
) __attribute__((unused
));
137 static int fpdata16(nFILE
*input
, u16
*output
) __attribute__((unused
));
138 static int fpdata32(nFILE
*input
, u32
*output
) __attribute__((unused
));
141 /*-------------------- Static Functions ----------------------------*/
144 clean_bmap_color(void *eng
)
148 buf
= (BITMAP_COLOR
*)eng
;
152 /* returns 0 on success and puts the data in *output
153 * 1 on error dont touch output
156 fpdata8(nFILE
*input
, u8
*output
)
158 if (input
== NULL
|| output
== NULL
)
161 *output
= gzgetc(input
);
162 #else /* NOT USE_ZLIB */
163 *output
= fgetc(input
);
164 #endif /* NOT USE_ZLIB */
170 /* returns 0 on success and puts the data in *output
171 * 1 on error dont touch output
174 fpdata16(nFILE
*input
, u16
*output
)
179 if (input
== NULL
|| output
== NULL
)
183 feed
[0] = gzgetc(input
);
184 feed
[1] = gzgetc(input
);
185 #else /* NOT USE_ZLIB */
186 feed
[0] = fgetc(input
);
187 feed
[1] = fgetc(input
);
188 #endif /* NOT USE_ZLIB */
197 /* returns 0 on success and puts the data in *output
198 * 1 on error dont touch output
201 fpdata32(nFILE
*input
, u32
*output
)
203 /* register int feed; */
208 if (input
== NULL
|| output
== NULL
)
212 feed
[0] = gzgetc(input
);
213 feed
[1] = gzgetc(input
);
214 feed
[2] = gzgetc(input
);
215 feed
[3] = gzgetc(input
);
216 #else /* NOT USE_ZLIB */
217 feed
[0] = fgetc(input
);
218 feed
[1] = fgetc(input
);
219 feed
[2] = fgetc(input
);
220 feed
[3] = fgetc(input
);
221 #endif /* NOT USE_ZLIB */
230 static BITMAP_HDATA
*
231 parse_bitmap_header(nFILE
*input
)
234 BITMAP_INFOHEADER
*tmp
;
239 buf
= calloc(1, sizeof(BITMAP_HDATA
));
241 tmp
= &buf
->infoheader
;
243 fpdata16(input
, &buf
->header
.type
);
244 fpdata32(input
, &buf
->header
.size
);
245 fpdata16(input
, &buf
->header
.reserved1
);
246 fpdata16(input
, &buf
->header
.reserved2
);
247 fpdata32(input
, &buf
->header
.offset
);
249 fpdata32(input
, &tmp
->size
);
250 fpdata32(input
, (u32
*)&tmp
->width
);
251 fpdata32(input
, (u32
*)&tmp
->height
);
252 fpdata16(input
, &tmp
->planes
);
253 fpdata16(input
, &tmp
->bits
);
254 fpdata32(input
, &tmp
->compression
);
255 fpdata32(input
, &tmp
->imagesize
);
256 fpdata32(input
, (u32
*)&tmp
->xresolution
);
257 fpdata32(input
, (u32
*)&tmp
->yresolution
);
258 fpdata32(input
, &tmp
->ncolors
);
259 fpdata32(input
, &tmp
->importantcolours
);
264 /* the magic number will probably not show correctly if big endian */
266 print_bitmap_infos(BITMAP_HDATA
*bmap
)
268 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",
270 bmap
->header
.type
& 0x00FF,
271 (bmap
->header
.type
& 0xFF00) >> 8,
274 bmap
->infoheader
.size
,
275 bmap
->infoheader
.width
,
276 bmap
->infoheader
.height
,
277 bmap
->infoheader
.planes
,
278 bmap
->infoheader
.bits
,
279 bmap
->infoheader
.compression
,
280 bmap
->infoheader
.imagesize
,
281 bmap
->infoheader
.xresolution
,
282 bmap
->infoheader
.yresolution
,
283 bmap
->infoheader
.ncolors
,
284 bmap
->infoheader
.importantcolours
);
289 process_palette(nFILE
*input
, BITMAP_HDATA
*bmap
, EBUF
*bcolors
)
294 while (i
< bmap
->infoheader
.ncolors
)
296 Neuro_AllocEBuf(bcolors
, sizeof(BITMAP_COLOR
*), sizeof(BITMAP_COLOR
));
298 buf
= Neuro_GiveCurEBuf(bcolors
);
300 /*buf->r = palette[(i * 4) + 2];
301 buf->g = palette[(i * 4) + 1];
302 buf->b = palette[(i * 4)];
306 fpdata8(input, &buf->b);
307 fpdata8(input, &buf->g);
308 fpdata8(input, &buf->r);
309 fpdata8(input, &buf->a);
312 buf
->b
= gzgetc(input
);
313 buf
->g
= gzgetc(input
);
314 buf
->r
= gzgetc(input
);
316 /* I leave this just in case */
317 /* buf->a = fgetc(input); */
319 /* skip the alpha color */
321 #else /* NOT USE_ZLIB */
322 buf
->b
= fgetc(input
);
323 buf
->g
= fgetc(input
);
324 buf
->r
= fgetc(input
);
326 /* I leave this just in case */
327 /* buf->a = fgetc(input); */
329 /* skip the alpha color */
331 #endif /* NOT USE_ZLIB */
336 /* input the bits per pixel of the image
337 * input a 1 byte of data to process
340 process_bitmap2(BITMAP_HDATA
*bmap
, v_object
*image
, u8
*palette
, u8
*data
, EBUF
*bcolors
, u32
*x
, u32
*y
, int *aux
, char **buf
)
343 /* we will call functions depending on the bpp of the image */
344 switch (bmap
->infoheader
.bits
)
348 /* will do a loop to get each 8 pixels from the data */
350 /* this is pretty much for little endian
351 * the minimum data size we can have for a certain width is
352 * 32 bits (4 bytes increments). Those 32 bits will be able
353 * to hold up to 32 pixels. In case the width is higher than
354 * 32 pixels, it will put 32 bits until the whole width
357 /* we will need to have the width value because we will need
358 * to know how many bits we have to read from 32 bits (4 bytes).
360 /* aux will keep how many 32 bits still need to be done in a
364 /* double calc = 0; */
368 const u8 values
[8] = {
383 *buf
= calloc(1, sizeof(char));
388 /* set up aux for remaining pixels */
390 *aux
= bmap
->infoheader
.width
;
392 /* set up the number of pixels we need to process in this cycle */
408 BITMAP_COLOR
*cbuf
= NULL
;
410 if (IsLittleEndian())
411 temp
= *data
& values
[i
];
413 temp
= *data
& values
[7 - i
];
419 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
421 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
427 if (*x
> bmap
->infoheader
.width
- 1)
437 /* will do a loop to get each 2 pixels from the data */
439 /* double calc = 0; */
443 const u8 values
[2] = {
452 *buf
= calloc(1, sizeof(char));
457 /* set up aux for remaining pixels */
459 *aux
= bmap
->infoheader
.width
;
461 /* set up the number of pixels we need to process in this cycle */
477 BITMAP_COLOR
*cbuf
= NULL
;
479 if (IsLittleEndian())
481 temp
= *data
& values
[i
];
483 if (temp
> values
[1])
488 temp
= *data
& values
[1 - i
];
490 if (temp
> values
[0])
494 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
496 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
502 if (*x
> bmap
->infoheader
.width
- 1)
513 /* will get the single pixel from the data */
515 /* double calc = 0; */
524 *buf
= calloc(1, sizeof(char));
529 /* set up aux for remaining pixels */
531 *aux
= bmap
->infoheader
.width
;
533 /* set up the number of pixels we need to process in this cycle */
549 BITMAP_COLOR
*cbuf
= NULL
;
553 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
555 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
561 if (*x
> bmap
->infoheader
.width
- 1)
572 /* we do not support 16 bit because I think they
573 * use 24 bit for those. we'll see through use.
574 * if not, I really think this depth is pointless...
581 /* will need to gather the data for 2 other bytes to get a
582 * single pixel. We will use the auxiliary variable to keep
583 * track of where we are at in the gathering.
588 *buf
= calloc(3, sizeof(u8
));
592 (*buf
)[*aux
] = *data
;
599 if (bmap
->infoheader
.height
== *y
)
601 NEURO_ERROR("attempted to draw an invalid location", NULL
);
605 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB((*buf
)[2], (*buf
)[1], (*buf
)[0]));
610 if (*x
> bmap
->infoheader
.width
- 1)
620 /* we do not support 32 bit because it is Very uncommon if it
621 * actually exist. Pretty much the same as 16 bpp.
628 /* an error occured */
636 processGradual_BMP(BMP_CTX
*ctx
, u32 loops
)
640 NEURO_WARN("argument ctx is NULL", NULL
);
644 if (ctx
->f_bitmap
== NULL
)
646 NEURO_WARN("bitmap file descriptor is NULL", NULL
);
652 ctx
->bmap
= parse_bitmap_header(ctx
->f_bitmap
);
654 /* TODO TODO XXX check here if the bitmap is valid or not
655 * first check for the BM word
656 * then we check for the size of the file in header and size
657 * we got when reading the file
660 /* print_bitmap_infos(ctx->bmap); */
662 if (ctx
->bmap
->header
.type
!= 0x4d42)
664 NEURO_WARN("Invalid bitmap file", NULL
);
671 /* if it is valid, we create the buffers */
672 Neuro_CreateEBuf(&ctx
->bmap_colors
);
673 Neuro_SetcallbEBuf(ctx
->bmap_colors
, &clean_bmap_color
);
676 /* print_bitmap_infos(bmap); */
678 /* process the bitmap(load it in memory) */
680 ctx
->psize
= ctx
->bmap
->header
.size
- (sizeof(BITMAP_HEADER
) + sizeof(BITMAP_INFOHEADER
));
681 ctx
->psize
= ctx
->psize
- (ctx
->bmap
->infoheader
.ncolors
* 4);
682 /* printf("data size %d\n", psize); */
684 if (ctx
->bmap
->infoheader
.ncolors
> 0)
686 process_palette(ctx
->f_bitmap
, ctx
->bmap
, ctx
->bmap_colors
);
689 /* we create the v_object
691 * will need to put better values for the masks to support SDL.
694 u32 rmask
= 0, gmask
= 0, bmask
= 0, amask
= 0;
696 if (IsLittleEndian())
698 switch (ctx
->bmap
->infoheader
.bits
)
734 switch (ctx
->bmap
->infoheader
.bits
)
770 if (IsLittleEndian())
786 ctx
->output
= Neuro_CreateVObject(0, ctx
->bmap
->infoheader
.width
, ctx
->bmap
->infoheader
.height
, ctx
->bmap
->infoheader
.bits
, rmask
, gmask
, bmask
, amask
);
788 if (ctx
->output
== NULL
)
790 NEURO_WARN("Created output v_object is NULL", NULL
);
795 /* semi static values to skip bytes that form 32 bit chunks in the data */
797 ctx
->pixellen
= (8 / (double)ctx
->bmap
->infoheader
.bits
);
798 ctx
->msize
= ctx
->pixellen
* 4;
800 /* we calculate the number of bytes there is per rows
801 * this is mainly so we can know how much "alignment"
802 * bytes there is (which need to be skipped)
805 ctx
->wmult
= (u32
)ctx
->bmap
->infoheader
.bits
/ 8;
810 ctx
->wmult
= ctx
->wmult
* ctx
->bmap
->infoheader
.width
;
813 ctx
->increm
= (u32
)ctx
->pixellen
;
815 if (ctx
->increm
== 0)
818 ctx
->x
= (u32
)(ctx
->bmap
->infoheader
.width
/ ctx
->msize
);
819 ctx
->tmp
= ctx
->msize
* ctx
->x
;
820 ctx
->tmp
= (double)ctx
->bmap
->infoheader
.width
- ctx
->tmp
;
821 ctx
->tmp
= ctx
->tmp
- 0.000001; /* to avoid bugs */
825 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
826 #else /* NOT USE_ZLIB */
827 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
828 #endif /* NOT USE_ZLIB */
831 /* else */ /* if i != 0 */
833 i32 initial
= ctx
->i
;
835 Lib_LockVObject(ctx
->output
);
839 /* while (ctx->i < ctx->psize) */
840 while (ctx
->i
< (initial
+ loops
))
844 /* skip bytes that are inside the bitmap for
845 * filling purpose. (the data is purposely filled
846 * with 0 bits so the data is 32bits aligned)
848 if (ctx
->skip_i
>= ctx
->wmult
)
850 ctx
->calc
= ctx
->tmp
/ ctx
->pixellen
;
851 ctx
->skip_i
= (u32
)ctx
->calc
;
852 if (ctx
->skip_i
< ctx
->calc
)
856 ctx
->skip_i
= (4 - ctx
->skip_i
);
857 ctx
->i
+= ctx
->skip_i
;
860 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
861 #else /* NOT USE_ZLIB */
862 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
863 #endif /* NOT USE_ZLIB */
866 printf("skipping %d bytes wmult %d width %d tmp %f plen %f calc %f\n",
869 bmap->infoheader.width,
877 ctx
->skip_i
+= ctx
->increm
;
879 if (ctx
->i
>= ctx
->psize
)
884 fpdata8(ctx
->f_bitmap
, &ctx
->DATA
);
886 process_bitmap2(ctx
->bmap
, ctx
->output
, ctx
->palette
, &ctx
->DATA
,
887 ctx
->bmap_colors
, &ctx
->x
, &ctx
->y
, &ctx
->aux_var
, &ctx
->aux_buf
);
892 Lib_UnlockVObject(ctx
->output
);
896 if (ctx
->i
>= ctx
->psize
)
897 { /* this bitmap finished being loaded, we free everything */
899 /* to prevent further calls to be processed */
909 Neuro_CleanEBuf(&ctx
->bmap_colors
);
913 gzclose(ctx
->f_bitmap
);
914 #else /* NOT USE_ZLIB */
916 fclose(ctx
->f_bitmap
);
917 #endif /* NOT USE_ZLIB */
922 /*Debug_Val(0, "((%d * 100) / %d) == %d\n",
924 (i8)((u32)((ctx->i * 100) / ctx->psize)));*/
926 return (i8
)((u32
)(ctx
->i
* 100) / ctx
->psize
);
929 /* this never happens unless the image was already loaded */
930 NEURO_TRACE("Useless call of the function #%d", ctx
->i
);
934 /*-------------------- Global Functions ----------------------------*/
937 readBitmapFile(const char *bitmap
)
942 ctx
= Bitmap_CreateCTX(bitmap
);
946 NEURO_WARN("Context creation failed", NULL
);
952 _err
= Bitmap_Poll(ctx
);
959 NEURO_WARN("Poll failed...", NULL
);
963 /* printf("loading progress : %d\n", _err); */
966 return Bitmap_DestroyCTX(ctx
);
969 /*-------------------- Poll ----------------------------------------*/
971 /* returns a percentage of progress */
973 Bitmap_Poll(BMP_CTX
*ctx
)
975 return processGradual_BMP(ctx
, 1024);
978 /*-------------------- Constructor Destructor ----------------------*/
981 Bitmap_CreateCTX(const char *path
)
985 output
= calloc(1, sizeof(BMP_CTX
));
990 output
->f_bitmap
= gzopen(path
, "r"); /* can also be used for non compressed files */
991 #else /* NOT USE_ZLIB */
992 output
->f_bitmap
= fopen(path
, "r");
993 #endif /* NOT USE_ZLIB */
995 if (output
->f_bitmap
== NULL
)
1005 Bitmap_DestroyCTX(BMP_CTX
*ctx
)
1007 v_object
*output
= NULL
;
1012 output
= ctx
->output
;