]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - plugins/image/lbmlib.cpp
8MB stack size linker options on all VC2008 proj files.
[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       if (targa_header.pixel_size == 32)
556                                 Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
557       // disable the alpha value
558       for (row = rows - 1; row >= 0; row--)
559       {
560         pixbuf = targa_rgba + row * columns * 4;
561         for (column = 0; column < columns; column++)
562         {
563           // 32 bit
564           pixbuf += 3;
565           *pixbuf++ = 255;
566         }
567       }
568     }
569   }
570   else if (targa_header.image_type == 10)
571   {                             // Runlength encoded RGB images
572     unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;
573
574     red = 0;
575     green = 0;
576     blue = 0;
577     alphabyte = 0xff;
578
579     for (row = rows - 1; row >= 0; row--)
580     {
581       pixbuf = targa_rgba + row * columns * 4;
582       for (column = 0; column < columns;)
583       {
584         packetHeader = *buf_p++;
585         packetSize = 1 + (packetHeader & 0x7f);
586         if (packetHeader & 0x80)
587         {                       // run-length packet
588           switch (targa_header.pixel_size)
589           {
590           case 24:
591             blue = *buf_p++;
592             green = *buf_p++;
593             red = *buf_p++;
594             alphabyte = 255;
595             break;
596           case 32:
597             blue = *buf_p++;
598             green = *buf_p++;
599             red = *buf_p++;
600             alphabyte = *buf_p++;
601             // detect if the whole alpha channel is 0
602             if (alphabyte != 0)
603               bAlphaOK = true;
604             break;
605           default:
606             Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,
607             name);
608             g_free (*pic);
609             *pic = NULL;
610             return;
611             break;
612           }
613
614           for (j = 0; j < packetSize; j++)
615           {
616             *pixbuf++ = red;
617             *pixbuf++ = green;
618             *pixbuf++ = blue;
619                   *pixbuf++ = alphabyte;
620             column++;
621             if (column == columns)
622             {                   // run spans across rows
623               column = 0;
624               if (row > 0)
625                 row--;
626               else
627                 goto breakOut;
628             pixbuf = targa_rgba + row * columns * 4;
629             }
630           }
631         }
632         else
633         {                       // non run-length packet
634           for (j = 0; j < packetSize; j++)
635           {
636             switch (targa_header.pixel_size)
637             {
638               case 24:
639                 blue = *buf_p++;
640                 green = *buf_p++;
641                 red = *buf_p++;
642                 *pixbuf++ = red;
643                 *pixbuf++ = green;
644                 *pixbuf++ = blue;
645                 *pixbuf++ = 255;
646                 break;
647               case 32:
648                 blue = *buf_p++;
649                 green = *buf_p++;
650                 red = *buf_p++;
651                 alphabyte = *buf_p++;
652                 // detect if the whole alpha channel is 0
653                 if (alphabyte != 0)
654                   bAlphaOK = true;
655                 *pixbuf++ = red;
656                 *pixbuf++ = green;
657                 *pixbuf++ = blue;
658                 *pixbuf++ = alphabyte;
659                 break;
660               default:
661                 Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n",
662                 targa_header.pixel_size, name);
663                 g_free (*pic);
664                 *pic = NULL;
665                 return;
666                 break;
667             }
668             column++;
669             if (column == columns)
670             {                   // pixel packet run spans across rows
671               column = 0;
672               if (row > 0)
673                 row--;
674               else
675                 goto breakOut;
676               pixbuf = targa_rgba + row * columns * 4;
677             }
678           }
679         }
680       }
681     breakOut:;
682     }
683
684     if (!bAlphaOK)
685     {
686       if (targa_header.pixel_size == 32)
687         Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
688       // disable the alpha value
689       for (row = rows - 1; row >= 0; row--)
690       {
691         pixbuf = targa_rgba + row * columns * 4;
692         for (column = 0; column < columns; column++)
693         {
694           // 32 bit
695           pixbuf += 3;
696           *pixbuf++ = 255;
697         }
698       }
699     }
700
701   }
702
703   // vertically flipped
704   if ( (targa_header.attributes & (1<<5)) ) {
705     int flip;
706     for (row = 0; row < .5f * rows; row++)
707     {
708       for (column = 0; column < columns; column++)
709       {
710         flip = *( (int*)targa_rgba + row * columns + column);
711                 *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
712                 *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
713           }
714         }
715   }
716
717   vfsFreeFile (buffer);
718 }
719
720 //===================================================================
721
722 /*
723 =================
724 LoadImage
725
726 Loads any of the supported image types into a cannonical
727 32 bit format.
728 =================
729 */
730 void LoadImage (const char *name, byte ** pic, int *width, int *height)
731 {
732   int len;
733   *pic = NULL;
734   *width = 0;
735   *height = 0;
736
737   len = strlen (name);
738   if (len < 5)
739   {
740     return;
741   }
742
743   if (!g_strcasecmp (name + len - 4, ".tga"))
744   {
745     LoadTGA (name, pic, width, height);
746   }
747   else if (!g_strcasecmp (name + len - 4, ".pcx"))
748   {
749     LoadPCX32 (name, pic, width, height);
750   }
751   else if (!g_strcasecmp (name + len - 4, ".bmp"))
752   {
753     LoadBMP (name, pic, width, height);
754   }
755   /*
756   else if (!g_strcasecmp (name + len - 4, ".jpg"))
757   {
758     LoadJPG (name, pic, width, height);
759   }
760   */
761 }