2007-11-04 03:34:51 +00:00
/*
2012-03-17 20:01:54 +00:00
Copyright ( C ) 1999 - 2007 id Software , Inc . and contributors .
For a list of contributors , see the accompanying CONTRIBUTORS file .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
This file is part of GtkRadiant .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
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 .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
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 .
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
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
*/
2007-11-04 03:34:51 +00:00
// To do
// Sound error handling (when sound too short)
// rle b4 huffing
// adpcm encoding of sound
2012-03-17 20:01:54 +00:00
#if 0
2007-11-04 03:34:51 +00:00
# include "qdata.h"
# include "flex.h"
# include "fc.h"
# include "adpcm.h"
2012-03-17 20:01:54 +00:00
# define MIN_REPT 15
# define MAX_REPT 0
# define HUF_TOKENS ( 256 + MAX_REPT )
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
# define BLOCKSIZE 8
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
# define M_PI 3.14159265358979323846 // matches value in gcc v2 math.h
# define SQRT2 1.414213562
2007-11-04 03:34:51 +00:00
typedef struct hnode_s
{
2012-03-17 20:01:54 +00:00
int count ;
qboolean used ;
int children [ 2 ] ;
2007-11-04 03:34:51 +00:00
} hnode_t ;
typedef struct
{
2012-03-17 20:01:54 +00:00
int rate ;
int width ;
int channels ;
int loopstart ;
int samples ;
int dataofs ; // chunk starts this many bytes from file start
2007-11-04 03:34:51 +00:00
} 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 ] =
{
2012-03-17 20:01:54 +00:00
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
2007-11-04 03:34:51 +00:00
} ;
int LUT_ZZ [ BLOCKSIZE * BLOCKSIZE ] =
{
2012-03-17 20:01:54 +00:00
0 ,
1 , 8 ,
2007-11-04 03:34:51 +00:00
16 , 9 , 2 ,
2012-03-17 20:01:54 +00:00
3 , 10 , 17 , 24 ,
2007-11-04 03:34:51 +00:00
32 , 25 , 18 , 11 , 4 ,
2012-03-17 20:01:54 +00:00
5 , 12 , 19 , 26 , 33 , 40 ,
2007-11-04 03:34:51 +00:00
48 , 41 , 34 , 27 , 20 , 13 , 6 ,
2012-03-17 20:01:54 +00:00
7 , 14 , 21 , 28 , 35 , 42 , 49 , 56 ,
2007-11-04 03:34:51 +00:00
57 , 50 , 43 , 36 , 29 , 22 , 15 ,
23 , 30 , 37 , 44 , 51 , 58 ,
2012-03-17 20:01:54 +00:00
59 , 52 , 45 , 38 , 31 ,
2007-11-04 03:34:51 +00:00
39 , 46 , 53 , 60 ,
61 , 54 , 47 ,
2012-03-17 20:01:54 +00:00
55 , 62 ,
2007-11-04 03:34:51 +00:00
63
} ;
2012-03-17 20:01:54 +00:00
char base [ 32 ] ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
byte * soundtrack ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
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 ] ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
CineHead_t cinehead ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
byte * data_p ;
byte * iff_end ;
byte * last_chunk ;
byte * iff_data ;
int iff_chunk_len ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
float dctbase [ BLOCKSIZE ] [ BLOCKSIZE ] ;
float red [ BLOCKSIZE * BLOCKSIZE ] ;
float green [ BLOCKSIZE * BLOCKSIZE ] ;
float blue [ BLOCKSIZE * BLOCKSIZE ] ;
float temp [ BLOCKSIZE * BLOCKSIZE ] ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
wavinfo_t wavinfo ;
adpcm_t adpcm ;
2007-11-04 03:34:51 +00:00
/*
2012-03-17 20:01:54 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
WAV loading
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
2007-11-04 03:34:51 +00:00
/* Intel ADPCM step variation table */
2012-03-17 20:01:54 +00:00
static int indexTable [ 16 ] =
2007-11-04 03:34:51 +00:00
{
- 1 , - 1 , - 1 , - 1 , 2 , 4 , 6 , 8 ,
- 1 , - 1 , - 1 , - 1 , 2 , 4 , 6 , 8 ,
} ;
2012-03-17 20:01:54 +00:00
static int stepsizeTable [ 89 ] =
2007-11-04 03:34:51 +00:00
{
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
} ;
2012-03-17 20:01:54 +00:00
#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 */
2007-11-04 03:34:51 +00:00
outp = outdata ;
inp = ( signed char * ) indata ;
valpred = state - > valprev ;
index = state - > index ;
step = stepsizeTable [ index ] ;
bufferstep = 0 ;
2012-03-17 20:01:54 +00:00
for ( ; len > 0 ; len - - )
2007-11-04 03:34:51 +00:00
{
/* Step 1 - get the delta value */
2012-03-17 20:01:54 +00:00
if ( bufferstep ) {
2007-11-04 03:34:51 +00:00
delta = inputbuffer & 0xf ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
else
{
inputbuffer = * inp + + ;
2012-03-17 20:01:54 +00:00
delta = ( inputbuffer > > 4 ) & 0xf ;
2007-11-04 03:34:51 +00:00
}
bufferstep = ! bufferstep ;
/* Step 2 - Find new index value (for later) */
index + = indexTable [ delta ] ;
2012-03-17 20:01:54 +00:00
if ( index < 0 ) {
2007-11-04 03:34:51 +00:00
index = 0 ;
2012-03-17 20:01:54 +00:00
}
if ( index > 88 ) {
2007-11-04 03:34:51 +00:00
index = 88 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* 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 ;
2012-03-17 20:01:54 +00:00
if ( delta & 4 ) {
2007-11-04 03:34:51 +00:00
vpdiff + = step ;
2012-03-17 20:01:54 +00:00
}
if ( delta & 2 ) {
vpdiff + = step > > 1 ;
}
if ( delta & 1 ) {
vpdiff + = step > > 2 ;
}
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
if ( sign ) {
valpred - = vpdiff ;
}
else {
valpred + = vpdiff ;
}
2007-11-04 03:34:51 +00:00
/* Step 5 - clamp output value */
2012-03-17 20:01:54 +00:00
if ( valpred > 32767 ) {
valpred = 32767 ;
}
else if ( valpred < - 32768 ) {
valpred = - 32768 ;
}
2007-11-04 03:34:51 +00:00
/* Step 6 - Update step value */
step = stepsizeTable [ index ] ;
/* Step 7 - Output value */
* outp + + = valpred ;
}
state - > valprev = valpred ;
state - > index = index ;
}
# endif
2012-03-17 20:01:54 +00:00
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 ;
2007-11-04 03:34:51 +00:00
state = & adpcm - > state ;
len = state - > count ;
outp = adpcm - > adpcm ;
valpred = state - > in_valprev ;
index = state - > in_index ;
step = stepsizeTable [ index ] ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
bufferstep = 1 ;
2012-03-17 20:01:54 +00:00
while ( len - - )
2007-11-04 03:34:51 +00:00
{
val = * inp + + ;
/* Step 1 - compute difference with previous value */
diff = val - valpred ;
2012-03-17 20:01:54 +00:00
sign = ( diff < 0 ) ? 8 : 0 ;
if ( sign ) {
2007-11-04 03:34:51 +00:00
diff = - diff ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
/* 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 ;
2012-03-17 20:01:54 +00:00
vpdiff = ( step > > 3 ) ;
if ( diff > = step ) {
2007-11-04 03:34:51 +00:00
delta = 4 ;
diff - = step ;
vpdiff + = step ;
}
step > > = 1 ;
2012-03-17 20:01:54 +00:00
if ( diff > = step ) {
2007-11-04 03:34:51 +00:00
delta | = 2 ;
diff - = step ;
vpdiff + = step ;
}
step > > = 1 ;
2012-03-17 20:01:54 +00:00
if ( diff > = step ) {
2007-11-04 03:34:51 +00:00
delta | = 1 ;
vpdiff + = step ;
}
/* Step 3 - Update previous value */
2012-03-17 20:01:54 +00:00
if ( sign ) {
valpred - = vpdiff ;
}
else {
valpred + = vpdiff ;
}
2007-11-04 03:34:51 +00:00
/* Step 4 - Clamp previous value to 16 bits */
2012-03-17 20:01:54 +00:00
if ( valpred > 32767 ) {
valpred = 32767 ;
}
else if ( valpred < - 32768 ) {
valpred = - 32768 ;
}
2007-11-04 03:34:51 +00:00
/* Step 5 - Assemble value, update index and step values */
delta | = sign ;
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
index + = indexTable [ delta ] ;
2012-03-17 20:01:54 +00:00
if ( index < 0 ) {
2007-11-04 03:34:51 +00:00
index = 0 ;
2012-03-17 20:01:54 +00:00
}
if ( index > 88 ) {
2007-11-04 03:34:51 +00:00
index = 88 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
step = stepsizeTable [ index ] ;
/* Step 6 - Output value */
2012-03-17 20:01:54 +00:00
if ( bufferstep ) {
outputbuffer = ( delta < < 4 ) & 0xf0 ;
}
else {
* outp + + = ( delta & 0x0f ) | outputbuffer ;
}
2007-11-04 03:34:51 +00:00
bufferstep = ! bufferstep ;
}
/* Output last step, if needed */
2012-03-17 20:01:54 +00:00
if ( ! bufferstep ) {
* outp + + = outputbuffer ;
}
2007-11-04 03:34:51 +00:00
state - > out_valprev = valpred ;
state - > out_index = index ;
}
2012-03-17 20:01:54 +00:00
void FindNextChunk ( char * name ) {
while ( 1 )
2007-11-04 03:34:51 +00:00
{
data_p = last_chunk ;
2012-03-17 20:01:54 +00:00
if ( data_p > = iff_end ) { // didn't find the chunk
2007-11-04 03:34:51 +00:00
data_p = NULL ;
return ;
}
2012-03-17 20:01:54 +00:00
2007-11-04 03:34:51 +00:00
data_p + = 4 ;
iff_chunk_len = * ( long * ) data_p ;
data_p + = 4 ;
2012-03-17 20:01:54 +00:00
if ( iff_chunk_len < 0 ) {
2007-11-04 03:34:51 +00:00
data_p = NULL ;
return ;
}
data_p - = 8 ;
2012-03-17 20:01:54 +00:00
last_chunk = data_p + 8 + ( ( iff_chunk_len + 1 ) & ~ 1 ) ;
if ( ! strncmp ( data_p , name , 4 ) ) {
2007-11-04 03:34:51 +00:00
return ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
}
2012-03-17 20:01:54 +00:00
void FindChunk ( char * name ) {
2007-11-04 03:34:51 +00:00
last_chunk = iff_data ;
2012-03-17 20:01:54 +00:00
FindNextChunk ( name ) ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
void DumpChunks ( void ) {
char str [ 5 ] ;
2007-11-04 03:34:51 +00:00
str [ 4 ] = 0 ;
data_p = iff_data ;
do
{
2012-03-17 20:01:54 +00:00
memcpy ( str , data_p , 4 ) ;
2007-11-04 03:34:51 +00:00
data_p + = 4 ;
iff_chunk_len = * ( long * ) data_p ;
data_p + = 4 ;
2012-03-17 20:01:54 +00:00
printf ( " 0x%x : %s (%d) \n " , ( int ) ( data_p - 4 ) , str , iff_chunk_len ) ;
data_p + = ( iff_chunk_len + 1 ) & ~ 1 ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
while ( data_p < iff_end ) ;
2007-11-04 03:34:51 +00:00
}
/*
2012-03-17 20:01:54 +00:00
= = = = = = = = = = = =
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 ) ;
}
2007-11-04 03:34:51 +00:00
iff_data = wav ;
iff_end = wav + wavlength ;
// find "RIFF" chunk
2012-03-17 20:01:54 +00:00
FindChunk ( " RIFF " ) ;
if ( ! ( data_p & & ! strncmp ( data_p + 8 , " WAVE " , 4 ) ) ) {
printf ( " Missing RIFF/WAVE chunks \n " ) ;
return ( info ) ;
2007-11-04 03:34:51 +00:00
}
// get "fmt " chunk
iff_data = data_p + 12 ;
2012-03-17 20:01:54 +00:00
FindChunk ( " fmt " ) ;
if ( ! data_p ) {
printf ( " Missing fmt chunk \n " ) ;
return ( info ) ;
2007-11-04 03:34:51 +00:00
}
data_p + = 8 ;
format = * ( short * ) data_p ;
data_p + = 2 ;
2012-03-17 20:01:54 +00:00
if ( format ! = 1 ) {
printf ( " Microsoft PCM format only \n " ) ;
return ( info ) ;
2007-11-04 03:34:51 +00:00
}
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
2012-03-17 20:01:54 +00:00
FindChunk ( " cue " ) ;
if ( data_p ) {
2007-11-04 03:34:51 +00:00
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
2012-03-17 20:01:54 +00:00
FindNextChunk ( " LIST " ) ;
if ( data_p ) {
2007-11-04 03:34:51 +00:00
// this is not a proper parse, but it works with cooledit...
2012-03-17 20:01:54 +00:00
if ( ! strncmp ( data_p + 28 , " mark " , 4 ) ) {
2007-11-04 03:34:51 +00:00
data_p + = 24 ;
2012-03-17 20:01:54 +00:00
i = * ( long * ) data_p ; // samples in loop
2007-11-04 03:34:51 +00:00
data_p + = 4 ;
info . samples = info . loopstart + i ;
}
}
}
2012-03-17 20:01:54 +00:00
else {
2007-11-04 03:34:51 +00:00
info . loopstart = - 1 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
// find data chunk
2012-03-17 20:01:54 +00:00
FindChunk ( " data " ) ;
if ( ! data_p ) {
printf ( " Missing data chunk \n " ) ;
return ( info ) ;
2007-11-04 03:34:51 +00:00
}
data_p + = 4 ;
samples = * ( long * ) data_p ;
data_p + = 4 ;
2012-03-17 20:01:54 +00:00
if ( info . samples ) {
if ( samples < info . samples ) {
Error ( " Sound %s has a bad loop length " , name ) ;
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
else {
2007-11-04 03:34:51 +00:00
info . samples = samples ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
info . dataofs = data_p - wav ;
2012-03-17 20:01:54 +00:00
return ( info ) ;
2007-11-04 03:34:51 +00:00
}
// ==============
// LoadSoundtrack
// ==============
2012-03-17 20:01:54 +00:00
void LoadSoundtrack ( ) {
char name [ 1024 ] ;
FILE * f ;
int len ;
2007-11-04 03:34:51 +00:00
soundtrack = NULL ;
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
return ;
}
2012-03-17 20:01:54 +00:00
len = Q_filelength ( f ) ;
soundtrack = SafeMalloc ( len , " LoadSoundtrack " ) ;
fread ( soundtrack , 1 , len , f ) ;
fclose ( f ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
wavinfo = GetWavinfo ( name , soundtrack , len ) ;
2007-11-04 03:34:51 +00:00
adpcm . state . out_valprev = 0 ;
adpcm . state . out_index = 0 ;
}
// ==================
// WriteSound
// ==================
2012-03-17 20:01:54 +00:00
int WriteSound ( FILE * output , int frame , int numframes ) {
int start , end ;
int count ;
int empty = 0 ;
int width ;
char * work ;
2007-11-04 03:34:51 +00:00
width = wavinfo . width * wavinfo . channels ;
2012-03-17 20:01:54 +00:00
start = ( ( frame * wavinfo . rate / 14 ) + 31 ) & 0xffffffe0 ; // start sample
end = ( ( ( frame + numframes ) * wavinfo . rate / 14 ) + 31 ) & 0xffffffe0 ; // end sample
2007-11-04 03:34:51 +00:00
count = end - start ;
2012-03-17 20:01:54 +00:00
work = soundtrack + wavinfo . dataofs + ( start * width ) ;
adpcm . state . count = count * wavinfo . channels ; // Number of samples
2007-11-04 03:34:51 +00:00
adpcm . state . in_valprev = adpcm . state . out_valprev ;
adpcm . state . in_index = adpcm . state . out_index ;
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
}
// ==============================
// Basic run length encoder
// ==============================
2012-03-17 20:01:54 +00:00
char * RLEZZ ( char * in , char * out ) {
int srun ;
char count ;
int idx = 0 ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
while ( idx < 64 )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
srun = idx ; // Start of run
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
while ( idx < 63 )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( in [ LUT_ZZ [ idx ] ] ! = in [ LUT_ZZ [ idx + 1 ] ] ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
idx + + ;
}
2012-03-17 20:01:54 +00:00
count = ( char ) ( idx - srun ) ; // count of repeated bytes
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
if ( ! count ) {
while ( idx < 63 )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( in [ LUT_ZZ [ idx ] ] = = in [ LUT_ZZ [ idx + 1 ] ] ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
idx + + ;
}
2012-03-17 20:01:54 +00:00
if ( idx = = 63 ) {
2007-11-04 03:34:51 +00:00
idx + + ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
count = ( char ) ( idx - srun ) ; // count of unique bytes
2007-11-04 03:34:51 +00:00
* out + + = count ;
2012-03-17 20:01:54 +00:00
while ( count - - )
2007-11-04 03:34:51 +00:00
* out + + = in [ LUT_ZZ [ srun + + ] ] ;
}
else
{
2012-03-17 20:01:54 +00:00
* out + + = - ( count + 1 ) ;
2007-11-04 03:34:51 +00:00
* out + + = in [ LUT_ZZ [ idx ] ] ;
idx + + ;
}
}
2012-03-17 20:01:54 +00:00
return ( out ) ;
2007-11-04 03:34:51 +00:00
}
// ==============================
// Discrete Cosine Transformation
// ==============================
2012-03-17 20:01:54 +00:00
void init_base ( float quant ) {
int y , x ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
for ( y = 0 ; y < BLOCKSIZE ; y + + )
for ( x = 0 ; x < BLOCKSIZE ; x + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( y = = 0 ) {
2007-11-04 03:34:51 +00:00
dctbase [ y ] [ x ] = 1 ;
2012-03-17 20:01:54 +00:00
}
else {
dctbase [ y ] [ x ] = SQRT2 * cos ( ( ( x * 2 + 1 ) * y * M_PI ) / ( BLOCKSIZE * 2 ) ) ;
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
for ( y = 0 ; y < BLOCKSIZE * BLOCKSIZE ; y + + )
2007-11-04 03:34:51 +00:00
Quantise [ y ] = LUT_Quantise [ y ] / quant ;
}
2012-03-17 20:01:54 +00:00
void SplitComponents ( byte * src , int width , int height ) {
int i , j ;
float * tr = red ;
float * tg = green ;
float * tb = blue ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < BLOCKSIZE ; i + + , src + = ( width - BLOCKSIZE ) * 4 )
for ( j = 0 ; j < BLOCKSIZE ; j + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
* tr + + = ( ( float ) * src + + ) - 128.0F ;
* tg + + = ( ( float ) * src + + ) - 128.0F ;
* tb + + = ( ( float ) * src + + ) - 128.0F ;
2007-11-04 03:34:51 +00:00
src + + ;
}
}
2012-03-17 20:01:54 +00:00
void transferH ( float * src , float * dst ) {
int y , dx , dy ;
float sum ;
float * work ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
for ( y = 0 ; y < BLOCKSIZE ; y + + , src + = BLOCKSIZE )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
for ( dy = 0 ; dy < BLOCKSIZE ; dy + + )
2007-11-04 03:34:51 +00:00
{
sum = 0 ;
work = src ;
2012-03-17 20:01:54 +00:00
for ( dx = 0 ; dx < BLOCKSIZE ; dx + + , work + + )
2007-11-04 03:34:51 +00:00
sum + = dctbase [ dy ] [ dx ] * * work ;
* dst + + = sum / BLOCKSIZE ;
}
}
}
2012-03-17 20:01:54 +00:00
void transferV ( float * src , float * dst ) {
int x , dy , fy ;
float sum ;
float * work ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
for ( x = 0 ; x < BLOCKSIZE ; x + + , src + + , dst + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
for ( fy = 0 ; fy < BLOCKSIZE ; fy + + )
2007-11-04 03:34:51 +00:00
{
sum = 0 ;
work = src ;
2012-03-17 20:01:54 +00:00
for ( dy = 0 ; dy < BLOCKSIZE ; dy + + , work + = BLOCKSIZE )
2007-11-04 03:34:51 +00:00
sum + = dctbase [ fy ] [ dy ] * * work ;
dst [ fy * BLOCKSIZE ] = sum / BLOCKSIZE ;
}
}
}
2012-03-17 20:01:54 +00:00
char * Combine ( byte * dst , float * p , float * q ) {
int i , j ;
byte rlesrc [ BLOCKSIZE * BLOCKSIZE ] ;
int c ;
byte * work ;
2007-11-04 03:34:51 +00:00
work = rlesrc ;
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < BLOCKSIZE ; j + + )
for ( i = 0 ; i < BLOCKSIZE ; i + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
c = ( int ) ( ( * p + + / * q + + ) + 128.5F ) ;
2007-11-04 03:34:51 +00:00
c - = 128 ;
2012-03-17 20:01:54 +00:00
if ( c < - 128 ) {
2007-11-04 03:34:51 +00:00
c = - 128 ;
2012-03-17 20:01:54 +00:00
}
if ( c > 127 ) {
2007-11-04 03:34:51 +00:00
c = 127 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
* work + + = ( char ) c ;
}
2012-03-17 20:01:54 +00:00
dst = RLEZZ ( rlesrc , dst ) ;
return ( dst ) ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
void DCT ( cblock_t * out , cblock_t in , int width , int height ) {
int x , y ;
char * cursrc ;
char * curdst ;
2007-11-04 03:34:51 +00:00
curdst = out - > data ;
2012-03-17 20:01:54 +00:00
for ( y = 0 ; y < height ; y + = BLOCKSIZE )
for ( x = 0 ; x < width ; x + = BLOCKSIZE )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
}
out - > count = curdst - out - > data ;
}
// ==================
// BuildChars1
// ==================
2012-03-17 20:01:54 +00:00
void BuildChars1 ( int prev , int nodenum , unsigned bits , int bitcount ) {
hnode_t * node ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
if ( nodenum < HUF_TOKENS ) {
if ( bitcount > 32 ) {
Error ( " bitcount > 32 " ) ;
}
2007-11-04 03:34:51 +00:00
charbits1 [ prev ] [ nodenum ] = bits ;
charbitscount1 [ prev ] [ nodenum ] = bitcount ;
return ;
}
node = & hnodes1 [ prev ] [ nodenum ] ;
bits < < = 1 ;
2012-03-17 20:01:54 +00:00
BuildChars1 ( prev , node - > children [ 0 ] , bits , bitcount + 1 ) ;
2007-11-04 03:34:51 +00:00
bits | = 1 ;
2012-03-17 20:01:54 +00:00
BuildChars1 ( prev , node - > children [ 1 ] , bits , bitcount + 1 ) ;
2007-11-04 03:34:51 +00:00
}
// ==================
// SmallestNode1
// ==================
2012-03-17 20:01:54 +00:00
int SmallestNode1 ( hnode_t * hnodes , int numhnodes ) {
int i ;
int best , bestnode ;
2007-11-04 03:34:51 +00:00
best = 99999999 ;
bestnode = - 1 ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < numhnodes ; i + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( hnodes [ i ] . used ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
if ( ! hnodes [ i ] . count ) {
2007-11-04 03:34:51 +00:00
continue ;
2012-03-17 20:01:54 +00:00
}
if ( hnodes [ i ] . count < best ) {
2007-11-04 03:34:51 +00:00
best = hnodes [ i ] . count ;
bestnode = i ;
}
}
2012-03-17 20:01:54 +00:00
if ( bestnode = = - 1 ) {
return ( - 1 ) ;
}
2007-11-04 03:34:51 +00:00
hnodes [ bestnode ] . used = true ;
2012-03-17 20:01:54 +00:00
return ( bestnode ) ;
2007-11-04 03:34:51 +00:00
}
// ==================
// BuildTree1
// ==================
2012-03-17 20:01:54 +00:00
void BuildTree1 ( int prev ) {
hnode_t * node , * nodebase ;
int numhnodes ;
2007-11-04 03:34:51 +00:00
// build the nodes
numhnodes = HUF_TOKENS ;
nodebase = hnodes1 [ prev ] ;
2012-03-17 20:01:54 +00:00
while ( 1 )
2007-11-04 03:34:51 +00:00
{
node = & nodebase [ numhnodes ] ;
// pick two lowest counts
2012-03-17 20:01:54 +00:00
node - > children [ 0 ] = SmallestNode1 ( nodebase , numhnodes ) ;
if ( node - > children [ 0 ] = = - 1 ) {
break ; // no more
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
}
node - > children [ 1 ] = SmallestNode1 ( nodebase , numhnodes ) ;
if ( node - > children [ 1 ] = = - 1 ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
node - > count = nodebase [ node - > children [ 0 ] ] . count +
nodebase [ node - > children [ 1 ] ] . count ;
2007-11-04 03:34:51 +00:00
numhnodes + + ;
}
2012-03-17 20:01:54 +00:00
numhnodes1 [ prev ] = numhnodes - 1 ;
BuildChars1 ( prev , numhnodes - 1 , 0 , 0 ) ;
2007-11-04 03:34:51 +00:00
}
// ==================
// Huffman1_Count
// ==================
2012-03-17 20:01:54 +00:00
void Huffman1_Count ( cblock_t in ) {
int i ;
int prev ;
int v ;
int rept ;
2007-11-04 03:34:51 +00:00
prev = 0 ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < in . count ; i + + )
2007-11-04 03:34:51 +00:00
{
v = in . data [ i ] ;
order0counts [ v ] + + ;
hnodes1 [ prev ] [ v ] . count + + ;
prev = v ;
2012-03-17 20:01:54 +00:00
for ( rept = 1 ; ( i + rept < in . count ) & & ( rept < MAX_REPT ) ; rept + + )
if ( in . data [ i + rept ] ! = v ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
if ( rept > MIN_REPT ) {
2007-11-04 03:34:51 +00:00
hnodes1 [ prev ] [ 255 + rept ] . count + + ;
i + = rept - 1 ;
}
}
}
// ==================
// Huffman1_Build
// ==================
2012-03-17 20:01:54 +00:00
void Huffman1_Build ( ) {
int i , j , v ;
int max ;
int total ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < 256 ; i + + )
2007-11-04 03:34:51 +00:00
{
// normalize and save the counts
max = 0 ;
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < HUF_TOKENS ; j + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
if ( hnodes1 [ i ] [ j ] . count > max ) {
2007-11-04 03:34:51 +00:00
max = hnodes1 [ i ] [ j ] . count ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
if ( max = = 0 ) {
2007-11-04 03:34:51 +00:00
max = 1 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
total = 0 ;
// easy to overflow 32 bits here!
2012-03-17 20:01:54 +00:00
for ( j = 0 ; j < HUF_TOKENS ; j + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
v = ( hnodes1 [ i ] [ j ] . count * ( double ) 255 + max - 1 ) / max ;
if ( v > 255 ) {
Error ( " v > 255 " ) ;
}
2007-11-04 03:34:51 +00:00
scaled [ i ] [ j ] = hnodes1 [ i ] [ j ] . count = v ;
2012-03-17 20:01:54 +00:00
if ( v ) {
2007-11-04 03:34:51 +00:00
total + + ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
if ( total = = 1 ) { // must have two tokens
if ( ! scaled [ i ] [ 0 ] ) {
2007-11-04 03:34:51 +00:00
scaled [ i ] [ 0 ] = hnodes1 [ i ] [ 0 ] . count = 1 ;
2012-03-17 20:01:54 +00:00
}
else {
2007-11-04 03:34:51 +00:00
scaled [ i ] [ 1 ] = hnodes1 [ i ] [ 1 ] . count = 1 ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
BuildTree1 ( i ) ;
2007-11-04 03:34:51 +00:00
}
}
// ==================
// Huffman1
// Order 1 compression with pre-built table
// ==================
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
// leave space for compressed count
out_p + = 4 ;
// write count
* ( long * ) out_p = in . count ;
out_p + = 4 ;
// write bits
outbits = 0 ;
prev = 0 ;
2012-03-17 20:01:54 +00:00
for ( i = 0 ; i < in . count ; i + + )
2007-11-04 03:34:51 +00:00
{
v = in . data [ i ] ;
c = charbitscount1 [ prev ] [ v ] ;
bits = charbits1 [ prev ] [ v ] ;
2012-03-17 20:01:54 +00:00
if ( ! c ) {
Error ( " !bits " ) ;
}
while ( c )
2007-11-04 03:34:51 +00:00
{
c - - ;
2012-03-17 20:01:54 +00:00
if ( bits & ( 1 < < c ) ) {
out_p [ outbits > > 3 ] | = 1 < < ( outbits & 7 ) ;
}
2007-11-04 03:34:51 +00:00
outbits + + ;
}
prev = v ;
// check for repeat encodes
2012-03-17 20:01:54 +00:00
for ( rept = 1 ; ( i + rept < in . count ) & & ( rept < MAX_REPT ) ; rept + + )
if ( in . data [ i + rept ] ! = v ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
if ( rept > MIN_REPT ) {
2007-11-04 03:34:51 +00:00
c = charbitscount1 [ prev ] [ 255 + rept ] ;
bits = charbits1 [ prev ] [ 255 + rept ] ;
2012-03-17 20:01:54 +00:00
if ( ! c ) {
Error ( " !bits " ) ;
}
while ( c )
2007-11-04 03:34:51 +00:00
{
c - - ;
2012-03-17 20:01:54 +00:00
if ( bits & ( 1 < < c ) ) {
out_p [ outbits > > 3 ] | = 1 < < ( outbits & 7 ) ;
}
2007-11-04 03:34:51 +00:00
outbits + + ;
}
i + = rept - 1 ;
}
}
2012-03-17 20:01:54 +00:00
out_p + = ( outbits + 7 ) > > 3 ;
2007-11-04 03:34:51 +00:00
out . count = out_p - out . data ;
out_p = out . data ;
* ( long * ) out_p = out . count ;
2012-03-17 20:01:54 +00:00
return ( out ) ;
2007-11-04 03:34:51 +00:00
}
// ===================
// LoadFrame
// ===================
2012-03-17 20:01:54 +00:00
void LoadFrame ( cblock_t * out , char * base , int frame ) {
cblock_t in ;
int width , height ;
char name [ 1024 ] ;
FILE * f ;
2007-11-04 03:34:51 +00:00
in . data = NULL ;
in . count = - 1 ;
2012-03-17 20:01:54 +00:00
sprintf ( name , " %svideo/%s/%s%04i.tga " , gamedir , base , base , frame ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
f = fopen ( name , " rb " ) ;
if ( ! f ) {
2007-11-04 03:34:51 +00:00
out - > data = NULL ;
return ;
}
2012-03-17 20:01:54 +00:00
fclose ( f ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
LoadTGA ( name , & in . data , & width , & height ) ;
if ( ( width ! = cinehead . Width ) | | ( height ! = cinehead . Height ) ) {
free ( in . data ) ;
printf ( " Invalid picture size \n " ) ;
2007-11-04 03:34:51 +00:00
out - > data = NULL ;
return ;
}
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
}
// ==================================
// Cmd_Video
2012-03-17 20:01:54 +00:00
//
2007-11-04 03:34:51 +00:00
// video <directory> <framedigits>
// ==================================
2012-03-17 20:01:54 +00:00
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 ) {
2007-11-04 03:34:51 +00:00
return ;
2012-03-17 20:01:54 +00:00
}
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
GetScriptToken ( false ) ;
dctconst = atof ( token ) ;
GetScriptToken ( false ) ;
maxsize = atoi ( token ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
sprintf ( savename , " %svideo/%s.cin " , gamedir , base ) ;
2007-11-04 03:34:51 +00:00
// clear stuff
2012-03-17 20:01:54 +00:00
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 ) ) ;
2007-11-04 03:34:51 +00:00
// load the entire sound wav file if present
LoadSoundtrack ( ) ;
cinehead . SndRate = wavinfo . rate ;
cinehead . SndWidth = wavinfo . width ;
cinehead . SndChannels = wavinfo . channels ;
2012-03-17 20:01:54 +00:00
sprintf ( name , " %svideo/%s/%s0000.tga " , gamedir , base , base ) ;
printf ( " Loading sequence : %s \n " , name ) ;
printf ( " DCT constant : %f \n " , dctconst ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
LoadTGA ( name , NULL , & width , & height ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
output = fopen ( savename , " wb " ) ;
if ( ! output ) {
Error ( " Can't open %s " , savename ) ;
}
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
if ( ( width % BLOCKSIZE ) | | ( height % BLOCKSIZE ) ) {
Error ( " Width and height must be a multiple of %d " , BLOCKSIZE ) ;
}
2007-11-04 03:34:51 +00:00
cinehead . Width = width ;
cinehead . Height = height ;
2012-03-17 20:01:54 +00:00
init_base ( dctconst ) ;
2007-11-04 03:34:51 +00:00
// build the dictionary
2012-03-17 20:01:54 +00:00
printf ( " Counting : " ) ;
2007-11-04 03:34:51 +00:00
min_rle_size = 0 ;
2012-03-17 20:01:54 +00:00
for ( frame = 0 ; ; frame + + )
2007-11-04 03:34:51 +00:00
{
2012-03-17 20:01:54 +00:00
printf ( " . " ) ;
LoadFrame ( & in , base , frame ) ;
if ( ! in . data ) {
2007-11-04 03:34:51 +00:00
break ;
2012-03-17 20:01:54 +00:00
}
Huffman1_Count ( in ) ;
if ( in . count > min_rle_size ) {
2007-11-04 03:34:51 +00:00
min_rle_size = in . count ;
2012-03-17 20:01:54 +00:00
}
free ( in . data ) ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
printf ( " \n " ) ;
2007-11-04 03:34:51 +00:00
cinehead . NumFrames = frame ;
2012-03-17 20:01:54 +00:00
printf ( " Num Frames : %d \n " , frame ) ;
cinehead . MaxRleSize = ( min_rle_size + 0x1f ) & 0xfffffe0 ;
cinehead . MaxSndSize = ( ( 4 * wavinfo . rate * wavinfo . channels / 14 ) + 0x1f ) & 0xffffffe0 ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
WriteHeader ( output , FC_HEADER_NAME , FC_HEADER_VERSION , sizeof ( CineHead_t ) , & cinehead ) ;
2007-11-04 03:34:51 +00:00
// build nodes and write counts
Huffman1_Build ( ) ;
2012-03-17 20:01:54 +00:00
WriteHeader ( output , FC_HUFFBITS_NAME , FC_HUFFBITS_VERSION , sizeof ( scaled ) , scaled ) ;
WriteHeader ( output , FC_QUANT_NAME , FC_QUANT_VERSION , sizeof ( Quantise ) , Quantise ) ;
2007-11-04 03:34:51 +00:00
ave_image = 0 ;
ave_sound = 0 ;
warnings = 0 ;
// compress it with the dictionary
2012-03-17 20:01:54 +00:00
if ( soundtrack ) {
ssize = WriteSound ( output , frame , 4 ) ;
2007-11-04 03:34:51 +00:00
ave_sound + = ssize ;
}
2012-03-17 20:01:54 +00:00
for ( frame = 0 ; frame < cinehead . NumFrames ; frame + + )
2007-11-04 03:34:51 +00:00
{
// save some sound samples
2012-03-17 20:01:54 +00:00
printf ( " Packing : " , frame ) ;
LoadFrame ( & in , base , frame ) ;
2007-11-04 03:34:51 +00:00
// save the image
2012-03-17 20:01:54 +00:00
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 ** " ) ;
2007-11-04 03:34:51 +00:00
warnings + + ;
}
2012-03-17 20:01:54 +00:00
printf ( " \n " ) ;
2007-11-04 03:34:51 +00:00
ave_image + = huffman . count ;
2012-03-17 20:01:54 +00:00
WriteHeader ( output , FC_IMAGE_NAME , FC_IMAGE_VERSION , size , huffman . data ) ;
if ( soundtrack ) {
ssize = WriteSound ( output , frame + 4 , 1 ) ;
2007-11-04 03:34:51 +00:00
ave_sound + = ssize ;
}
2012-03-17 20:01:54 +00:00
free ( in . data ) ;
free ( huffman . data ) ;
2007-11-04 03:34:51 +00:00
}
2012-03-17 20:01:54 +00:00
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 ) ;
2007-11-04 03:34:51 +00:00
2012-03-17 20:01:54 +00:00
if ( soundtrack ) {
free ( soundtrack ) ;
}
2007-11-04 03:34:51 +00:00
}
# endif
2012-03-17 20:01:54 +00:00
void Cmd_Video ( ) {
2007-11-04 03:34:51 +00:00
}
// end