2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
24 // by Hydra - hydra@hydras-world.com
26 // This module is based on the image module, but just more stripped down.
27 // it still currently supports TGA file loading, even though this is not
28 // required for HalfLife support (unless MD2 files use TGA's)
30 // use the #defines in imagehl.h to enable/disable the various formats.
32 // HLW = Half-Life-WAD, I don't know if the actual in data in the WAD files
33 // has it's own name, so I'm just calling the individal textures .HLW files :)
35 // Thanks to the guys that made Wally for releasing an example WAD loader.
36 // without it this would not have been possible.
46 #define Sys_Printf g_FuncTable.m_pfnSysPrintf
47 #define Sys_FPrintf g_FuncTable.m_pfnSysFPrintf
52 ============================================================================
54 IDSP IMAGE (.spr files)
56 Some code copied straight from the Q1 source, also used the HalfLife SDK as
59 ============================================================================
62 typedef enum {ST_SYNC = 0, ST_RAND } synctype_t;
63 typedef enum { SPR_SINGLE = 0, SPR_GROUP } spriteframetype_t;
65 typedef struct dspriteheader_s {
101 } dspriteframetype_t;
109 #define IDSPRITEHEADER ( ( 'P' << 24 ) + ( 'S' << 16 ) + ( 'D' << 8 ) + 'I' )
110 // little-endian "IDSP"
118 static void LoadIDSP( const char *name, byte ** pic, int *width, int *height ){
122 int columns, rows, numPixels;
128 unsigned char red, green, blue, alphabyte;
130 dspriteheader_t *header;
133 dspriteframetype_t *pframetype;
136 dspriteframe_t *spriteframe;
143 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
144 if ( length == (unsigned int) -1 ) {
148 header = (dspriteheader_t *)buffer;
150 if ( header->ident != IDSPRITEHEADER ) {
151 Sys_Printf( "WARNING: %s has wrong header\n" );
152 vfsFreeFile( buffer );
156 version = header->version;
157 if ( version != 1 && version != 2 ) {
158 Sys_Printf( "WARNING: %s has wrong version number "
159 "(%i should be 1 or 2)\n", name, version );
160 vfsFreeFile( buffer );
164 // initialise variables depending on the sprite version.
168 pinv1 = (dspritev1_t *)( header + 1 );
169 numframes = pinv1->numframes;
170 columns = pinv1->width;
171 rows = pinv1->height;
172 pframetype = (dspriteframetype_t *)( pinv1 + 1 );
175 pinv2 = (dspritev2_t *)( header + 1 );
176 numframes = pinv2->numframes;
177 columns = pinv2->width;
178 rows = pinv2->height;
179 pframetype = (dspriteframetype_t *)( pinv2 + 1 );
182 if ( numframes > 1 ) {
183 Sys_Printf( "WARNING: %s has multiple frames, only the first frame will be used.\n", name );
186 // palette = buffer+mipdatasize+2;
187 // buf_p = buffer+lpMip->offsets[0];
189 numPixels = columns * rows;
198 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
202 spriteframetype_t frametype = spriteframetype_t( LittleLong( pframetype->type ) );
203 if ( frametype == SPR_SINGLE ) {
204 Sys_Printf( "Single Frame\n" );
206 else if ( frametype == SPR_GROUP ) {
207 Sys_Printf( "Group of Frames\n" );
211 Sys_Printf( "Bleh!\n" ); // <-- we always get this, wtf!
215 palette = (byte *)( pframetype + 1 );
216 spriteframe = (dspriteframe_t *)( palette + ( 256 * 3 ) + 4 ); // what are those 4 extra bytes ? what's missing ?
217 buf_p = (byte *)( spriteframe + 1 );
221 temp = buf_p - buffer;
223 for ( row = 0; row < rows; row++ )
225 pixbuf = bmpRGBA + row * columns * 4;
227 for ( column = 0; column < columns; column++ )
233 red = *( palette + ( palIndex * 3 ) );
234 green = *( palette + ( palIndex * 3 ) + 1 );
235 blue = *( palette + ( palIndex * 3 ) + 2 );
237 // HalfLife engine makes pixels that are BLUE transparent. (RGB = 0x0000FF)
238 // So show them that way in the editor.
239 if ( blue == 0xff && red == 0x00 && green == 0x00 ) {
240 alphabyte = 0xff; //FIXME: backwards? (so sprite models to render correctly)
241 blue = 0x00; // don't set the resulting pixel to blue
245 alphabyte = 0x00; //FIXME: backwards? (so sprite models to render correctly)
252 *pixbuf++ = alphabyte;
256 vfsFreeFile( buffer );
262 ============================================================================
266 HalfLife WAD files contain files that look like this:
271 First mip (width * height)
272 Second mip (width * height / 4)
273 Third mip (width * height / 16)
274 Fourth mip (width * height / 64)
276 Palette (Palette size * 3)
279 ============================================================================
282 #define GET_MIP_DATA_SIZE( WIDTH, HEIGHT ) ( sizeof( WAD3_MIP ) + ( WIDTH * HEIGHT ) + ( WIDTH * HEIGHT / 4 ) + ( WIDTH * HEIGHT / 16 ) + ( WIDTH * HEIGHT / 64 ) )
288 DWORD offsets[4]; // four mip maps stored
289 } WAD3_MIP, *LPWAD3_MIP;
292 =========================================================
296 Hydra: this code isn't bullet proof and probably won't
297 like corrupt WAD files, but it works for now.
299 TODO: make it more robust.
300 =========================================================
309 static void LoadHLW( const char *name, byte ** pic, int *width, int *height ){
313 unsigned long mipdatasize;
314 int columns, rows, numPixels;
320 unsigned char red, green, blue, alphabyte;
327 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
328 if ( length == (unsigned int) -1 ) {
332 lpMip = (LPWAD3_MIP)buffer;
334 mipdatasize = GET_MIP_DATA_SIZE( lpMip->width,lpMip->height );
336 palette = buffer + mipdatasize + 2;
338 buf_p = buffer + lpMip->offsets[0];
340 columns = lpMip->width;
341 rows = lpMip->height;
342 numPixels = columns * rows;
351 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
354 for ( row = 0; row < rows; row++ )
356 pixbuf = bmpRGBA + row * columns * 4;
358 for ( column = 0; column < columns; column++ )
364 red = *( palette + ( palIndex * 3 ) );
365 green = *( palette + ( palIndex * 3 ) + 1 );
366 blue = *( palette + ( palIndex * 3 ) + 2 );
368 // HalfLife engine makes pixels that are BLUE transparent.
369 // So show them that way in the editor.
370 if ( blue == 0xff && red == 0x00 && green == 0x00 ) {
372 blue = 0x00; // don't set the resulting pixel to blue
383 *pixbuf++ = alphabyte;
387 vfsFreeFile( buffer );
393 ============================================================================
397 Quake WAD files contain miptex files that look like this:
402 First mip (width * height)
403 Second mip (width * height / 4)
404 Third mip (width * height / 16)
405 Fourth mip (width * height / 64)
407 ============================================================================
411 =========================================================
415 LordHavoc: this code is based on the HLW code above.
416 =========================================================
420 static const byte quakepalette[768] =
422 0x00,0x00,0x00, 0x0f,0x0f,0x0f, 0x1f,0x1f,0x1f, 0x2f,0x2f,0x2f,
423 0x3f,0x3f,0x3f, 0x4b,0x4b,0x4b, 0x5b,0x5b,0x5b, 0x6b,0x6b,0x6b,
424 0x7b,0x7b,0x7b, 0x8b,0x8b,0x8b, 0x9b,0x9b,0x9b, 0xab,0xab,0xab,
425 0xbb,0xbb,0xbb, 0xcb,0xcb,0xcb, 0xdb,0xdb,0xdb, 0xeb,0xeb,0xeb,
426 0x0f,0x0b,0x07, 0x17,0x0f,0x0b, 0x1f,0x17,0x0b, 0x27,0x1b,0x0f,
427 0x2f,0x23,0x13, 0x37,0x2b,0x17, 0x3f,0x2f,0x17, 0x4b,0x37,0x1b,
428 0x53,0x3b,0x1b, 0x5b,0x43,0x1f, 0x63,0x4b,0x1f, 0x6b,0x53,0x1f,
429 0x73,0x57,0x1f, 0x7b,0x5f,0x23, 0x83,0x67,0x23, 0x8f,0x6f,0x23,
430 0x0b,0x0b,0x0f, 0x13,0x13,0x1b, 0x1b,0x1b,0x27, 0x27,0x27,0x33,
431 0x2f,0x2f,0x3f, 0x37,0x37,0x4b, 0x3f,0x3f,0x57, 0x47,0x47,0x67,
432 0x4f,0x4f,0x73, 0x5b,0x5b,0x7f, 0x63,0x63,0x8b, 0x6b,0x6b,0x97,
433 0x73,0x73,0xa3, 0x7b,0x7b,0xaf, 0x83,0x83,0xbb, 0x8b,0x8b,0xcb,
434 0x00,0x00,0x00, 0x07,0x07,0x00, 0x0b,0x0b,0x00, 0x13,0x13,0x00,
435 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2b,0x2b,0x07, 0x2f,0x2f,0x07,
436 0x37,0x37,0x07, 0x3f,0x3f,0x07, 0x47,0x47,0x07, 0x4b,0x4b,0x0b,
437 0x53,0x53,0x0b, 0x5b,0x5b,0x0b, 0x63,0x63,0x0b, 0x6b,0x6b,0x0f,
438 0x07,0x00,0x00, 0x0f,0x00,0x00, 0x17,0x00,0x00, 0x1f,0x00,0x00,
439 0x27,0x00,0x00, 0x2f,0x00,0x00, 0x37,0x00,0x00, 0x3f,0x00,0x00,
440 0x47,0x00,0x00, 0x4f,0x00,0x00, 0x57,0x00,0x00, 0x5f,0x00,0x00,
441 0x67,0x00,0x00, 0x6f,0x00,0x00, 0x77,0x00,0x00, 0x7f,0x00,0x00,
442 0x13,0x13,0x00, 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2f,0x2b,0x00,
443 0x37,0x2f,0x00, 0x43,0x37,0x00, 0x4b,0x3b,0x07, 0x57,0x43,0x07,
444 0x5f,0x47,0x07, 0x6b,0x4b,0x0b, 0x77,0x53,0x0f, 0x83,0x57,0x13,
445 0x8b,0x5b,0x13, 0x97,0x5f,0x1b, 0xa3,0x63,0x1f, 0xaf,0x67,0x23,
446 0x23,0x13,0x07, 0x2f,0x17,0x0b, 0x3b,0x1f,0x0f, 0x4b,0x23,0x13,
447 0x57,0x2b,0x17, 0x63,0x2f,0x1f, 0x73,0x37,0x23, 0x7f,0x3b,0x2b,
448 0x8f,0x43,0x33, 0x9f,0x4f,0x33, 0xaf,0x63,0x2f, 0xbf,0x77,0x2f,
449 0xcf,0x8f,0x2b, 0xdf,0xab,0x27, 0xef,0xcb,0x1f, 0xff,0xf3,0x1b,
450 0x0b,0x07,0x00, 0x1b,0x13,0x00, 0x2b,0x23,0x0f, 0x37,0x2b,0x13,
451 0x47,0x33,0x1b, 0x53,0x37,0x23, 0x63,0x3f,0x2b, 0x6f,0x47,0x33,
452 0x7f,0x53,0x3f, 0x8b,0x5f,0x47, 0x9b,0x6b,0x53, 0xa7,0x7b,0x5f,
453 0xb7,0x87,0x6b, 0xc3,0x93,0x7b, 0xd3,0xa3,0x8b, 0xe3,0xb3,0x97,
454 0xab,0x8b,0xa3, 0x9f,0x7f,0x97, 0x93,0x73,0x87, 0x8b,0x67,0x7b,
455 0x7f,0x5b,0x6f, 0x77,0x53,0x63, 0x6b,0x4b,0x57, 0x5f,0x3f,0x4b,
456 0x57,0x37,0x43, 0x4b,0x2f,0x37, 0x43,0x27,0x2f, 0x37,0x1f,0x23,
457 0x2b,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07,
458 0xbb,0x73,0x9f, 0xaf,0x6b,0x8f, 0xa3,0x5f,0x83, 0x97,0x57,0x77,
459 0x8b,0x4f,0x6b, 0x7f,0x4b,0x5f, 0x73,0x43,0x53, 0x6b,0x3b,0x4b,
460 0x5f,0x33,0x3f, 0x53,0x2b,0x37, 0x47,0x23,0x2b, 0x3b,0x1f,0x23,
461 0x2f,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07,
462 0xdb,0xc3,0xbb, 0xcb,0xb3,0xa7, 0xbf,0xa3,0x9b, 0xaf,0x97,0x8b,
463 0xa3,0x87,0x7b, 0x97,0x7b,0x6f, 0x87,0x6f,0x5f, 0x7b,0x63,0x53,
464 0x6b,0x57,0x47, 0x5f,0x4b,0x3b, 0x53,0x3f,0x33, 0x43,0x33,0x27,
465 0x37,0x2b,0x1f, 0x27,0x1f,0x17, 0x1b,0x13,0x0f, 0x0f,0x0b,0x07,
466 0x6f,0x83,0x7b, 0x67,0x7b,0x6f, 0x5f,0x73,0x67, 0x57,0x6b,0x5f,
467 0x4f,0x63,0x57, 0x47,0x5b,0x4f, 0x3f,0x53,0x47, 0x37,0x4b,0x3f,
468 0x2f,0x43,0x37, 0x2b,0x3b,0x2f, 0x23,0x33,0x27, 0x1f,0x2b,0x1f,
469 0x17,0x23,0x17, 0x0f,0x1b,0x13, 0x0b,0x13,0x0b, 0x07,0x0b,0x07,
470 0xff,0xf3,0x1b, 0xef,0xdf,0x17, 0xdb,0xcb,0x13, 0xcb,0xb7,0x0f,
471 0xbb,0xa7,0x0f, 0xab,0x97,0x0b, 0x9b,0x83,0x07, 0x8b,0x73,0x07,
472 0x7b,0x63,0x07, 0x6b,0x53,0x00, 0x5b,0x47,0x00, 0x4b,0x37,0x00,
473 0x3b,0x2b,0x00, 0x2b,0x1f,0x00, 0x1b,0x0f,0x00, 0x0b,0x07,0x00,
474 0x00,0x00,0xff, 0x0b,0x0b,0xef, 0x13,0x13,0xdf, 0x1b,0x1b,0xcf,
475 0x23,0x23,0xbf, 0x2b,0x2b,0xaf, 0x2f,0x2f,0x9f, 0x2f,0x2f,0x8f,
476 0x2f,0x2f,0x7f, 0x2f,0x2f,0x6f, 0x2f,0x2f,0x5f, 0x2b,0x2b,0x4f,
477 0x23,0x23,0x3f, 0x1b,0x1b,0x2f, 0x13,0x13,0x1f, 0x0b,0x0b,0x0f,
478 0x2b,0x00,0x00, 0x3b,0x00,0x00, 0x4b,0x07,0x00, 0x5f,0x07,0x00,
479 0x6f,0x0f,0x00, 0x7f,0x17,0x07, 0x93,0x1f,0x07, 0xa3,0x27,0x0b,
480 0xb7,0x33,0x0f, 0xc3,0x4b,0x1b, 0xcf,0x63,0x2b, 0xdb,0x7f,0x3b,
481 0xe3,0x97,0x4f, 0xe7,0xab,0x5f, 0xef,0xbf,0x77, 0xf7,0xd3,0x8b,
482 0xa7,0x7b,0x3b, 0xb7,0x9b,0x37, 0xc7,0xc3,0x37, 0xe7,0xe3,0x57,
483 0x7f,0xbf,0xff, 0xab,0xe7,0xff, 0xd7,0xff,0xff, 0x67,0x00,0x00,
484 0x8b,0x00,0x00, 0xb3,0x00,0x00, 0xd7,0x00,0x00, 0xff,0x00,0x00,
485 0xff,0xf3,0x93, 0xff,0xf7,0xc7, 0xff,0xff,0xff, 0x9f,0x5b,0x53
494 static void LoadMIP( const char *name, byte ** pic, int *width, int *height ){
497 unsigned int length, palettelength;
498 unsigned long mipdatasize;
499 int columns, rows, numPixels;
508 loadedpalette = NULL;
513 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
514 if ( length == (unsigned int) -1 ) {
518 lpMip = (LPWAD3_MIP)buffer;
520 mipdatasize = GET_MIP_DATA_SIZE( lpMip->width,lpMip->height );
522 palettelength = vfsLoadFile( "textures/palette.lmp", (void **) &loadedpalette, 0 );
523 if ( palettelength == 768 ) {
524 palette = loadedpalette;
528 loadedpalette = NULL;
529 palette = quakepalette;
532 buf_p = buffer + lpMip->offsets[0];
534 columns = lpMip->width;
535 rows = lpMip->height;
536 numPixels = columns * rows;
545 //Sys_Printf("lpMip->width = %i, lpMip->height = %i, lpMip->offsets[0] = %i, lpMip->offsets[1] = %i, lpMip->offsets[2] = %i, lpMip->offsets[3] = %i, numPixels = %i\n", lpMip->width, lpMip->height, lpMip->offsets[0], lpMip->offsets[1], lpMip->offsets[2], lpMip->offsets[3], numPixels);
546 //for (i = 0; i < sizeof(*lpMip); i++)
547 // Sys_Printf("%02x", (int) ((unsigned char *)lpMip)[i]);
549 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
553 for ( i = 0; i < numPixels; i++ )
555 int palIndex = *buf_p++;
556 *pixbuf++ = palette[palIndex * 3];
557 *pixbuf++ = palette[palIndex * 3 + 1];
558 *pixbuf++ = palette[palIndex * 3 + 2];
562 vfsFreeFile( buffer );
563 if ( loadedpalette != NULL ) {
564 vfsFreeFile( loadedpalette );
573 Loads any of the supported image types into a cannonical
577 void LoadImage( const char *name, byte ** pic, int *width, int *height ){
583 len = strlen( name );
589 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".hlw" ) ) {
590 LoadHLW( name, pic, width, height );
595 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".mip" ) ) {
596 LoadMIP( name, pic, width, height );
601 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".spr" ) ) {
602 LoadIDSP( name, pic, width, height );