wolf3d-ios/wolf3d/wolfextractor/wolf/wolf_gfx.c

1708 lines
37 KiB
C

/*
Copyright (C) 2004 Michael Liebscher
This program 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.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* wolf_gfx.c: Decode Wolfenstein3-D GFX data.
*
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
* Date: 2004
*
* Acknowledgement:
* This code was derived from Wolfenstein3-D, and was originally
* written by Id Software, Inc.
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "wolf_def.h"
#include "../loaders/tga.h"
#include "../hq2x.h"
#include "../string/com_string.h"
#include "../filesys/file.h"
#include "../../../common/common_utils.h"
#include "../../../common/arch.h"
#include "../memory/memory.h"
extern char gamepal[];
#define FILEPOSSIZE 3
#define GFXHEADFNAME "VGAHEAD"
#define GFXFNAME "VGAGRAPH"
#define GFXDICTFNAME "VGADICT"
#define FONTWIDTH 256
#define FONTHEIGHT 128
typedef struct
{
short height;
short location[ 256 ];
char width[ 256 ];
} fontstruct;
typedef struct
{
// 0-255 is a character, > is a pointer to a node
W16 bit0, bit1;
} huffnode;
typedef struct
{
W16 width, height;
} pictabletype;
pictabletype *pictable;
huffnode grhuffman[ 255 ];
FILE *grhandle;
SW32 *grstarts; // array of offsets in vgagraph, -1 for sparse
void *grsegs[ NUMCHUNKS ];
/*
-----------------------------------------------------------------------------
Function: GRFILEPOS() -Calculate graphic file position.
Parameters: chunk -[in] Chunk number to calculate file offset.
Returns: File offset value or -1 for sparse tile.
Notes: See 'wl6_name.h' for valid chunk numbers for SOD and WL6.
grstarts must be allocated and initialized before call.
Uses global variable grstarts.
-----------------------------------------------------------------------------
*/
PRIVATE SW32 GRFILEPOS( W32 c )
{
SW32 value;
W32 offset;
offset = c * 3;
value = *(PW32)( ( (PW8)grstarts ) + offset );
value &= 0x00ffffffl;
if( value == 0xffffffl )
{
value = -1;
}
return value;
};
/*
-----------------------------------------------------------------------------
Function: CAL_GetGrChunkLength() -Calculate length of compressed graphic
chunk.
Parameters: chunk -[in] Chunk number to calculate file offset.
Returns: The length of the compressed graphic chunk.
Notes: Gets the length of an explicit length chunk (not tiles).
The file pointer is positioned so the compressed data
can be read in next.
-----------------------------------------------------------------------------
*/
PRIVATE SW32 CAL_GetGrChunkLength( W32 chunk )
{
fseek( grhandle, GRFILEPOS( chunk ) + sizeof( W32 ), SEEK_SET );
return ( GRFILEPOS( chunk + 1 ) - GRFILEPOS( chunk ) - 4 );
}
/*
-----------------------------------------------------------------------------
Function: CAL_HuffExpand() -Expand compressed data.
Parameters: source -[in] Pointer to compressed data.
destination -[out] Pointer to hold decompressed data.
length -[in] Length of expanded data.
hufftable -[in] Huffman dictionary data.
Returns: Nothing.
Notes: Uses classic Huffman node tree (not optimized).
-----------------------------------------------------------------------------
*/
PRIVATE void CAL_HuffExpand( const W8 *source,
W8 *destination,
W32 length,
huffnode *hufftable )
{
W32 bx; // node pointer
W32 dx;
W32 ch; // high order of CX
W32 cl; // low order of CX
const W8 *si; // Source Index
W8 *di; // Destination Index
bx = 254; // head node is always node 254
si = source;
di = destination;
ch = *si; // load first byte
si++;
cl = 1;
do
{
if( (ch & cl) & 0xff ) // bit set?
dx = hufftable[ bx ].bit1; // take bit1 path from node
else
dx = hufftable[ bx ].bit0; // take bit0 path from node
cl <<= 1; // advance to next bit position
if( cl & 0x100 )
{
ch = *si; // load next byte
si++;
cl = 1; // back to first bit
}
if( (cl & 0x100) == 0 )
{
if( dx < 256 )
{
*di = (W8)(dx & 0xff); // write a decompressed byte out
di++;
bx = 254; // back to the head node for next bit
length--;
}
else
{
bx = dx - 256; // next node = (huffnode *)code
}
}
} while( length );
}
/*
-----------------------------------------------------------------------------
Function: CAL_SetupGrFile() -Initialize graphic files and arrays.
Parameters: extension -[in] Pointer to a null-terminated string that
specifies the file extension.
(must be in '.XXX' format).
Returns: 1 on success, 0 otherwise.
Notes:
Uses global variables grhandle and pictable.
1. Open vgadict.XXX, read huffman dictionary data.
2. Open vgahead.XXX, read data offsets.
3. Open vgagraph.XXX, read pic and sprite header, expand data.
-----------------------------------------------------------------------------
*/
PRIVATE W8 CAL_SetupGrFile( const char *extension )
{
void *compseg;
FILE *handle;
char filename[ 16 ];
SW32 chunkcomplen; // chunk compressed length
//
// load vgadict.ext (huffman dictionary for graphics files)
//
cs_strlcpy( filename, GFXDICTFNAME, sizeof( filename ) );
cs_strlcat( filename, extension, sizeof( filename ) );
if( ( handle = fopen( cs_strupr( filename ), "rb" ) ) == NULL )
{
if( ( handle = fopen( cs_strlwr( filename ), "rb" ) ) == NULL )
{
printf( "Could not open file (%s) for read!\n", filename );
return 0;
}
}
fread( grhuffman, sizeof( grhuffman ), 1, handle );
fclose( handle );
//
// Open then load the data offsets from vgahead.ext
//
cs_strlcpy( filename, GFXHEADFNAME, sizeof( filename ) );
cs_strlcat( filename, extension, sizeof( filename ) );
if( (handle = fopen( cs_strupr( filename ), "rb" )) == NULL )
{
if( (handle = fopen( cs_strlwr( filename ), "rb" )) == NULL )
{
printf( "Could not open file (%s) for read!\n", filename );
return 0;
}
}
grstarts = MM_MALLOC( (NUMCHUNKS+1) * FILEPOSSIZE );
if( grstarts == NULL )
{
return 0;
}
fread( grstarts, sizeof( long ), (NUMCHUNKS+1) * FILEPOSSIZE, handle );
fclose( handle );
//
// Open the graphics file 'vgagraph.XXX'.
//
cs_strlcpy( filename, GFXFNAME, sizeof( filename ) );
cs_strlcat( filename, extension, sizeof( filename ) );
if( ( grhandle = fopen( cs_strupr( filename ), "rb" ) ) == NULL )
{
if( ( grhandle = fopen( cs_strlwr( filename ), "rb" ) ) == NULL )
{
printf( "Could not open file (%s) for read!\n", filename );
return 0;
}
}
//
// load the pic and sprite headers into the arrays.
//
pictable = MM_MALLOC( NUMPICS * sizeof( pictabletype ) );
if( pictable == NULL )
{
return 0;
}
chunkcomplen = CAL_GetGrChunkLength( STRUCTPIC ); // position file pointer
compseg = MM_MALLOC( chunkcomplen );
if( compseg == NULL )
{
return 0;
}
fread( compseg, chunkcomplen, 1, grhandle );
CAL_HuffExpand( compseg, (PW8)pictable,
NUMPICS * sizeof( pictabletype ),
grhuffman );
MM_FREE( compseg );
return 1;
}
/*
-----------------------------------------------------------------------------
Function: CAL_Shutdown() -Shutdown module.
Parameters: Nothing.
Returns: Nothing.
Notes: Frees grstarts, pictable and grsegs data. Closes grhandle file handle.
-----------------------------------------------------------------------------
*/
PUBLIC void CAL_Shutdown( void )
{
W32 i;
if( grstarts )
{
MM_FREE( grstarts );
}
if( pictable )
{
MM_FREE( pictable );
}
if( grhandle )
{
fclose( grhandle );
}
for( i = 0; i < NUMCHUNKS; ++i )
{
if( grsegs[ i ] )
{
MM_FREE( grsegs[ i ] );
}
}
}
/*
-----------------------------------------------------------------------------
Function: CAL_ExpandGrChunk() -Expand compressed graphic chunk.
Parameters: chunk -[in] Chunk number to expand.
source -[in] Pointer to compressed data.
version -[in] extension version.
1 -WL6
2 -SOD
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE void CAL_ExpandGrChunk( W32 chunk, const W8 *source, W16 version )
{
W32 expanded;
W16 offset = 0;
if( version & SOD_PAK )
offset = SOD_STARTDIFF;
if( chunk >= ( STARTTILE8 + offset ) &&
chunk < ( STARTEXTERNS + offset ) )
{
//
// expanded sizes of tile8/16/32 are implicit
//
#define BLOCK 64
#define MASKBLOCK 128
if( chunk < (STARTTILE8M + offset) ) // tile 8s are all in one chunk!
expanded = BLOCK * NUMTILE8;
else if( chunk < (STARTTILE16 + offset) )
expanded = MASKBLOCK * NUMTILE8M;
else if( chunk < (STARTTILE16M + offset) ) // all other tiles are one/chunk
expanded = BLOCK << 2;
else if( chunk < (STARTTILE32 + offset) )
expanded = MASKBLOCK << 2;
else if( chunk < (STARTTILE32M + offset) )
expanded = BLOCK << 4;
else
expanded = MASKBLOCK << 4;
}
else
{
//
// everything else has an explicit size longword
//
expanded = *(PW32)source;
source += 4; // skip over length
}
//
// allocate final space and decompress it.
// Sprites need to have shifts made and various other junk.
//
grsegs[ chunk ] = MM_MALLOC( expanded );
if( grsegs[ chunk ] == NULL )
{
return;
}
CAL_HuffExpand( source, grsegs[ chunk ], expanded, grhuffman );
}
/*
-----------------------------------------------------------------------------
Function: CA_CacheGrChunk() -Cache graphic chunk.
Parameters: chunk -[in] Chunk number to cache.
version -[in] extension version.
1 -WL6
2 -SOD
Returns: Nothing.
Notes: Makes sure a given chunk is in memory, loading it if needed.
-----------------------------------------------------------------------------
*/
PRIVATE void CA_CacheGrChunk( W32 chunk, W16 version )
{
SW32 pos;
W32 compressed;
void *buffer;
W32 next;
if( grsegs[ chunk ] )
{
return; // already in memory
}
//
// load the chunk into a buffer
//
pos = GRFILEPOS( chunk );
if( pos < 0 ) // $FFFFFFFF start is a sparse tile
{
return;
}
next = chunk + 1;
while( GRFILEPOS( next ) == -1 ) // skip past any sparse tiles
{
next++;
}
compressed = GRFILEPOS( next ) - pos;
fseek( grhandle, pos, SEEK_SET );
buffer = MM_MALLOC( compressed );
if( buffer == NULL )
{
return;
}
fread( buffer, 1, compressed, grhandle );
CAL_ExpandGrChunk( chunk, buffer, version );
MM_FREE( buffer );
}
/*
-----------------------------------------------------------------------------
Function: RGB32toRGB24() -Convert image from 32bits to 24bits.
Parameters: src -[in] Buffer to convert from.
dest -[in/out] Buffer to convert to.
size -[in] Size of src buffer.
Returns: Nothing.
Notes: src and dest can point to the same memory block.
-----------------------------------------------------------------------------
*/
PUBLIC void RGB32toRGB24( const W8 *src, W8 *dest, size_t size )
{
size_t i;
size_t npixels = size >> 2;
for( i = 0 ; i < npixels ; ++i )
{
dest[ i * 3 + 0 ] = src[ i * 4 + 0 ];
dest[ i * 3 + 1 ] = src[ i * 4 + 1 ];
dest[ i * 3 + 2 ] = src[ i * 4 + 2 ];
}
}
/*
-----------------------------------------------------------------------------
Function: MergePics() -Merge image inside another image.
Parameters: src -[in] Source image to copy from.
dest -[in] Destination image to copy to.
width -[in] Width of source image.
height -[in] Height of source image.
bpp -[in] Bytes per pixel of images.
totalwidth -[in] -Total width (in pixels) of destination image.
x_offset -[in] X offset (in pixels) in destination image.
y_offset -[in] Y offset (in pixels) in destination image.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE void MergePics( const W8 *src, W8 *dest, W16 width, W16 height, W16 bpp, W16 totalwidth,
W32 x_offset,
W32 y_offset )
{
W16 x, y;
W8 *dptr;
dptr = dest + (y_offset * totalwidth * bpp) + (x_offset * bpp);
for( y = 0 ; y < height ; ++y )
{
for( x = 0 ; x < width ; ++x )
{
dptr[ 0 ] = src[ 0 ];
dptr[ 1 ] = src[ 1 ];
src += bpp;
dptr += bpp;
}
dptr += (totalwidth * bpp) - width * bpp;
}
}
PRIVATE void MergeImages( W8 *src, W16 src_bpp, W16 src_totalwidth, W16 src_region_width, W16 src_region_height, W32 src_x_offset, W32 src_y_offset,
W8 *dest, W16 dest_bpp, W16 dest_totalwidth, W16 dest_region_width, W16 dest_region_height, W32 dest_x_offset, W32 dest_y_offset )
{
W16 x, y;
W8 *dptr;
W8 *sptr;
dptr = dest + (dest_y_offset * dest_totalwidth * dest_bpp) + (dest_x_offset * dest_bpp);
sptr = src + (src_y_offset * src_totalwidth * src_bpp) + (src_x_offset * src_bpp);
for( y = 0 ; y < src_region_height ; ++y )
{
for( x = 0 ; x < src_region_width ; ++x )
{
dptr[ 0 ] = sptr[ 0 ];
dptr[ 1 ] = sptr[ 1 ];
sptr += src_bpp;
dptr += dest_bpp;
}
dptr += (dest_totalwidth * dest_bpp) - dest_region_width * dest_bpp;
sptr += (src_totalwidth * src_bpp) - src_region_width * src_bpp;
}
}
/*
-----------------------------------------------------------------------------
Function: SavePic() -Save graphic lump in targa image format.
Parameters: chunk -[in] Chunk number to save.
version -[in] extension version.
1 -WL6
2 -SOD
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE void SavePic( W32 chunknum, W16 version, W8 *buffer, W8 *buffer2 )
{
W16 i;
W16 temp;
char filename[32];
char *fname;
W8 *ptr;
W8 *pic;
W32 picnum;
W16 width, height;
W16 linewidth, plane, sx, sy;
W8 r,g,b;
W16 rgb;
W8 *tpalette = gamepal;
static W16 offset = 0;
if( ( (chunknum == WL1_N_BLANKPIC ||
chunknum == WL1_NOKEYPIC ) && (version & WL1_PAK) ) )
{
return;
}
if( ( (chunknum == N_BLANKPIC ||
chunknum == NOKEYPIC ) && (version & WL6_PAK) ) )
{
return;
}
if( ( (chunknum == SDM_N_BLANKPIC ||
chunknum == SDM_NOKEYPIC ) && (version & SDM_PAK) ) )
{
return;
}
if( ( (chunknum == SOD_N_BLANKPIC ||
chunknum == SOD_NOKEYPIC ) && (version & SOD_PAK) ) )
{
return;
}
// Spear used multiple palettes, so
// pull out the one we need.
if( version & SDM_PAK )
{
switch( chunknum )
{
case SDM_TITLE1PIC:
case SDM_TITLE2PIC:
CA_CacheGrChunk( SDM_TITLEPALETTE, version );
tpalette = grsegs[ SDM_TITLEPALETTE ];
break;
default:
tpalette = gamepal;
break;
}
}
if( version & SOD_PAK )
{
switch( chunknum )
{
case SOD_IDGUYS1PIC:
case SOD_IDGUYS2PIC:
CA_CacheGrChunk( SOD_IDGUYSPALETTE, version );
tpalette = grsegs[ SOD_IDGUYSPALETTE ];
break;
case SOD_TITLE1PIC:
case SOD_TITLE2PIC:
CA_CacheGrChunk( SOD_TITLEPALETTE, version );
tpalette = grsegs[ SOD_TITLEPALETTE ];
break;
case SOD_ENDSCREEN11PIC:
CA_CacheGrChunk( SOD_END1PALETTE, version );
tpalette = grsegs[ SOD_END1PALETTE ];
break;
case SOD_ENDSCREEN12PIC:
CA_CacheGrChunk( SOD_END2PALETTE, version );
tpalette = grsegs[ SOD_END2PALETTE ];
break;
case SOD_ENDSCREEN3PIC:
CA_CacheGrChunk( SOD_END3PALETTE, version );
tpalette = grsegs[ SOD_END3PALETTE ];
break;
case SOD_ENDSCREEN4PIC:
CA_CacheGrChunk( SOD_END4PALETTE, version );
tpalette = grsegs[ SOD_END4PALETTE ];
break;
case SOD_ENDSCREEN5PIC:
CA_CacheGrChunk( SOD_END5PALETTE, version );
tpalette = grsegs[ SOD_END5PALETTE ];
break;
case SOD_ENDSCREEN6PIC:
CA_CacheGrChunk( SOD_END6PALETTE, version );
tpalette = grsegs[ SOD_END6PALETTE ];
break;
case SOD_ENDSCREEN7PIC:
CA_CacheGrChunk( SOD_END7PALETTE, version );
tpalette = grsegs[ SOD_END7PALETTE ];
break;
case SOD_ENDSCREEN8PIC:
CA_CacheGrChunk( SOD_END8PALETTE, version );
tpalette = grsegs[ SOD_END8PALETTE ];
break;
case SOD_ENDSCREEN9PIC:
CA_CacheGrChunk( SOD_END9PALETTE, version );
tpalette = grsegs[ SOD_END9PALETTE ];
break;
default:
tpalette = gamepal;
break;
} // End switch chunknum
} // End if version & SOD_PAK
STATUSBARHACK:
picnum = chunknum - STARTPICS;
pic = grsegs[ chunknum ];
width = pictable[ picnum ].width;
height= pictable[ picnum ].height;
linewidth = width / 4;
for( i = 0; i < ( width * height ); ++i, pic++ )
{
plane = i / ( (width * height) / 4 );
sx = ( ( i % ( linewidth ) ) * 4 ) + plane;
sy = ( ( i / linewidth ) % height );
ptr = buffer + ( (sx*2) + (sy * width)*2);
temp = (*pic) * 3;
r = tpalette[ temp ] >> 1;
g = tpalette[ temp+1 ];
b = tpalette[ temp+2 ] >> 1;
rgb = (b << 11) | (g << 5) | r;
ptr[ 0 ] = rgb & 0xff;
ptr[ 1 ] = rgb >> 8;
}
//
// Hacks to reassemble images
//
if( version & WL1_PAK )
{
if( chunknum == WL1_STATUSBARPIC )
{
memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic
CA_CacheGrChunk( WL1_NOKEYPIC, version ); // cache NOKEYPIC
chunknum = WL1_NOKEYPIC;
goto STATUSBARHACK;
}
else if( chunknum == WL1_H_BOTTOMINFOPIC )
{
MergeImages( buffer, 2, 304, 91, 16, 24, 4,
buffer2, 2, 91, 91, 16, 0, 0 );
MergeImages( buffer, 2, 304, 91, 16, 192, 4,
buffer2, 2, 91, 91, 16, 0, 16 );
hq2x_32( buffer2, buffer, 91, 16, (91*2)*4 );
RGB32toRGB24( buffer, buffer, 182*32*4 );
cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_PAGE" );
WriteTGA( filename, 24, 182, 32, buffer, 0, 0 );
hq2x_32( buffer2 + (16 * 91 * 2), buffer, 91, 16, (91*2)*4 );
RGB32toRGB24( buffer, buffer, 182*32*4 );
cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_BLANK" );
WriteTGA( filename, 24, 182, 32, buffer, 0, 1 );
return;
}
else if( chunknum == WL1_NOKEYPIC )
{
chunknum = WL1_STATUSBARPIC;
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 );
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height );
memcpy( buffer, buffer2, 320 * 40 * 2 );
width = 320;
height = 40;
}
else if( chunknum == WL1_L_COLONPIC )
{
memset( buffer2, 0, 256*64*2 );
MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 );
return;
}
else if( chunknum == WL1_L_EXPOINTPIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 );
return;
}
else if( chunknum == WL1_L_APOSTROPHEPIC )
{
W16 i;
MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 );
memcpy( buffer, buffer2, 256 * 64 * 2 );
for( i = 0 ; i < 256 * 64 * 2 ; i += 2 )
{
if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 )
{
buffer[ i + 1 ] = 66;
}
}
offset = 0;
width = 256;
height = 64;
}
else if( chunknum == WL1_L_PERCENTPIC )
{
offset = 16; // this is for L_APIC...
MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 );
return;
}
else if( chunknum >= WL1_L_NUM0PIC && chunknum <= WL1_L_NUM9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 );
offset += width;
return;
}
else if( chunknum >= WL1_N_0PIC && chunknum < WL1_N_9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
offset += width + 1;
return;
}
else if( chunknum == WL1_N_9PIC )
{
W32 i;
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
memcpy( buffer, buffer2, 90 * height * 2 );
for( i = 0 ; i < 90 * 16 * 2 ; i += 2 )
{
if( ! (i % 9) && i != 0 )
{
buffer[ i - 2 ] = 0;
buffer[ i - 1 ] = 160;
}
}
width = 90;
offset = 0;
}
else if( chunknum >= WL1_L_APIC && chunknum <= WL1_L_ZPIC )
{
static W32 yoffset = 32;
MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset );
offset += width;
if( offset >= 256 )
{
offset = 0;
yoffset += 16;
}
return;
}
else if( chunknum == WL1_FACE5CPIC )
{
// hmmm... Why is this one messed up?
MergeImages( buffer, 2, 24, 18, height-2, 8, 2,
buffer2, 2, 24, 18, height-2, 0, 0 );
MergeImages( buffer, 2, 24, 8, height-3, 0, 3,
buffer2, 2, 24, 8, height-2, 16, 0 );
MergeImages( buffer, 2, 24, 18, 2, 9, 0,
buffer2, 2, 24, 18, 2, 0, height-2 );
MergeImages( buffer, 2, 24, 7, 3, 1, 0,
buffer2, 2, 24, 7, 3, 16, height-3 );
memcpy( buffer, buffer2, 24 * 32 * 2 );
buffer[ (30 * 24 * 2) + (3 * 2) ] = 73;
buffer[ (30 * 24 * 2) + (3 * 2) + 1 ] = 74;
buffer[ (31 * 24 * 2) + (3 * 2) ] = 73;
buffer[ (31 * 24 * 2) + (3 * 2) + 1 ] = 74;
buffer[ (29 * 24 * 2) + (23 * 2) ] = 73;
buffer[ (29 * 24 * 2) + (23 * 2) + 1 ] = 74;
buffer[ (30 * 24 * 2) + (23 * 2) ] = 73;
buffer[ (30 * 24 * 2) + (23 * 2) + 1 ] = 74;
buffer[ (31 * 24 * 2) + (23 * 2) ] = 73;
buffer[ (31 * 24 * 2) + (23 * 2) + 1 ] = 74;
buffer[ (29 * 24 * 2) + (19 * 2) ] = 255;
buffer[ (29 * 24 * 2) + (19 * 2) + 1 ] = 100;
buffer[ (30 * 24 * 2) + (19 * 2) ] = 63;
buffer[ (30 * 24 * 2) + (19 * 2) + 1 ] = 117;
buffer[ (31 * 24 * 2) + (19 * 2) ] = 52;
buffer[ (31 * 24 * 2) + (19 * 2) + 1 ] = 59;
buffer[ (30 * 24 * 2) + (7 * 2) ] = 19;
buffer[ (30 * 24 * 2) + (7 * 2) + 1 ] = 59;
buffer[ (31 * 24 * 2) + (7 * 2) ] = 19;
buffer[ (31 * 24 * 2) + (7 * 2) + 1 ] = 59;
buffer[ (30 * 24 * 2) + (11 * 2) ] = 91;
buffer[ (30 * 24 * 2) + (11 * 2) + 1 ] = 84;
buffer[ (31 * 24 * 2) + (11 * 2) ] = 190;
buffer[ (31 * 24 * 2) + (11 * 2) + 1 ] = 92;
buffer[ (30 * 24 * 2) + (15 * 2) ] = 249;
buffer[ (30 * 24 * 2) + (15 * 2) + 1 ] = 75;
buffer[ (31 * 24 * 2) + (15 * 2) ] = 190;
buffer[ (31 * 24 * 2) + (15 * 2) + 1 ] = 92;
}
}
else if( version & WL6_PAK )
{
if( chunknum == STATUSBARPIC )
{
memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic
CA_CacheGrChunk( NOKEYPIC, version ); // cache NOKEYPIC
chunknum = NOKEYPIC;
goto STATUSBARHACK;
}
else if( chunknum == H_BOTTOMINFOPIC )
{
MergeImages( buffer, 2, 304, 91, 16, 24, 4,
buffer2, 2, 91, 91, 16, 0, 0 );
MergeImages( buffer, 2, 304, 91, 16, 192, 4,
buffer2, 2, 91, 91, 16, 0, 16 );
hq2x_32( buffer2, buffer, 91, 16, (91*2)*4 );
RGB32toRGB24( buffer, buffer, 182*32*4 );
cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_PAGE" );
WriteTGA( filename, 24, 182, 32, buffer, 0, 0 );
hq2x_32( buffer2 + (16 * 91 * 2), buffer, 91, 16, (91*2)*4 );
RGB32toRGB24( buffer, buffer, 182*32*4 );
cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, "PLAQUE_BLANK" );
WriteTGA( filename, 24, 182, 32, buffer, 0, 1 );
return;
}
else if( chunknum == NOKEYPIC )
{
chunknum = STATUSBARPIC;
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 );
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height );
memcpy( buffer, buffer2, 320 * 40 * 2 );
width = 320;
height = 40;
}
else if( chunknum == L_COLONPIC )
{
memset( buffer2, 0, 256*64*2 );
MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 );
return;
}
else if( chunknum == L_EXPOINTPIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 );
return;
}
else if( chunknum == L_APOSTROPHEPIC )
{
W16 i;
MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 );
memcpy( buffer, buffer2, 256 * 64 * 2 );
for( i = 0 ; i < 256 * 64 * 2 ; i += 2 )
{
if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 )
{
buffer[ i + 1 ] = 66;
}
}
offset = 0;
width = 256;
height = 64;
}
else if( chunknum == L_PERCENTPIC )
{
offset = 16; // this is for L_APIC...
MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 );
return;
}
else if( chunknum >= L_NUM0PIC && chunknum <= L_NUM9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 );
offset += width;
return;
}
else if( chunknum >= N_0PIC && chunknum < N_9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
offset += width + 1;
return;
}
else if( chunknum == N_9PIC )
{
W32 i;
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
memcpy( buffer, buffer2, 90 * height * 2 );
for( i = 0 ; i < 90 * 16 * 2 ; i += 2 )
{
if( ! (i % 9) && i != 0 )
{
buffer[ i - 2 ] = 0;
buffer[ i - 1 ] = 160;
}
}
width = 90;
offset = 0;
}
else if( chunknum >= L_APIC && chunknum <= L_ZPIC )
{
static W32 yoffset = 32;
MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset );
offset += width;
if( offset >= 256 )
{
offset = 0;
yoffset += 16;
}
return;
}
}
else if( version & SDM_PAK )
{
if( chunknum == SDM_STATUSBARPIC )
{
memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic
CA_CacheGrChunk( SDM_NOKEYPIC, version ); // cache SOD_NOKEYPIC
chunknum = SDM_NOKEYPIC;
goto STATUSBARHACK;
}
else if( chunknum == SDM_NOKEYPIC )
{
chunknum = SDM_STATUSBARPIC;
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 );
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height );
memcpy( buffer, buffer2, 320 * 40 * 2 );
width = 320;
height = 40;
}
else if( chunknum == SDM_L_COLONPIC )
{
memset( buffer2, 0, 256*64*2 );
MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 );
return;
}
else if( chunknum == SDM_L_EXPOINTPIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 );
return;
}
else if( chunknum == SDM_L_APOSTROPHEPIC )
{
W16 i;
MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 );
memcpy( buffer, buffer2, 256 * 64 * 2 );
for( i = 0 ; i < 256 * 64 * 2 ; i += 2 )
{
if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 )
{
buffer[ i + 1 ] = 66;
}
}
offset = 0;
width = 256;
height = 64;
}
else if( chunknum == SDM_L_PERCENTPIC )
{
offset = 16; // this is for L_APIC...
MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 );
return;
}
else if( chunknum >= SDM_L_NUM0PIC && chunknum <= SDM_L_NUM9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 );
offset += width;
return;
}
else if( chunknum >= SDM_N_0PIC && chunknum < SDM_N_9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
offset += width + 1;
return;
}
else if( chunknum == SDM_N_9PIC )
{
W32 i;
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
memcpy( buffer, buffer2, 90 * height * 2 );
for( i = 0 ; i < 90 * 16 * 2 ; i += 2 )
{
if( ! (i % 9) && i != 0 )
{
buffer[ i - 2 ] = 0;
buffer[ i - 1 ] = 160;
}
}
width = 90;
offset = 0;
}
else if( chunknum >= SDM_L_APIC && chunknum <= SDM_L_ZPIC )
{
static W32 yoffset = 32;
MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset );
offset += width;
if( offset >= 256 )
{
offset = 0;
yoffset += 16;
}
return;
}
else if( chunknum == SDM_TITLE1PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
offset += width*height*2;
return;
}
else if( chunknum == SDM_TITLE2PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
memcpy( buffer, buffer2, 320*200*2 );
height = 200;
offset = 0;
}
}
else if( version & SOD_PAK )
{
if( chunknum == SOD_STATUSBARPIC )
{
memcpy( buffer2, buffer, width * height * 2 ); // Save Status bar pic
CA_CacheGrChunk( SOD_NOKEYPIC, version ); // cache SOD_NOKEYPIC
chunknum = SOD_NOKEYPIC;
goto STATUSBARHACK;
}
else if( chunknum == SOD_NOKEYPIC )
{
chunknum = SOD_STATUSBARPIC;
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4 );
MergePics( buffer, buffer2, width, height, 2, 320, 240, 4+height );
memcpy( buffer, buffer2, 320 * 40 * 2 );
width = 320;
height = 40;
}
else if( chunknum == SOD_L_COLONPIC )
{
memset( buffer2, 0, 256*64*2 );
MergePics( buffer, buffer2, width, height, 2, 256, 160, 16 );
return;
}
else if( chunknum == SOD_L_EXPOINTPIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, 16, 0 );
return;
}
else if( chunknum == SOD_L_APOSTROPHEPIC )
{
W16 i;
MergePics( buffer, buffer2, width, height, 2, 256, 112, 0 );
memcpy( buffer, buffer2, 256 * 64 * 2 );
for( i = 0 ; i < 256 * 64 * 2 ; i += 2 )
{
if( buffer[ i ] == 0 && buffer[ i + 1 ] == 0 )
{
buffer[ i + 1 ] = 66;
}
}
offset = 0;
width = 256;
height = 64;
}
else if( chunknum == SOD_L_PERCENTPIC )
{
offset = 16; // this is for L_APIC...
MergePics( buffer, buffer2, width, height, 2, 256, 80, 0 );
return;
}
else if( chunknum >= SOD_L_NUM0PIC && chunknum <= SOD_L_NUM9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 256, offset, 16 );
offset += width;
return;
}
else if( chunknum >= SOD_N_0PIC && chunknum < SOD_N_9PIC )
{
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
offset += width + 1;
return;
}
else if( chunknum == SOD_N_9PIC )
{
W32 i;
MergePics( buffer, buffer2, width, height, 2, 90, offset, 0 );
memcpy( buffer, buffer2, 90 * height * 2 );
for( i = 0 ; i < 90 * 16 * 2 ; i += 2 )
{
if( ! (i % 9) && i != 0 )
{
buffer[ i - 2 ] = 0;
buffer[ i - 1 ] = 160;
}
}
width = 90;
offset = 0;
}
else if( chunknum >= SOD_L_APIC && chunknum <= SOD_L_ZPIC )
{
static W32 yoffset = 32;
MergePics( buffer, buffer2, width, height, 2, 256, offset, yoffset );
offset += width;
if( offset >= 256 )
{
offset = 0;
yoffset += 16;
}
return;
}
else if( chunknum == SOD_IDGUYS1PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
offset += width*height*2;
return;
}
else if( chunknum == SOD_IDGUYS2PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
memcpy( buffer, buffer2, 320*200*2 );
height = 200;
offset = 0;
}
else if( chunknum == SOD_TITLE1PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
offset += width*height*2;
return;
}
else if( chunknum == SOD_TITLE2PIC )
{
memcpy( buffer2+offset, buffer, (width*height*2) );
memcpy( buffer, buffer2, 320*200*2 );
height = 200;
offset = 0;
}
}
//
// End of images hacks
//
if( version & WL1_PAK )
{
fname = GetLumpFileName_WL1( chunknum );
}
else if( version & WL6_PAK )
{
fname = GetLumpFileName_WL6( chunknum );
}
else if( version & SDM_PAK )
{
fname = GetLumpFileName_SDM( chunknum );
}
else if( version & SOD_PAK )
{
fname = GetLumpFileName_SOD( chunknum );
}
else
{
printf( "Unknown file extension!\n" );
return;
}
if( fname == NULL )
{
printf( "File name not found for item: (%d)\n", chunknum );
return;
}
cs_snprintf( filename, sizeof( filename ), "%s/%s.tga", LGFXDIR, fname );
hq2x_32( buffer, buffer2, width, height, (width*2)*4 );
// Get rid of alpha channel
RGB32toRGB24( buffer2, buffer2, (width*2)*(height*2)*4 );
WriteTGA( filename, 24, (width*2), (height*2), buffer2, 0, 1 );
return;
}
/*
-----------------------------------------------------------------------------
Function: Fontline() -Extract and save font.
Parameters: fontnumber -[in] font to save.
version -[in] extension version.
1 -WL6
2 -SOD
Returns: Nothing.
Notes: Font must be cached in grsegs[] before calling.
-----------------------------------------------------------------------------
*/
PRIVATE void Fontline( W32 fontnumber, W16 version )
{
fontstruct *font;
W16 i;
W16 x, y;
W16 px, py;
W8 *buffer;
W8 *source;
W8 *ptr;
char filename[ 256 ];
font = (fontstruct *)grsegs[ fontnumber ];
buffer = MM_MALLOC( FONTWIDTH * FONTHEIGHT * 4 );
if( buffer == NULL )
return;
ptr = buffer;
for( x = 0; x < FONTWIDTH; ++x )
{
for( y = 0; y < FONTHEIGHT; ++y, ptr += 4 )
{
ptr[ 0 ] = ptr[ 1 ] = ptr[ 2 ] = 0xFF;
ptr[ 3 ] = 0x00;
}
}
px = py = 0;
for( i = 0; i < 256; ++i )
{
if( ! font->width[ i ] )
continue;
if( px + font->width[ i ] > FONTWIDTH-1 )
{
py += font->height;
px = 0;
}
source = ((PW8) font) + font->location[ i ];
ptr = buffer + (py * FONTWIDTH + px) * 4;
for( y = 0; y < font->height; ++y, ptr += FONTWIDTH * 4 )
{
for( x = 0; x < font->width[ i ]; ++x )
{
if( *source++ )
{
ptr[ x * 4 + 3 ] = 0xFF;
}
}
}
px += 16;
} // end for i = 0; i < 256; ++i
cs_snprintf( filename, sizeof( filename ), "%s/font%d.tga", LGFXDIR, fontnumber );
WriteTGA( filename, 32, FONTWIDTH, FONTHEIGHT, buffer, 0, 1 );
MM_FREE( buffer );
}
PRIVATE void DecodeText( W16 version )
{
char *text;
int artnum;
int endextern;
int i;
int length;
FILE *fhandle;
int limit;
limit = 6;
if( version & SOD_PAK )
{
endextern = 168;
fhandle = fopen( "sod.txt", "wb" );
if( ! fhandle )
{
return;
}
limit = 1;
}
else if( version & WL6_PAK )
{
endextern = 143;
fhandle = fopen( "wl6.txt", "wb" );
if( ! fhandle )
{
return;
}
}
else
{
return;
}
for( i = 0 ; i < limit ; ++i )
{
artnum = endextern + i;
CA_CacheGrChunk( artnum, version );
text = (char *)grsegs[ artnum ];
length = strlen( text );
fwrite( text, sizeof( W8 ), length, fhandle );
fprintf( fhandle, "\n\n" );
MM_FREE( grsegs[ artnum ] );
}
fclose( fhandle );
}
/*
-----------------------------------------------------------------------------
Function: LumpExtractor() -Extract Lump gfx from Wolf3D and SOD data files.
Parameters: fextension -[in] String holding file extension
(must be in '.XXX' format).
limit -[in] max
version -[in] extension version.
1 -WL6
2 -SOD
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC _boolean LumpExtractor( const char *fextension, W32 limit, W16 version )
{
W32 i;
W8 *buffer, *buffer2;
if( ! fextension || ! *fextension )
{
printf( "Invalid file extension passed into LumpExtractor!\n" );
return false;
}
//
// Setup
//
if( 0 == FS_Mkdir( LGFXDIR ) )
{
printf( "[%s] Could not create directory (%s)!\n", "wolf_gfx.c", LGFXDIR );
return false;
}
if( ! CAL_SetupGrFile( fextension ) )
{
CAL_Shutdown();
return false;
}
//
// Allocate buffers
//
buffer = MM_MALLOC( 320 * 416 * 2 );
if( buffer == NULL )
{
CAL_Shutdown();
return false;
}
buffer2 = MM_MALLOC( 640 * 400 * 4 );
if( buffer2 == NULL )
{
MM_FREE( buffer );
CAL_Shutdown();
return false;
}
//
// Decode GFX data
//
printf( "Decoding GFX Data...\n" );
// (void)DecodeText( version );
for( i = STARTFONT; i < STARTPICS; ++i )
{
CA_CacheGrChunk( i, version );
Fontline( i, version );
}
for( i = STARTPICS; i < limit+1; ++i )
{
CA_CacheGrChunk( i, version );
SavePic( i, version, buffer, buffer2 );
}
//
// Shutdown
//
MM_FREE( buffer2 );
MM_FREE( buffer );
CAL_Shutdown();
return true;
}