2007-11-04 03:34:51 +00:00
/*
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
*/
// To do
// Sound error handling (when sound too short)
// rle b4 huffing
// adpcm encoding of sound
#if 0
# include "qdata.h"
# include "flex.h"
# include "fc.h"
# include "adpcm.h"
# define MIN_REPT 15
# define MAX_REPT 0
# define HUF_TOKENS (256 + MAX_REPT)
# define BLOCKSIZE 8
# define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
# define SQRT2 1.414213562
typedef struct hnode_s
{
int count ;
qboolean used ;
int children [ 2 ] ;
} hnode_t ;
typedef struct
{
int rate ;
int width ;
int channels ;
int loopstart ;
int samples ;
int dataofs ; // chunk starts this many bytes from file start
} wavinfo_t ;
// These weren`t picked out my ass....
// They were defined at http://www.rahul.net/jfm/dct.html
// However, I think he plucked them out of his ass.....
float Quantise [ BLOCKSIZE * BLOCKSIZE ] ;
float LUT_Quantise [ BLOCKSIZE * BLOCKSIZE ] =
{
16.0F / 16.0F , 11.0F / 16.0F , 10.0F / 16.0F , 16.0F / 16.0F , 24.0F / 16.0F , 40.0F / 16.0F , 51.0F / 16.0F , 61.0F / 16.0F ,
12.0F / 16.0F , 13.0F / 16.0F , 14.0F / 16.0F , 19.0F / 16.0F , 26.0F / 16.0F , 58.0F / 16.0F , 60.0F / 16.0F , 55.0F / 16.0F ,
14.0F / 16.0F , 13.0F / 16.0F , 16.0F / 16.0F , 24.0F / 16.0F , 40.0F / 16.0F , 57.0F / 16.0F , 69.0F / 16.0F , 56.0F / 16.0F ,
14.0F / 16.0F , 17.0F / 16.0F , 22.0F / 16.0F , 29.0F / 16.0F , 51.0F / 16.0F , 87.0F / 16.0F , 80.0F / 16.0F , 62.0F / 16.0F ,
18.0F / 16.0F , 22.0F / 16.0F , 37.0F / 16.0F , 56.0F / 16.0F , 68.0F / 16.0F , 109.0F / 16.0F , 103.0F / 16.0F , 77.0F / 16.0F ,
24.0F / 16.0F , 35.0F / 16.0F , 55.0F / 16.0F , 64.0F / 16.0F , 81.0F / 16.0F , 104.0F / 16.0F , 113.0F / 16.0F , 92.0F / 16.0F ,
49.0F / 16.0F , 64.0F / 16.0F , 78.0F / 16.0F , 87.0F / 16.0F , 103.0F / 16.0F , 121.0F / 16.0F , 120.0F / 16.0F , 101.0F / 16.0F ,
72.0F / 16.0F , 92.0F / 16.0F , 95.0F / 16.0F , 98.0F / 16.0F , 112.0F / 16.0F , 100.0F / 16.0F , 103.0F / 16.0F , 99.0F / 16.0F
} ;
int LUT_ZZ [ BLOCKSIZE * BLOCKSIZE ] =
{
0 ,
1 , 8 ,
16 , 9 , 2 ,
3 , 10 , 17 , 24 ,
32 , 25 , 18 , 11 , 4 ,
5 , 12 , 19 , 26 , 33 , 40 ,
48 , 41 , 34 , 27 , 20 , 13 , 6 ,
7 , 14 , 21 , 28 , 35 , 42 , 49 , 56 ,
57 , 50 , 43 , 36 , 29 , 22 , 15 ,
23 , 30 , 37 , 44 , 51 , 58 ,
59 , 52 , 45 , 38 , 31 ,
39 , 46 , 53 , 60 ,
61 , 54 , 47 ,
55 , 62 ,
63
} ;
char base [ 32 ] ;
byte * soundtrack ;
byte scaled [ 256 ] [ HUF_TOKENS ] ;
unsigned int charbits1 [ 256 ] [ HUF_TOKENS ] ;
int charbitscount1 [ 256 ] [ HUF_TOKENS ] ;
hnode_t hnodes1 [ 256 ] [ HUF_TOKENS * 2 ] ;
int numhnodes1 [ 256 ] ;
int order0counts [ 256 ] ;
int numhnodes ;
hnode_t hnodes [ 512 ] ;
unsigned charbits [ 256 ] ;
int charbitscount [ 256 ] ;
CineHead_t cinehead ;
byte * data_p ;
byte * iff_end ;
byte * last_chunk ;
byte * iff_data ;
int iff_chunk_len ;
float dctbase [ BLOCKSIZE ] [ BLOCKSIZE ] ;
float red [ BLOCKSIZE * BLOCKSIZE ] ;
float green [ BLOCKSIZE * BLOCKSIZE ] ;
float blue [ BLOCKSIZE * BLOCKSIZE ] ;
float temp [ BLOCKSIZE * BLOCKSIZE ] ;
wavinfo_t wavinfo ;
adpcm_t adpcm ;
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
WAV loading
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/* Intel ADPCM step variation table */
static int indexTable [ 16 ] =
{
- 1 , - 1 , - 1 , - 1 , 2 , 4 , 6 , 8 ,
- 1 , - 1 , - 1 , - 1 , 2 , 4 , 6 , 8 ,
} ;
static int stepsizeTable [ 89 ] =
{
7 , 8 , 9 , 10 , 11 , 12 , 13 , 14 , 16 , 17 ,
19 , 21 , 23 , 25 , 28 , 31 , 34 , 37 , 41 , 45 ,
50 , 55 , 60 , 66 , 73 , 80 , 88 , 97 , 107 , 118 ,
130 , 143 , 157 , 173 , 190 , 209 , 230 , 253 , 279 , 307 ,
337 , 371 , 408 , 449 , 494 , 544 , 598 , 658 , 724 , 796 ,
876 , 963 , 1060 , 1166 , 1282 , 1411 , 1552 , 1707 , 1878 , 2066 ,
2272 , 2499 , 2749 , 3024 , 3327 , 3660 , 4026 , 4428 , 4871 , 5358 ,
5894 , 6484 , 7132 , 7845 , 8630 , 9493 , 10442 , 11487 , 12635 , 13899 ,
15289 , 16818 , 18500 , 20350 , 22385 , 24623 , 27086 , 29794 , 32767
} ;
#if 0
static void adpcm_decoder ( char * indata , short * outdata , int len , adpcm_state_t * state )
{
signed char * inp ; /* Input buffer pointer */
short * outp ; /* output buffer pointer */
int sign ; /* Current adpcm sign bit */
int delta ; /* Current adpcm output value */
int step ; /* Stepsize */
int valpred ; /* Predicted value */
int vpdiff ; /* Current change to valpred */
int index ; /* Current step change index */
int inputbuffer ; /* place to keep next 4-bit value */
int bufferstep ; /* toggle between inputbuffer/input */
outp = outdata ;
inp = ( signed char * ) indata ;
valpred = state - > valprev ;
index = state - > index ;
step = stepsizeTable [ index ] ;
bufferstep = 0 ;
for ( ; len > 0 ; len - - )
{
/* Step 1 - get the delta value */
if ( bufferstep )
delta = inputbuffer & 0xf ;
else
{
inputbuffer = * inp + + ;
delta = ( inputbuffer > > 4 ) & 0xf ;
}
bufferstep = ! bufferstep ;
/* Step 2 - Find new index value (for later) */
index + = indexTable [ delta ] ;
if ( index < 0 )
index = 0 ;
if ( index > 88 )
index = 88 ;
/* Step 3 - Separate sign and magnitude */
sign = delta & 8 ;
delta = delta & 7 ;
/* Step 4 - Compute difference and new predicted value */
/*
* * Computes ' vpdiff = ( delta + 0.5 ) * step / 4 ' , but see comment
* * in adpcm_coder .
*/
vpdiff = step > > 3 ;
if ( delta & 4 )
vpdiff + = step ;
if ( delta & 2 )
vpdiff + = step > > 1 ;
if ( delta & 1 )
vpdiff + = step > > 2 ;
if ( sign )
valpred - = vpdiff ;
else
valpred + = vpdiff ;
/* Step 5 - clamp output value */
if ( valpred > 32767 )
valpred = 32767 ;
else if ( valpred < - 32768 )
valpred = - 32768 ;
/* Step 6 - Update step value */
step = stepsizeTable [ index ] ;
/* Step 7 - Output value */
* outp + + = valpred ;
}
state - > valprev = valpred ;
state - > index = index ;
}
# endif
void adpcm_coder ( short * inp , adpcm_t * adpcm )
{
int val ; /* Current input sample value */
int sign ; /* Current adpcm sign bit */
int delta ; /* Current adpcm output value */
int diff ; /* Difference between val and valprev */
int step ; /* Stepsize */
int valpred ; /* Predicted output value */
int vpdiff ; /* Current change to valpred */
int index ; /* Current step change index */
int outputbuffer ; /* place to keep previous 4-bit value */
int bufferstep ; /* toggle between outputbuffer/output */
adpcm_state_t * state ;
char * outp ;
int len ;
state = & adpcm - > state ;
len = state - > count ;
outp = adpcm - > adpcm ;
valpred = state - > in_valprev ;
index = state - > in_index ;
step = stepsizeTable [ index ] ;
bufferstep = 1 ;
while ( len - - )
{
val = * inp + + ;
/* Step 1 - compute difference with previous value */
diff = val - valpred ;
sign = ( diff < 0 ) ? 8 : 0 ;
if ( sign )
diff = - diff ;
/* Step 2 - Divide and clamp */
/* Note:
* * This code * approximately * computes :
* * delta = diff * 4 / step ;
* * vpdiff = ( delta + 0.5 ) * step / 4 ;
* * but in shift step bits are dropped . The net result of this is
* * that even if you have fast mul / div hardware you cannot put it to
* * good use since the fixup would be too expensive .
*/
delta = 0 ;
vpdiff = ( step > > 3 ) ;
if ( diff > = step )
{
delta = 4 ;
diff - = step ;
vpdiff + = step ;
}
step > > = 1 ;
if ( diff > = step )
{
delta | = 2 ;
diff - = step ;
vpdiff + = step ;
}
step > > = 1 ;
if ( diff > = step )
{
delta | = 1 ;
vpdiff + = step ;
}
/* Step 3 - Update previous value */
if ( sign )
valpred - = vpdiff ;
else
valpred + = vpdiff ;
/* Step 4 - Clamp previous value to 16 bits */
if ( valpred > 32767 )
valpred = 32767 ;
else if ( valpred < - 32768 )
valpred = - 32768 ;
/* Step 5 - Assemble value, update index and step values */
delta | = sign ;
index + = indexTable [ delta ] ;
if ( index < 0 )
index = 0 ;
if ( index > 88 )
index = 88 ;
step = stepsizeTable [ index ] ;
/* Step 6 - Output value */
if ( bufferstep )
outputbuffer = ( delta < < 4 ) & 0xf0 ;
else
* outp + + = ( delta & 0x0f ) | outputbuffer ;
bufferstep = ! bufferstep ;
}
/* Output last step, if needed */
if ( ! bufferstep )
* outp + + = outputbuffer ;
state - > out_valprev = valpred ;
state - > out_index = index ;
}
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 = * ( long * ) data_p ;
data_p + = 4 ;
if ( iff_chunk_len < 0 )
{
data_p = NULL ;
return ;
}
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 = * ( long * ) data_p ;
data_p + = 4 ;
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 ;
FindChunk ( " fmt " ) ;
if ( ! data_p )
{
printf ( " Missing fmt chunk \n " ) ;
return ( info ) ;
}
data_p + = 8 ;
format = * ( short * ) data_p ;
data_p + = 2 ;
if ( format ! = 1 )
{
printf ( " Microsoft PCM format only \n " ) ;
return ( info ) ;
}
info . channels = * ( short * ) data_p ;
data_p + = 2 ;
info . rate = * ( long * ) data_p ;
data_p + = 4 ;
data_p + = 6 ;
info . width = * ( short * ) data_p / 8 ;
data_p + = 2 ;
// get cue chunk
FindChunk ( " cue " ) ;
if ( data_p )
{
data_p + = 32 ;
info . loopstart = * ( long * ) data_p ;
data_p + = 4 ;
// if the next chunk is a LIST chunk, look for a cue length marker
FindNextChunk ( " LIST " ) ;
if ( data_p )
{
// this is not a proper parse, but it works with cooledit...
if ( ! strncmp ( data_p + 28 , " mark " , 4 ) )
{
data_p + = 24 ;
i = * ( long * ) data_p ; // samples in loop
data_p + = 4 ;
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 = * ( long * ) data_p ;
data_p + = 4 ;
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 ( )
{
char name [ 1024 ] ;
FILE * f ;
int len ;
soundtrack = NULL ;
sprintf ( name , " %svideo/%s/%s.wav " , gamedir , base , base ) ;
printf ( " \n Loading sound : %s \n " , name ) ;
f = fopen ( name , " rb " ) ;
if ( ! f )
{
printf ( " \n No soundtrack for %s \n " , base ) ;
return ;
}
len = Q_filelength ( f ) ;
soundtrack = SafeMalloc ( len , " LoadSoundtrack " ) ;
fread ( soundtrack , 1 , len , f ) ;
fclose ( f ) ;
wavinfo = GetWavinfo ( name , soundtrack , len ) ;
adpcm . state . out_valprev = 0 ;
adpcm . state . out_index = 0 ;
}
// ==================
// WriteSound
// ==================
int WriteSound ( FILE * output , int frame , int numframes )
{
int start , end ;
int count ;
int empty = 0 ;
int width ;
char * work ;
width = wavinfo . width * wavinfo . channels ;
start = ( ( frame * wavinfo . rate / 14 ) + 31 ) & 0xffffffe0 ; // start sample
end = ( ( ( frame + numframes ) * wavinfo . rate / 14 ) + 31 ) & 0xffffffe0 ; // end sample
count = end - start ;
work = soundtrack + wavinfo . dataofs + ( start * width ) ;
adpcm . state . count = count * wavinfo . channels ; // Number of samples
adpcm . state . in_valprev = adpcm . state . out_valprev ;
adpcm . state . in_index = adpcm . state . out_index ;
adpcm_coder ( ( short * ) work , & adpcm ) ;
WriteHeader ( output , FC_SOUND_22KMADPCM , FC_ADPCM_VERSION , ( adpcm . state . count / 2 ) + sizeof ( adpcm_state_t ) , ( char * ) & adpcm ) ;
return ( count / 2 ) ;
}
// ==============================
// Basic run length encoder
// ==============================
char * RLEZZ ( char * in , char * out )
{
int srun ;
char count ;
int idx = 0 ;
while ( idx < 64 )
{
srun = idx ; // Start of run
while ( idx < 63 )
{
if ( in [ LUT_ZZ [ idx ] ] ! = in [ LUT_ZZ [ idx + 1 ] ] )
break ;
idx + + ;
}
count = ( char ) ( idx - srun ) ; // count of repeated bytes
if ( ! count )
{
while ( idx < 63 )
{
if ( in [ LUT_ZZ [ idx ] ] = = in [ LUT_ZZ [ idx + 1 ] ] )
break ;
idx + + ;
}
if ( idx = = 63 )
idx + + ;
count = ( char ) ( idx - srun ) ; // count of unique bytes
* out + + = count ;
while ( count - - )
* out + + = in [ LUT_ZZ [ srun + + ] ] ;
}
else
{
* out + + = - ( count + 1 ) ;
* out + + = in [ LUT_ZZ [ idx ] ] ;
idx + + ;
}
}
return ( out ) ;
}
// ==============================
// Discrete Cosine Transformation
// ==============================
void init_base ( float quant )
{
int y , x ;
for ( y = 0 ; y < BLOCKSIZE ; y + + )
for ( x = 0 ; x < BLOCKSIZE ; x + + )
{
if ( y = = 0 )
dctbase [ y ] [ x ] = 1 ;
else
dctbase [ y ] [ x ] = SQRT2 * cos ( ( ( x * 2 + 1 ) * y * M_PI ) / ( BLOCKSIZE * 2 ) ) ;
}
for ( y = 0 ; y < BLOCKSIZE * BLOCKSIZE ; y + + )
Quantise [ y ] = LUT_Quantise [ y ] / quant ;
}
void SplitComponents ( byte * src , int width , int height )
{
int i , j ;
float * tr = red ;
float * tg = green ;
float * tb = blue ;
for ( i = 0 ; i < BLOCKSIZE ; i + + , src + = ( width - BLOCKSIZE ) * 4 )
for ( j = 0 ; j < BLOCKSIZE ; j + + )
{
* tr + + = ( ( float ) * src + + ) - 128.0F ;
* tg + + = ( ( float ) * src + + ) - 128.0F ;
* tb + + = ( ( float ) * src + + ) - 128.0F ;
src + + ;
}
}
void transferH ( float * src , float * dst )
{
int y , dx , dy ;
float sum ;
float * work ;
for ( y = 0 ; y < BLOCKSIZE ; y + + , src + = BLOCKSIZE )
{
for ( dy = 0 ; dy < BLOCKSIZE ; dy + + )
{
sum = 0 ;
work = src ;
for ( dx = 0 ; dx < BLOCKSIZE ; dx + + , work + + )
sum + = dctbase [ dy ] [ dx ] * * work ;
* dst + + = sum / BLOCKSIZE ;
}
}
}
void transferV ( float * src , float * dst )
{
int x , dy , fy ;
float sum ;
float * work ;
for ( x = 0 ; x < BLOCKSIZE ; x + + , src + + , dst + + )
{
for ( fy = 0 ; fy < BLOCKSIZE ; fy + + )
{
sum = 0 ;
work = src ;
for ( dy = 0 ; dy < BLOCKSIZE ; dy + + , work + = BLOCKSIZE )
sum + = dctbase [ fy ] [ dy ] * * work ;
dst [ fy * BLOCKSIZE ] = sum / BLOCKSIZE ;
}
}
}
char * Combine ( byte * dst , float * p , float * q )
{
int i , j ;
byte rlesrc [ BLOCKSIZE * BLOCKSIZE ] ;
int c ;
byte * work ;
work = rlesrc ;
for ( j = 0 ; j < BLOCKSIZE ; j + + )
for ( i = 0 ; i < BLOCKSIZE ; i + + )
{
c = ( int ) ( ( * p + + / * q + + ) + 128.5F ) ;
c - = 128 ;
if ( c < - 128 )
c = - 128 ;
if ( c > 127 )
c = 127 ;
* work + + = ( char ) c ;
}
dst = RLEZZ ( rlesrc , dst ) ;
return ( dst ) ;
}
char * CombineComponents ( char * dst , int width , int height )
{
dst = Combine ( dst , red , Quantise ) ;
dst = Combine ( dst , green , Quantise ) ;
dst = Combine ( dst , blue , Quantise ) ;
return ( dst ) ;
}
void DCT ( cblock_t * out , cblock_t in , int width , int height )
{
int x , y ;
char * cursrc ;
char * curdst ;
curdst = out - > data ;
for ( y = 0 ; y < height ; y + = BLOCKSIZE )
for ( x = 0 ; x < width ; x + = BLOCKSIZE )
{
cursrc = in . data + ( ( y * width ) + x ) * 4 ;
SplitComponents ( cursrc , width , height ) ;
transferH ( red , temp ) ;
transferV ( temp , red ) ;
transferH ( green , temp ) ;
transferV ( temp , green ) ;
transferH ( blue , temp ) ;
transferV ( temp , blue ) ;
curdst = CombineComponents ( curdst , width , height ) ;
}
out - > count = curdst - out - > data ;
}
// ==================
// 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 ) ;
}
// ==================
// 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 ) ;
}
// ==================
// 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 ;
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 ;
}
}
}
// ==================
// Huffman1_Build
// ==================
void Huffman1_Build ( )
{
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 ;
// easy to overflow 32 bits here!
for ( j = 0 ; j < HUF_TOKENS ; j + + )
{
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 ) ;
}
}
// ==================
// 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 = SafeMalloc ( ( in . count * 2 ) + 1024 + 4 , " Huffman " ) ;
memset ( out_p , 0 , ( in . count * 2 ) + 1024 + 4 ) ;
// leave space for compressed count
out_p + = 4 ;
// write count
* ( long * ) out_p = in . count ;
out_p + = 4 ;
// 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 ;
// 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 ;
}
}
out_p + = ( outbits + 7 ) > > 3 ;
out . count = out_p - out . data ;
out_p = out . data ;
* ( long * ) out_p = out . count ;
return ( out ) ;
}
// ===================
// LoadFrame
// ===================
void LoadFrame ( cblock_t * out , char * base , int frame )
{
cblock_t in ;
int width , height ;
char name [ 1024 ] ;
FILE * f ;
in . data = NULL ;
in . count = - 1 ;
sprintf ( name , " %svideo/%s/%s%04i.tga " , gamedir , base , base , frame ) ;
f = fopen ( name , " rb " ) ;
if ( ! f )
{
out - > data = NULL ;
return ;
}
fclose ( f ) ;
LoadTGA ( name , & in . data , & width , & height ) ;
if ( ( width ! = cinehead . Width ) | | ( height ! = cinehead . Height ) )
{
free ( in . data ) ;
printf ( " Invalid picture size \n " ) ;
out - > data = NULL ;
return ;
}
out - > data = SafeMalloc ( width * height * 3 , " LoadFrame " ) ; // rle could possibly expand file so this not 100% safe (however DCT should force a lot of compression)
DCT ( out , in , width , height ) ;
free ( in . data ) ;
}
// ==================================
// Cmd_Video
//
// video <directory> <framedigits>
// ==================================
void Cmd_Video ( )
{
char savename [ 256 ] ;
char name [ 256 ] ;
FILE * output ;
int frame ;
int width , height ;
cblock_t in , huffman ;
int size ;
float dctconst ;
int maxsize , ssize ;
int min_rle_size , warnings ;
int ave_image , ave_sound ;
GetScriptToken ( false ) ;
strcpy ( base , token ) ;
if ( g_release )
return ;
GetScriptToken ( false ) ;
dctconst = atof ( token ) ;
GetScriptToken ( false ) ;
maxsize = atoi ( token ) ;
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 ( ) ;
cinehead . SndRate = wavinfo . rate ;
cinehead . SndWidth = wavinfo . width ;
cinehead . SndChannels = wavinfo . channels ;
sprintf ( name , " %svideo/%s/%s0000.tga " , gamedir , base , base ) ;
printf ( " Loading sequence : %s \n " , name ) ;
printf ( " DCT constant : %f \n " , dctconst ) ;
LoadTGA ( name , NULL , & width , & height ) ;
output = fopen ( savename , " wb " ) ;
if ( ! output )
Error ( " Can't open %s " , savename ) ;
if ( ( width % BLOCKSIZE ) | | ( height % BLOCKSIZE ) )
Error ( " Width and height must be a multiple of %d " , BLOCKSIZE ) ;
cinehead . Width = width ;
cinehead . Height = height ;
init_base ( dctconst ) ;
// build the dictionary
printf ( " Counting : " ) ;
min_rle_size = 0 ;
for ( frame = 0 ; ; frame + + )
{
printf ( " . " ) ;
LoadFrame ( & in , base , frame ) ;
if ( ! in . data )
break ;
Huffman1_Count ( in ) ;
if ( in . count > min_rle_size )
min_rle_size = in . count ;
free ( in . data ) ;
}
printf ( " \n " ) ;
cinehead . NumFrames = frame ;
printf ( " Num Frames : %d \n " , frame ) ;
cinehead . MaxRleSize = ( min_rle_size + 0x1f ) & 0xfffffe0 ;
cinehead . MaxSndSize = ( ( 4 * wavinfo . rate * wavinfo . channels / 14 ) + 0x1f ) & 0xffffffe0 ;
WriteHeader ( output , FC_HEADER_NAME , FC_HEADER_VERSION , sizeof ( CineHead_t ) , & cinehead ) ;
// build nodes and write counts
Huffman1_Build ( ) ;
WriteHeader ( output , FC_HUFFBITS_NAME , FC_HUFFBITS_VERSION , sizeof ( scaled ) , scaled ) ;
WriteHeader ( output , FC_QUANT_NAME , FC_QUANT_VERSION , sizeof ( Quantise ) , Quantise ) ;
ave_image = 0 ;
ave_sound = 0 ;
warnings = 0 ;
// compress it with the dictionary
if ( soundtrack )
{
ssize = WriteSound ( output , frame , 4 ) ;
ave_sound + = ssize ;
}
for ( frame = 0 ; frame < cinehead . NumFrames ; frame + + )
{
// save some sound samples
printf ( " Packing : " , frame ) ;
LoadFrame ( & in , base , frame ) ;
// save the image
huffman = Huffman1 ( in ) ;
printf ( " %d bytes rle, %d bytes huffman " , in . count , huffman . count ) ;
size = ( huffman . count + 3 ) & 0xfffffffc ; // round up to longwords
if ( size > maxsize )
{
printf ( " ** WARNING ** " ) ;
warnings + + ;
}
printf ( " \n " ) ;
ave_image + = huffman . count ;
WriteHeader ( output , FC_IMAGE_NAME , FC_IMAGE_VERSION , size , huffman . data ) ;
if ( soundtrack )
{
ssize = WriteSound ( output , frame + 4 , 1 ) ;
ave_sound + = ssize ;
}
free ( in . data ) ;
free ( huffman . data ) ;
}
printf ( " \n Total size: %d (headers + %d image + %d sound) \n " , ftell ( output ) , ave_image , ave_sound ) ;
printf ( " Data rate : %d bytes per sec (image and sound) \n " , ( ave_image + ave_sound ) / cinehead . NumFrames ) ;
printf ( " Cin created ok with %d warnings. \n " , warnings ) ;
fclose ( output ) ;
if ( soundtrack )
free ( soundtrack ) ;
}
# endif
void Cmd_Video ( )
{
}
// end