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;
137 spriteframetype_t frametype;
138 dspriteframe_t *spriteframe;
145 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
146 if ( length == (unsigned int) -1 ) {
150 header = (dspriteheader_t *)buffer;
152 if ( header->ident != IDSPRITEHEADER ) {
153 Sys_Printf( "WARNING: %s has wrong header\n" );
154 vfsFreeFile( buffer );
158 version = header->version;
159 if ( version != 1 && version != 2 ) {
160 Sys_Printf( "WARNING: %s has wrong version number "
161 "(%i should be 1 or 2)\n", name, version );
162 vfsFreeFile( buffer );
166 // initialise variables depending on the sprite version.
170 pinv1 = (dspritev1_t *)( header + 1 );
171 numframes = pinv1->numframes;
172 columns = pinv1->width;
173 rows = pinv1->height;
174 pframetype = (dspriteframetype_t *)( pinv1 + 1 );
177 pinv2 = (dspritev2_t *)( header + 1 );
178 numframes = pinv2->numframes;
179 columns = pinv2->width;
180 rows = pinv2->height;
181 pframetype = (dspriteframetype_t *)( pinv2 + 1 );
184 if ( numframes > 1 ) {
185 Sys_Printf( "WARNING: %s has multiple frames, only the first frame will be used.\n", name );
188 // palette = buffer+mipdatasize+2;
189 // buf_p = buffer+lpMip->offsets[0];
191 numPixels = columns * rows;
200 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
204 frametype = spriteframetype_t( LittleLong( pframetype->type ) );
205 if ( frametype == SPR_SINGLE ) {
206 Sys_Printf( "Single Frame\n" );
208 else if ( frametype == SPR_GROUP ) {
209 Sys_Printf( "Group of Frames\n" );
213 Sys_Printf( "Bleh!\n" ); // <-- we always get this, wtf!
217 palette = (byte *)( pframetype + 1 );
218 spriteframe = (dspriteframe_t *)( palette + ( 256 * 3 ) + 4 ); // what are those 4 extra bytes ? what's missing ?
219 buf_p = (byte *)( spriteframe + 1 );
223 temp = buf_p - buffer;
225 for ( row = 0; row < rows; row++ )
227 pixbuf = bmpRGBA + row * columns * 4;
229 for ( column = 0; column < columns; column++ )
235 red = *( palette + ( palIndex * 3 ) );
236 green = *( palette + ( palIndex * 3 ) + 1 );
237 blue = *( palette + ( palIndex * 3 ) + 2 );
239 // HalfLife engine makes pixels that are BLUE transparent. (RGB = 0x0000FF)
240 // So show them that way in the editor.
241 if ( blue == 0xff && red == 0x00 && green == 0x00 ) {
242 alphabyte = 0xff; //FIXME: backwards? (so sprite models to render correctly)
243 blue = 0x00; // don't set the resulting pixel to blue
247 alphabyte = 0x00; //FIXME: backwards? (so sprite models to render correctly)
254 *pixbuf++ = alphabyte;
258 vfsFreeFile( buffer );
264 ============================================================================
268 HalfLife WAD files contain files that look like this:
273 First mip (width * height)
274 Second mip (width * height / 4)
275 Third mip (width * height / 16)
276 Fourth mip (width * height / 64)
278 Palette (Palette size * 3)
281 ============================================================================
284 #define GET_MIP_DATA_SIZE( WIDTH, HEIGHT ) ( sizeof( WAD3_MIP ) + ( WIDTH * HEIGHT ) + ( WIDTH * HEIGHT / 4 ) + ( WIDTH * HEIGHT / 16 ) + ( WIDTH * HEIGHT / 64 ) )
290 DWORD offsets[4]; // four mip maps stored
291 } WAD3_MIP, *LPWAD3_MIP;
294 =========================================================
298 Hydra: this code isn't bullet proof and probably won't
299 like corrupt WAD files, but it works for now.
301 TODO: make it more robust.
302 =========================================================
311 static void LoadHLW( const char *name, byte ** pic, int *width, int *height ){
315 unsigned long mipdatasize;
316 int columns, rows, numPixels;
322 unsigned char red, green, blue, alphabyte;
329 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
330 if ( length == (unsigned int) -1 ) {
334 lpMip = (LPWAD3_MIP)buffer;
336 mipdatasize = GET_MIP_DATA_SIZE( lpMip->width,lpMip->height );
338 palette = buffer + mipdatasize + 2;
340 buf_p = buffer + lpMip->offsets[0];
342 columns = lpMip->width;
343 rows = lpMip->height;
344 numPixels = columns * rows;
353 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
356 for ( row = 0; row < rows; row++ )
358 pixbuf = bmpRGBA + row * columns * 4;
360 for ( column = 0; column < columns; column++ )
366 red = *( palette + ( palIndex * 3 ) );
367 green = *( palette + ( palIndex * 3 ) + 1 );
368 blue = *( palette + ( palIndex * 3 ) + 2 );
370 // HalfLife engine makes pixels that are BLUE transparent.
371 // So show them that way in the editor.
372 if ( blue == 0xff && red == 0x00 && green == 0x00 ) {
374 blue = 0x00; // don't set the resulting pixel to blue
385 *pixbuf++ = alphabyte;
389 vfsFreeFile( buffer );
395 ============================================================================
399 Quake WAD files contain miptex files that look like this:
404 First mip (width * height)
405 Second mip (width * height / 4)
406 Third mip (width * height / 16)
407 Fourth mip (width * height / 64)
409 ============================================================================
413 =========================================================
417 LordHavoc: this code is based on the HLW code above.
418 =========================================================
422 static const byte quakepalette[768] =
424 0x00,0x00,0x00, 0x0f,0x0f,0x0f, 0x1f,0x1f,0x1f, 0x2f,0x2f,0x2f,
425 0x3f,0x3f,0x3f, 0x4b,0x4b,0x4b, 0x5b,0x5b,0x5b, 0x6b,0x6b,0x6b,
426 0x7b,0x7b,0x7b, 0x8b,0x8b,0x8b, 0x9b,0x9b,0x9b, 0xab,0xab,0xab,
427 0xbb,0xbb,0xbb, 0xcb,0xcb,0xcb, 0xdb,0xdb,0xdb, 0xeb,0xeb,0xeb,
428 0x0f,0x0b,0x07, 0x17,0x0f,0x0b, 0x1f,0x17,0x0b, 0x27,0x1b,0x0f,
429 0x2f,0x23,0x13, 0x37,0x2b,0x17, 0x3f,0x2f,0x17, 0x4b,0x37,0x1b,
430 0x53,0x3b,0x1b, 0x5b,0x43,0x1f, 0x63,0x4b,0x1f, 0x6b,0x53,0x1f,
431 0x73,0x57,0x1f, 0x7b,0x5f,0x23, 0x83,0x67,0x23, 0x8f,0x6f,0x23,
432 0x0b,0x0b,0x0f, 0x13,0x13,0x1b, 0x1b,0x1b,0x27, 0x27,0x27,0x33,
433 0x2f,0x2f,0x3f, 0x37,0x37,0x4b, 0x3f,0x3f,0x57, 0x47,0x47,0x67,
434 0x4f,0x4f,0x73, 0x5b,0x5b,0x7f, 0x63,0x63,0x8b, 0x6b,0x6b,0x97,
435 0x73,0x73,0xa3, 0x7b,0x7b,0xaf, 0x83,0x83,0xbb, 0x8b,0x8b,0xcb,
436 0x00,0x00,0x00, 0x07,0x07,0x00, 0x0b,0x0b,0x00, 0x13,0x13,0x00,
437 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2b,0x2b,0x07, 0x2f,0x2f,0x07,
438 0x37,0x37,0x07, 0x3f,0x3f,0x07, 0x47,0x47,0x07, 0x4b,0x4b,0x0b,
439 0x53,0x53,0x0b, 0x5b,0x5b,0x0b, 0x63,0x63,0x0b, 0x6b,0x6b,0x0f,
440 0x07,0x00,0x00, 0x0f,0x00,0x00, 0x17,0x00,0x00, 0x1f,0x00,0x00,
441 0x27,0x00,0x00, 0x2f,0x00,0x00, 0x37,0x00,0x00, 0x3f,0x00,0x00,
442 0x47,0x00,0x00, 0x4f,0x00,0x00, 0x57,0x00,0x00, 0x5f,0x00,0x00,
443 0x67,0x00,0x00, 0x6f,0x00,0x00, 0x77,0x00,0x00, 0x7f,0x00,0x00,
444 0x13,0x13,0x00, 0x1b,0x1b,0x00, 0x23,0x23,0x00, 0x2f,0x2b,0x00,
445 0x37,0x2f,0x00, 0x43,0x37,0x00, 0x4b,0x3b,0x07, 0x57,0x43,0x07,
446 0x5f,0x47,0x07, 0x6b,0x4b,0x0b, 0x77,0x53,0x0f, 0x83,0x57,0x13,
447 0x8b,0x5b,0x13, 0x97,0x5f,0x1b, 0xa3,0x63,0x1f, 0xaf,0x67,0x23,
448 0x23,0x13,0x07, 0x2f,0x17,0x0b, 0x3b,0x1f,0x0f, 0x4b,0x23,0x13,
449 0x57,0x2b,0x17, 0x63,0x2f,0x1f, 0x73,0x37,0x23, 0x7f,0x3b,0x2b,
450 0x8f,0x43,0x33, 0x9f,0x4f,0x33, 0xaf,0x63,0x2f, 0xbf,0x77,0x2f,
451 0xcf,0x8f,0x2b, 0xdf,0xab,0x27, 0xef,0xcb,0x1f, 0xff,0xf3,0x1b,
452 0x0b,0x07,0x00, 0x1b,0x13,0x00, 0x2b,0x23,0x0f, 0x37,0x2b,0x13,
453 0x47,0x33,0x1b, 0x53,0x37,0x23, 0x63,0x3f,0x2b, 0x6f,0x47,0x33,
454 0x7f,0x53,0x3f, 0x8b,0x5f,0x47, 0x9b,0x6b,0x53, 0xa7,0x7b,0x5f,
455 0xb7,0x87,0x6b, 0xc3,0x93,0x7b, 0xd3,0xa3,0x8b, 0xe3,0xb3,0x97,
456 0xab,0x8b,0xa3, 0x9f,0x7f,0x97, 0x93,0x73,0x87, 0x8b,0x67,0x7b,
457 0x7f,0x5b,0x6f, 0x77,0x53,0x63, 0x6b,0x4b,0x57, 0x5f,0x3f,0x4b,
458 0x57,0x37,0x43, 0x4b,0x2f,0x37, 0x43,0x27,0x2f, 0x37,0x1f,0x23,
459 0x2b,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07,
460 0xbb,0x73,0x9f, 0xaf,0x6b,0x8f, 0xa3,0x5f,0x83, 0x97,0x57,0x77,
461 0x8b,0x4f,0x6b, 0x7f,0x4b,0x5f, 0x73,0x43,0x53, 0x6b,0x3b,0x4b,
462 0x5f,0x33,0x3f, 0x53,0x2b,0x37, 0x47,0x23,0x2b, 0x3b,0x1f,0x23,
463 0x2f,0x17,0x1b, 0x23,0x13,0x13, 0x17,0x0b,0x0b, 0x0f,0x07,0x07,
464 0xdb,0xc3,0xbb, 0xcb,0xb3,0xa7, 0xbf,0xa3,0x9b, 0xaf,0x97,0x8b,
465 0xa3,0x87,0x7b, 0x97,0x7b,0x6f, 0x87,0x6f,0x5f, 0x7b,0x63,0x53,
466 0x6b,0x57,0x47, 0x5f,0x4b,0x3b, 0x53,0x3f,0x33, 0x43,0x33,0x27,
467 0x37,0x2b,0x1f, 0x27,0x1f,0x17, 0x1b,0x13,0x0f, 0x0f,0x0b,0x07,
468 0x6f,0x83,0x7b, 0x67,0x7b,0x6f, 0x5f,0x73,0x67, 0x57,0x6b,0x5f,
469 0x4f,0x63,0x57, 0x47,0x5b,0x4f, 0x3f,0x53,0x47, 0x37,0x4b,0x3f,
470 0x2f,0x43,0x37, 0x2b,0x3b,0x2f, 0x23,0x33,0x27, 0x1f,0x2b,0x1f,
471 0x17,0x23,0x17, 0x0f,0x1b,0x13, 0x0b,0x13,0x0b, 0x07,0x0b,0x07,
472 0xff,0xf3,0x1b, 0xef,0xdf,0x17, 0xdb,0xcb,0x13, 0xcb,0xb7,0x0f,
473 0xbb,0xa7,0x0f, 0xab,0x97,0x0b, 0x9b,0x83,0x07, 0x8b,0x73,0x07,
474 0x7b,0x63,0x07, 0x6b,0x53,0x00, 0x5b,0x47,0x00, 0x4b,0x37,0x00,
475 0x3b,0x2b,0x00, 0x2b,0x1f,0x00, 0x1b,0x0f,0x00, 0x0b,0x07,0x00,
476 0x00,0x00,0xff, 0x0b,0x0b,0xef, 0x13,0x13,0xdf, 0x1b,0x1b,0xcf,
477 0x23,0x23,0xbf, 0x2b,0x2b,0xaf, 0x2f,0x2f,0x9f, 0x2f,0x2f,0x8f,
478 0x2f,0x2f,0x7f, 0x2f,0x2f,0x6f, 0x2f,0x2f,0x5f, 0x2b,0x2b,0x4f,
479 0x23,0x23,0x3f, 0x1b,0x1b,0x2f, 0x13,0x13,0x1f, 0x0b,0x0b,0x0f,
480 0x2b,0x00,0x00, 0x3b,0x00,0x00, 0x4b,0x07,0x00, 0x5f,0x07,0x00,
481 0x6f,0x0f,0x00, 0x7f,0x17,0x07, 0x93,0x1f,0x07, 0xa3,0x27,0x0b,
482 0xb7,0x33,0x0f, 0xc3,0x4b,0x1b, 0xcf,0x63,0x2b, 0xdb,0x7f,0x3b,
483 0xe3,0x97,0x4f, 0xe7,0xab,0x5f, 0xef,0xbf,0x77, 0xf7,0xd3,0x8b,
484 0xa7,0x7b,0x3b, 0xb7,0x9b,0x37, 0xc7,0xc3,0x37, 0xe7,0xe3,0x57,
485 0x7f,0xbf,0xff, 0xab,0xe7,0xff, 0xd7,0xff,0xff, 0x67,0x00,0x00,
486 0x8b,0x00,0x00, 0xb3,0x00,0x00, 0xd7,0x00,0x00, 0xff,0x00,0x00,
487 0xff,0xf3,0x93, 0xff,0xf7,0xc7, 0xff,0xff,0xff, 0x9f,0x5b,0x53
496 static void LoadMIP( const char *name, byte ** pic, int *width, int *height ){
499 unsigned int length, palettelength;
500 unsigned long mipdatasize;
501 int columns, rows, numPixels;
510 loadedpalette = NULL;
515 length = vfsLoadFile( (char *) name, (void **) &buffer, 0 );
516 if ( length == (unsigned int) -1 ) {
520 lpMip = (LPWAD3_MIP)buffer;
522 mipdatasize = GET_MIP_DATA_SIZE( lpMip->width,lpMip->height );
524 palettelength = vfsLoadFile( "textures/palette.lmp", (void **) &loadedpalette, 0 );
525 if ( palettelength == 768 ) {
526 palette = loadedpalette;
530 loadedpalette = NULL;
531 palette = quakepalette;
534 buf_p = buffer + lpMip->offsets[0];
536 columns = lpMip->width;
537 rows = lpMip->height;
538 numPixels = columns * rows;
547 //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);
548 //for (i = 0; i < sizeof(*lpMip); i++)
549 // Sys_Printf("%02x", (int) ((unsigned char *)lpMip)[i]);
551 bmpRGBA = reinterpret_cast < unsigned char *>( g_malloc( numPixels * 4 ) );
555 for ( i = 0; i < numPixels; i++ )
557 int palIndex = *buf_p++;
558 *pixbuf++ = palette[palIndex * 3];
559 *pixbuf++ = palette[palIndex * 3 + 1];
560 *pixbuf++ = palette[palIndex * 3 + 2];
564 vfsFreeFile( buffer );
565 if ( loadedpalette != NULL ) {
566 vfsFreeFile( loadedpalette );
575 Loads any of the supported image types into a cannonical
579 void LoadImage( const char *name, byte ** pic, int *width, int *height ){
585 len = strlen( name );
591 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".hlw" ) ) {
592 LoadHLW( name, pic, width, height );
597 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".mip" ) ) {
598 LoadMIP( name, pic, width, height );
603 if ( *pic == NULL && !g_strcasecmp( name + len - 4, ".spr" ) ) {
604 LoadIDSP( name, pic, width, height );