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
)
180 if (input
== NULL
|| output
== NULL
)
184 feed
[0] = gzgetc(input
);
185 feed
[1] = gzgetc(input
);
186 #else /* NOT USE_ZLIB */
187 feed
[0] = fgetc(input
);
188 feed
[1] = fgetc(input
);
189 #endif /* NOT USE_ZLIB */
197 temp
= gzgetc(input
);
199 temp
+= gzgetc(input
);
206 /* returns 0 on success and puts the data in *output
207 * 1 on error dont touch output
210 fpdata32(nFILE
*input
, u32
*output
)
212 /* register int feed; */
217 if (input
== NULL
|| output
== NULL
)
221 feed
[0] = gzgetc(input
);
222 feed
[1] = gzgetc(input
);
223 feed
[2] = gzgetc(input
);
224 feed
[3] = gzgetc(input
);
225 #else /* NOT USE_ZLIB */
226 feed
[0] = fgetc(input
);
227 feed
[1] = fgetc(input
);
228 feed
[2] = fgetc(input
);
229 feed
[3] = fgetc(input
);
230 #endif /* NOT USE_ZLIB */
239 static BITMAP_HDATA
*
240 parse_bitmap_header(nFILE
*input
)
243 BITMAP_INFOHEADER
*tmp
;
248 buf
= calloc(1, sizeof(BITMAP_HDATA
));
250 tmp
= &buf
->infoheader
;
252 fpdata16(input
, &buf
->header
.type
);
253 fpdata32(input
, &buf
->header
.size
);
254 fpdata16(input
, &buf
->header
.reserved1
);
255 fpdata16(input
, &buf
->header
.reserved2
);
256 fpdata32(input
, &buf
->header
.offset
);
258 fpdata32(input
, &tmp
->size
);
259 fpdata32(input
, (u32
*)&tmp
->width
);
260 fpdata32(input
, (u32
*)&tmp
->height
);
261 fpdata16(input
, &tmp
->planes
);
262 fpdata16(input
, &tmp
->bits
);
263 fpdata32(input
, &tmp
->compression
);
264 fpdata32(input
, &tmp
->imagesize
);
265 fpdata32(input
, (u32
*)&tmp
->xresolution
);
266 fpdata32(input
, (u32
*)&tmp
->yresolution
);
267 fpdata32(input
, &tmp
->ncolors
);
268 fpdata32(input
, &tmp
->importantcolours
);
273 /* the magic number will probably not show correctly if big endian */
275 print_bitmap_infos(BITMAP_HDATA
*bmap
)
277 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",
279 bmap
->header
.type
& 0x00FF,
280 (bmap
->header
.type
& 0xFF00) >> 8,
283 bmap
->infoheader
.size
,
284 bmap
->infoheader
.width
,
285 bmap
->infoheader
.height
,
286 bmap
->infoheader
.planes
,
287 bmap
->infoheader
.bits
,
288 bmap
->infoheader
.compression
,
289 bmap
->infoheader
.imagesize
,
290 bmap
->infoheader
.xresolution
,
291 bmap
->infoheader
.yresolution
,
292 bmap
->infoheader
.ncolors
,
293 bmap
->infoheader
.importantcolours
);
298 process_palette(nFILE
*input
, BITMAP_HDATA
*bmap
, EBUF
*bcolors
)
303 while (i
< bmap
->infoheader
.ncolors
)
305 Neuro_AllocEBuf(bcolors
, sizeof(BITMAP_COLOR
*), sizeof(BITMAP_COLOR
));
307 buf
= Neuro_GiveCurEBuf(bcolors
);
309 /*buf->r = palette[(i * 4) + 2];
310 buf->g = palette[(i * 4) + 1];
311 buf->b = palette[(i * 4)];
315 fpdata8(input, &buf->b);
316 fpdata8(input, &buf->g);
317 fpdata8(input, &buf->r);
318 fpdata8(input, &buf->a);
321 buf
->b
= gzgetc(input
);
322 buf
->g
= gzgetc(input
);
323 buf
->r
= gzgetc(input
);
325 /* I leave this just in case */
326 /* buf->a = fgetc(input); */
328 /* skip the alpha color */
330 #else /* NOT USE_ZLIB */
331 buf
->b
= fgetc(input
);
332 buf
->g
= fgetc(input
);
333 buf
->r
= fgetc(input
);
335 /* I leave this just in case */
336 /* buf->a = fgetc(input); */
338 /* skip the alpha color */
340 #endif /* NOT USE_ZLIB */
345 /* input the bits per pixel of the image
346 * input a 1 byte of data to process
349 process_bitmap2(BITMAP_HDATA
*bmap
, v_object
*image
, u8
*palette
, u8
*data
, EBUF
*bcolors
, u32
*x
, u32
*y
, int *aux
, char **buf
)
352 /* we will call functions depending on the bpp of the image */
353 switch (bmap
->infoheader
.bits
)
357 /* will do a loop to get each 8 pixels from the data */
359 /* this is pretty much for little endian
360 * the minimum data size we can have for a certain width is
361 * 32 bits (4 bytes increments). Those 32 bits will be able
362 * to hold up to 32 pixels. In case the width is higher than
363 * 32 pixels, it will put 32 bits until the whole width
366 /* we will need to have the width value because we will need
367 * to know how many bits we have to read from 32 bits (4 bytes).
369 /* aux will keep how many 32 bits still need to be done in a
373 /* double calc = 0; */
377 const u8 values
[8] = {
392 *buf
= calloc(1, sizeof(char));
397 /* set up aux for remaining pixels */
399 *aux
= bmap
->infoheader
.width
;
401 /* set up the number of pixels we need to process in this cycle */
417 BITMAP_COLOR
*cbuf
= NULL
;
419 if (IsLittleEndian())
420 temp
= *data
& values
[i
];
422 temp
= *data
& values
[7 - i
];
428 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
430 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
436 if (*x
> bmap
->infoheader
.width
- 1)
446 /* will do a loop to get each 2 pixels from the data */
448 /* double calc = 0; */
452 const u8 values
[2] = {
461 *buf
= calloc(1, sizeof(char));
466 /* set up aux for remaining pixels */
468 *aux
= bmap
->infoheader
.width
;
470 /* set up the number of pixels we need to process in this cycle */
486 BITMAP_COLOR
*cbuf
= NULL
;
488 if (IsLittleEndian())
490 temp
= *data
& values
[i
];
492 if (temp
> values
[1])
497 temp
= *data
& values
[1 - i
];
499 if (temp
> values
[0])
503 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
505 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
511 if (*x
> bmap
->infoheader
.width
- 1)
522 /* will get the single pixel from the data */
524 /* double calc = 0; */
533 *buf
= calloc(1, sizeof(char));
538 /* set up aux for remaining pixels */
540 *aux
= bmap
->infoheader
.width
;
542 /* set up the number of pixels we need to process in this cycle */
558 BITMAP_COLOR
*cbuf
= NULL
;
562 cbuf
= Neuro_GiveEBuf(bcolors
, temp
);
564 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB(cbuf
->r
, cbuf
->g
, cbuf
->b
));
570 if (*x
> bmap
->infoheader
.width
- 1)
581 /* we do not support 16 bit because I think they
582 * use 24 bit for those. we'll see through use.
583 * if not, I really think this depth is pointless...
590 /* will need to gather the data for 2 other bytes to get a
591 * single pixel. We will use the auxiliary variable to keep
592 * track of where we are at in the gathering.
597 *buf
= calloc(3, sizeof(u8
));
601 (*buf
)[*aux
] = *data
;
608 Neuro_PutPixel(image
, *x
, (bmap
->infoheader
.height
- 1) - *y
, Neuro_MapRGB((*buf
)[2], (*buf
)[1], (*buf
)[0]));
613 if (*x
> bmap
->infoheader
.width
- 1)
623 /* we do not support 32 bit because it is Very uncommon if it
624 * actually exist. Pretty much the same as 16 bpp.
631 /* an error occured */
639 processGradual_BMP(BMP_CTX
*ctx
, u32 loops
)
643 NEURO_WARN("argument ctx is NULL", NULL
);
647 if (ctx
->f_bitmap
== NULL
)
649 NEURO_WARN("bitmap file descriptor is NULL", NULL
);
655 ctx
->bmap
= parse_bitmap_header(ctx
->f_bitmap
);
657 /* TODO TODO XXX check here if the bitmap is valid or not
658 * first check for the BM word
659 * then we check for the size of the file in header and size
660 * we got when reading the file
663 print_bitmap_infos(ctx
->bmap
);
665 if (ctx
->bmap
->header
.type
!= 0x424d)
667 NEURO_WARN("Invalid bitmap file", NULL
);
674 /* if it is valid, we create the buffers */
675 Neuro_CreateEBuf(&ctx
->bmap_colors
);
676 Neuro_SetcallbEBuf(ctx
->bmap_colors
, &clean_bmap_color
);
679 /* print_bitmap_infos(bmap); */
681 /* process the bitmap(load it in memory) */
683 ctx
->psize
= ctx
->bmap
->header
.size
- (sizeof(BITMAP_HEADER
) + sizeof(BITMAP_INFOHEADER
));
684 ctx
->psize
= ctx
->psize
- (ctx
->bmap
->infoheader
.ncolors
* 4);
685 /* printf("data size %d\n", psize); */
687 printf("ncolors : %d\n", ctx
->bmap
->infoheader
.ncolors
);
691 if (ctx
->bmap
->infoheader
.ncolors
> 0)
693 process_palette(ctx
->f_bitmap
, ctx
->bmap
, ctx
->bmap_colors
);
699 /* we create the v_object
701 * will need to put better values for the masks to support SDL.
704 u32 rmask
= 0, gmask
= 0, bmask
= 0, amask
= 0;
706 if (IsLittleEndian())
708 switch (ctx
->bmap
->infoheader
.bits
)
744 switch (ctx
->bmap
->infoheader
.bits
)
778 ctx
->output
= Neuro_CreateVObject(0, ctx
->bmap
->infoheader
.width
, ctx
->bmap
->infoheader
.height
, ctx
->bmap
->infoheader
.bits
, rmask
, gmask
, bmask
, amask
);
780 if (ctx
->output
== NULL
)
782 NEURO_WARN("Created output v_object is NULL", NULL
);
787 /* semi static values to skip bytes that form 32 bit chunks in the data */
789 ctx
->pixellen
= (8 / (double)ctx
->bmap
->infoheader
.bits
);
790 ctx
->msize
= ctx
->pixellen
* 4;
792 /* we calculate the number of bytes there is per rows
793 * this is mainly so we can know how much "alignment"
794 * bytes there is (which need to be skipped)
797 ctx
->wmult
= (u32
)ctx
->bmap
->infoheader
.bits
/ 8;
802 ctx
->wmult
= ctx
->wmult
* ctx
->bmap
->infoheader
.width
;
805 ctx
->increm
= (u32
)ctx
->pixellen
;
807 if (ctx
->increm
== 0)
810 ctx
->x
= (u32
)(ctx
->bmap
->infoheader
.width
/ ctx
->msize
);
811 ctx
->tmp
= ctx
->msize
* ctx
->x
;
812 ctx
->tmp
= (double)ctx
->bmap
->infoheader
.width
- ctx
->tmp
;
813 ctx
->tmp
= ctx
->tmp
- 0.000001; /* to avoid bugs */
817 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
818 #else /* NOT USE_ZLIB */
819 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
, SEEK_SET
);
820 #endif /* NOT USE_ZLIB */
823 /* else */ /* if i != 0 */
825 i32 initial
= ctx
->i
;
827 Lib_LockVObject(ctx
->output
);
831 /* while (ctx->i < ctx->psize) */
832 while (ctx
->i
< (initial
+ loops
))
836 /* skip bytes that are inside the bitmap for
837 * filling purpose. (the data is purposely filled
838 * with 0 bits so the data is 32bits aligned)
840 if (ctx
->skip_i
>= ctx
->wmult
)
842 ctx
->calc
= ctx
->tmp
/ ctx
->pixellen
;
843 ctx
->skip_i
= (u32
)ctx
->calc
;
844 if (ctx
->skip_i
< ctx
->calc
)
848 ctx
->skip_i
= (4 - ctx
->skip_i
);
849 ctx
->i
+= ctx
->skip_i
;
852 gzseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
853 #else /* NOT USE_ZLIB */
854 fseek(ctx
->f_bitmap
, ctx
->bmap
->header
.offset
+ ctx
->i
, SEEK_SET
);
855 #endif /* NOT USE_ZLIB */
858 printf("skipping %d bytes wmult %d width %d tmp %f plen %f calc %f\n",
861 bmap->infoheader.width,
869 ctx
->skip_i
+= ctx
->increm
;
871 if (ctx
->i
>= ctx
->psize
)
876 fpdata8(ctx
->f_bitmap
, &ctx
->DATA
);
878 process_bitmap2(ctx
->bmap
, ctx
->output
, ctx
->palette
, &ctx
->DATA
,
879 ctx
->bmap_colors
, &ctx
->x
, &ctx
->y
, &ctx
->aux_var
, &ctx
->aux_buf
);
884 Lib_UnlockVObject(ctx
->output
);
888 if (ctx
->i
>= ctx
->psize
)
889 { /* this bitmap finished being loaded, we free everything */
891 /* to prevent further calls to be processed */
901 Neuro_CleanEBuf(&ctx
->bmap_colors
);
905 gzclose(ctx
->f_bitmap
);
906 #else /* NOT USE_ZLIB */
908 fclose(ctx
->f_bitmap
);
909 #endif /* NOT USE_ZLIB */
914 /*Debug_Val(0, "((%d * 100) / %d) == %d\n",
916 (i8)((u32)((ctx->i * 100) / ctx->psize)));*/
918 return (i8
)((u32
)(ctx
->i
* 100) / ctx
->psize
);
921 /* this never happens unless the image was already loaded */
922 NEURO_TRACE("Useless call of the function #%d", ctx
->i
);
926 /*-------------------- Global Functions ----------------------------*/
929 readBitmapFile(const char *bitmap
)
934 ctx
= Bitmap_CreateCTX(bitmap
);
938 NEURO_WARN("Context creation failed", NULL
);
944 _err
= Bitmap_Poll(ctx
);
951 NEURO_WARN("Poll failed...", NULL
);
955 printf("loading progress : %d\n", _err
);
958 return Bitmap_DestroyCTX(ctx
);
961 /*-------------------- Poll ----------------------------------------*/
963 /* returns a percentage of progress */
965 Bitmap_Poll(BMP_CTX
*ctx
)
967 return processGradual_BMP(ctx
, 512);
970 /*-------------------- Constructor Destructor ----------------------*/
973 Bitmap_CreateCTX(const char *path
)
977 output
= calloc(1, sizeof(BMP_CTX
));
982 output
= gzopen(path
, "r"); /* can also be used for non compressed files */
983 #else /* NOT USE_ZLIB */
984 output
= fopen(path
, "r");
985 #endif /* NOT USE_ZLIB */
987 if (output
->f_bitmap
== NULL
)
997 Bitmap_DestroyCTX(BMP_CTX
*ctx
)
999 v_object
*output
= NULL
;
1004 output
= ctx
->output
;