123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856 |
- /*
- ===========================================================================
- Doom 3 GPL Source Code
- Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
- This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
- Doom 3 Source Code 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 3 of the License, or
- (at your option) any later version.
- Doom 3 Source Code 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 Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
- In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
- If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
- ===========================================================================
- */
- #include "../../../idlib/precompiled.h"
- #pragma hdrstop
- #include "roq.h"
- #include "codec.h"
- roq *theRoQ; // current roq file
- roq::roq( void )
- {
- image = 0;
- quietMode = false;
- encoder = 0;
- previousSize = 0;
- lastFrame = false;
- dataStuff=false;
- }
- roq::~roq( void )
- {
- if (image) delete image;
- if (encoder) delete encoder;
- return;
- }
- void roq::EncodeQuietly( bool which )
- {
- quietMode = which;
- }
- bool roq::IsQuiet( void )
- {
- return quietMode;
- }
- bool roq::IsLastFrame( void )
- {
- return lastFrame;
- }
- bool roq::Scaleable( void )
- {
- return paramFile->IsScaleable();
- }
- bool roq::ParamNoAlpha( void )
- {
- return paramFile->NoAlpha();
- }
- bool roq::MakingVideo( void )
- {
- return true; //paramFile->timecode];
- }
- bool roq::SearchType( void )
- {
- return paramFile->SearchType();
- }
- bool roq::HasSound( void )
- {
- return paramFile->HasSound();
- }
- int roq::PreviousFrameSize( void )
- {
- return previousSize;
- }
- int roq::FirstFrameSize( void )
- {
- return paramFile->FirstFrameSize();
- }
- int roq::NormalFrameSize( void )
- {
- return paramFile->NormalFrameSize();
- }
- const char * roq::CurrentFilename( void )
- {
- return currentFile.c_str();
- }
- void roq::EncodeStream( const char *paramInputFile )
- {
- int onFrame;
- idStr f0, f1, f2;
- int morestuff;
- onFrame = 1;
-
- encoder = new codec;
- paramFile = new roqParam;
- paramFile->numInputFiles = 0;
-
- paramFile->InitFromFile( paramInputFile );
- if (!paramFile->NumberOfFrames()) {
- return;
- }
-
- InitRoQFile( paramFile->outputFilename);
- numberOfFrames = paramFile->NumberOfFrames();
- if (paramFile->NoAlpha()==true) common->Printf("encodeStream: eluding alpha\n");
-
- f0 = "";
- f1 = paramFile->GetNextImageFilename();
- if (( paramFile->MoreFrames() == true )) {
- f2 = paramFile->GetNextImageFilename();
- }
- morestuff = numberOfFrames;
-
- while( morestuff ) {
- LoadAndDisplayImage( f1 );
-
- if (onFrame==1) {
- encoder->SparseEncode();
- // WriteLossless();
- } else {
- if (!strcmp( f0, f1 ) && strcmp( f1, f2) ) {
- WriteHangFrame();
- } else {
- encoder->SparseEncode();
- }
- }
- onFrame++;
- f0 = f1;
- f1 = f2;
- if (paramFile->MoreFrames() == true) {
- f2 = paramFile->GetNextImageFilename();
- }
- morestuff--;
- session->UpdateScreen();
- }
- // if (numberOfFrames != 1) {
- // if (image->hasAlpha() && paramFile->NoAlpha()==false) {
- // lastFrame = true;
- // encoder->SparseEncode();
- // } else {
- // WriteLossless();
- // }
- // }
- CloseRoQFile();
- }
- void roq::Write16Word( word *aWord, idFile *stream )
- {
- byte a, b;
-
- a = *aWord & 0xff;
- b = *aWord >> 8;
- stream->Write( &a, 1 );
- stream->Write( &b, 1 );
- }
- void roq::Write32Word( unsigned int *aWord, idFile *stream )
- {
- byte a, b, c, d;
-
- a = *aWord & 0xff;
- b = (*aWord >> 8) & 0xff;
- c = (*aWord >> 16) & 0xff;
- d = (*aWord >> 24) & 0xff;
- stream->Write( &a, 1 );
- stream->Write( &b, 1 );
- stream->Write( &c, 1 );
- stream->Write( &d, 1 );
- }
- int roq::SizeFile( idFile *ftosize )
- {
- return ftosize->Length();
- }
- /* Expanded data destination object for stdio output */
- typedef struct {
- struct jpeg_destination_mgr pub; /* public fields */
- byte* outfile; /* target stream */
- int size;
- } my_destination_mgr;
- typedef my_destination_mgr * my_dest_ptr;
- /*
- * Initialize destination --- called by jpeg_start_compress
- * before any data is actually written.
- */
- void roq::JPEGInitDestination (j_compress_ptr cinfo) {
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
- dest->pub.next_output_byte = dest->outfile;
- dest->pub.free_in_buffer = dest->size;
- }
- /*
- * Empty the output buffer --- called whenever buffer fills up.
- *
- * In typical applications, this should write the entire output buffer
- * (ignoring the current state of next_output_byte & free_in_buffer),
- * reset the pointer & count to the start of the buffer, and return true
- * indicating that the buffer has been dumped.
- *
- * In applications that need to be able to suspend compression due to output
- * overrun, a FALSE return indicates that the buffer cannot be emptied now.
- * In this situation, the compressor will return to its caller (possibly with
- * an indication that it has not accepted all the supplied scanlines). The
- * application should resume compression after it has made more room in the
- * output buffer. Note that there are substantial restrictions on the use of
- * suspension --- see the documentation.
- *
- * When suspending, the compressor will back up to a convenient restart point
- * (typically the start of the current MCU). next_output_byte & free_in_buffer
- * indicate where the restart point will be if the current call returns FALSE.
- * Data beyond this point will be regenerated after resumption, so do not
- * write it out when emptying the buffer externally.
- */
- boolean roq::JPEGEmptyOutputBuffer (j_compress_ptr cinfo) {
- return true;
- }
- /*
- * Compression initialization.
- * Before calling this, all parameters and a data destination must be set up.
- *
- * We require a write_all_tables parameter as a failsafe check when writing
- * multiple datastreams from the same compression object. Since prior runs
- * will have left all the tables marked sent_table=true, a subsequent run
- * would emit an abbreviated stream (no tables) by default. This may be what
- * is wanted, but for safety's sake it should not be the default behavior:
- * programmers should have to make a deliberate choice to emit abbreviated
- * images. Therefore the documentation and examples should encourage people
- * to pass write_all_tables=true; then it will take active thought to do the
- * wrong thing.
- */
- void roq::JPEGStartCompress (j_compress_ptr cinfo, bool write_all_tables) {
- if (cinfo->global_state != CSTATE_START)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (write_all_tables)
- jpeg_suppress_tables(cinfo, FALSE); /* mark all tables to be written */
- /* (Re)initialize error mgr and destination modules */
- (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
- (*cinfo->dest->init_destination) (cinfo);
- /* Perform master selection of active modules */
- jinit_compress_master(cinfo);
- /* Set up for the first pass */
- (*cinfo->master->prepare_for_pass) (cinfo);
- /* Ready for application to drive first pass through jpeg_write_scanlines
- * or jpeg_write_raw_data.
- */
- cinfo->next_scanline = 0;
- cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
- }
- /*
- * Write some scanlines of data to the JPEG compressor.
- *
- * The return value will be the number of lines actually written.
- * This should be less than the supplied num_lines only in case that
- * the data destination module has requested suspension of the compressor,
- * or if more than image_height scanlines are passed in.
- *
- * Note: we warn about excess calls to jpeg_write_scanlines() since
- * this likely signals an application programmer error. However,
- * excess scanlines passed in the last valid call are *silently* ignored,
- * so that the application need not adjust num_lines for end-of-image
- * when using a multiple-scanline buffer.
- */
- JDIMENSION roq::JPEGWriteScanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines) {
- JDIMENSION row_ctr, rows_left;
- if (cinfo->global_state != CSTATE_SCANNING)
- ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
- if (cinfo->next_scanline >= cinfo->image_height)
- WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
- /* Call progress monitor hook if present */
- if (cinfo->progress != NULL) {
- cinfo->progress->pass_counter = (long) cinfo->next_scanline;
- cinfo->progress->pass_limit = (long) cinfo->image_height;
- (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
- }
- /* Give master control module another chance if this is first call to
- * jpeg_write_scanlines. This lets output of the frame/scan headers be
- * delayed so that application can write COM, etc, markers between
- * jpeg_start_compress and jpeg_write_scanlines.
- */
- if (cinfo->master->call_pass_startup)
- (*cinfo->master->pass_startup) (cinfo);
- /* Ignore any extra scanlines at bottom of image. */
- rows_left = cinfo->image_height - cinfo->next_scanline;
- if (num_lines > rows_left)
- num_lines = rows_left;
- row_ctr = 0;
- (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
- cinfo->next_scanline += row_ctr;
- return row_ctr;
- }
- /*
- * Terminate destination --- called by jpeg_finish_compress
- * after all data has been written. Usually needs to flush buffer.
- *
- * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
- * application must deal with any cleanup that should happen even
- * for error exit.
- */
- static int hackSize;
- void roq::JPEGTermDestination (j_compress_ptr cinfo) {
- my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
- size_t datacount = dest->size - dest->pub.free_in_buffer;
- hackSize = datacount;
- }
- /*
- * Prepare for output to a stdio stream.
- * The caller must have already opened the stream, and is responsible
- * for closing it after finishing compression.
- */
- void roq::JPEGDest (j_compress_ptr cinfo, byte* outfile, int size) {
- my_dest_ptr dest;
- /* The destination object is made permanent so that multiple JPEG images
- * can be written to the same file without re-executing jpeg_stdio_dest.
- * This makes it dangerous to use this manager and a different destination
- * manager serially with the same JPEG object, because their private object
- * sizes may be different. Caveat programmer.
- */
- if (cinfo->dest == NULL) { /* first time for this JPEG object? */
- cinfo->dest = (struct jpeg_destination_mgr *)
- (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
- sizeof(my_destination_mgr));
- }
- dest = (my_dest_ptr) cinfo->dest;
- dest->pub.init_destination = JPEGInitDestination;
- dest->pub.empty_output_buffer = JPEGEmptyOutputBuffer;
- dest->pub.term_destination = JPEGTermDestination;
- dest->outfile = outfile;
- dest->size = size;
- }
- void roq::WriteLossless( void ) {
- word direct;
- uint directdw;
- if (!dataStuff) {
- InitRoQPatterns();
- dataStuff=true;
- }
- direct = RoQ_QUAD_JPEG;
- Write16Word( &direct, RoQFile);
- /* This struct contains the JPEG compression parameters and pointers to
- * working space (which is allocated as needed by the JPEG library).
- * It is possible to have several such structures, representing multiple
- * compression/decompression processes, in existence at once. We refer
- * to any one struct (and its associated working data) as a "JPEG object".
- */
- struct jpeg_compress_struct cinfo;
- /* This struct represents a JPEG error handler. It is declared separately
- * because applications often want to supply a specialized error handler
- * (see the second half of this file for an example). But here we just
- * take the easy way out and use the standard error handler, which will
- * print a message on stderr and call exit() if compression fails.
- * Note that this struct must live as long as the main JPEG parameter
- * struct, to avoid dangling-pointer problems.
- */
- struct jpeg_error_mgr jerr;
- /* More stuff */
- JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
- int row_stride; /* physical row width in image buffer */
- byte *out;
- /* Step 1: allocate and initialize JPEG compression object */
- /* We have to set up the error handler first, in case the initialization
- * step fails. (Unlikely, but it could happen if you are out of memory.)
- * This routine fills in the contents of struct jerr, and returns jerr's
- * address which we place into the link field in cinfo.
- */
- cinfo.err = jpeg_std_error(&jerr);
- /* Now we can initialize the JPEG compression object. */
- jpeg_create_compress(&cinfo);
- /* Step 2: specify data destination (eg, a file) */
- /* Note: steps 2 and 3 can be done in either order. */
- /* Here we use the library-supplied code to send compressed data to a
- * stdio stream. You can also write your own code to do something else.
- * VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
- * requires it in order to write binary files.
- */
- out = (byte *)Mem_Alloc(image->pixelsWide()*image->pixelsHigh()*4);
- JPEGDest(&cinfo, out, image->pixelsWide()*image->pixelsHigh()*4);
- /* Step 3: set parameters for compression */
- /* First we supply a description of the input image.
- * Four fields of the cinfo struct must be filled in:
- */
- cinfo.image_width = image->pixelsWide(); /* image width and height, in pixels */
- cinfo.image_height = image->pixelsHigh();
- cinfo.input_components = 4; /* # of color components per pixel */
- cinfo.in_color_space = JCS_RGB; /* colorspace of input image */
- /* Now use the library's routine to set default compression parameters.
- * (You must set at least cinfo.in_color_space before calling this,
- * since the defaults depend on the source color space.)
- */
- jpeg_set_defaults(&cinfo);
- /* Now you can set any non-default parameters you wish to.
- * Here we just illustrate the use of quality (quantization table) scaling:
- */
- jpeg_set_quality(&cinfo, paramFile->JpegQuality(), true /* limit to baseline-JPEG values */);
- /* Step 4: Start compressor */
- /* true ensures that we will write a complete interchange-JPEG file.
- * Pass true unless you are very sure of what you're doing.
- */
- JPEGStartCompress(&cinfo, true);
- /* Step 5: while (scan lines remain to be written) */
- /* jpeg_write_scanlines(...); */
- /* Here we use the library's state variable cinfo.next_scanline as the
- * loop counter, so that we don't have to keep track ourselves.
- * To keep things simple, we pass one scanline per call; you can pass
- * more if you wish, though.
- */
- row_stride = image->pixelsWide() * 4; /* JSAMPLEs per row in image_buffer */
- byte *pixbuf = image->bitmapData();
- while (cinfo.next_scanline < cinfo.image_height) {
- /* jpeg_write_scanlines expects an array of pointers to scanlines.
- * Here the array is only one element long, but you could pass
- * more than one scanline at a time if that's more convenient.
- */
- row_pointer[0] = &pixbuf[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
- (void) JPEGWriteScanlines(&cinfo, row_pointer, 1);
- }
- /* Step 6: Finish compression */
- jpeg_finish_compress(&cinfo);
- /* After finish_compress, we can close the output file. */
- directdw = hackSize;
- common->Printf("writeLossless: writing %d bytes to RoQ_QUAD_JPEG\n", hackSize);
- Write32Word( &directdw, RoQFile );
- direct = 0; // flags
- Write16Word( &direct, RoQFile );
- RoQFile->Write( out, hackSize );
- Mem_Free(out);
- /* Step 7: release JPEG compression object */
- /* This is an important step since it will release a good deal of memory. */
- jpeg_destroy_compress(&cinfo);
- /* And we're done! */
- encoder->SetPreviousImage( "first frame", image );
- }
- void roq::InitRoQFile( const char *RoQFilename )
- {
- word i;
- static int finit = 0;
- if (!finit) {
- finit++;
- common->Printf("initRoQFile: %s\n", RoQFilename);
- RoQFile = fileSystem->OpenFileWrite( RoQFilename );
- // chmod(RoQFilename, S_IREAD|S_IWRITE|S_ISUID|S_ISGID|0070|0007 );
- if ( !RoQFile ) {
- common->Error("Unable to open output file %s.\n", RoQFilename);
- }
- i = RoQ_ID;
- Write16Word( &i, RoQFile );
- i = 0xffff;
- Write16Word( &i, RoQFile );
- Write16Word( &i, RoQFile );
- // to retain exact file format write out 32 for new roq's
- // on loading this will be noted and converted to 1000 / 30
- // as with any new sound dump avi demos we need to playback
- // at the speed the sound engine dumps the audio
- i = 30; // framerate
- Write16Word( &i, RoQFile );
- }
- roqOutfile = RoQFilename;
- }
- void roq::InitRoQPatterns( void )
- {
- uint j;
- word direct;
- direct = RoQ_QUAD_INFO;
- Write16Word( &direct, RoQFile );
- j = 8;
- Write32Word( &j, RoQFile );
- common->Printf("initRoQPatterns: outputting %d bytes to RoQ_INFO\n", j);
- direct = image->hasAlpha();
- if (ParamNoAlpha() == true) direct = 0;
- Write16Word( &direct, RoQFile );
- direct = image->pixelsWide();
- Write16Word( &direct, RoQFile );
- direct = image->pixelsHigh();
- Write16Word( &direct, RoQFile );
- direct = 8;
- Write16Word( &direct, RoQFile );
- direct = 4;
- Write16Word( &direct, RoQFile );
- }
- void roq::CloseRoQFile( void )
- {
- common->Printf("closeRoQFile: closing RoQ file\n");
- fileSystem->CloseFile( RoQFile );
- }
- void roq::WriteHangFrame( void )
- {
- uint j;
- word direct;
- common->Printf("*******************************************************************\n");
- direct = RoQ_QUAD_HANG;
- Write16Word( &direct, RoQFile);
- j = 0;
- Write32Word( &j, RoQFile);
- direct = 0;
- Write16Word( &direct, RoQFile);
- }
- void roq::WriteCodeBookToStream( byte *codebook, int csize, word cflags )
- {
- uint j;
- word direct;
- if (!csize) {
- common->Printf("writeCodeBook: false VQ DATA!!!!\n");
- return;
- }
-
- direct = RoQ_QUAD_CODEBOOK;
- Write16Word( &direct, RoQFile);
- j = csize;
- Write32Word( &j, RoQFile);
- common->Printf("writeCodeBook: outputting %d bytes to RoQ_QUAD_CODEBOOK\n", j);
- direct = cflags;
- Write16Word( &direct, RoQFile);
- RoQFile->Write( codebook, j );
- }
- void roq::WriteCodeBook( byte *codebook )
- {
- memcpy( codes, codebook, 4096 );
- }
- void roq::WriteFrame( quadcel *pquad )
- {
- word action, direct;
- int onCCC, onAction, i, code;
- uint j;
- byte *cccList;
- bool *use2, *use4;
- int dx,dy,dxMean,dyMean,index2[256],index4[256], dimension;
- cccList = (byte *)Mem_Alloc( numQuadCels * 8); // maximum length
- use2 = (bool *)Mem_Alloc(256*sizeof(bool));
- use4 = (bool *)Mem_Alloc(256*sizeof(bool));
- for(i=0;i<256;i++) {
- use2[i] = false;
- use4[i] = false;
- }
- action = 0;
- j = onAction = 0;
- onCCC = 2; // onAction going to go at zero
- dxMean = encoder->MotMeanX();
- dyMean = encoder->MotMeanY();
- if (image->hasAlpha()) dimension = 10; else dimension = 6;
- for (i=0; i<numQuadCels; i++) {
- if ( pquad[i].size && pquad[i].size < 16 ) {
- switch( pquad[i].status ) {
- case SLD:
- use4[pquad[i].patten[0]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = true;
- break;
- case PAT:
- use4[pquad[i].patten[0]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = true;
- use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = true;
- break;
- case CCC:
- use2[pquad[i].patten[1]] = true;
- use2[pquad[i].patten[2]] = true;
- use2[pquad[i].patten[3]] = true;
- use2[pquad[i].patten[4]] = true;
- }
- }
- }
- if (!dataStuff) {
- dataStuff=true;
- InitRoQPatterns();
- if (image->hasAlpha()) i = 3584; else i = 2560;
- WriteCodeBookToStream( codes, i, 0 );
- for(i=0;i<256;i++) {
- index2[i] = i;
- index4[i] = i;
- }
- } else {
- j = 0;
- for(i=0;i<256;i++) {
- if (use2[i]) {
- index2[i] = j;
- for(dx=0;dx<dimension;dx++) cccList[j*dimension+dx] = codes[i*dimension+dx];
- j++;
- }
- }
- code = j*dimension;
- direct = j;
- common->Printf("writeFrame: really used %d 2x2 cels\n", j);
- j = 0;
- for(i=0;i<256;i++) {
- if (use4[i]) {
- index4[i] = j;
- for(dx=0;dx<4;dx++) cccList[j*4+code+dx] = index2[codes[i*4+(dimension*256)+dx]];
- j++;
- }
- }
- code += j*4;
- direct = (direct<<8) + j;
- common->Printf("writeFrame: really used %d 4x4 cels\n", j);
- if (image->hasAlpha()) i = 3584; else i = 2560;
- if ( code == i || j == 256) {
- WriteCodeBookToStream( codes, i, 0 );
- } else {
- WriteCodeBookToStream( cccList, code, direct );
- }
- }
- action = 0;
- j = onAction = 0;
- for (i=0; i<numQuadCels; i++) {
- if ( pquad[i].size && pquad[i].size < 16 ) {
- code = -1;
- switch( pquad[i].status ) {
- case DEP:
- code = 3;
- break;
- case SLD:
- code = 2;
- cccList[onCCC++] = index4[pquad[i].patten[0]];
- break;
- case MOT:
- code = 0;
- break;
- case FCC:
- code = 1;
- dx = ((pquad[i].domain >> 8 )) - 128 - dxMean + 8;
- dy = ((pquad[i].domain & 0xff)) - 128 - dyMean + 8;
- if (dx>15 || dx<0 || dy>15 || dy<0 ) {
- common->Error("writeFrame: FCC error %d,%d mean %d,%d at %d,%d,%d rmse %f\n", dx,dy, dxMean, dyMean,pquad[i].xat,pquad[i].yat,pquad[i].size, pquad[i].snr[FCC] );
- }
- cccList[onCCC++] = (dx<<4)+dy;
- break;
- case PAT:
- code = 2;
- cccList[onCCC++] = index4[pquad[i].patten[0]];
- break;
- case CCC:
- code = 3;
- cccList[onCCC++] = index2[pquad[i].patten[1]];
- cccList[onCCC++] = index2[pquad[i].patten[2]];
- cccList[onCCC++] = index2[pquad[i].patten[3]];
- cccList[onCCC++] = index2[pquad[i].patten[4]];
- break;
- case DEAD:
- common->Error("dead cels in picture\n");
- break;
- }
- if (code == -1) {
- common->Error( "writeFrame: an error occurred writing the frame\n");
- }
- action = (action<<2)|code;
- j++;
- if (j == 8) {
- j = 0;
- cccList[onAction+0] = (action & 0xff);
- cccList[onAction+1] = ((action >> 8) & 0xff);
- onAction = onCCC;
- onCCC += 2;
- }
- }
- }
- if (j) {
- action <<= ((8-j)*2);
- cccList[onAction+0] = (action & 0xff);
- cccList[onAction+1] = ((action >> 8) & 0xff);
- }
- direct = RoQ_QUAD_VQ;
-
- Write16Word( &direct, RoQFile);
- j = onCCC;
- Write32Word( &j, RoQFile);
- direct = dyMean;
- direct &= 0xff;
- direct += (dxMean<<8); // flags
- Write16Word( &direct, RoQFile);
- common->Printf("writeFrame: outputting %d bytes to RoQ_QUAD_VQ\n", j);
- previousSize = j;
-
- RoQFile->Write( cccList, onCCC );
- Mem_Free( cccList );
- Mem_Free( use2 );
- Mem_Free( use4 );
- }
- //
- // load a frame, create a window (if neccesary) and display the frame
- //
- void roq::LoadAndDisplayImage( const char * filename )
- {
- if (image) delete image;
- common->Printf("loadAndDisplayImage: %s\n", filename);
- currentFile = filename;
- image = new NSBitmapImageRep( filename );
-
- numQuadCels = ((image->pixelsWide() & 0xfff0)*(image->pixelsHigh() & 0xfff0))/(MINSIZE*MINSIZE);
- numQuadCels += numQuadCels/4 + numQuadCels/16;
- // if (paramFile->deltaFrames] == true && cleared == false && [image isPlanar] == false) {
- // cleared = true;
- // imageData = [image data];
- // memset( imageData, 0, image->pixelsWide()*image->pixelsHigh()*[image samplesPerPixel]);
- // }
-
- if (!quietMode) common->Printf("loadAndDisplayImage: %dx%d\n", image->pixelsWide(), image->pixelsHigh());
- }
- void roq::MarkQuadx( int xat, int yat, int size, float cerror, int choice ) {
- }
- NSBitmapImageRep* roq::CurrentImage( void )
- {
- return image;
- }
- int roq::NumberOfFrames( void ) {
- return numberOfFrames;
- }
- void RoQFileEncode_f( const idCmdArgs &args ) {
- if ( args.Argc() != 2 ) {
- common->Printf( "Usage: roq <paramfile>\n" );
- return;
- }
- theRoQ = new roq;
- int startMsec = Sys_Milliseconds();
- theRoQ->EncodeStream( args.Argv( 1 ) );
- int stopMsec = Sys_Milliseconds();
- common->Printf( "total encoding time: %i second\n", ( stopMsec - startMsec ) / 1000 );
- }
|