-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-// lbmlib.c\r
-\r
-#include <stdlib.h>\r
-#include <string.h>\r
-#include <glib.h>\r
-#include "image.h"\r
-#include "lbmlib.h"\r
-#include "bmp.h"\r
-\r
-#define LittleLong(a) GINT32_FROM_LE(a)\r
-#define LittleShort(a) GINT16_FROM_LE(a)\r
-\r
-#include <stdio.h>\r
-\r
-#define Sys_Printf g_FuncTable.m_pfnSysPrintf\r
-#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf\r
-\r
-/*\r
-============================================================================\r
-\r
-LOAD PCX\r
-\r
-============================================================================\r
-*/\r
-typedef struct\r
-{\r
- char manufacturer;\r
- char version;\r
- char encoding;\r
- char bits_per_pixel;\r
- unsigned short xmin, ymin, xmax, ymax;\r
- unsigned short hres, vres;\r
- unsigned char palette[48];\r
- char reserved;\r
- char color_planes;\r
- unsigned short bytes_per_line;\r
- unsigned short palette_type;\r
- char filler[58];\r
- unsigned char data; // unbounded\r
-} pcx_t;\r
-\r
-/*\r
-============================================================================\r
-\r
-TARGA IMAGE\r
-\r
-============================================================================\r
-*/\r
-typedef struct _TargaHeader\r
-{\r
- unsigned char id_length, colormap_type, image_type;\r
- unsigned short colormap_index, colormap_length;\r
- unsigned char colormap_size;\r
- unsigned short x_origin, y_origin, width, height;\r
- unsigned char pixel_size, attributes;\r
-} TargaHeader;\r
-\r
-/*\r
-=========================================================\r
-\r
-BMP LOADING\r
-\r
-=========================================================\r
-*/\r
-typedef struct\r
-{\r
- char id[2];\r
- unsigned long fileSize;\r
- unsigned long reserved0;\r
- unsigned long bitmapDataOffset;\r
- unsigned long bitmapHeaderSize;\r
- unsigned long width;\r
- unsigned long height;\r
- unsigned short planes;\r
- unsigned short bitsPerPixel;\r
- unsigned long compression;\r
- unsigned long bitmapDataSize;\r
- unsigned long hRes;\r
- unsigned long vRes;\r
- unsigned long colors;\r
- unsigned long importantColors;\r
- unsigned char palette[256][4];\r
-} BMPHeader_t;\r
-\r
-static void LoadBMP (const char *name, byte ** pic, int *width, int *height)\r
-{\r
- int columns, rows, numPixels;\r
- byte *pixbuf;\r
- int row, column;\r
- byte *buf_p;\r
- byte *buffer;\r
- unsigned int length;\r
- BMPHeader_t bmpHeader;\r
- byte *bmpRGBA;\r
-\r
- *pic = NULL;\r
-\r
- //\r
- // load the file\r
- //\r
- length = vfsLoadFile( (char *)name, (void **)&buffer, 0 );\r
- if (length == (unsigned int) -1)\r
- return;\r
-\r
- buf_p = buffer;\r
-\r
- bmpHeader.id[0] = *buf_p++;\r
- bmpHeader.id[1] = *buf_p++;\r
- bmpHeader.fileSize = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.reserved0 = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.bitmapDataOffset = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.bitmapHeaderSize = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.width = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.height = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.planes = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- bmpHeader.bitsPerPixel = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- bmpHeader.compression = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.bitmapDataSize = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.hRes = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.vRes = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.colors = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
- bmpHeader.importantColors = LittleLong (*(long *) buf_p);\r
- buf_p += 4;\r
-\r
- memcpy (bmpHeader.palette, buf_p, sizeof (bmpHeader.palette));\r
-\r
- if (bmpHeader.bitsPerPixel == 8)\r
- buf_p += 1024;\r
-\r
- if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M')\r
- {\r
- Sys_Printf ("LoadBMP: only Windows-style BMP files supported (%s)\n", name);\r
- return;\r
- }\r
- if (bmpHeader.fileSize != length)\r
- {\r
- Sys_Printf ("LoadBMP: header size does not match file size (%d vs. %d) (%s)\n",\r
- bmpHeader.fileSize, length, name);\r
- return;\r
- }\r
- if (bmpHeader.compression != 0)\r
- {\r
- Sys_Printf ("LoadBMP: only uncompressed BMP files supported (%s)\n", name);\r
- return;\r
- }\r
- if (bmpHeader.bitsPerPixel < 8)\r
- {\r
- Sys_Printf ("LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name);\r
- return;\r
- }\r
-\r
- columns = bmpHeader.width;\r
- rows = bmpHeader.height;\r
- if (rows < 0)\r
- rows = -rows;\r
- numPixels = columns * rows;\r
-\r
- if (width)\r
- *width = columns;\r
- if (height)\r
- *height = rows;\r
-\r
- bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));\r
- *pic = bmpRGBA;\r
-\r
-\r
- for (row = rows - 1; row >= 0; row--)\r
- {\r
- pixbuf = bmpRGBA + row * columns * 4;\r
-\r
- for (column = 0; column < columns; column++)\r
- {\r
- unsigned char red, green, blue, alpha;\r
- int palIndex;\r
- unsigned short shortPixel;\r
-\r
- switch (bmpHeader.bitsPerPixel)\r
- {\r
- case 8:\r
- palIndex = *buf_p++;\r
- *pixbuf++ = bmpHeader.palette[palIndex][2];\r
- *pixbuf++ = bmpHeader.palette[palIndex][1];\r
- *pixbuf++ = bmpHeader.palette[palIndex][0];\r
- *pixbuf++ = 0xff;\r
- break;\r
- case 16:\r
- shortPixel = *(unsigned short *) pixbuf;\r
- pixbuf += 2;\r
- *pixbuf++ = (shortPixel & (31 << 10)) >> 7;\r
- *pixbuf++ = (shortPixel & (31 << 5)) >> 2;\r
- *pixbuf++ = (shortPixel & (31)) << 3;\r
- *pixbuf++ = 0xff;\r
- break;\r
- case 24:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = 255;\r
- break;\r
- case 32:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- alpha = *buf_p++;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = alpha;\r
- break;\r
- default:\r
- Sys_Printf ("LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel,\r
- name);\r
- g_free (*pic);\r
- *pic = NULL;\r
- return;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- vfsFreeFile (buffer);\r
-\r
-}\r
-\r
-\r
-/*\r
-=================================================================\r
-\r
-PCX LOADING\r
-\r
-=================================================================\r
-*/\r
-\r
-\r
-/*\r
-==============\r
-LoadPCX\r
-==============\r
-*/\r
-\r
-/* RR2DO2 */\r
-#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}\r
-\r
-static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )\r
-{\r
- byte *raw;\r
- pcx_t *pcx;\r
- int x, y, lsize;\r
- int len;\r
- int dataByte, runLength;\r
- byte *out, *pix;\r
- \r
-\r
- /* load the file */\r
- len = vfsLoadFile (filename, (void **)&raw, 0);\r
- if( len == -1 ) \r
- Error( "LoadPCX: Couldn't read %s", filename );\r
-\r
-\r
- /* parse the PCX file */\r
- pcx = (pcx_t *)raw;\r
- raw = &pcx->data;\r
- \r
- pcx->xmin = LittleShort(pcx->xmin);\r
- pcx->ymin = LittleShort(pcx->ymin);\r
- pcx->xmax = LittleShort(pcx->xmax);\r
- pcx->ymax = LittleShort(pcx->ymax);\r
- pcx->hres = LittleShort(pcx->hres);\r
- pcx->vres = LittleShort(pcx->vres);\r
- pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);\r
- pcx->palette_type = LittleShort(pcx->palette_type);\r
- \r
- if (pcx->manufacturer != 0x0a\r
- || pcx->version != 5\r
- || pcx->encoding != 1\r
- || pcx->bits_per_pixel != 8\r
- || pcx->xmax >= 640\r
- || pcx->ymax >= 480)\r
- Error ("Bad pcx file %s", filename);\r
-\r
- if (palette)\r
- {\r
- *palette = (byte *)malloc(768);\r
- memcpy (*palette, (byte *)pcx + len - 768, 768);\r
- }\r
-\r
- if (width)\r
- *width = pcx->xmax+1;\r
- if (height)\r
- *height = pcx->ymax+1;\r
-\r
- if (!pic)\r
- return;\r
-\r
- out = (byte *)malloc ( (pcx->ymax+1) * (pcx->xmax+1) );\r
- if (!out)\r
- Error( "LoadPCX: couldn't allocate");\r
-\r
- *pic = out;\r
- pix = out;\r
- \r
- /* RR2DO2: pcx fix */\r
- lsize = pcx->color_planes * pcx->bytes_per_line;\r
- \r
- /* go scanline by scanline */\r
- for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )\r
- {\r
- /* do a scanline */\r
- for( x=0; x <= pcx->xmax; )\r
- {\r
- /* RR2DO2 */\r
- DECODEPCX( raw, dataByte, runLength );\r
- while( runLength-- > 0 )\r
- pix[ x++ ] = dataByte;\r
- }\r
-\r
- /* RR2DO2: discard any other data */\r
- while( x < lsize )\r
- {\r
- DECODEPCX( raw, dataByte, runLength );\r
- x++;\r
- }\r
- while( runLength-- > 0 )\r
- x++;\r
- }\r
- \r
- /* validity check */\r
- if( raw - (byte *) pcx > len)\r
- Error( "PCX file %s was malformed", filename );\r
- free( pcx );\r
-}\r
-\r
-/*\r
-==============\r
-LoadPCX32\r
-==============\r
-*/\r
-static void LoadPCX32 (const char *filename, byte ** pic, int *width, int *height)\r
-{\r
- byte *palette;\r
- byte *pic8;\r
- int i, c, p;\r
- byte *pic32;\r
-\r
- LoadPCX (filename, &pic8, &palette, width, height);\r
- if (!pic8)\r
- {\r
- *pic = NULL;\r
- return;\r
- }\r
-\r
- c = (*width) * (*height);\r
- pic32 = *pic = reinterpret_cast < unsigned char *>(g_malloc (4 * c));\r
- for (i = 0; i < c; i++)\r
- {\r
- p = pic8[i];\r
- pic32[0] = palette[p * 3];\r
- pic32[1] = palette[p * 3 + 1];\r
- pic32[2] = palette[p * 3 + 2];\r
- pic32[3] = 255;\r
- pic32 += 4;\r
- }\r
-\r
- g_free (pic8);\r
- g_free (palette);\r
-}\r
-\r
-/*\r
-=========================================================\r
-\r
-TARGA LOADING\r
-\r
- TTimo: added code to get rid of alphachannel from prefs or ignore it if completely empty\r
- was required since Radiant is using alpha channel when binding the textures for proper curry operation\r
- can be fully turned off from the prefs though\r
-=========================================================\r
-*/\r
-\r
-/*\r
-=============\r
-LoadTGA\r
-=============\r
-*/\r
-void LoadTGA (const char *name, byte ** pic, int *width, int *height)\r
-{\r
- int columns, rows, numPixels;\r
- byte *pixbuf;\r
- int row, column;\r
- byte *buf_p;\r
- byte *buffer;\r
- TargaHeader targa_header;\r
- byte *targa_rgba;\r
-\r
- *pic = NULL;\r
-\r
- //\r
- // load the file\r
- //\r
- int nLen = vfsLoadFile( (char *)name, (void **)&buffer, 0 );\r
- if (nLen == -1)\r
- return;\r
-\r
- buf_p = buffer;\r
-\r
- targa_header.id_length = *buf_p++;\r
- targa_header.colormap_type = *buf_p++;\r
- targa_header.image_type = *buf_p++;\r
-\r
- targa_header.colormap_index = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.colormap_length = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.colormap_size = *buf_p++;\r
- targa_header.x_origin = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.y_origin = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.width = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.height = LittleShort (*(short *) buf_p);\r
- buf_p += 2;\r
- targa_header.pixel_size = *buf_p++;\r
- targa_header.attributes = *buf_p++;\r
-\r
- bool bAlphaOK = false;\r
-\r
- if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)\r
- {\r
- Sys_Printf ("LoadTGA: TGA type %d not supported\n", targa_header.image_type);\r
- Sys_Printf ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");\r
- return;\r
- }\r
-\r
- if (targa_header.colormap_type != 0)\r
- {\r
- Sys_Printf ("LoadTGA: colormaps not supported\n");\r
- return;\r
- }\r
-\r
- if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)\r
- && targa_header.image_type != 3)\r
- {\r
- Sys_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");\r
- return;\r
- }\r
-\r
- columns = targa_header.width;\r
- rows = targa_header.height;\r
- numPixels = columns * rows;\r
-\r
- if (width)\r
- *width = columns;\r
- if (height)\r
- *height = rows;\r
-\r
- targa_rgba = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));\r
- *pic = targa_rgba;\r
-\r
- if (targa_header.id_length != 0)\r
- buf_p += targa_header.id_length; // skip TARGA image comment\r
-\r
- if (targa_header.image_type == 2 || targa_header.image_type == 3)\r
- {\r
- // Uncompressed RGB or gray scale image\r
- for (row = rows - 1; row >= 0; row--)\r
- {\r
- pixbuf = targa_rgba + row * columns * 4;\r
- for (column = 0; column < columns; column++)\r
- {\r
- unsigned char red, green, blue, alphabyte;\r
- switch (targa_header.pixel_size)\r
- {\r
- case 8:\r
- blue = *buf_p++;\r
- green = blue;\r
- red = blue;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = 255;\r
- break;\r
- \r
- case 24:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = 255;\r
- break;\r
- case 32:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- alphabyte = *buf_p++;\r
- // detect if the whole alpha channel is 0\r
- if (alphabyte != 0)\r
- bAlphaOK = true;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = alphabyte;\r
- break;\r
- default:\r
- Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,\r
- name);\r
- g_free (*pic);\r
- *pic = NULL;\r
- return;\r
- break;\r
- }\r
- }\r
- }\r
-\r
- if (!bAlphaOK)\r
- {\r
- // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444\r
- if (targa_header.pixel_size == 32) \r
- Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);\r
- // disable the alpha value\r
- for (row = rows - 1; row >= 0; row--)\r
- {\r
- pixbuf = targa_rgba + row * columns * 4;\r
- for (column = 0; column < columns; column++)\r
- {\r
- // 32 bit\r
- pixbuf += 3;\r
- *pixbuf++ = 255;\r
- }\r
- }\r
- }\r
- }\r
- else if (targa_header.image_type == 10)\r
- { // Runlength encoded RGB images\r
- unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;\r
-\r
- red = 0;\r
- green = 0;\r
- blue = 0;\r
- alphabyte = 0xff;\r
-\r
- for (row = rows - 1; row >= 0; row--)\r
- {\r
- pixbuf = targa_rgba + row * columns * 4;\r
- for (column = 0; column < columns;)\r
- {\r
- packetHeader = *buf_p++;\r
- packetSize = 1 + (packetHeader & 0x7f);\r
- if (packetHeader & 0x80)\r
- { // run-length packet\r
- switch (targa_header.pixel_size)\r
- {\r
- case 24:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- alphabyte = 255;\r
- break;\r
- case 32:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- alphabyte = *buf_p++;\r
- // detect if the whole alpha channel is 0\r
- if (alphabyte != 0)\r
- bAlphaOK = true;\r
- break;\r
- default:\r
- Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,\r
- name);\r
- g_free (*pic);\r
- *pic = NULL;\r
- return;\r
- break;\r
- }\r
-\r
- for (j = 0; j < packetSize; j++)\r
- {\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = alphabyte;\r
- column++;\r
- if (column == columns)\r
- { // run spans across rows\r
- column = 0;\r
- if (row > 0)\r
- row--;\r
- else\r
- goto breakOut;\r
- pixbuf = targa_rgba + row * columns * 4;\r
- }\r
- }\r
- }\r
- else\r
- { // non run-length packet\r
- for (j = 0; j < packetSize; j++)\r
- {\r
- switch (targa_header.pixel_size)\r
- {\r
- case 24:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = 255;\r
- break;\r
- case 32:\r
- blue = *buf_p++;\r
- green = *buf_p++;\r
- red = *buf_p++;\r
- alphabyte = *buf_p++;\r
- // detect if the whole alpha channel is 0\r
- if (alphabyte != 0)\r
- bAlphaOK = true;\r
- *pixbuf++ = red;\r
- *pixbuf++ = green;\r
- *pixbuf++ = blue;\r
- *pixbuf++ = alphabyte;\r
- break;\r
- default:\r
- Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n",\r
- targa_header.pixel_size, name);\r
- g_free (*pic);\r
- *pic = NULL;\r
- return;\r
- break;\r
- }\r
- column++;\r
- if (column == columns)\r
- { // pixel packet run spans across rows\r
- column = 0;\r
- if (row > 0)\r
- row--;\r
- else\r
- goto breakOut;\r
- pixbuf = targa_rgba + row * columns * 4;\r
- }\r
- }\r
- }\r
- }\r
- breakOut:;\r
- }\r
-\r
- if (!bAlphaOK)\r
- {\r
- if (targa_header.pixel_size == 32)\r
- Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);\r
- // disable the alpha value\r
- for (row = rows - 1; row >= 0; row--)\r
- {\r
- pixbuf = targa_rgba + row * columns * 4;\r
- for (column = 0; column < columns; column++)\r
- {\r
- // 32 bit\r
- pixbuf += 3;\r
- *pixbuf++ = 255;\r
- }\r
- }\r
- }\r
-\r
- }\r
-\r
- // vertically flipped\r
- if ( (targa_header.attributes & (1<<5)) ) {\r
- int flip;\r
- for (row = 0; row < .5f * rows; row++)\r
- {\r
- for (column = 0; column < columns; column++)\r
- {\r
- flip = *( (int*)targa_rgba + row * columns + column);\r
- *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );\r
- *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;\r
- }\r
- }\r
- }\r
-\r
- vfsFreeFile (buffer);\r
-}\r
-\r
-//===================================================================\r
-\r
-/*\r
-=================\r
-LoadImage\r
-\r
-Loads any of the supported image types into a cannonical\r
-32 bit format.\r
-=================\r
-*/\r
-void LoadImage (const char *name, byte ** pic, int *width, int *height)\r
-{\r
- int len;\r
- *pic = NULL;\r
- *width = 0;\r
- *height = 0;\r
-\r
- len = strlen (name);\r
- if (len < 5)\r
- {\r
- return;\r
- }\r
-\r
- if (!g_strcasecmp (name + len - 4, ".tga"))\r
- {\r
- LoadTGA (name, pic, width, height);\r
- }\r
- else if (!g_strcasecmp (name + len - 4, ".pcx"))\r
- {\r
- LoadPCX32 (name, pic, width, height);\r
- }\r
- else if (!g_strcasecmp (name + len - 4, ".bmp"))\r
- {\r
- LoadBMP (name, pic, width, height);\r
- }\r
- /*\r
- else if (!g_strcasecmp (name + len - 4, ".jpg"))\r
- {\r
- LoadJPG (name, pic, width, height);\r
- }\r
- */\r
-}\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+// lbmlib.c
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib.h>
+#include "image.h"
+#include "lbmlib.h"
+#include "bmp.h"
+
+#define LittleLong(a) GINT32_FROM_LE(a)
+#define LittleShort(a) GINT16_FROM_LE(a)
+
+#include <stdio.h>
+
+#define Sys_Printf g_FuncTable.m_pfnSysPrintf
+#define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf
+
+/*
+============================================================================
+
+LOAD PCX
+
+============================================================================
+*/
+typedef struct
+{
+ char manufacturer;
+ char version;
+ char encoding;
+ char bits_per_pixel;
+ unsigned short xmin, ymin, xmax, ymax;
+ unsigned short hres, vres;
+ unsigned char palette[48];
+ char reserved;
+ char color_planes;
+ unsigned short bytes_per_line;
+ unsigned short palette_type;
+ char filler[58];
+ unsigned char data; // unbounded
+} pcx_t;
+
+/*
+============================================================================
+
+TARGA IMAGE
+
+============================================================================
+*/
+typedef struct _TargaHeader
+{
+ unsigned char id_length, colormap_type, image_type;
+ unsigned short colormap_index, colormap_length;
+ unsigned char colormap_size;
+ unsigned short x_origin, y_origin, width, height;
+ unsigned char pixel_size, attributes;
+} TargaHeader;
+
+/*
+=========================================================
+
+BMP LOADING
+
+=========================================================
+*/
+typedef struct
+{
+ char id[2];
+ unsigned long fileSize;
+ unsigned long reserved0;
+ unsigned long bitmapDataOffset;
+ unsigned long bitmapHeaderSize;
+ unsigned long width;
+ unsigned long height;
+ unsigned short planes;
+ unsigned short bitsPerPixel;
+ unsigned long compression;
+ unsigned long bitmapDataSize;
+ unsigned long hRes;
+ unsigned long vRes;
+ unsigned long colors;
+ unsigned long importantColors;
+ unsigned char palette[256][4];
+} BMPHeader_t;
+
+static void LoadBMP (const char *name, byte ** pic, int *width, int *height)
+{
+ int columns, rows, numPixels;
+ byte *pixbuf;
+ int row, column;
+ byte *buf_p;
+ byte *buffer;
+ unsigned int length;
+ BMPHeader_t bmpHeader;
+ byte *bmpRGBA;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ length = vfsLoadFile( (char *)name, (void **)&buffer, 0 );
+ if (length == (unsigned int) -1)
+ return;
+
+ buf_p = buffer;
+
+ bmpHeader.id[0] = *buf_p++;
+ bmpHeader.id[1] = *buf_p++;
+ bmpHeader.fileSize = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.reserved0 = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.bitmapDataOffset = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.bitmapHeaderSize = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.width = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.height = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.planes = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ bmpHeader.bitsPerPixel = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ bmpHeader.compression = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.bitmapDataSize = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.hRes = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.vRes = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.colors = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+ bmpHeader.importantColors = LittleLong (*(long *) buf_p);
+ buf_p += 4;
+
+ memcpy (bmpHeader.palette, buf_p, sizeof (bmpHeader.palette));
+
+ if (bmpHeader.bitsPerPixel == 8)
+ buf_p += 1024;
+
+ if (bmpHeader.id[0] != 'B' && bmpHeader.id[1] != 'M')
+ {
+ Sys_Printf ("LoadBMP: only Windows-style BMP files supported (%s)\n", name);
+ return;
+ }
+ if (bmpHeader.fileSize != length)
+ {
+ Sys_Printf ("LoadBMP: header size does not match file size (%d vs. %d) (%s)\n",
+ bmpHeader.fileSize, length, name);
+ return;
+ }
+ if (bmpHeader.compression != 0)
+ {
+ Sys_Printf ("LoadBMP: only uncompressed BMP files supported (%s)\n", name);
+ return;
+ }
+ if (bmpHeader.bitsPerPixel < 8)
+ {
+ Sys_Printf ("LoadBMP: monochrome and 4-bit BMP files not supported (%s)\n", name);
+ return;
+ }
+
+ columns = bmpHeader.width;
+ rows = bmpHeader.height;
+ if (rows < 0)
+ rows = -rows;
+ numPixels = columns * rows;
+
+ if (width)
+ *width = columns;
+ if (height)
+ *height = rows;
+
+ bmpRGBA = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));
+ *pic = bmpRGBA;
+
+
+ for (row = rows - 1; row >= 0; row--)
+ {
+ pixbuf = bmpRGBA + row * columns * 4;
+
+ for (column = 0; column < columns; column++)
+ {
+ unsigned char red, green, blue, alpha;
+ int palIndex;
+ unsigned short shortPixel;
+
+ switch (bmpHeader.bitsPerPixel)
+ {
+ case 8:
+ palIndex = *buf_p++;
+ *pixbuf++ = bmpHeader.palette[palIndex][2];
+ *pixbuf++ = bmpHeader.palette[palIndex][1];
+ *pixbuf++ = bmpHeader.palette[palIndex][0];
+ *pixbuf++ = 0xff;
+ break;
+ case 16:
+ shortPixel = *(unsigned short *) pixbuf;
+ pixbuf += 2;
+ *pixbuf++ = (shortPixel & (31 << 10)) >> 7;
+ *pixbuf++ = (shortPixel & (31 << 5)) >> 2;
+ *pixbuf++ = (shortPixel & (31)) << 3;
+ *pixbuf++ = 0xff;
+ break;
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alpha = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alpha;
+ break;
+ default:
+ Sys_Printf ("LoadBMP: illegal pixel_size '%d' in file '%s'\n", bmpHeader.bitsPerPixel,
+ name);
+ g_free (*pic);
+ *pic = NULL;
+ return;
+ break;
+ }
+ }
+ }
+
+ vfsFreeFile (buffer);
+
+}
+
+
+/*
+=================================================================
+
+PCX LOADING
+
+=================================================================
+*/
+
+
+/*
+==============
+LoadPCX
+==============
+*/
+
+/* RR2DO2 */
+#define DECODEPCX( b, d, r ) d=*b++;if((d&0xC0)==0xC0){r=d&0x3F;d=*b++;}else{r=1;}
+
+static void LoadPCX( const char *filename, byte **pic, byte **palette, int *width, int *height )
+{
+ byte *raw;
+ pcx_t *pcx;
+ int x, y, lsize;
+ int len;
+ int dataByte, runLength;
+ byte *out, *pix;
+
+
+ /* load the file */
+ len = vfsLoadFile (filename, (void **)&raw, 0);
+ if( len == -1 )
+ Error( "LoadPCX: Couldn't read %s", filename );
+
+
+ /* parse the PCX file */
+ pcx = (pcx_t *)raw;
+ raw = &pcx->data;
+
+ pcx->xmin = LittleShort(pcx->xmin);
+ pcx->ymin = LittleShort(pcx->ymin);
+ pcx->xmax = LittleShort(pcx->xmax);
+ pcx->ymax = LittleShort(pcx->ymax);
+ pcx->hres = LittleShort(pcx->hres);
+ pcx->vres = LittleShort(pcx->vres);
+ pcx->bytes_per_line = LittleShort(pcx->bytes_per_line);
+ pcx->palette_type = LittleShort(pcx->palette_type);
+
+ if (pcx->manufacturer != 0x0a
+ || pcx->version != 5
+ || pcx->encoding != 1
+ || pcx->bits_per_pixel != 8
+ || pcx->xmax >= 640
+ || pcx->ymax >= 480)
+ Error ("Bad pcx file %s", filename);
+
+ if (palette)
+ {
+ *palette = (byte *)malloc(768);
+ memcpy (*palette, (byte *)pcx + len - 768, 768);
+ }
+
+ if (width)
+ *width = pcx->xmax+1;
+ if (height)
+ *height = pcx->ymax+1;
+
+ if (!pic)
+ return;
+
+ out = (byte *)malloc ( (pcx->ymax+1) * (pcx->xmax+1) );
+ if (!out)
+ Error( "LoadPCX: couldn't allocate");
+
+ *pic = out;
+ pix = out;
+
+ /* RR2DO2: pcx fix */
+ lsize = pcx->color_planes * pcx->bytes_per_line;
+
+ /* go scanline by scanline */
+ for( y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1 )
+ {
+ /* do a scanline */
+ for( x=0; x <= pcx->xmax; )
+ {
+ /* RR2DO2 */
+ DECODEPCX( raw, dataByte, runLength );
+ while( runLength-- > 0 )
+ pix[ x++ ] = dataByte;
+ }
+
+ /* RR2DO2: discard any other data */
+ while( x < lsize )
+ {
+ DECODEPCX( raw, dataByte, runLength );
+ x++;
+ }
+ while( runLength-- > 0 )
+ x++;
+ }
+
+ /* validity check */
+ if( raw - (byte *) pcx > len)
+ Error( "PCX file %s was malformed", filename );
+ free( pcx );
+}
+
+/*
+==============
+LoadPCX32
+==============
+*/
+static void LoadPCX32 (const char *filename, byte ** pic, int *width, int *height)
+{
+ byte *palette;
+ byte *pic8;
+ int i, c, p;
+ byte *pic32;
+
+ LoadPCX (filename, &pic8, &palette, width, height);
+ if (!pic8)
+ {
+ *pic = NULL;
+ return;
+ }
+
+ c = (*width) * (*height);
+ pic32 = *pic = reinterpret_cast < unsigned char *>(g_malloc (4 * c));
+ for (i = 0; i < c; i++)
+ {
+ p = pic8[i];
+ pic32[0] = palette[p * 3];
+ pic32[1] = palette[p * 3 + 1];
+ pic32[2] = palette[p * 3 + 2];
+ pic32[3] = 255;
+ pic32 += 4;
+ }
+
+ g_free (pic8);
+ g_free (palette);
+}
+
+/*
+=========================================================
+
+TARGA LOADING
+
+ TTimo: added code to get rid of alphachannel from prefs or ignore it if completely empty
+ was required since Radiant is using alpha channel when binding the textures for proper curry operation
+ can be fully turned off from the prefs though
+=========================================================
+*/
+
+/*
+=============
+LoadTGA
+=============
+*/
+void LoadTGA (const char *name, byte ** pic, int *width, int *height)
+{
+ int columns, rows, numPixels;
+ byte *pixbuf;
+ int row, column;
+ byte *buf_p;
+ byte *buffer;
+ TargaHeader targa_header;
+ byte *targa_rgba;
+
+ *pic = NULL;
+
+ //
+ // load the file
+ //
+ int nLen = vfsLoadFile( (char *)name, (void **)&buffer, 0 );
+ if (nLen == -1)
+ return;
+
+ buf_p = buffer;
+
+ targa_header.id_length = *buf_p++;
+ targa_header.colormap_type = *buf_p++;
+ targa_header.image_type = *buf_p++;
+
+ targa_header.colormap_index = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.colormap_length = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.colormap_size = *buf_p++;
+ targa_header.x_origin = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.y_origin = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.width = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.height = LittleShort (*(short *) buf_p);
+ buf_p += 2;
+ targa_header.pixel_size = *buf_p++;
+ targa_header.attributes = *buf_p++;
+
+ bool bAlphaOK = false;
+
+ if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)
+ {
+ Sys_Printf ("LoadTGA: TGA type %d not supported\n", targa_header.image_type);
+ Sys_Printf ("LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n");
+ return;
+ }
+
+ if (targa_header.colormap_type != 0)
+ {
+ Sys_Printf ("LoadTGA: colormaps not supported\n");
+ return;
+ }
+
+ if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)
+ && targa_header.image_type != 3)
+ {
+ Sys_Printf ("LoadTGA: Only 32 or 24 bit images supported (no colormaps)\n");
+ return;
+ }
+
+ columns = targa_header.width;
+ rows = targa_header.height;
+ numPixels = columns * rows;
+
+ if (width)
+ *width = columns;
+ if (height)
+ *height = rows;
+
+ targa_rgba = reinterpret_cast < unsigned char *>(g_malloc (numPixels * 4));
+ *pic = targa_rgba;
+
+ if (targa_header.id_length != 0)
+ buf_p += targa_header.id_length; // skip TARGA image comment
+
+ if (targa_header.image_type == 2 || targa_header.image_type == 3)
+ {
+ // Uncompressed RGB or gray scale image
+ for (row = rows - 1; row >= 0; row--)
+ {
+ pixbuf = targa_rgba + row * columns * 4;
+ for (column = 0; column < columns; column++)
+ {
+ unsigned char red, green, blue, alphabyte;
+ switch (targa_header.pixel_size)
+ {
+ case 8:
+ blue = *buf_p++;
+ green = blue;
+ red = blue;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ // detect if the whole alpha channel is 0
+ if (alphabyte != 0)
+ bAlphaOK = true;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ default:
+ Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,
+ name);
+ g_free (*pic);
+ *pic = NULL;
+ return;
+ break;
+ }
+ }
+ }
+
+ if (!bAlphaOK)
+ {
+ // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444
+ if (targa_header.pixel_size == 32)
+ Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
+ // disable the alpha value
+ for (row = rows - 1; row >= 0; row--)
+ {
+ pixbuf = targa_rgba + row * columns * 4;
+ for (column = 0; column < columns; column++)
+ {
+ // 32 bit
+ pixbuf += 3;
+ *pixbuf++ = 255;
+ }
+ }
+ }
+ }
+ else if (targa_header.image_type == 10)
+ { // Runlength encoded RGB images
+ unsigned char red, green, blue, alphabyte, packetHeader, packetSize, j;
+
+ red = 0;
+ green = 0;
+ blue = 0;
+ alphabyte = 0xff;
+
+ for (row = rows - 1; row >= 0; row--)
+ {
+ pixbuf = targa_rgba + row * columns * 4;
+ for (column = 0; column < columns;)
+ {
+ packetHeader = *buf_p++;
+ packetSize = 1 + (packetHeader & 0x7f);
+ if (packetHeader & 0x80)
+ { // run-length packet
+ switch (targa_header.pixel_size)
+ {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ // detect if the whole alpha channel is 0
+ if (alphabyte != 0)
+ bAlphaOK = true;
+ break;
+ default:
+ Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n", targa_header.pixel_size,
+ name);
+ g_free (*pic);
+ *pic = NULL;
+ return;
+ break;
+ }
+
+ for (j = 0; j < packetSize; j++)
+ {
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ column++;
+ if (column == columns)
+ { // run spans across rows
+ column = 0;
+ if (row > 0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row * columns * 4;
+ }
+ }
+ }
+ else
+ { // non run-length packet
+ for (j = 0; j < packetSize; j++)
+ {
+ switch (targa_header.pixel_size)
+ {
+ case 24:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = 255;
+ break;
+ case 32:
+ blue = *buf_p++;
+ green = *buf_p++;
+ red = *buf_p++;
+ alphabyte = *buf_p++;
+ // detect if the whole alpha channel is 0
+ if (alphabyte != 0)
+ bAlphaOK = true;
+ *pixbuf++ = red;
+ *pixbuf++ = green;
+ *pixbuf++ = blue;
+ *pixbuf++ = alphabyte;
+ break;
+ default:
+ Sys_Printf ("LoadTGA: illegal pixel_size '%d' in file '%s'\n",
+ targa_header.pixel_size, name);
+ g_free (*pic);
+ *pic = NULL;
+ return;
+ break;
+ }
+ column++;
+ if (column == columns)
+ { // pixel packet run spans across rows
+ column = 0;
+ if (row > 0)
+ row--;
+ else
+ goto breakOut;
+ pixbuf = targa_rgba + row * columns * 4;
+ }
+ }
+ }
+ }
+ breakOut:;
+ }
+
+ if (!bAlphaOK)
+ {
+ if (targa_header.pixel_size == 32)
+ Sys_FPrintf (SYS_WRN, "WARNING: %s has empty alpha channel\n", name);
+ // disable the alpha value
+ for (row = rows - 1; row >= 0; row--)
+ {
+ pixbuf = targa_rgba + row * columns * 4;
+ for (column = 0; column < columns; column++)
+ {
+ // 32 bit
+ pixbuf += 3;
+ *pixbuf++ = 255;
+ }
+ }
+ }
+
+ }
+
+ // vertically flipped
+ if ( (targa_header.attributes & (1<<5)) ) {
+ int flip;
+ for (row = 0; row < .5f * rows; row++)
+ {
+ for (column = 0; column < columns; column++)
+ {
+ flip = *( (int*)targa_rgba + row * columns + column);
+ *( (int*)targa_rgba + row * columns + column) = *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column );
+ *( (int*)targa_rgba + ( ( rows - 1 ) - row ) * columns + column ) = flip;
+ }
+ }
+ }
+
+ vfsFreeFile (buffer);
+}
+
+//===================================================================
+
+/*
+=================
+LoadImage
+
+Loads any of the supported image types into a cannonical
+32 bit format.
+=================
+*/
+void LoadImage (const char *name, byte ** pic, int *width, int *height)
+{
+ int len;
+ *pic = NULL;
+ *width = 0;
+ *height = 0;
+
+ len = strlen (name);
+ if (len < 5)
+ {
+ return;
+ }
+
+ if (!g_strcasecmp (name + len - 4, ".tga"))
+ {
+ LoadTGA (name, pic, width, height);
+ }
+ else if (!g_strcasecmp (name + len - 4, ".pcx"))
+ {
+ LoadPCX32 (name, pic, width, height);
+ }
+ else if (!g_strcasecmp (name + len - 4, ".bmp"))
+ {
+ LoadBMP (name, pic, width, height);
+ }
+ /*
+ else if (!g_strcasecmp (name + len - 4, ".jpg"))
+ {
+ LoadJPG (name, pic, width, height);
+ }
+ */
+}