/tools/quake2/qdata/video.c
C | 1266 lines | 897 code | 198 blank | 171 comment | 165 complexity | 1a0f8fc6297b478955eca978b5b4d336 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, LGPL-2.0
- /*
- 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
- */
- #include "qdata.h"
- #include "inout.h"
- byte *soundtrack;
- char base[32];
- /*
- ===============================================================================
- WAV loading
- ===============================================================================
- */
- typedef struct
- {
- int rate;
- int width;
- int channels;
- int loopstart;
- int samples;
- int dataofs; // chunk starts this many bytes from file start
- } wavinfo_t;
- byte *data_p;
- byte *iff_end;
- byte *last_chunk;
- byte *iff_data;
- int iff_chunk_len;
- int samplecounts[0x10000];
- wavinfo_t wavinfo;
- short GetLittleShort( void ){
- short val = 0;
- val = *data_p;
- val = val + ( *( data_p + 1 ) << 8 );
- data_p += 2;
- return val;
- }
- int GetLittleLong( void ){
- int val = 0;
- val = *data_p;
- val = val + ( *( data_p + 1 ) << 8 );
- val = val + ( *( data_p + 2 ) << 16 );
- val = val + ( *( data_p + 3 ) << 24 );
- data_p += 4;
- return val;
- }
- void FindNextChunk( char *name ){
- while ( 1 )
- {
- data_p = last_chunk;
- if ( data_p >= iff_end ) { // didn't find the chunk
- data_p = NULL;
- return;
- }
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- if ( iff_chunk_len < 0 ) {
- data_p = NULL;
- return;
- }
- // if (iff_chunk_len > 1024*1024)
- // Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
- data_p -= 8;
- last_chunk = data_p + 8 + ( ( iff_chunk_len + 1 ) & ~1 );
- if ( !strncmp( data_p, name, 4 ) ) {
- return;
- }
- }
- }
- void FindChunk( char *name ){
- last_chunk = iff_data;
- FindNextChunk( name );
- }
- void DumpChunks( void ){
- char str[5];
- str[4] = 0;
- data_p = iff_data;
- do
- {
- memcpy( str, data_p, 4 );
- data_p += 4;
- iff_chunk_len = GetLittleLong();
- printf( "0x%x : %s (%d)\n", (int)( data_p - 4 ), str, iff_chunk_len );
- data_p += ( iff_chunk_len + 1 ) & ~1;
- } while ( data_p < iff_end );
- }
- /*
- ============
- GetWavinfo
- ============
- */
- wavinfo_t GetWavinfo( char *name, byte *wav, int wavlength ){
- wavinfo_t info;
- int i;
- int format;
- int samples;
- memset( &info, 0, sizeof( info ) );
- if ( !wav ) {
- return info;
- }
- iff_data = wav;
- iff_end = wav + wavlength;
- // find "RIFF" chunk
- FindChunk( "RIFF" );
- if ( !( data_p && !strncmp( data_p + 8, "WAVE", 4 ) ) ) {
- printf( "Missing RIFF/WAVE chunks\n" );
- return info;
- }
- // get "fmt " chunk
- iff_data = data_p + 12;
- // DumpChunks ();
- FindChunk( "fmt " );
- if ( !data_p ) {
- printf( "Missing fmt chunk\n" );
- return info;
- }
- data_p += 8;
- format = GetLittleShort();
- if ( format != 1 ) {
- printf( "Microsoft PCM format only\n" );
- return info;
- }
- info.channels = GetLittleShort();
- info.rate = GetLittleLong();
- data_p += 4 + 2;
- info.width = GetLittleShort() / 8;
- // get cue chunk
- FindChunk( "cue " );
- if ( data_p ) {
- data_p += 32;
- info.loopstart = GetLittleLong();
- // Com_Printf("loopstart=%d\n", sfx->loopstart);
- // if the next chunk is a LIST chunk, look for a cue length marker
- FindNextChunk( "LIST" );
- if ( data_p ) {
- if ( !strncmp( data_p + 28, "mark", 4 ) ) { // this is not a proper parse, but it works with cooledit...
- data_p += 24;
- i = GetLittleLong(); // samples in loop
- info.samples = info.loopstart + i;
- }
- }
- }
- else{
- info.loopstart = -1;
- }
- // find data chunk
- FindChunk( "data" );
- if ( !data_p ) {
- printf( "Missing data chunk\n" );
- return info;
- }
- data_p += 4;
- samples = GetLittleLong();
- if ( info.samples ) {
- if ( samples < info.samples ) {
- Error( "Sound %s has a bad loop length", name );
- }
- }
- else{
- info.samples = samples;
- }
- info.dataofs = data_p - wav;
- return info;
- }
- //=====================================================================
- /*
- ==============
- LoadSoundtrack
- ==============
- */
- void LoadSoundtrack( void ){
- char name[1024];
- FILE *f;
- int len;
- int i, val, j;
- soundtrack = NULL;
- sprintf( name, "%svideo/%s/%s.wav", gamedir, base, base );
- printf( "%s\n", name );
- f = fopen( name, "rb" );
- if ( !f ) {
- printf( "no soundtrack for %s\n", base );
- return;
- }
- len = Q_filelength( f );
- soundtrack = malloc( len );
- fread( soundtrack, 1, len, f );
- fclose( f );
- wavinfo = GetWavinfo( name, soundtrack, len );
- // count samples for compression
- memset( samplecounts, 0, sizeof( samplecounts ) );
- j = wavinfo.samples / 2;
- for ( i = 0 ; i < j ; i++ )
- {
- val = ( (unsigned short *)( soundtrack + wavinfo.dataofs ) )[i];
- samplecounts[val]++;
- }
- val = 0;
- for ( i = 0 ; i < 0x10000 ; i++ )
- if ( samplecounts[i] ) {
- val++;
- }
- printf( "%i unique sample values\n", val );
- }
- /*
- ==================
- WriteSound
- ==================
- */
- void WriteSound( FILE *output, int frame ){
- int start, end;
- int count;
- int empty = 0;
- int i;
- int sample;
- int width;
- width = wavinfo.width * wavinfo.channels;
- start = frame * wavinfo.rate / 14;
- end = ( frame + 1 ) * wavinfo.rate / 14;
- count = end - start;
- for ( i = 0 ; i < count ; i++ )
- {
- sample = start + i;
- if ( sample > wavinfo.samples || !soundtrack ) {
- fwrite( &empty, 1, width, output );
- }
- else{
- fwrite( soundtrack + wavinfo.dataofs + sample * width, 1, width,output );
- }
- }
- }
- //==========================================================================
- /*
- ==================
- MTF
- ==================
- */
- cblock_t MTF( cblock_t in ){
- int i, j, b, code;
- byte *out_p;
- int index[256];
- cblock_t out;
- out_p = out.data = malloc( in.count + 4 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- for ( i = 0 ; i < 256 ; i++ )
- index[i] = i;
- for ( i = 0 ; i < in.count ; i++ )
- {
- b = in.data[i];
- code = index[b];
- *out_p++ = code;
- // shuffle b indexes to 0
- for ( j = 0 ; j < 256 ; j++ )
- if ( index[j] < code ) {
- index[j]++;
- }
- index[b] = 0;
- }
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- int bwt_size;
- byte *bwt_data;
- int bwtCompare( const void *elem1, const void *elem2 ){
- int i;
- int i1, i2;
- int b1, b2;
- i1 = *(int *)elem1;
- i2 = *(int *)elem2;
- for ( i = 0 ; i < bwt_size ; i++ )
- {
- b1 = bwt_data[i1];
- b2 = bwt_data[i2];
- if ( b1 < b2 ) {
- return -1;
- }
- if ( b1 > b2 ) {
- return 1;
- }
- if ( ++i1 == bwt_size ) {
- i1 = 0;
- }
- if ( ++i2 == bwt_size ) {
- i2 = 0;
- }
- }
- return 0;
- }
- /*
- ==================
- BWT
- ==================
- */
- cblock_t BWT( cblock_t in ){
- int *sorted;
- int i;
- byte *out_p;
- cblock_t out;
- bwt_size = in.count;
- bwt_data = in.data;
- sorted = malloc( in.count * sizeof( *sorted ) );
- for ( i = 0 ; i < in.count ; i++ )
- sorted[i] = i;
- qsort( sorted, in.count, sizeof( *sorted ), bwtCompare );
- out_p = out.data = malloc( in.count + 8 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- // write head index
- for ( i = 0 ; i < in.count ; i++ )
- if ( sorted[i] == 0 ) {
- break;
- }
- *out_p++ = i & 255;
- *out_p++ = ( i >> 8 ) & 255;
- *out_p++ = ( i >> 16 ) & 255;
- *out_p++ = ( i >> 24 ) & 255;
- // write the L column
- for ( i = 0 ; i < in.count ; i++ )
- *out_p++ = in.data[( sorted[i] + in.count - 1 ) % in.count];
- free( sorted );
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- typedef struct hnode_s
- {
- int count;
- qboolean used;
- int children[2];
- } hnode_t;
- int numhnodes;
- hnode_t hnodes[512];
- unsigned charbits[256];
- int charbitscount[256];
- int SmallestNode( void ){
- int i;
- int best, bestnode;
- best = 99999999;
- bestnode = -1;
- for ( i = 0 ; i < numhnodes ; i++ )
- {
- if ( hnodes[i].used ) {
- continue;
- }
- if ( !hnodes[i].count ) {
- continue;
- }
- if ( hnodes[i].count < best ) {
- best = hnodes[i].count;
- bestnode = i;
- }
- }
- if ( bestnode == -1 ) {
- return -1;
- }
- hnodes[bestnode].used = true;
- return bestnode;
- }
- void BuildChars( int nodenum, unsigned bits, int bitcount ){
- hnode_t *node;
- if ( nodenum < 256 ) {
- if ( bitcount > 32 ) {
- Error( "bitcount > 32" );
- }
- charbits[nodenum] = bits;
- charbitscount[nodenum] = bitcount;
- return;
- }
- node = &hnodes[nodenum];
- bits <<= 1;
- BuildChars( node->children[0], bits, bitcount + 1 );
- bits |= 1;
- BuildChars( node->children[1], bits, bitcount + 1 );
- }
- /*
- ==================
- Huffman
- ==================
- */
- cblock_t Huffman( cblock_t in ){
- int i;
- hnode_t *node;
- int outbits, c;
- unsigned bits;
- byte *out_p;
- cblock_t out;
- int max, maxchar;
- // count
- memset( hnodes, 0, sizeof( hnodes ) );
- for ( i = 0 ; i < in.count ; i++ )
- hnodes[in.data[i]].count++;
- // normalize counts
- max = 0;
- maxchar = 0;
- for ( i = 0 ; i < 256 ; i++ )
- {
- if ( hnodes[i].count > max ) {
- max = hnodes[i].count;
- maxchar = i;
- }
- }
- if ( max == 0 ) {
- Error( "Huffman: max == 0" );
- }
- for ( i = 0 ; i < 256 ; i++ )
- {
- hnodes[i].count = ( hnodes[i].count * 255 + max - 1 ) / max;
- }
- // build the nodes
- numhnodes = 256;
- while ( numhnodes != 511 )
- {
- node = &hnodes[numhnodes];
- // pick two lowest counts
- node->children[0] = SmallestNode();
- if ( node->children[0] == -1 ) {
- break; // no more
- }
- node->children[1] = SmallestNode();
- if ( node->children[1] == -1 ) {
- if ( node->children[0] != numhnodes - 1 ) {
- Error( "Bad smallestnode" );
- }
- break;
- }
- node->count = hnodes[node->children[0]].count +
- hnodes[node->children[1]].count;
- numhnodes++;
- }
- BuildChars( numhnodes - 1, 0, 0 );
- out_p = out.data = malloc( in.count * 2 + 1024 );
- memset( out_p, 0, in.count * 2 + 1024 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- // save out the 256 normalized counts so the tree can be recreated
- for ( i = 0 ; i < 256 ; i++ )
- *out_p++ = hnodes[i].count;
- // write bits
- outbits = 0;
- for ( i = 0 ; i < in.count ; i++ )
- {
- c = charbitscount[in.data[i]];
- bits = charbits[in.data[i]];
- while ( c )
- {
- c--;
- if ( bits & ( 1 << c ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- outbits++;
- }
- }
- out_p += ( outbits + 7 ) >> 3;
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- /*
- ==================
- RLE
- ==================
- */
- #define RLE_CODE 0xe8
- #define RLE_TRIPPLE 0xe9
- int rle_counts[256];
- int rle_bytes[256];
- cblock_t RLE( cblock_t in ){
- int i;
- byte *out_p;
- int val;
- int repeat;
- cblock_t out;
- out_p = out.data = malloc( in.count * 2 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- for ( i = 0 ; i < in.count ; )
- {
- val = in.data[i];
- rle_bytes[val]++;
- repeat = 1;
- i++;
- while ( i < in.count && repeat < 255 && in.data[i] == val )
- {
- repeat++;
- i++;
- }
- if ( repeat < 256 ) {
- rle_counts[repeat]++;
- }
- if ( repeat > 3 || val == RLE_CODE ) {
- *out_p++ = RLE_CODE;
- *out_p++ = val;
- *out_p++ = repeat;
- }
- else
- {
- while ( repeat-- )
- *out_p++ = val;
- }
- }
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- unsigned lzss_head[256];
- unsigned lzss_next[0x20000];
- /*
- ==================
- LZSS
- ==================
- */
- #define BACK_WINDOW 0x10000
- #define BACK_BITS 16
- #define FRONT_WINDOW 16
- #define FRONT_BITS 4
- cblock_t LZSS( cblock_t in ){
- int i;
- byte *out_p;
- cblock_t out;
- int val;
- int j, start, max;
- int bestlength, beststart;
- int outbits;
- if ( in.count >= sizeof( lzss_next ) / 4 ) {
- Error( "LZSS: too big" );
- }
- memset( lzss_head, -1, sizeof( lzss_head ) );
- out_p = out.data = malloc( in.count * 2 );
- memset( out.data, 0, in.count * 2 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- outbits = 0;
- for ( i = 0 ; i < in.count ; )
- {
- val = in.data[i];
- #if 1
- // chained search
- bestlength = 0;
- beststart = 0;
- max = FRONT_WINDOW;
- if ( i + max > in.count ) {
- max = in.count - i;
- }
- start = lzss_head[val];
- while ( start != -1 && start >= i - BACK_WINDOW )
- {
- // count match length
- for ( j = 0 ; j < max ; j++ )
- if ( in.data[start + j] != in.data[i + j] ) {
- break;
- }
- if ( j > bestlength ) {
- bestlength = j;
- beststart = start;
- }
- start = lzss_next[start];
- }
- #else
- // slow simple search
- // search for a match
- max = FRONT_WINDOW;
- if ( i + max > in.count ) {
- max = in.count - i;
- }
- start = i - BACK_WINDOW;
- if ( start < 0 ) {
- start = 0;
- }
- bestlength = 0;
- beststart = 0;
- for ( ; start < i ; start++ )
- {
- if ( in.data[start] != val ) {
- continue;
- }
- // count match length
- for ( j = 0 ; j < max ; j++ )
- if ( in.data[start + j] != in.data[i + j] ) {
- break;
- }
- if ( j > bestlength ) {
- bestlength = j;
- beststart = start;
- }
- }
- #endif
- beststart = BACK_WINDOW - ( i - beststart );
- if ( bestlength < 3 ) { // output a single char
- bestlength = 1;
- out_p[outbits >> 3] |= 1 << ( outbits & 7 ); // set bit to mark char
- outbits++;
- for ( j = 0 ; j < 8 ; j++, outbits++ )
- if ( val & ( 1 << j ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- }
- else
- { // output a phrase
- outbits++; // leave a 0 bit to mark phrase
- for ( j = 0 ; j < BACK_BITS ; j++, outbits++ )
- if ( beststart & ( 1 << j ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- for ( j = 0 ; j < FRONT_BITS ; j++, outbits++ )
- if ( bestlength & ( 1 << j ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- }
- while ( bestlength-- )
- {
- val = in.data[i];
- lzss_next[i] = lzss_head[val];
- lzss_head[val] = i;
- i++;
- }
- }
- out_p += ( outbits + 7 ) >> 3;
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- #define MIN_REPT 15
- #define MAX_REPT 0
- #define HUF_TOKENS ( 256 + MAX_REPT )
- unsigned charbits1[256][HUF_TOKENS];
- int charbitscount1[256][HUF_TOKENS];
- hnode_t hnodes1[256][HUF_TOKENS * 2];
- int numhnodes1[256];
- int order0counts[256];
- /*
- ==================
- SmallestNode1
- ==================
- */
- int SmallestNode1( hnode_t *hnodes, int numhnodes ){
- int i;
- int best, bestnode;
- best = 99999999;
- bestnode = -1;
- for ( i = 0 ; i < numhnodes ; i++ )
- {
- if ( hnodes[i].used ) {
- continue;
- }
- if ( !hnodes[i].count ) {
- continue;
- }
- if ( hnodes[i].count < best ) {
- best = hnodes[i].count;
- bestnode = i;
- }
- }
- if ( bestnode == -1 ) {
- return -1;
- }
- hnodes[bestnode].used = true;
- return bestnode;
- }
- /*
- ==================
- BuildChars1
- ==================
- */
- void BuildChars1( int prev, int nodenum, unsigned bits, int bitcount ){
- hnode_t *node;
- if ( nodenum < HUF_TOKENS ) {
- if ( bitcount > 32 ) {
- Error( "bitcount > 32" );
- }
- charbits1[prev][nodenum] = bits;
- charbitscount1[prev][nodenum] = bitcount;
- return;
- }
- node = &hnodes1[prev][nodenum];
- bits <<= 1;
- BuildChars1( prev, node->children[0], bits, bitcount + 1 );
- bits |= 1;
- BuildChars1( prev, node->children[1], bits, bitcount + 1 );
- }
- /*
- ==================
- BuildTree1
- ==================
- */
- void BuildTree1( int prev ){
- hnode_t *node, *nodebase;
- int numhnodes;
- // build the nodes
- numhnodes = HUF_TOKENS;
- nodebase = hnodes1[prev];
- while ( 1 )
- {
- node = &nodebase[numhnodes];
- // pick two lowest counts
- node->children[0] = SmallestNode1( nodebase, numhnodes );
- if ( node->children[0] == -1 ) {
- break; // no more
- }
- node->children[1] = SmallestNode1( nodebase, numhnodes );
- if ( node->children[1] == -1 ) {
- break;
- }
- node->count = nodebase[node->children[0]].count +
- nodebase[node->children[1]].count;
- numhnodes++;
- }
- numhnodes1[prev] = numhnodes - 1;
- BuildChars1( prev, numhnodes - 1, 0, 0 );
- }
- /*
- ==================
- Huffman1_Count
- ==================
- */
- void Huffman1_Count( cblock_t in ){
- int i;
- int prev;
- int v;
- int rept;
- prev = 0;
- for ( i = 0 ; i < in.count ; i++ )
- {
- v = in.data[i];
- order0counts[v]++;
- hnodes1[prev][v].count++;
- prev = v;
- #if 1
- for ( rept = 1 ; i + rept < in.count && rept < MAX_REPT ; rept++ )
- if ( in.data[i + rept] != v ) {
- break;
- }
- if ( rept > MIN_REPT ) {
- hnodes1[prev][255 + rept].count++;
- i += rept - 1;
- }
- #endif
- }
- }
- /*
- ==================
- Huffman1_Build
- ==================
- */
- byte scaled[256][HUF_TOKENS];
- void Huffman1_Build( FILE *f ){
- int i, j, v;
- int max;
- int total;
- for ( i = 0 ; i < 256 ; i++ )
- {
- // normalize and save the counts
- max = 0;
- for ( j = 0 ; j < HUF_TOKENS ; j++ )
- {
- if ( hnodes1[i][j].count > max ) {
- max = hnodes1[i][j].count;
- }
- }
- if ( max == 0 ) {
- max = 1;
- }
- total = 0;
- for ( j = 0 ; j < HUF_TOKENS ; j++ )
- { // easy to overflow 32 bits here!
- v = ( hnodes1[i][j].count * (double)255 + max - 1 ) / max;
- if ( v > 255 ) {
- Error( "v > 255" );
- }
- scaled[i][j] = hnodes1[i][j].count = v;
- if ( v ) {
- total++;
- }
- }
- if ( total == 1 ) { // must have two tokens
- if ( !scaled[i][0] ) {
- scaled[i][0] = hnodes1[i][0].count = 1;
- }
- else{
- scaled[i][1] = hnodes1[i][1].count = 1;
- }
- }
- BuildTree1( i );
- }
- #if 0
- // count up the total bits
- total = 0;
- for ( i = 0 ; i < 256 ; i++ )
- for ( j = 0 ; j < 256 ; j++ )
- total += charbitscount1[i][j] * hnodes1[i][j].count;
- total = ( total + 7 ) / 8;
- printf( "%i bytes huffman1 compressed\n", total );
- #endif
- fwrite( scaled, 1, sizeof( scaled ), f );
- }
- /*
- ==================
- Huffman1
- Order 1 compression with pre-built table
- ==================
- */
- cblock_t Huffman1( cblock_t in ){
- int i;
- int outbits, c;
- unsigned bits;
- byte *out_p;
- cblock_t out;
- int prev;
- int v;
- int rept;
- out_p = out.data = malloc( in.count * 2 + 1024 );
- memset( out_p, 0, in.count * 2 + 1024 );
- // write count
- *out_p++ = in.count & 255;
- *out_p++ = ( in.count >> 8 ) & 255;
- *out_p++ = ( in.count >> 16 ) & 255;
- *out_p++ = ( in.count >> 24 ) & 255;
- // write bits
- outbits = 0;
- prev = 0;
- for ( i = 0 ; i < in.count ; i++ )
- {
- v = in.data[i];
- c = charbitscount1[prev][v];
- bits = charbits1[prev][v];
- if ( !c ) {
- Error( "!bits" );
- }
- while ( c )
- {
- c--;
- if ( bits & ( 1 << c ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- outbits++;
- }
- prev = v;
- #if 1
- // check for repeat encodes
- for ( rept = 1 ; i + rept < in.count && rept < MAX_REPT ; rept++ )
- if ( in.data[i + rept] != v ) {
- break;
- }
- if ( rept > MIN_REPT ) {
- c = charbitscount1[prev][255 + rept];
- bits = charbits1[prev][255 + rept];
- if ( !c ) {
- Error( "!bits" );
- }
- while ( c )
- {
- c--;
- if ( bits & ( 1 << c ) ) {
- out_p[outbits >> 3] |= 1 << ( outbits & 7 );
- }
- outbits++;
- }
- i += rept - 1;
- }
- #endif
- }
- out_p += ( outbits + 7 ) >> 3;
- out.count = out_p - out.data;
- return out;
- }
- //==========================================================================
- /*
- ===================
- LoadFrame
- ===================
- */
- cblock_t LoadFrame( char *base, int frame, int digits, byte **palette ){
- int ten3, ten2, ten1, ten0;
- cblock_t in;
- int width, height;
- char name[1024];
- FILE *f;
- in.data = NULL;
- in.count = -1;
- ten3 = frame / 1000;
- ten2 = ( frame - ten3 * 1000 ) / 100;
- ten1 = ( frame - ten3 * 1000 - ten2 * 100 ) / 10;
- ten0 = frame % 10;
- if ( digits == 4 ) {
- sprintf( name, "%svideo/%s/%s%i%i%i%i.pcx", gamedir, base, base, ten3, ten2, ten1, ten0 );
- }
- else{
- sprintf( name, "%svideo/%s/%s%i%i%i.pcx", gamedir, base, base, ten2, ten1, ten0 );
- }
- f = fopen( name, "rb" );
- if ( !f ) {
- in.data = NULL;
- return in;
- }
- fclose( f );
- printf( "%s\n", name );
- Load256Image( name, &in.data, palette, &width, &height );
- in.count = width * height;
- // FIXME: map 0 and 255!
- #if 0
- // rle compress
- rle = RLE( in );
- free( in.data );
- return rle;
- #endif
- return in;
- }
- /*
- ===============
- Cmd_Video
- video <directory> <framedigits>
- ===============
- */
- void Cmd_Video( void ){
- char savename[1024];
- char name[1024];
- FILE *output;
- int startframe, frame;
- byte *palette;
- int width, height;
- byte current_palette[768];
- int command;
- int i;
- int digits;
- cblock_t in, huffman;
- int swap;
- GetToken( false );
- strcpy( base, token );
- if ( g_release ) {
- // sprintf (savename, "video/%s.cin", token);
- // ReleaseFile (savename);
- return;
- }
- GetToken( false );
- digits = atoi( token );
- // optionally skip frames
- if ( TokenAvailable() ) {
- GetToken( false );
- startframe = atoi( token );
- }
- else{
- startframe = 0;
- }
- sprintf( savename, "%svideo/%s.cin", gamedir, base );
- // clear stuff
- memset( charbits1, 0, sizeof( charbits1 ) );
- memset( charbitscount1, 0, sizeof( charbitscount1 ) );
- memset( hnodes1, 0, sizeof( hnodes1 ) );
- memset( numhnodes1, 0, sizeof( numhnodes1 ) );
- memset( order0counts, 0, sizeof( order0counts ) );
- // load the entire sound wav file if present
- LoadSoundtrack();
- if ( digits == 4 ) {
- sprintf( name, "%svideo/%s/%s0000.pcx", gamedir, base, base );
- }
- else{
- sprintf( name, "%svideo/%s/%s000.pcx", gamedir, base, base );
- }
- printf( "%s\n", name );
- Load256Image( name, NULL, &palette, &width, &height );
- output = fopen( savename, "wb" );
- if ( !output ) {
- Error( "Can't open %s", savename );
- }
- // write header info
- i = LittleLong( width );
- fwrite( &i, 4, 1, output );
- i = LittleLong( height );
- fwrite( &i, 4, 1, output );
- i = LittleLong( wavinfo.rate );
- fwrite( &i, 4, 1, output );
- i = LittleLong( wavinfo.width );
- fwrite( &i, 4, 1, output );
- i = LittleLong( wavinfo.channels );
- fwrite( &i, 4, 1, output );
- // build the dictionary
- for ( frame = startframe ; ; frame++ )
- {
- printf( "counting ", frame );
- in = LoadFrame( base, frame, digits, &palette );
- if ( !in.data ) {
- break;
- }
- Huffman1_Count( in );
- free( in.data );
- }
- printf( "\n" );
- // build nodes and write counts
- Huffman1_Build( output );
- memset( current_palette, 0, sizeof( current_palette ) );
- // compress it with the dictionary
- for ( frame = startframe ; ; frame++ )
- {
- printf( "packing ", frame );
- in = LoadFrame( base, frame, digits, &palette );
- if ( !in.data ) {
- break;
- }
- // see if the palette has changed
- for ( i = 0 ; i < 768 ; i++ )
- if ( palette[i] != current_palette[i] ) {
- // write a palette change
- memcpy( current_palette, palette, sizeof( current_palette ) );
- command = LittleLong( 1 );
- fwrite( &command, 1, 4, output );
- fwrite( current_palette, 1, sizeof( current_palette ), output );
- break;
- }
- if ( i == 768 ) {
- command = 0; // no palette change
- fwrite( &command, 1, 4, output );
- }
- // save the image
- huffman = Huffman1( in );
- printf( "%5i bytes after huffman1\n", huffman.count );
- swap = LittleLong( huffman.count );
- fwrite( &swap, 1, sizeof( swap ), output );
- fwrite( huffman.data, 1, huffman.count, output );
- // save some sound samples
- WriteSound( output, frame );
- free( palette );
- free( in.data );
- free( huffman.data );
- }
- printf( "\n" );
- // write end-of-file command
- command = 2;
- fwrite( &command, 1, 4, output );
- printf( "Total size: %i\n", ftell( output ) );
- fclose( output );
- if ( soundtrack ) {
- free( soundtrack );
- }
- }