more eol-style
[xonotic/netradiant.git] / plugins / image / lbmlib.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant 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
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 // lbmlib.c
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include <glib.h>
27 #include "image.h"
28 #include "lbmlib.h"
29 #include "bmp.h"
30
31 #define LittleLong(a) GINT32_FROM_LE(a)
32 #define LittleShort(a) GINT16_FROM_LE(a)
33
34 #include <stdio.h>
35
36 #define Sys_Printf g_FuncTable.m_pfnSysPrintf
37 #define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf
38
39 /*
40 ============================================================================
41
42 LOAD PCX
43
44 ============================================================================
45 */
46 typedef struct
47 {
48   char manufacturer;
49   char version;
50   char encoding;
51   char bits_per_pixel;
52   unsigned short xmin, ymin, xmax, ymax;
53   unsigned short hres, vres;
54   unsigned char palette[48];
55   char reserved;
56   char color_planes;
57   unsigned short bytes_per_line;
58   unsigned short palette_type;
59   char filler[58];
60   unsigned char data;           // unbounded
61 } pcx_t;
62
63 /*
64 ============================================================================
65
66 TARGA IMAGE
67
68 ============================================================================
69 */
70 typedef struct _TargaHeader
71 {
72   unsigned char id_length, colormap_type, image_type;
73   unsigned short colormap_index, colormap_length;
74   unsigned char colormap_size;
75   unsigned short x_origin, y_origin, width, height;
76   unsigned char pixel_size, attributes;
77 } TargaHeader;
78
79 /*
80 =========================================================
81
82 BMP LOADING
83
84 =========================================================
85 */
86 typedef struct
87 {
88   char id[2];
89   unsigned long fileSize;
90   unsigned long reserved0;
91   unsigned long bitmapDataOffset;
92   unsigned long bitmapHeaderSize;
93   unsigned long width;
94   unsigned long height;
95   unsigned short planes;
96   unsigned short bitsPerPixel;
97   unsigned long compression;
98   unsigned long bitmapDataSize;
99   unsigned long hRes;
100   unsigned long vRes;
101   unsigned long colors;
102   unsigned long importantColors;
103   unsigned char palette[256][4];
104 } BMPHeader_t;
105
106 static void LoadBMP (const char *name, byte ** pic, int *width, int *height)
107 {
108   int columns, rows, numPixels;
109   byte *pixbuf;
110   int row, column;
111   byte *buf_p;
112   byte *buffer;
113   unsigned int length;
114   BMPHeader_t bmpHeader;
115   byte *bmpRGBA;
116
117   *pic = NULL;
118
119   //
120   // load the file
121   //
122   length = vfsLoadFile( (char *)name, (void **)&buffer, 0 );
123   if (length == (unsigned int) -1)
124     return;
125
126   buf_p = buffer;
127
128   bmpHeader.id[0] = *buf_p++;
129   bmpHeader.id[1] = *buf_p++;
130   bmpHeader.fileSize = LittleLong (*(long *) buf_p);
131   buf_p += 4;
132   bmpHeader.reserved0 = LittleLong (*(long *) buf_p);
133   buf_p += 4;
134   bmpHeader.bitmapDataOffset = LittleLong (*(long *) buf_p);
135   buf_p += 4;
136   bmpHeader.bitmapHeaderSize = LittleLong (*(long *) buf_p);
137   buf_p += 4;
138   bmpHeader.width = LittleLong (*(long *) buf_p);
139   buf_p += 4;
140   bmpHeader.height = LittleLong (*(long *) buf_p);
141   buf_p += 4;
142   bmpHeader.planes = LittleShort (*(short *) buf_p);
143   buf_p += 2;
144   bmpHeader.bitsPerPixel = LittleShort (*(short *) buf_p);
145   buf_p += 2;
146   bmpHeader.compression = LittleLong (*(long *) buf_p);
147   buf_p += 4;
148   bmpHeader.bitmapDataSize = LittleLong (*(long *) buf_p);
149   buf_p += 4;
150   bmpHeader.hRes = LittleLong (*(long *) buf_p);
151   buf_p += 4;
152   bmpHeader.vRes = LittleLong (*(long *) buf_p);
153   buf_p += 4;
154   bmpHeader.colors = LittleLong (*(long *) buf_p);
155   buf_p += 4;
156   bmpHeader.importantColors = LittleLong (*(long *) buf_p);
157   buf_p += 4;
158
159   memcpy (bmpHeader.palette, buf_p, sizeof (bmpHeader.palette));
160
161   if (bmpHeader.bitsPerPixel == 8)
162     buf_p += 1024;
163
164   if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M')
165   {
166     Sys_Printf ("LoadBMP: only Windows-style BMP files supported (%s)\n", name);
167     return;
168   }
169   if (bmpHeader.fileSize != length)
170   {
171     Sys_Printf ("LoadBMP: header size does not match file size (%d vs. %d) (%s)\n",
172                 bmpHeader.fileSize, length, name);
173     return;
174   }
175   if (bmpHeader.compression != 0)
176   {
177     Sys_Printf ("LoadBMP: only uncompressed BMP files supported (%s)\n", name);
178     return;
179   }
180   if (bmpHeader.bitsPerPixel < 8)
181   {
182     Sys_Printf ("LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name);
183     return;
184   }
185
186   columns = bmpHeader.width;
187   rows = bmpHeader.height;
188   if (rows < 0)
189     rows = -rows;
190   numPixels = columns * rows;
191
192   if (width)
193     *width = columns;
194   if (height)
195     *height = rows;
196
197   bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));
198   *pic = bmpRGBA;
199
200
201   for (row = rows - 1; row >= 0; row--)
202   {
203     pixbuf = bmpRGBA + row * columns * 4;
204
205     for (column = 0; column < columns; column++)
206     {
207       unsigned char red, green, blue, alpha;
208       int palIndex;
209       unsigned short shortPixel;
210
211       switch (bmpHeader.bitsPerPixel)
212       {
213       case 8:
214         palIndex = *buf_p++;
215         *pixbuf++ = bmpHeader.palette[palIndex][2];
216         *pixbuf++ = bmpHeader.palette[palIndex][1];
217         *pixbuf++ = bmpHeader.palette[palIndex][0];
218         *pixbuf++ = 0xff;
219         break;
220       case 16:
221         shortPixel = *(unsigned short *) pixbuf;
222         pixbuf += 2;
223         *pixbuf++ = (shortPixel & (31 << 10)) >> 7;
224         *pixbuf++ = (shortPixel & (31 << 5)) >> 2;
225         *pixbuf++ = (shortPixel & (31)) << 3;
226         *pixbuf++ = 0xff;
227         break;
228       case 24:
229         blue = *buf_p++;
230         green = *buf_p++;
231         red = *buf_p++;
232         *pixbuf++ = red;
233         *pixbuf++ = green;
234         *pixbuf++ = blue;
235         *pixbuf++ = 255;
236         break;
237       case 32:
238         blue = *buf_p++;
239         green = *buf_p++;
240         red = *buf_p++;
241         alpha = *buf_p++;
242         *pixbuf++ = red;
243         *pixbuf++ = green;
244         *pixbuf++ = blue;
245         *pixbuf++ = alpha;
246         break;
247       default:
248         Sys_Printf ("LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel,
249               name);
250         g_free (*pic);
251         *pic = NULL;
252         return;
253         break;
254       }
255     }
256   }
257
258   vfsFreeFile (buffer);
259
260 }
261
262
263 /*
264 =================================================================
265
266 PCX LOADING
267
268 =================================================================
269 */
270
271
272 /*
273 ==============
274 LoadPCX
275 ==============
276 */
277
278 /* RR2DO2 */
279 #define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
280
281 static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
282 {
283   byte  *raw;
284   pcx_t *pcx;
285   int           x, y, lsize;
286   int           len;
287   int           dataByte, runLength;
288   byte  *out, *pix;
289         
290
291   /* load the file */
292   len = vfsLoadFile (filename, (void **)&raw, 0);
293   if( len == -1 ) 
294     Error( "LoadPCX: Couldn't read %s", filename );
295
296
297   /* parse the PCX file */
298   pcx = (pcx_t *)raw;
299   raw = &pcx->data;
300   
301   pcx->xmin = LittleShort(pcx->xmin);
302   pcx->ymin = LittleShort(pcx->ymin);
303   pcx->xmax = LittleShort(pcx->xmax);
304   pcx->ymax = LittleShort(pcx->ymax);
305   pcx->hres = LittleShort(pcx->hres);
306   pcx->vres = LittleShort(pcx->vres);
307   pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
308   pcx->palette_type = LittleShort(pcx->palette_type);
309   
310   if (pcx->manufacturer != 0x0a
311     || pcx->version != 5
312     || pcx->encoding != 1
313     || pcx->bits_per_pixel != 8
314     || pcx->xmax >= 640
315     || pcx->ymax >= 480)
316     Error ("Bad pcx file %s", filename);
317
318   if (palette)
319   {
320     *palette = (byte *)malloc(768);
321     memcpy (*palette, (byte *)pcx + len - 768, 768);
322   }
323
324   if (width)
325     *width = pcx->xmax+1;
326   if (height)
327     *height = pcx->ymax+1;
328
329   if (!pic)
330     return;
331
332   out = (byte *)malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
333   if (!out)
334     Error( "LoadPCX: couldn't allocate");
335
336   *pic = out;
337   pix = out;
338         
339   /* RR2DO2: pcx fix  */
340   lsize = pcx->color_planes * pcx->bytes_per_line;
341         
342   /* go scanline by scanline */
343   for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
344   {
345     /* do a scanline */
346     for( x=0; x <= pcx->xmax; )
347     {
348       /* RR2DO2 */
349       DECODEPCX( raw, dataByte, runLength );
350       while( runLength-- > 0 )
351         pix[ x++ ] = dataByte;
352     }
353
354     /* RR2DO2: discard any other data */
355     while( x < lsize )
356     {
357       DECODEPCX( raw, dataByte, runLength );
358       x++;
359     }
360     while( runLength-- > 0 )
361       x++;
362   }
363         
364   /* validity check */
365   if( raw - (byte *) pcx > len)
366     Error( "PCX file %s was malformed", filename );
367   free( pcx );
368 }
369
370 /*
371 ==============
372 LoadPCX32
373 ==============
374 */
375 static void LoadPCX32 (const char *filename, byte ** pic, int *width, int *height)
376 {
377   byte *palette;
378   byte *pic8;
379   int i, c, p;
380   byte *pic32;
381
382   LoadPCX (filename, &pic8, &palette, width, height);
383   if (!pic8)
384   {
385     *pic = NULL;
386     return;
387   }
388
389   c = (*width) * (*height);
390   pic32 = *pic = reinterpret_cast < unsigned char *>(g_malloc (4 * c));
391   for (i = 0; i < c; i++)
392   {
393     p = pic8[i];
394     pic32[0] = palette[p * 3];
395     pic32[1] = palette[p * 3 + 1];
396     pic32[2] = palette[p * 3 + 2];
397     pic32[3] = 255;
398     pic32 += 4;
399   }
400
401   g_free (pic8);
402   g_free (palette);
403 }
404
405 /*
406 =========================================================
407
408 TARGA LOADING
409
410   TTimo: added code to get rid of alphachannel from prefs or ignore it if completely empty
411     was required since Radiant is using alpha channel when binding the textures for proper curry operation
412     can be fully turned off from the prefs though
413 =========================================================
414 */
415
416 /*
417 =============
418 LoadTGA
419 =============
420 */
421 void LoadTGA (const char *name, byte ** pic, int *width, int *height)
422 {
423   int columns, rows, numPixels;
424   byte *pixbuf;
425   int row, column;
426   byte *buf_p;
427   byte *buffer;
428   TargaHeader targa_header;
429   byte *targa_rgba;
430
431   *pic = NULL;
432
433   //
434   // load the file
435   //
436   int nLen = vfsLoadFile( (char *)name, (void **)&buffer, 0 );
437   if (nLen == -1)
438     return;
439
440   buf_p = buffer;
441
442   targa_header.id_length = *buf_p++;
443   targa_header.colormap_type = *buf_p++;
444   targa_header.image_type = *buf_p++;
445
446   targa_header.colormap_index = LittleShort (*(short *) buf_p);
447   buf_p += 2;
448   targa_header.colormap_length = LittleShort (*(short *) buf_p);
449   buf_p += 2;
450   targa_header.colormap_size = *buf_p++;
451   targa_header.x_origin = LittleShort (*(short *) buf_p);
452   buf_p += 2;
453   targa_header.y_origin = LittleShort (*(short *) buf_p);
454   buf_p += 2;
455   targa_header.width = LittleShort (*(short *) buf_p);
456   buf_p += 2;
457   targa_header.height = LittleShort (*(short *) buf_p);
458   buf_p += 2;
459   targa_header.pixel_size = *buf_p++;
460   targa_header.attributes = *buf_p++;
461
462   bool bAlphaOK = false;
463
464   if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)
465   {
466     Sys_Printf ("LoadTGA: TGA type %d not supported\n", targa_header.image_type);
467     Sys_Printf ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
468     return;
469   }
470
471   if (targa_header.colormap_type != 0)
472   {
473     Sys_Printf ("LoadTGA: colormaps not supported\n");
474     return;
475   }
476
477   if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)
478       && targa_header.image_type != 3)
479   {
480     Sys_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
481     return;
482   }
483
484   columns = targa_header.width;
485   rows = targa_header.height;
486   numPixels = columns * rows;
487
488   if (width)
489     *width = columns;
490   if (height)
491     *height = rows;
492
493   targa_rgba = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));
494   *pic = targa_rgba;
495
496   if (targa_header.id_length != 0)
497     buf_p += targa_header.id_length;    // skip TARGA image comment
498
499   if (targa_header.image_type == 2 || targa_header.image_type == 3)
500   {
501     // Uncompressed RGB or gray scale image
502     for (row = rows - 1; row >= 0; row--)
503     {
504       pixbuf = targa_rgba + row * columns * 4;
505       for (column = 0; column < columns; column++)
506       {
507         unsigned char red, green, blue, alphabyte;
508         switch (targa_header.pixel_size)
509         {
510           case 8:
511             blue = *buf_p++;
512             green = blue;
513             red = blue;
514             *pixbuf++ = red;
515             *pixbuf++ = green;
516             *pixbuf++ = blue;
517             *pixbuf++ = 255;
518             break;
519           
520           case 24:
521             blue = *buf_p++;
522             green = *buf_p++;
523             red = *buf_p++;
524             *pixbuf++ = red;
525             *pixbuf++ = green;
526             *pixbuf++ = blue;
527             *pixbuf++ = 255;
528             break;
529           case 32:
530             blue = *buf_p++;
531             green = *buf_p++;
532             red = *buf_p++;
533             alphabyte = *buf_p++;
534             // detect if the whole alpha channel is 0
535             if (alphabyte != 0)
536               bAlphaOK = true;
537             *pixbuf++ = red;
538             *pixbuf++ = green;
539             *pixbuf++ = blue;
540             *pixbuf++ = alphabyte;
541             break;
542           default:
543             Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,
544                   name);
545             g_free (*pic);
546             *pic = NULL;
547             return;
548             break;
549         }
550       }
551     }
552
553     if (!bAlphaOK)
554     {
555       // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444
556       if (targa_header.pixel_size == 32) 
557                                 Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
558       // disable the alpha value
559       for (row = rows - 1; row >= 0; row--)
560       {
561         pixbuf = targa_rgba + row * columns * 4;
562         for (column = 0; column < columns; column++)
563         {
564           // 32 bit
565           pixbuf += 3;
566           *pixbuf++ = 255;
567         }
568       }
569     }
570   }
571   else if (targa_header.image_type == 10)
572   {                             // Runlength encoded RGB images
573     unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;
574
575     red = 0;
576     green = 0;
577     blue = 0;
578     alphabyte = 0xff;
579
580     for (row = rows - 1; row >= 0; row--)
581     {
582       pixbuf = targa_rgba + row * columns * 4;
583       for (column = 0; column < columns;)
584       {
585         packetHeader = *buf_p++;
586         packetSize = 1 + (packetHeader & 0x7f);
587         if (packetHeader & 0x80)
588         {                       // run-length packet
589           switch (targa_header.pixel_size)
590           {
591           case 24:
592             blue = *buf_p++;
593             green = *buf_p++;
594             red = *buf_p++;
595             alphabyte = 255;
596             break;
597           case 32:
598             blue = *buf_p++;
599             green = *buf_p++;
600             red = *buf_p++;
601             alphabyte = *buf_p++;
602             // detect if the whole alpha channel is 0
603             if (alphabyte != 0)
604               bAlphaOK = true;
605             break;
606           default:
607             Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,
608             name);
609             g_free (*pic);
610             *pic = NULL;
611             return;
612             break;
613           }
614
615           for (j = 0; j < packetSize; j++)
616           {
617             *pixbuf++ = red;
618             *pixbuf++ = green;
619             *pixbuf++ = blue;
620                   *pixbuf++ = alphabyte;
621             column++;
622             if (column == columns)
623             {                   // run spans across rows
624               column = 0;
625               if (row > 0)
626                 row--;
627               else
628                 goto breakOut;
629             pixbuf = targa_rgba + row * columns * 4;
630             }
631           }
632         }
633         else
634         {                       // non run-length packet
635           for (j = 0; j < packetSize; j++)
636           {
637             switch (targa_header.pixel_size)
638             {
639               case 24:
640                 blue = *buf_p++;
641                 green = *buf_p++;
642                 red = *buf_p++;
643                 *pixbuf++ = red;
644                 *pixbuf++ = green;
645                 *pixbuf++ = blue;
646                 *pixbuf++ = 255;
647                 break;
648               case 32:
649                 blue = *buf_p++;
650                 green = *buf_p++;
651                 red = *buf_p++;
652                 alphabyte = *buf_p++;
653                 // detect if the whole alpha channel is 0
654                 if (alphabyte != 0)
655                   bAlphaOK = true;
656                 *pixbuf++ = red;
657                 *pixbuf++ = green;
658                 *pixbuf++ = blue;
659                 *pixbuf++ = alphabyte;
660                 break;
661               default:
662                 Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n",
663                 targa_header.pixel_size, name);
664                 g_free (*pic);
665                 *pic = NULL;
666                 return;
667                 break;
668             }
669             column++;
670             if (column == columns)
671             {                   // pixel packet run spans across rows
672               column = 0;
673               if (row > 0)
674                 row--;
675               else
676                 goto breakOut;
677               pixbuf = targa_rgba + row * columns * 4;
678             }
679           }
680         }
681       }
682     breakOut:;
683     }
684
685     if (!bAlphaOK)
686     {
687       if (targa_header.pixel_size == 32)
688         Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
689       // disable the alpha value
690       for (row = rows - 1; row >= 0; row--)
691       {
692         pixbuf = targa_rgba + row * columns * 4;
693         for (column = 0; column < columns; column++)
694         {
695           // 32 bit
696           pixbuf += 3;
697           *pixbuf++ = 255;
698         }
699       }
700     }
701
702   }
703
704   // vertically flipped
705   if ( (targa_header.attributes & (1<<5)) ) {
706     int flip;
707     for (row = 0; row < .5f * rows; row++)
708     {
709       for (column = 0; column < columns; column++)
710       {
711         flip = *( (int*)targa_rgba + row * columns + column);
712                 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
713                 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
714           }
715         }
716   }
717
718   vfsFreeFile (buffer);
719 }
720
721 //===================================================================
722
723 /*
724 =================
725 LoadImage
726
727 Loads any of the supported image types into a cannonical
728 32 bit format.
729 =================
730 */
731 void LoadImage (const char *name, byte ** pic, int *width, int *height)
732 {
733   int len;
734   *pic = NULL;
735   *width = 0;
736   *height = 0;
737
738   len = strlen (name);
739   if (len < 5)
740   {
741     return;
742   }
743
744   if (!g_strcasecmp (name + len - 4, ".tga"))
745   {
746     LoadTGA (name, pic, width, height);
747   }
748   else if (!g_strcasecmp (name + len - 4, ".pcx"))
749   {
750     LoadPCX32 (name, pic, width, height);
751   }
752   else if (!g_strcasecmp (name + len - 4, ".bmp"))
753   {
754     LoadBMP (name, pic, width, height);
755   }
756   /*
757   else if (!g_strcasecmp (name + len - 4, ".jpg"))
758   {
759     LoadJPG (name, pic, width, height);
760   }
761   */
762 }