Rice GLES2 (from mupen64plus-ae) plugin. Compile but doesn't works well on the OpenPa...
[mupen64plus-pandora.git] / source / gles2rice / src / liblinux / BMGImage.c
1 /*
2 // source code for the BMGImage functions
3 //
4 // Copyright (C) 2001 Michael S. Heiman
5 //
6 // You may use the software for any purpose you see fit. You may modify
7 // it, incorporate it in a commercial application, use it for school,
8 // even turn it in as homework. You must keep the Copyright in the
9 // header and source files. This software is not in the "Public Domain".
10 // You may use this software at your own risk. I have made a reasonable
11 // effort to verify that this software works in the manner I expect it to;
12 // however,...
13 //
14 // THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS" AND
15 // WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE, INCLUDING
16 // WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR FITNESS FOR A
17 // PARTICULAR PURPOSE. IN NO EVENT SHALL MICHAEL S. HEIMAN BE LIABLE TO
18 // YOU OR ANYONE ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR
19 // CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING
20 // WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE,
21 // OR THE CLAIMS OF THIRD PARTIES, WHETHER OR NOT MICHAEL S. HEIMAN HAS
22 // BEEN ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
23 // ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
24 // POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
25 */
26
27 #include <memory.h>
28 #include <setjmp.h>
29 #include <stdlib.h>
30
31 #include "BMGUtils.h"
32
33 /* initializes a BMGImage to default values */
34 void InitBMGImage( struct BMGImageStruct *img )
35 {
36     img->width = img->height = 0;
37     img->bits_per_pixel = 0;
38     img->palette_size = 0;
39     img->bytes_per_palette_entry = 0;
40     img->bits = NULL;
41     img->palette = NULL;
42     img->opt_for_bmp = 0;
43     img->scan_width = 0;
44     img->transparency_index = -1;
45 }
46
47 /* frees memory allocated to a BMGImage */
48 void FreeBMGImage( struct BMGImageStruct *img )
49 {
50     if ( img->bits != NULL )
51     {
52         free( img->bits );
53         img->bits = NULL;
54     }
55     if ( img->palette != NULL )
56     {
57         free( img->palette );
58         img->palette = NULL;
59     }
60     img->bits_per_pixel = 0;
61     img->palette_size = 0;
62     img->bytes_per_palette_entry = 0;
63     img->width = img->height = 0;
64     img->opt_for_bmp = 0;
65     img->scan_width = 0;
66     img->transparency_index = -1;
67 }
68
69 /* allocates memory for the bits & palette.  Assigned values to scan_line
70    & bits_per_palette_entry as well.  Assumes opt_for_bmp has been set before
71    this function is called. Assumes that all images with bits_per_pixel <= 8
72    require a palette.
73  */
74 BMGError AllocateBMGImage( struct BMGImageStruct *img )
75 {
76     unsigned int mempal;
77
78     SetLastBMGError( BMG_OK );
79
80     /* make sure that all REQUIRED parameters are valid */
81     if ( img->width * img->height <= 0 )
82     {
83         SetLastBMGError(errInvalidSize);
84         return errInvalidSize;
85     }
86
87     switch( img->bits_per_pixel )
88     {
89         case  1:
90         case  4:
91         case  8:
92         case 16:
93         case 24:
94         case 32:
95             break;
96         default:
97             SetLastBMGError( errInvalidPixelFormat );
98             return errInvalidPixelFormat;
99     }
100
101     /* delete old memory */
102     if ( img->bits != NULL )
103     {
104         free( img->bits );
105         img->bits = NULL;
106     }
107     if ( img->palette != NULL )
108     {
109         free( img->palette );
110         img->palette = NULL;
111     }
112
113     /* allocate memory for the palette */
114     if ( img->bits_per_pixel <= 8 )
115     {
116         if ( img->opt_for_bmp > 0 )
117             img->bytes_per_palette_entry = 4U;
118         else
119         {
120             /* we only support 3-byte and 4-byte palettes */
121             if ( img->bytes_per_palette_entry <= 3U )
122                 img->bytes_per_palette_entry = 3U;
123             else
124                 img->bytes_per_palette_entry = 4U;
125         }
126         /*
127            use bits_per_pixel to determine palette_size if none was
128            specified
129         */
130         if ( img->palette_size == 0 )
131             img->palette_size = (unsigned short)(1 << img->bits_per_pixel);
132
133         mempal = img->bytes_per_palette_entry * img->palette_size;
134         img->palette = (unsigned char *)calloc( mempal, sizeof(unsigned char) );
135         if ( img->palette == NULL )
136         {
137             SetLastBMGError(errMemoryAllocation);
138             return errMemoryAllocation;
139         }
140     }
141     else
142     {
143         img->bytes_per_palette_entry = 0;
144         img->palette_size = 0;
145     }
146
147     /*
148        set the scan width.  Bitmaps optimized for windows have scan widths that
149        are evenly divisible by 4.
150     */
151     img->scan_width = ( img->bits_per_pixel * img->width + 7 ) / 8;
152     if ( img->opt_for_bmp && img->scan_width % 4 )
153         img->scan_width += 4 - img->scan_width % 4;
154
155     /* allocate memory for the bits */
156     mempal = img->scan_width * img->height;
157     if ( mempal > 0 )
158     {
159         img->bits = (unsigned char *)calloc( mempal, sizeof( unsigned char) );
160         if ( img->bits == NULL )
161         {
162             if ( img->palette != NULL )
163             {
164                 free( img->palette );
165                 img->palette = NULL;
166             }
167             SetLastBMGError(errMemoryAllocation);
168             return errMemoryAllocation;
169         }
170     }
171     else
172     {
173         SetLastBMGError(errInvalidSize);
174         return errInvalidSize;
175     }
176
177     return BMG_OK;
178 }
179
180 /*******************************************************************************
181  A utility function for compressing paletted images.  Will automatically
182  convert 8-bit paletted images to 1-bit or 4-bit paletted images based
183  upon palette_size.  Assumes that indices in img->bits are valid.  That is,
184  0 <= img->bits[i] <= 1 for all i if 1-bit compression is desired, and
185  0 <= img->bits[i] <= 15 for all i if 4-bit compression is desired  Returns
186  BMG_OK if successful, or an error code otherwise.
187 *******************************************************************************/
188 BMGError CompressBMGImage( struct BMGImageStruct *img )
189 {
190     unsigned char new_bits_per_pixel;
191     unsigned int new_scan_width;
192     unsigned char *new_bits = NULL;
193     unsigned int new_bit_size;
194     unsigned char *new_row, *old_row, *p, *q;
195     unsigned char *end;
196     unsigned short scale;
197
198     SetLastBMGError( BMG_OK );
199
200     /* if we cannot compress it then do no harm and return "true" */
201     if ( img->palette == NULL ||
202          img->palette_size > 16 ||
203          img->bits_per_pixel != 8 )
204     {
205         return BMG_OK;
206     }
207
208     /* calculate new dimensions */
209     new_bits_per_pixel = img->palette_size <= 2 ? 1U : 4U;
210     new_scan_width = ( new_bits_per_pixel * img->width + 7 ) / 8;
211     if ( img->opt_for_bmp > 0 && new_scan_width % 4 )
212         new_scan_width += 4 - new_scan_width % 4;
213     new_bit_size = new_scan_width * img->height;
214
215     /* allocate & test memory */
216     new_bits = (unsigned char *)calloc( new_bit_size, sizeof(unsigned char) );
217     if ( new_bits == NULL )
218     {
219         SetLastBMGError( errMemoryAllocation );
220         return errMemoryAllocation;
221     }
222
223     old_row = img->bits;
224     for ( new_row = new_bits; new_row < new_bits + new_bit_size;
225           new_row += new_scan_width, old_row += img->scan_width )
226     {
227         scale = 8 / new_bits_per_pixel;
228         end = new_row + img->width / scale;
229         p = old_row;
230         if ( new_bits_per_pixel == 1 )
231         {
232             for ( q = new_row; q < end; q++, p += scale )
233             {
234                 *q = (unsigned char)( (p[0] << 7) | (p[1] << 6) |
235                                       (p[2] << 5) | (p[3] << 4) |
236                                       (p[4] << 3) | (p[5] << 2) |
237                                       (p[6] << 1) | p[7] );
238             }
239             scale = img->width % scale;
240             if  ( scale-- > 0 )
241             {
242                 *q = (unsigned char)(p[0] << 7);
243                 if ( scale-- )
244                 {
245                     *q |= (unsigned char)(p[1] << 6);
246                     if ( scale-- )
247                     {
248                         *q |= (unsigned char)(p[2] << 5);
249                         if ( scale-- )
250                         {
251                             *q |= (unsigned char)(p[3] << 4);
252                             if ( scale-- )
253                             {
254                                 *q |= (unsigned char)(p[4] << 3);
255                                 if ( scale-- )
256                                 {
257                                     *q |= (unsigned char)(p[5] << 2);
258                                     if ( scale-- )
259                                         *q |= (unsigned char)(p[6] << 1);
260                                 }
261                             }
262                         }
263                     }
264                 }
265             }
266         }
267         else /* new_bits_per_pixel == 4 */
268         {
269             for ( q = new_row; q < end; q++, p += scale )
270             {
271                 *q = (unsigned char)( (p[0] << 4) | (p[1] & 0x0F) );
272             }
273             if  ( img->width % scale )
274                 *q = (unsigned char)(p[0] << 4);
275         }
276     }
277
278     /* replace old values with new values */
279     free( img->bits );
280     img->bits = new_bits;
281     img->scan_width = new_scan_width;
282     img->bits_per_pixel = new_bits_per_pixel;
283
284     return BMG_OK;
285 }
286
287 /* this function simply frees memory that was allocated by any function
288    in the BMGLib.  This was required because acces violations occurred
289    when I tried to delete memory created by CreateRGBAArray in the demo
290    applications */
291 void FreeBMGMemory( unsigned char *mem )
292 {
293     if ( mem != NULL )
294         free( mem );
295 }
296
297 /* converts a BGR to a gray scale
298 // color[0] = blue, color[1] = green, color[2] = red */
299 static unsigned char CreateGrayScale( unsigned char *color )
300 {
301     return (unsigned char)( 0.299f * color[2] + 0.587f * color[1]
302                                + 0.114f * color[0] + 0.5f );
303 }
304
305 /*
306 // converts a color image to a gray scale image.  If img is a 16 or
307 // 24-BPP image then it is converted to a 256 color grayscale bitmap.
308 // If img is a 1, 4, or 8 BPP image, then it will have the same number
309 // of grayscales as it has palette entries.  If it is a 32-BPP bitmap then
310 // it will remain a 32-BPP bitmap to preserve the alpha channel.
311 //
312 // This function returns BMG_OK if successfull, or an error state
313 // otherwise.
314 */
315 BMGError ConvertToGrayScale( struct BMGImageStruct *img )
316 {
317     unsigned char *p, *q, *r, *end, gray;
318
319     SetLastBMGError( BMG_OK );
320
321     /* if this is a paletted image then we simply need to convert the
322     // palette entries */
323     switch ( img->bits_per_pixel )
324     {
325     default:
326         end = img->palette + img->palette_size * img->bytes_per_palette_entry;
327         for ( p = img->palette; p < end; p += img->bytes_per_palette_entry )
328         {
329             gray = CreateGrayScale( p );
330             memset( (void *)p, gray, 3 );
331         }
332         break;
333     /* 16 BPP image are converted to 24 BPP images */
334     case 16:
335     {
336         BMGError tmp = Convert16to24( img );
337         if ( tmp != BMG_OK )
338         {
339             SetLastBMGError( tmp );
340             return tmp;
341         }
342     }
343     case 24:
344     {
345         unsigned char *new_bits;
346         unsigned char *s, *s_end;
347         unsigned short i;
348
349         /* calculate the new scan width */
350         unsigned int new_scan_width = img->width;
351         if ( new_scan_width % 4 && img->opt_for_bmp )
352             new_scan_width += 4 - new_scan_width % 4;
353
354         /* allocate memory for the new pixel values */
355         new_bits = (unsigned char *)calloc( new_scan_width * img->height,
356                     sizeof(unsigned char) );
357         if ( new_bits == NULL )
358         {
359             SetLastBMGError( errMemoryAllocation );
360             return errMemoryAllocation;
361         }
362
363         /* allocate memory for a 256 gray scale palette */
364         img->bytes_per_palette_entry = img->opt_for_bmp == 1 ? 4 : 3;
365         img->palette_size = 256;
366         img->palette =
367             (unsigned char *)calloc(img->bytes_per_palette_entry *
368                                     img->palette_size,
369                                     sizeof(unsigned char) );
370         if ( img->palette == NULL )
371         {
372             free( new_bits );
373             img->bytes_per_palette_entry = 0;
374             img->palette_size = 0;
375             SetLastBMGError( errMemoryAllocation );
376             return errMemoryAllocation;
377         }
378
379         /* assign values to the gray scale palette */
380         for ( i = 0; i < 256; i++ )
381         {
382             p = img->palette + i * img->bytes_per_palette_entry;
383             memset( (void *)p, i, 3 );
384             if ( img->bytes_per_palette_entry == 4 )
385                 p[3] = 0;
386         }
387
388         /* cycle through the pixels and convert them to gray scale values */
389         q = new_bits;
390         end = img->bits + img->scan_width * img->height;
391
392         for ( p = img->bits; p < end; p += img->scan_width, q += new_scan_width )
393         {
394             s_end = p + 3 * img->width;
395             r = q;
396             for ( s = p; s < s_end; s += 3, r++ )
397                 *r = CreateGrayScale( s );
398         }
399
400         free( img->bits );
401         img->bits = new_bits;
402         img->scan_width = new_scan_width;
403         img->bits_per_pixel = 8;
404
405         break;
406     }
407     case 32:
408         end = img->bits + img->scan_width * img->height;
409         for ( p = img->bits; p < end; p += img->scan_width )
410         {
411             r = p + img->scan_width;
412             for ( q = p; q < r; q += 4 )
413             {
414                 gray = CreateGrayScale( q );
415                 memset( (void *)q, gray, 3 );
416             }
417         }
418         break;
419     }
420
421     return BMG_OK;
422 }
423
424 /*
425 // converts a color image to a pseudo-gray scale image.  This is a implementation
426 // is based upon the code published by Rich Franzen
427 // <http://rocq.home.att.net/pseudoGrey.html>. I have "simplified" the 2 functions
428 // he published into a single function.  This implementation creates 1786 gray
429 // scales from a 24-bit image. 16-BPP images are converted to 24-BPP images.  24
430 // and 32-BPP images will keep the same bitdepth. Paletted images and 16-BPP images
431 // are not supported.
432 //
433 // This function returns BMK_OK if successfull,
434 // errInvalidPixelFormat otherwise
435 */
436 BMGError ConvertToPseudoGrayScale( struct BMGImageStruct *img )
437 {
438     unsigned char *p, *p_end;
439     unsigned char *q, *q_end;
440     unsigned char gray;
441     unsigned int bytes_per_pixel;
442
443     SetLastBMGError( errMemoryAllocation );
444
445     if ( img->bits_per_pixel <= 16 )
446     {
447         SetLastBMGError( errInvalidPixelFormat );
448         return errInvalidPixelFormat;
449     }
450
451     bytes_per_pixel = img->bits_per_pixel / 8;
452     p_end = img->bits + img->scan_width * img->height;
453
454     for ( p = img->bits; p < p_end; p += img->scan_width )
455     {
456         q_end = p + bytes_per_pixel * img->width;
457         for ( q = p; q < q_end; q += bytes_per_pixel )
458         {
459         /* Rich's code has 1 function that converts an RGB triplet to a float
460         // bounded by 0 and 1.  He has a second function that converts a
461         // float to a pseudo gray value.  Pseudo gray values are RGB triplets
462         // whose red, green and blue values differ by no more than 1.  I have
463         // combined these two functions into a single function that simply
464         // looks for pseudo gray RGB triplets.  If an RGB triplet meets this
465         // criteria, I leave it unchanged; otherwise, I use the common intensity
466         // conversion to create a grayscale value */
467             unsigned char cmin, cmax;
468
469             cmin = q[0];
470             if ( q[1] < cmin )
471                 cmin = q[1];
472             if ( q[2] < cmin )
473                 cmin = q[2];
474
475             cmax = q[0];
476             if ( q[1] > cmax )
477                 cmax = q[1];
478             if ( q[2] > cmax )
479                 cmax = q[2];
480
481             if ( cmax - cmin > 2 )
482             {
483                 gray = CreateGrayScale( q );
484                 memset( (void *)q, gray, 3 );
485             }
486         }
487     }
488
489     return BMG_OK;
490 }
491
492 #ifdef _WIN32
493 /*******************************************************************************
494 // extracts the dimensional information, pixel array, and color table from an
495 // HBITMAP.
496 // hBitmap can be a handle to a DIB or a DDB.  This function assumes that DDBs
497 // will not have a palette.  If you create a DDB on a 256-color graphics card,
498 // then the DDB will have a palette and this function will fail.
499 //
500 // returns BMK_OK if successfull, and error state otherwise.
501 ********************************************************************************/
502 BMGError GetDataFromBitmap( HBITMAP hBitmap,
503                             struct BMGImageStruct *img,
504                             int remove_alpha )
505 {
506     unsigned int        DIBScanWidth;
507     DIBSECTION          DS;
508     HWND                hWnd = GetForegroundWindow();
509     HDC                 hDC = NULL;
510     HDC                 hMemDC = NULL;
511     unsigned char       red, green, blue;
512     int                 FreelpBits = 0;
513     unsigned int        numBytes;
514     size_t              soDIBSECTION = sizeof(DIBSECTION);
515     size_t              soBITMAP = sizeof(BITMAP);
516
517     unsigned char *p, *q, *lpBits, alpha;
518
519     jmp_buf err_jmp;
520     int error;
521     BMGError bmgerr;
522
523     /* error handler */
524     error = setjmp( err_jmp );
525     if ( error != 0 )
526     {
527         if ( hMemDC != NULL )
528             DeleteDC( hMemDC );
529         if ( hDC != NULL )
530             ReleaseDC( hWnd, hDC );
531         if ( FreelpBits )
532             free( lpBits );
533         FreeBMGImage( img );
534         SetLastBMGError( (BMGError)error );
535         return (BMGError)error;
536     }
537
538     SetLastBMGError( BMG_OK );
539     /* check for valid bitmap*/
540     if ( !hBitmap )
541         longjmp( err_jmp, (int)errInvalidBitmapHandle );
542
543     /* Extract DIBSECTION info from the HBITMAP.  numBytes will equal
544     // soDIBSECTION (84) if hBitmap is a handle to a DIBSECTION (DIB).
545     // numBytes will equal soBITMAP (24) if hBitmap is a handle to a
546     // BITMAP (DDB). */
547     numBytes = GetObject( hBitmap, sizeof(DIBSECTION), &DS );
548     if ( numBytes == 0 )
549         longjmp( err_jmp, (int)errWindowsAPI );
550
551     img->opt_for_bmp = 1;
552     if ( numBytes == soDIBSECTION )
553     {
554         img->width = DS.dsBmih.biWidth;
555         img->height = DS.dsBmih.biHeight;
556         img->bits_per_pixel = (unsigned char)DS.dsBmih.biBitCount;
557         if ( img->bits_per_pixel <= 8 && DS.dsBmih.biClrUsed > 0 )
558             img->palette_size = (unsigned short)DS.dsBmih.biClrUsed;
559         lpBits = (unsigned char *)DS.dsBm.bmBits;
560     }
561     /* this may be a DDB which must be handled differently */
562     else if ( numBytes == soBITMAP )
563     {
564         BITMAP bm;
565         BITMAPINFO bmi;
566
567         if ( GetObject( hBitmap, sizeof(BITMAP), &bm ) == 0 )
568             longjmp( err_jmp, (int)errWindowsAPI );
569
570         /* DDB with a palette */
571         if ( bm.bmBitsPixel <= 8 )
572             longjmp( err_jmp, (int)errInvalidPixelFormat );
573
574         img->width = bm.bmWidth;
575         img->height = bm.bmHeight;
576         img->bits_per_pixel = (unsigned char)bm.bmBitsPixel;
577         bmi = InternalCreateBMI( bm.bmWidth, bm.bmHeight, bm.bmBitsPixel,
578                                  BI_RGB );
579
580         lpBits = (unsigned char *)calloc( bm.bmHeight * bm.bmWidthBytes,
581                                           sizeof(unsigned char) );
582         if ( lpBits == 0 )
583             longjmp( err_jmp, (int)errMemoryAllocation );
584         FreelpBits = 1;
585         hDC = GetDC( hWnd );
586         if ( GetDIBits(hDC, hBitmap, 0, bm.bmHeight, (void *)lpBits, &bmi,
587                        DIB_RGB_COLORS ) == 0 )
588             longjmp( err_jmp, (int)errWindowsAPI );
589         ReleaseDC( hWnd, hDC );
590         hDC = NULL;
591     }
592     else /* I have no idea what this is */
593         longjmp( err_jmp, (int)errInvalidBitmapHandle );
594
595     /* allocate memory */
596     bmgerr = AllocateBMGImage( img );
597     if ( bmgerr != BMG_OK )
598         longjmp( err_jmp, (int)bmgerr );
599
600     /* dimensions */
601     DIBScanWidth = ( img->width * img->bits_per_pixel + 7 )/8;
602     if ( DIBScanWidth % 4 )
603         DIBScanWidth += 4 - DIBScanWidth % 4;
604
605     p = img->bits;
606     for ( q = lpBits; q < lpBits + DIBScanWidth * img->height;
607             p += img->scan_width, q += DIBScanWidth )
608     {
609         memcpy( (void *)p, (void *)q, DIBScanWidth );
610     }
611
612     /* "un-blend" the image if requested.  NOTE: unblending only works with
613     // bland backgrounds */
614     if ( remove_alpha > 0 &&
615          img->bits_per_pixel == 32 &&
616          numBytes == soDIBSECTION )
617     {
618         unsigned char *color = GetBackgroundColor();
619         red   = color[2];
620         green = color[1];
621         blue  = color[0];
622
623         for ( p = img->bits; p < img->bits + img->scan_width * img->height;
624               p += 4 )
625         {
626             alpha = p[3];
627             p[2] = InverseAlphaComp( p[2], alpha, blue);
628             p[1] = InverseAlphaComp( p[1], alpha, green);
629             p[0] = InverseAlphaComp( p[0], alpha, red);
630         }
631     }
632
633     /* 32-bit DDBs must have the alpha channel set to 0xFF before they are
634     // saved to a file. This may not be true for all devices that generate
635     // 32-bit DDBs.  I have only created 32-bit DDBs using an Intense3D Wildcat
636     // 4110 card.  The alpha channel was always 0. */
637     if (img->bits_per_pixel == 32 && numBytes == soBITMAP )
638     {
639         for ( p = img->bits + 3; p < img->bits + img->scan_width * img->height;
640                                  p += 4 )
641         {
642             *p = 0xFF;
643         }
644     }
645
646     /* create palette if necessary */
647     if ( img->bits_per_pixel <= 8 )
648     {
649         hDC = GetDC( hWnd );
650         hMemDC = CreateCompatibleDC( hDC );
651         SelectObject( hMemDC, hBitmap );
652         if ( !GetDIBColorTable( hMemDC, 0, img->palette_size,
653                                 (RGBQUAD *)img->palette ) )
654         {
655             longjmp( err_jmp, (int)errWindowsAPI );
656         }
657         DeleteDC( hMemDC );
658         ReleaseDC( hWnd, hDC );
659     }
660
661     if ( FreelpBits )
662         free( lpBits );
663
664     return BMG_OK;
665 }
666
667 /*******************************************************************************
668 // this function creates a bitmap from raw data. Returns an HBITMAP if it
669 // succeeds, otherwise NULL */
670 HBITMAP CreateBitmapFromData( struct BMGImageStruct img,
671                               int alpha_blend )
672 {
673     HBITMAP hBitmap = NULL;
674     HDC hMemDC = NULL;
675     HWND hWnd = GetForegroundWindow();
676     HDC hDC = NULL;
677     RGBQUAD *pColor = NULL;
678     BITMAPINFO bmi;
679     unsigned char *rbits;
680     unsigned char *bits;
681     unsigned char *lpBits;
682     unsigned char alpha;
683     unsigned int DIBScanWidth;
684     int i;
685
686     jmp_buf err_jmp;
687     int error;
688
689     /* error handler */
690     error = setjmp( err_jmp );
691     if ( error != 0 )
692     {
693         if ( hMemDC != NULL )
694             DeleteDC( hMemDC );
695         if ( hDC != NULL )
696             ReleaseDC( hWnd, hDC );
697         if ( pColor != NULL && img.bytes_per_palette_entry == 3U )
698             free( pColor );
699         SetLastBMGError( (BMGError)error );
700         return 0;
701     }
702
703     SetLastBMGError( BMG_OK );
704
705     /* create the DIB section that will hold this bitmap */
706     bmi = InternalCreateBMI( (unsigned int)img.width, (unsigned int)img.height,
707                               (unsigned short)img.bits_per_pixel, BI_RGB );
708     bmi.bmiHeader.biClrUsed = bmi.bmiHeader.biClrImportant =
709          img.palette_size;
710     hDC = GetDC( hWnd );
711     hBitmap = CreateDIBSection( hDC, &bmi, DIB_RGB_COLORS,
712                                    (void **)&lpBits, NULL, 0 );
713
714     if ( !hBitmap || !lpBits )
715         longjmp( err_jmp, (int)errWindowsAPI );
716
717     /* create a palette if needed */
718     if ( img.palette != NULL )
719     {
720         /* copy pixel data to pColor */
721         if ( img.bytes_per_palette_entry == 4U )
722             pColor = (RGBQUAD *)img.palette;
723         else /* bytes_per_palette_entry === 3 */
724         {
725             pColor = (RGBQUAD *)calloc(img.palette_size, sizeof(RGBQUAD) );
726             if ( pColor == NULL )
727                 longjmp( err_jmp, (int)errMemoryAllocation );
728
729             bits = img.palette;
730             for ( i = 0; i < (int)bmi.bmiHeader.biClrUsed; i++, bits += 3 )
731             {
732                 pColor[i].rgbRed   = bits[0];
733                 pColor[i].rgbGreen = bits[1];
734                 pColor[i].rgbBlue  = bits[2];
735             }
736         }
737
738         if ( img.transparency_index > -1 )
739         {
740             unsigned char *color = GetBackgroundColor();
741             rbits = img.palette + img.bytes_per_palette_entry *
742                     img.transparency_index;
743             rbits[0] = color[2];
744             rbits[1] = color[1];
745             rbits[2] = color[0];
746         }
747         /* save color table in bitmap */
748         hMemDC = CreateCompatibleDC( hDC );
749         SelectObject( hMemDC, hBitmap );
750         if ( !SetDIBColorTable( hMemDC, 0, img.palette_size, pColor ) )
751             longjmp( err_jmp, (int)errWindowsAPI );
752
753         DeleteDC( hMemDC );
754         hMemDC = NULL;
755         if ( img.bytes_per_palette_entry == 3U )
756             free( pColor );
757         pColor = NULL;
758     }
759
760     /* calculate the scan line width */
761     DIBScanWidth = img.scan_width;
762     if ( DIBScanWidth % 4 )
763         DIBScanWidth += 4 - DIBScanWidth % 4;
764
765     if ( img.opt_for_bmp == 0 )
766     {
767         /* store bits into hBitmap */
768         rbits = img.bits;
769         for ( bits = lpBits;
770               bits < lpBits + img.height * DIBScanWidth;
771               bits += DIBScanWidth, rbits += img.scan_width )
772         {
773             memcpy( (void *)bits, (void *)rbits, img.scan_width );
774         }
775     }
776     else
777         memcpy( (void *)lpBits, (void *)img.bits, img.scan_width * img.height );
778
779     /* blend the image with the window background if alpha pixels
780     // are present */
781     if ( img.bits_per_pixel == 32 )
782     {
783         /* blend with a bland background */
784         if ( alpha_blend == 1 )
785         {
786             unsigned char *color = GetBackgroundColor();
787             unsigned char red   = color[2];
788             unsigned char green = color[1];
789             unsigned char blue  = color[0];
790
791             for ( rbits = lpBits;
792                   rbits < lpBits + img.height*DIBScanWidth;
793                   rbits += DIBScanWidth )
794             {
795                 for ( bits = rbits; bits < rbits + DIBScanWidth; bits += 4 )
796                 {
797                     alpha = bits[3];
798                     bits[2] = AlphaComp( bits[2], alpha, blue );
799                     bits[1] = AlphaComp( bits[1], alpha, green );
800                     bits[0] = AlphaComp( bits[0], alpha, red );
801                 }
802             }
803         }
804         /* blend with a background image */
805         else if ( alpha_blend == 2 )
806         {
807             unsigned char *bg_bits;
808             unsigned char *bg_bits_2;
809             unsigned int bg_bytes_per_pixel;
810             struct BMGImageStruct *bg = GetBackgroundImage();
811
812             /* make sure we can blend with a background image
813             // I assume that the background image is invalid if it does not
814             // have a valid width */
815             if ( bg->width <= 0 || bg->height <= 0 )
816                 longjmp( err_jmp, (int)errUndefinedBGImage );
817
818             /* I cannot blend a foreground image with a background image that
819             // is smaller than it */
820             if ( bg->width < img.width || bg->height < img.height )
821                 longjmp( err_jmp, (int)errBGImageTooSmall );
822
823             /* the background image was forced to be a 24 or 32-BPP image;
824             // therefore, we can safely divide by 8 to determined the
825             // bytes per pixel*/
826             bg_bytes_per_pixel = bg->bits_per_pixel / 8;
827
828             /* I will assume that the upper left corner of the input image
829             // must be aligned with the upper left corner of the background
830             // image.  This allows me to have background images that are bigger
831             // than the input image. */
832             bg_bits = bg->bits;
833             for ( rbits = lpBits;
834                   rbits < lpBits + img.height*DIBScanWidth;
835                   rbits += DIBScanWidth, bg_bits += bg->scan_width )
836             {
837                 bg_bits_2 = bg_bits;
838                 for ( bits = rbits; bits < rbits + DIBScanWidth;
839                       bits += 4, bg_bits_2 += bg_bytes_per_pixel )
840                 {
841                     alpha = bits[3];
842                     bits[2] = AlphaComp( bits[2], alpha, bg_bits_2[2] );
843                     bits[1] = AlphaComp( bits[1], alpha, bg_bits_2[1] );
844                     bits[0] = AlphaComp( bits[0], alpha, bg_bits_2[0] );
845                 }
846             }
847
848         }
849     }
850
851     ReleaseDC( hWnd, hDC );
852
853     return hBitmap;
854 }
855 #endif // _WIN32
856 /******************************************************************************
857 //  ConvertPaletteToRGB converts paletted and 16-BPP images that do not have
858 // transparent pixels to 24-BPP images.  Paletted images with transparent pixels
859 // are converted to 32-BPP images.  24-BPP and 32-BPP images are simply copied
860 // to the output structure
861 //
862 // INPUTS:
863 //  img_in
864 // OUTPUTS:
865 //  img_out
866 //
867 // returns BMG_OK if no errors occur, an error code otherwise
868 ******************************************************************************/
869 BMGError ConvertPaletteToRGB( struct BMGImageStruct img_in,
870                               struct BMGImageStruct *img_out )
871 {
872     jmp_buf err_jmp;
873     int error;
874
875     /* error handler */
876     error = setjmp( err_jmp );
877     if ( error != 0 )
878     {
879         FreeBMGImage( img_out );
880         SetLastBMGError( (BMGError)error );
881         return (BMGError)error;
882     }
883
884     SetLastBMGError( BMG_OK );
885
886     if ( img_in.height == 0 || img_in.width == 0 )
887         longjmp( err_jmp, (int)errInvalidSize );
888
889     InitBMGImage( img_out );
890
891     // copy 16, 24, and 32-BPP images into the output image
892     if ( img_in.bits_per_pixel > 8 )
893     {
894         BMGError out;
895         img_out->bits_per_pixel = img_in.bits_per_pixel;
896         out = CopyBMGImage( img_in, img_out );
897         if ( out != BMG_OK )
898             longjmp( err_jmp, (int)out );
899
900         // 16-BPP are converted to 24-BPP images
901         if ( img_out->bits_per_pixel == 16 )
902         {
903             out = Convert16to24( img_out );
904             if ( out != BMG_OK )
905                 longjmp( err_jmp, (int)out );
906         }
907     }
908     else // convert paletted images to 24-BPP BGR or 32-BPP BGRA images
909     {
910         BMGError out;
911         unsigned char *buf;
912         unsigned int scan_width;
913         int dealloc;
914         unsigned char *q0, *q1, *p0, *p1;
915         unsigned int bpp;
916
917         // allocate memory for the 24-BPP output image
918         img_out->width  = img_in.width;
919         img_out->height = img_in.height;
920         img_out->opt_for_bmp = img_in.opt_for_bmp;
921         img_out->bits_per_pixel = img_in.transparency_index > -1 ? 32 : 24;
922
923         out = AllocateBMGImage( img_out );
924         if ( out != BMG_OK )
925             longjmp( err_jmp, (int)out );
926
927         // 1-BPP and 4-BPP images are packed, so we need to unpack them
928         if ( img_in.bits_per_pixel < 8 )
929         {
930             dealloc = 1;
931             scan_width = img_in.width;
932             buf = (unsigned char *)malloc(scan_width * img_in.height);
933             if ( buf == NULL )
934                 longjmp( err_jmp, (int)errMemoryAllocation );
935
936             if ( img_in.bits_per_pixel == 1 )
937                 Convert1to8( img_in, buf );
938             else
939                 Convert4to8( img_in, buf );
940         }
941         else // simply point to the bits array if we have a 8-BPP image
942         {
943             dealloc = 0;
944             buf = img_in.bits;
945             scan_width = img_in.scan_width;
946         }
947
948         // convert palette indices to BGR pixels
949         bpp = img_out->bits_per_pixel / 8;
950         q0 = img_out->bits;
951         for ( p0 = buf; p0 < buf + scan_width * img_in.height;
952                     p0 += scan_width, q0 += img_out->scan_width )
953         {
954             q1 = q0;
955             for ( p1 = p0; p1 < p0 + img_in.width; p1++, q1 += bpp )
956             {
957                 memcpy( (void *)q1,
958                     (void *)(img_in.palette + *p1 * img_in.bytes_per_palette_entry), 3 );
959                 if ( bpp == 4 )
960                 {
961                     q1[3] = *p1 == img_in.transparency_index ? 0 : 0xFF;
962                 }
963             }
964         }
965
966         if ( dealloc == 1 )
967             free( buf );
968     }
969
970     return BMG_OK;
971 }
972
973 /******************************************************************************
974 // CopyBMG copies the contents of img_in into img_out.
975 //
976 // CopyBMG returns BMG_OK if successful, otherwise, it returns an error code
977 ******************************************************************************/
978 BMGError CopyBMGImage( struct BMGImageStruct img_in,
979                        struct BMGImageStruct *img_out )
980 {
981     BMGError out = BMG_OK;
982     SetLastBMGError( out );
983
984     FreeBMGImage( img_out );
985
986     img_out->height = img_in.height;
987     img_out->width = img_in.width;
988     img_out->bits_per_pixel = img_in.bits_per_pixel;
989     img_out->palette_size = img_in.palette_size;
990     img_out->opt_for_bmp = img_in.opt_for_bmp;
991
992     if ( img_in.width > 0 && img_in.height > 0 )
993     {
994         out = AllocateBMGImage( img_out );
995         if ( out == BMG_OK )
996         {
997             memcpy( (void *)img_out->bits, (void *)img_in.bits,
998                 img_in.scan_width * img_in.height );
999             if ( img_in.palette_size > 0 )
1000                 memcpy( (void *)img_out->palette, (void *)img_in.palette,
1001                     img_in.palette_size * img_in.bytes_per_palette_entry );
1002         }
1003     }
1004
1005     return out;
1006 }
1007
1008 /* sets the background color for alpha blending
1009   color points to an array of 4 unsigned chars
1010   color[0] = blue, color[1] = green, color[2] = red, color[3] = unused */
1011 void SetBMGBackgroundColor( unsigned char *color )
1012 {
1013     memcpy( (void *)GetBackgroundColor(), (void *)color,
1014             4*sizeof(unsigned char) );
1015 }
1016
1017 #ifdef _WIN32
1018 /* defines the background bitmap that is used for alpha blending & transparent
1019    pixels */
1020 BMGError SetBMGBackgroundBitmap( HBITMAP hBitmap )
1021 {
1022     BMGError out;
1023     struct BMGImageStruct tmp;
1024     InitBMGImage( &tmp );
1025
1026     /* first we extract the data from the HBITMAP */
1027     out = GetDataFromBitmap( hBitmap, &tmp, 0 );
1028     if ( out == BMG_OK )
1029     {
1030         /* clean up the old background image */
1031         FreeBMGImage( GetBackgroundImage() );
1032
1033         /* next, we convert paletted & 16-BPP images to 24 or 32-BPP images.
1034         // this will simplify the alpha blending. */
1035         out = ConvertPaletteToRGB( tmp, GetBackgroundImage() );
1036     }
1037
1038     return out;
1039 }
1040 #endif // _WIN32
1041
1042 /* defines the background image that is used for alpha blending & transparent
1043    pixels */
1044 BMGError SetBMGBackgroundImage( struct BMGImageStruct img )
1045 {
1046     /* clean up the old background image */
1047     FreeBMGImage( GetBackgroundImage() );
1048
1049     /* convert paletted and 16-BPP images to 24-BPP or 32-BPP images.  This
1050     // will simplify the alpha blending logic*/
1051     return ConvertPaletteToRGB( img, GetBackgroundImage() );
1052 }
1053