1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code ("Doom 3 Source Code").
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code.  If not, see <http://www.gnu.org/licenses/>.
21 
22 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.
23 
24 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.
25 
26 ===========================================================================
27 */
28 
29 #include "sys/platform.h"
30 #include "framework/FileSystem.h"
31 #include "framework/Session.h"
32 
33 #include "tools/compilers/roqvq/roq.h"
34 #include "tools/compilers/roqvq/codec.h"
35 
36 roq		*theRoQ;				// current roq file
37 
roq(void)38 roq::roq( void )
39 {
40 	image = 0;
41 	quietMode = false;
42 	encoder = 0;
43 	previousSize = 0;
44 	lastFrame = false;
45 	dataStuff=false;
46 }
47 
~roq(void)48 roq::~roq( void )
49 {
50 	if (image) delete image;
51 	if (encoder) delete encoder;
52 	return;
53 }
54 
EncodeQuietly(bool which)55 void roq::EncodeQuietly( bool which )
56 {
57 	quietMode = which;
58 }
59 
IsQuiet(void)60 bool roq::IsQuiet( void )
61 {
62 	return quietMode;
63 }
64 
IsLastFrame(void)65 bool roq::IsLastFrame( void )
66 {
67 	return lastFrame;
68 }
69 
Scaleable(void)70 bool roq::Scaleable( void )
71 {
72 	return paramFile->IsScaleable();
73 }
74 
ParamNoAlpha(void)75 bool roq::ParamNoAlpha( void )
76 {
77 	return paramFile->NoAlpha();
78 }
79 
MakingVideo(void)80 bool roq::MakingVideo( void )
81 {
82 	return true;	//paramFile->timecode];
83 }
84 
SearchType(void)85 bool roq::SearchType( void )
86 {
87 	return	paramFile->SearchType();
88 }
89 
HasSound(void)90 bool roq::HasSound( void )
91 {
92 	return	paramFile->HasSound();
93 }
94 
PreviousFrameSize(void)95 int roq::PreviousFrameSize( void )
96 {
97 	return	previousSize;
98 }
99 
FirstFrameSize(void)100 int roq::FirstFrameSize( void )
101 {
102 	return paramFile->FirstFrameSize();
103 }
104 
NormalFrameSize(void)105 int roq::NormalFrameSize( void )
106 {
107 	return	paramFile->NormalFrameSize();
108 }
109 
CurrentFilename(void)110 const char * roq::CurrentFilename( void )
111 {
112 	return currentFile.c_str();
113 }
114 
EncodeStream(const char * paramInputFile)115 void roq::EncodeStream( const char *paramInputFile )
116 {
117 	int		onFrame;
118 	idStr	f0, f1, f2;
119 	int		morestuff;
120 
121 	onFrame = 1;
122 
123 	encoder = new codec;
124 	paramFile = new roqParam;
125 	paramFile->numInputFiles = 0;
126 
127 	paramFile->InitFromFile( paramInputFile );
128 
129 	if (!paramFile->NumberOfFrames()) {
130 		return;
131 	}
132 
133 	InitRoQFile( paramFile->outputFilename);
134 
135 	numberOfFrames = paramFile->NumberOfFrames();
136 
137 	if (paramFile->NoAlpha()==true) common->Printf("encodeStream: eluding alpha\n");
138 
139 	f0 = "";
140 	f1 = paramFile->GetNextImageFilename();
141 	if (( paramFile->MoreFrames() == true )) {
142 		f2 = paramFile->GetNextImageFilename();
143 	}
144 	morestuff = numberOfFrames;
145 
146 	while( morestuff ) {
147 		LoadAndDisplayImage( f1 );
148 
149 		if (onFrame==1) {
150 			encoder->SparseEncode();
151 //			WriteLossless();
152 		} else {
153 			if (!strcmp( f0, f1 ) && strcmp( f1, f2) ) {
154 				WriteHangFrame();
155 			} else {
156 				encoder->SparseEncode();
157 			}
158 		}
159 
160 		onFrame++;
161 		f0 = f1;
162 		f1 = f2;
163 		if (paramFile->MoreFrames() == true) {
164 			f2 = paramFile->GetNextImageFilename();
165 		}
166 		morestuff--;
167 		session->UpdateScreen();
168 	}
169 
170 //	if (numberOfFrames != 1) {
171 //		if (image->hasAlpha() && paramFile->NoAlpha()==false) {
172 //			lastFrame = true;
173 //			encoder->SparseEncode();
174 //		} else {
175 //			WriteLossless();
176 //		}
177 //	}
178 	CloseRoQFile();
179 }
180 
Write16Word(word * aWord,idFile * stream)181 void roq::Write16Word( word *aWord, idFile *stream )
182 {
183 	byte	a, b;
184 
185 	a = *aWord & 0xff;
186 	b = *aWord >> 8;
187 
188 	stream->Write( &a, 1 );
189 	stream->Write( &b, 1 );
190 }
191 
Write32Word(unsigned int * aWord,idFile * stream)192 void roq::Write32Word( unsigned int *aWord, idFile *stream )
193 {
194 	byte	a, b, c, d;
195 
196 	a = *aWord & 0xff;
197 	b = (*aWord >> 8) & 0xff;
198 	c = (*aWord >> 16) & 0xff;
199 	d = (*aWord >> 24) & 0xff;
200 
201 	stream->Write( &a, 1 );
202 	stream->Write( &b, 1 );
203 	stream->Write( &c, 1 );
204 	stream->Write( &d, 1 );
205 }
206 
SizeFile(idFile * ftosize)207 int roq::SizeFile( idFile *ftosize )
208 {
209 	return ftosize->Length();
210 }
211 
212 #if 0
213 /* Expanded data destination object for stdio output */
214 
215 typedef struct {
216   struct jpeg_destination_mgr pub; /* public fields */
217 
218   byte* outfile;		/* target stream */
219   int	size;
220 } my_destination_mgr;
221 
222 typedef my_destination_mgr * my_dest_ptr;
223 
224 
225 /*
226  * Initialize destination --- called by jpeg_start_compress
227  * before any data is actually written.
228  */
229 
230 void roq::JPEGInitDestination (j_compress_ptr cinfo) {
231   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
232 
233   dest->pub.next_output_byte = dest->outfile;
234   dest->pub.free_in_buffer = dest->size;
235 }
236 
237 
238 /*
239  * Empty the output buffer --- called whenever buffer fills up.
240  *
241  * In typical applications, this should write the entire output buffer
242  * (ignoring the current state of next_output_byte & free_in_buffer),
243  * reset the pointer & count to the start of the buffer, and return true
244  * indicating that the buffer has been dumped.
245  *
246  * In applications that need to be able to suspend compression due to output
247  * overrun, a FALSE return indicates that the buffer cannot be emptied now.
248  * In this situation, the compressor will return to its caller (possibly with
249  * an indication that it has not accepted all the supplied scanlines).  The
250  * application should resume compression after it has made more room in the
251  * output buffer.  Note that there are substantial restrictions on the use of
252  * suspension --- see the documentation.
253  *
254  * When suspending, the compressor will back up to a convenient restart point
255  * (typically the start of the current MCU). next_output_byte & free_in_buffer
256  * indicate where the restart point will be if the current call returns FALSE.
257  * Data beyond this point will be regenerated after resumption, so do not
258  * write it out when emptying the buffer externally.
259  */
260 
261 boolean roq::JPEGEmptyOutputBuffer (j_compress_ptr cinfo) {
262   return true;
263 }
264 
265 
266 /*
267  * Compression initialization.
268  * Before calling this, all parameters and a data destination must be set up.
269  *
270  * We require a write_all_tables parameter as a failsafe check when writing
271  * multiple datastreams from the same compression object.  Since prior runs
272  * will have left all the tables marked sent_table=true, a subsequent run
273  * would emit an abbreviated stream (no tables) by default.  This may be what
274  * is wanted, but for safety's sake it should not be the default behavior:
275  * programmers should have to make a deliberate choice to emit abbreviated
276  * images.  Therefore the documentation and examples should encourage people
277  * to pass write_all_tables=true; then it will take active thought to do the
278  * wrong thing.
279  */
280 
281 void roq::JPEGStartCompress (j_compress_ptr cinfo, bool write_all_tables) {
282   if (cinfo->global_state != CSTATE_START)
283 	ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
284 
285   if (write_all_tables)
286 	jpeg_suppress_tables(cinfo, FALSE);	/* mark all tables to be written */
287 
288   /* (Re)initialize error mgr and destination modules */
289   (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo);
290   (*cinfo->dest->init_destination) (cinfo);
291   /* Perform master selection of active modules */
292   jinit_compress_master(cinfo);
293   /* Set up for the first pass */
294   (*cinfo->master->prepare_for_pass) (cinfo);
295   /* Ready for application to drive first pass through jpeg_write_scanlines
296    * or jpeg_write_raw_data.
297    */
298   cinfo->next_scanline = 0;
299   cinfo->global_state = (cinfo->raw_data_in ? CSTATE_RAW_OK : CSTATE_SCANNING);
300 }
301 
302 
303 /*
304  * Write some scanlines of data to the JPEG compressor.
305  *
306  * The return value will be the number of lines actually written.
307  * This should be less than the supplied num_lines only in case that
308  * the data destination module has requested suspension of the compressor,
309  * or if more than image_height scanlines are passed in.
310  *
311  * Note: we warn about excess calls to jpeg_write_scanlines() since
312  * this likely signals an application programmer error.  However,
313  * excess scanlines passed in the last valid call are *silently* ignored,
314  * so that the application need not adjust num_lines for end-of-image
315  * when using a multiple-scanline buffer.
316  */
317 
318 JDIMENSION roq::JPEGWriteScanlines (j_compress_ptr cinfo, JSAMPARRAY scanlines, JDIMENSION num_lines) {
319   JDIMENSION row_ctr, rows_left;
320 
321   if (cinfo->global_state != CSTATE_SCANNING)
322 	ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state);
323   if (cinfo->next_scanline >= cinfo->image_height)
324 	WARNMS(cinfo, JWRN_TOO_MUCH_DATA);
325 
326   /* Call progress monitor hook if present */
327   if (cinfo->progress != NULL) {
328 	cinfo->progress->pass_counter = (long) cinfo->next_scanline;
329 	cinfo->progress->pass_limit = (long) cinfo->image_height;
330 	(*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo);
331   }
332 
333   /* Give master control module another chance if this is first call to
334    * jpeg_write_scanlines.  This lets output of the frame/scan headers be
335    * delayed so that application can write COM, etc, markers between
336    * jpeg_start_compress and jpeg_write_scanlines.
337    */
338   if (cinfo->master->call_pass_startup)
339 	(*cinfo->master->pass_startup) (cinfo);
340 
341   /* Ignore any extra scanlines at bottom of image. */
342   rows_left = cinfo->image_height - cinfo->next_scanline;
343   if (num_lines > rows_left)
344 	num_lines = rows_left;
345 
346   row_ctr = 0;
347   (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, num_lines);
348   cinfo->next_scanline += row_ctr;
349   return row_ctr;
350 }
351 
352 /*
353  * Terminate destination --- called by jpeg_finish_compress
354  * after all data has been written.  Usually needs to flush buffer.
355  *
356  * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding
357  * application must deal with any cleanup that should happen even
358  * for error exit.
359  */
360 
361 static int hackSize;
362 
363 void roq::JPEGTermDestination (j_compress_ptr cinfo) {
364   my_dest_ptr dest = (my_dest_ptr) cinfo->dest;
365   size_t datacount = dest->size - dest->pub.free_in_buffer;
366   hackSize = datacount;
367 }
368 
369 
370 /*
371  * Prepare for output to a stdio stream.
372  * The caller must have already opened the stream, and is responsible
373  * for closing it after finishing compression.
374  */
375 
376 void roq::JPEGDest (j_compress_ptr cinfo, byte* outfile, int size) {
377   my_dest_ptr dest;
378 
379   /* The destination object is made permanent so that multiple JPEG images
380    * can be written to the same file without re-executing jpeg_stdio_dest.
381    * This makes it dangerous to use this manager and a different destination
382    * manager serially with the same JPEG object, because their private object
383    * sizes may be different.  Caveat programmer.
384    */
385   if (cinfo->dest == NULL) {	/* first time for this JPEG object? */
386 	cinfo->dest = (struct jpeg_destination_mgr *)
387 	  (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
388 				  sizeof(my_destination_mgr));
389   }
390 
391   dest = (my_dest_ptr) cinfo->dest;
392   dest->pub.init_destination = JPEGInitDestination;
393   dest->pub.empty_output_buffer = JPEGEmptyOutputBuffer;
394   dest->pub.term_destination = JPEGTermDestination;
395   dest->outfile = outfile;
396   dest->size = size;
397 }
398 
399 void roq::WriteLossless( void ) {
400 
401 	word direct;
402 	uint directdw;
403 
404 	if (!dataStuff) {
405 		InitRoQPatterns();
406 		dataStuff=true;
407 	}
408 	direct = RoQ_QUAD_JPEG;
409 	Write16Word( &direct, RoQFile);
410 
411 	/* This struct contains the JPEG compression parameters and pointers to
412 	* working space (which is allocated as needed by the JPEG library).
413 	* It is possible to have several such structures, representing multiple
414 	* compression/decompression processes, in existence at once.  We refer
415 	* to any one struct (and its associated working data) as a "JPEG object".
416 	*/
417 	struct jpeg_compress_struct cinfo;
418 	/* This struct represents a JPEG error handler.  It is declared separately
419 	* because applications often want to supply a specialized error handler
420 	* (see the second half of this file for an example).  But here we just
421 	* take the easy way out and use the standard error handler, which will
422 	* print a message on stderr and call exit() if compression fails.
423 	* Note that this struct must live as long as the main JPEG parameter
424 	* struct, to avoid dangling-pointer problems.
425 	*/
426 	struct jpeg_error_mgr jerr;
427 	/* More stuff */
428 	JSAMPROW row_pointer[1];	/* pointer to JSAMPLE row[s] */
429 	int row_stride;		/* physical row width in image buffer */
430 	byte *out;
431 
432 	/* Step 1: allocate and initialize JPEG compression object */
433 
434 	/* We have to set up the error handler first, in case the initialization
435 	* step fails.  (Unlikely, but it could happen if you are out of memory.)
436 	* This routine fills in the contents of struct jerr, and returns jerr's
437 	* address which we place into the link field in cinfo.
438 	*/
439 	cinfo.err = jpeg_std_error(&jerr);
440 	/* Now we can initialize the JPEG compression object. */
441 	jpeg_create_compress(&cinfo);
442 
443 	/* Step 2: specify data destination (eg, a file) */
444 	/* Note: steps 2 and 3 can be done in either order. */
445 
446 	/* Here we use the library-supplied code to send compressed data to a
447 	* stdio stream.  You can also write your own code to do something else.
448 	* VERY IMPORTANT: use "b" option to fopen() if you are on a machine that
449 	* requires it in order to write binary files.
450 	*/
451 	out = (byte *)Mem_Alloc(image->pixelsWide()*image->pixelsHigh()*4);
452 	JPEGDest(&cinfo, out, image->pixelsWide()*image->pixelsHigh()*4);
453 
454 	/* Step 3: set parameters for compression */
455 
456 	/* First we supply a description of the input image.
457 	* Four fields of the cinfo struct must be filled in:
458 	*/
459 	cinfo.image_width = image->pixelsWide();	/* image width and height, in pixels */
460 	cinfo.image_height = image->pixelsHigh();
461 	cinfo.input_components = 4;		/* # of color components per pixel */
462 	cinfo.in_color_space = JCS_RGB;	/* colorspace of input image */
463 	/* Now use the library's routine to set default compression parameters.
464 	* (You must set at least cinfo.in_color_space before calling this,
465 	* since the defaults depend on the source color space.)
466 	*/
467 	jpeg_set_defaults(&cinfo);
468 	/* Now you can set any non-default parameters you wish to.
469 	* Here we just illustrate the use of quality (quantization table) scaling:
470 	*/
471 	jpeg_set_quality(&cinfo, paramFile->JpegQuality(), true /* limit to baseline-JPEG values */);
472 
473 	/* Step 4: Start compressor */
474 
475 	/* true ensures that we will write a complete interchange-JPEG file.
476 	* Pass true unless you are very sure of what you're doing.
477 	*/
478 	JPEGStartCompress(&cinfo, true);
479 
480 	/* Step 5: while (scan lines remain to be written) */
481 	/*           jpeg_write_scanlines(...); */
482 
483 	/* Here we use the library's state variable cinfo.next_scanline as the
484 	* loop counter, so that we don't have to keep track ourselves.
485 	* To keep things simple, we pass one scanline per call; you can pass
486 	* more if you wish, though.
487 	*/
488 	row_stride = image->pixelsWide() * 4;	/* JSAMPLEs per row in image_buffer */
489 
490 	byte *pixbuf = image->bitmapData();
491 	while (cinfo.next_scanline < cinfo.image_height) {
492 		/* jpeg_write_scanlines expects an array of pointers to scanlines.
493 		 * Here the array is only one element long, but you could pass
494 		 * more than one scanline at a time if that's more convenient.
495 		 */
496 		row_pointer[0] = &pixbuf[((cinfo.image_height-1)*row_stride)-cinfo.next_scanline * row_stride];
497 		(void) JPEGWriteScanlines(&cinfo, row_pointer, 1);
498 	}
499 
500 	/* Step 6: Finish compression */
501 
502 	jpeg_finish_compress(&cinfo);
503 	/* After finish_compress, we can close the output file. */
504 
505 	directdw = hackSize;
506 	common->Printf("writeLossless: writing %d bytes to RoQ_QUAD_JPEG\n", hackSize);
507 	Write32Word( &directdw, RoQFile );
508 	direct = 0;		// flags
509 	Write16Word( &direct, RoQFile );
510 
511 	RoQFile->Write( out, hackSize );
512 	Mem_Free(out);
513 
514 	/* Step 7: release JPEG compression object */
515 
516 	/* This is an important step since it will release a good deal of memory. */
517 	jpeg_destroy_compress(&cinfo);
518 
519 	/* And we're done! */
520 	encoder->SetPreviousImage( "first frame", image );
521 }
522 #endif
523 
InitRoQFile(const char * RoQFilename)524 void roq::InitRoQFile( const char *RoQFilename )
525 {
526 	word i;
527 	static int finit = 0;
528 
529 	if (!finit) {
530 		finit++;
531 		common->Printf("initRoQFile: %s\n", RoQFilename);
532 		RoQFile = fileSystem->OpenFileWrite( RoQFilename );
533 //		chmod(RoQFilename, S_IREAD|S_IWRITE|S_ISUID|S_ISGID|0070|0007 );
534 		if ( !RoQFile ) {
535 			common->Error("Unable to open output file %s.\n", RoQFilename);
536 		}
537 
538 		i = RoQ_ID;
539 		Write16Word( &i, RoQFile );
540 
541 		i = 0xffff;
542 		Write16Word( &i, RoQFile );
543 		Write16Word( &i, RoQFile );
544 
545 		// to retain exact file format write out 32 for new roq's
546 		// on loading this will be noted and converted to 1000 / 30
547 		// as with any new sound dump avi demos we need to playback
548 		// at the speed the sound engine dumps the audio
549 		i = 30;						// framerate
550 		Write16Word( &i, RoQFile );
551 	}
552 	roqOutfile = RoQFilename;
553 }
554 
InitRoQPatterns(void)555 void roq::InitRoQPatterns( void )
556 {
557 uint j;
558 word direct;
559 
560 	direct = RoQ_QUAD_INFO;
561 	Write16Word( &direct, RoQFile );
562 
563 	j = 8;
564 
565 	Write32Word( &j, RoQFile );
566 	common->Printf("initRoQPatterns: outputting %d bytes to RoQ_INFO\n", j);
567 	direct = image->hasAlpha();
568 	if (ParamNoAlpha() == true) direct = 0;
569 
570 	Write16Word( &direct, RoQFile );
571 
572 	direct = image->pixelsWide();
573 	Write16Word( &direct, RoQFile );
574 	direct = image->pixelsHigh();
575 	Write16Word( &direct, RoQFile );
576 	direct = 8;
577 	Write16Word( &direct, RoQFile );
578 	direct = 4;
579 	Write16Word( &direct, RoQFile );
580 }
581 
CloseRoQFile(void)582 void roq::CloseRoQFile( void )
583 {
584 	common->Printf("closeRoQFile: closing RoQ file\n");
585 	fileSystem->CloseFile( RoQFile );
586 }
587 
WriteHangFrame(void)588 void roq::WriteHangFrame( void )
589 {
590 uint j;
591 word direct;
592 	common->Printf("*******************************************************************\n");
593 	direct = RoQ_QUAD_HANG;
594 	Write16Word( &direct, RoQFile);
595 	j = 0;
596 	Write32Word( &j, RoQFile);
597 	direct = 0;
598 	Write16Word( &direct, RoQFile);
599 }
600 
WriteCodeBookToStream(byte * codebook,int csize,word cflags)601 void roq::WriteCodeBookToStream( byte *codebook, int csize, word cflags )
602 {
603 uint j;
604 word direct;
605 
606 	if (!csize) {
607 		common->Printf("writeCodeBook: false VQ DATA!!!!\n");
608 		return;
609 	}
610 
611 	direct = RoQ_QUAD_CODEBOOK;
612 
613 	Write16Word( &direct, RoQFile);
614 
615 	j = csize;
616 
617 	Write32Word( &j, RoQFile);
618 	common->Printf("writeCodeBook: outputting %d bytes to RoQ_QUAD_CODEBOOK\n", j);
619 
620 	direct = cflags;
621 	Write16Word( &direct, RoQFile);
622 
623 	RoQFile->Write( codebook, j );
624 }
625 
WriteCodeBook(byte * codebook)626 void roq::WriteCodeBook( byte *codebook )
627 {
628 	memcpy( codes, codebook, 4096 );
629 }
630 
WriteFrame(quadcel * pquad)631 void roq::WriteFrame( quadcel *pquad )
632 {
633 word action, direct;
634 int	onCCC, onAction, i, code;
635 uint j;
636 byte *cccList;
637 bool *use2, *use4;
638 int dx,dy,dxMean,dyMean,index2[256],index4[256], dimension;
639 
640 	cccList = (byte *)Mem_Alloc( numQuadCels * 8);					// maximum length
641 	use2 = (bool *)Mem_Alloc(256*sizeof(bool));
642 	use4 = (bool *)Mem_Alloc(256*sizeof(bool));
643 
644 	for(i=0;i<256;i++) {
645 		use2[i] = false;
646 		use4[i] = false;
647 	}
648 
649 	action = 0;
650 	j = onAction = 0;
651 	onCCC = 2;											// onAction going to go at zero
652 
653 	dxMean = encoder->MotMeanX();
654 	dyMean = encoder->MotMeanY();
655 
656 	if (image->hasAlpha()) dimension = 10; else dimension = 6;
657 
658 	for (i=0; i<numQuadCels; i++) {
659 	if ( pquad[i].size && pquad[i].size < 16 ) {
660 		switch( pquad[i].status ) {
661 			case	SLD:
662 				use4[pquad[i].patten[0]] = true;
663 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = true;
664 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = true;
665 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = true;
666 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = true;
667 				break;
668 			case	PAT:
669 				use4[pquad[i].patten[0]] = true;
670 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+0]] = true;
671 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+1]] = true;
672 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+2]] = true;
673 				use2[codes[dimension*256+(pquad[i].patten[0]*4)+3]] = true;
674 				break;
675 			case	CCC:
676 				use2[pquad[i].patten[1]] = true;
677 				use2[pquad[i].patten[2]] = true;
678 				use2[pquad[i].patten[3]] = true;
679 				use2[pquad[i].patten[4]] = true;
680 		}
681 	}
682 	}
683 
684 	if (!dataStuff) {
685 		dataStuff=true;
686 		InitRoQPatterns();
687 		if (image->hasAlpha()) i = 3584; else i = 2560;
688 		WriteCodeBookToStream( codes, i, 0 );
689 		for(i=0;i<256;i++) {
690 			index2[i] = i;
691 			index4[i] = i;
692 		}
693 	} else {
694 		j = 0;
695 		for(i=0;i<256;i++) {
696 			if (use2[i]) {
697 				index2[i] = j;
698 				for(dx=0;dx<dimension;dx++) cccList[j*dimension+dx] = codes[i*dimension+dx];
699 				j++;
700 			}
701 		}
702 		code = j*dimension;
703 		direct = j;
704 		common->Printf("writeFrame: really used %d 2x2 cels\n", j);
705 		j = 0;
706 		for(i=0;i<256;i++) {
707 			if (use4[i]) {
708 				index4[i] = j;
709 				for(dx=0;dx<4;dx++) cccList[j*4+code+dx] = index2[codes[i*4+(dimension*256)+dx]];
710 				j++;
711 			}
712 		}
713 		code += j*4;
714 		direct = (direct<<8) + j;
715 		common->Printf("writeFrame: really used %d 4x4 cels\n", j);
716 		if (image->hasAlpha()) i = 3584; else i = 2560;
717 		if ( code == i || j == 256) {
718 			WriteCodeBookToStream( codes, i, 0 );
719 		} else {
720 			WriteCodeBookToStream( cccList, code, direct );
721 		}
722 	}
723 
724 	action = 0;
725 	j = onAction = 0;
726 
727 	for (i=0; i<numQuadCels; i++) {
728 	if ( pquad[i].size && pquad[i].size < 16 ) {
729 		code = -1;
730 		switch( pquad[i].status ) {
731 			case	DEP:
732 				code = 3;
733 				break;
734 			case	SLD:
735 				code = 2;
736 				cccList[onCCC++] = index4[pquad[i].patten[0]];
737 				break;
738 			case	MOT:
739 				code = 0;
740 				break;
741 			case	FCC:
742 				code = 1;
743 				dx = ((pquad[i].domain >> 8  )) - 128 - dxMean + 8;
744 				dy = ((pquad[i].domain & 0xff)) - 128 - dyMean + 8;
745 				if (dx>15 || dx<0 || dy>15 || dy<0 ) {
746 					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] );
747 				}
748 				cccList[onCCC++] = (dx<<4)+dy;
749 				break;
750 			case	PAT:
751 				code = 2;
752 				cccList[onCCC++] = index4[pquad[i].patten[0]];
753 				break;
754 			case	CCC:
755 				code = 3;
756 				cccList[onCCC++] = index2[pquad[i].patten[1]];
757 				cccList[onCCC++] = index2[pquad[i].patten[2]];
758 				cccList[onCCC++] = index2[pquad[i].patten[3]];
759 				cccList[onCCC++] = index2[pquad[i].patten[4]];
760 				break;
761 			case	DEAD:
762 				common->Error("dead cels in picture\n");
763 				break;
764 		}
765 		if (code == -1) {
766 			common->Error( "writeFrame: an error occurred writing the frame\n");
767 		}
768 
769 		action = (action<<2)|code;
770 		j++;
771 		if (j == 8) {
772 			j = 0;
773 			cccList[onAction+0] = (action & 0xff);
774 			cccList[onAction+1] = ((action >> 8) & 0xff);
775 			onAction = onCCC;
776 			onCCC += 2;
777 		}
778 	}
779 	}
780 
781 	if (j) {
782 		action <<= ((8-j)*2);
783 		cccList[onAction+0] = (action & 0xff);
784 		cccList[onAction+1] = ((action >> 8) & 0xff);
785 	}
786 
787 	direct = RoQ_QUAD_VQ;
788 
789 	Write16Word( &direct, RoQFile);
790 
791 	j = onCCC;
792 	Write32Word( &j, RoQFile);
793 
794 	direct  = dyMean;
795 	direct &= 0xff;
796 	direct += (dxMean<<8);		// flags
797 
798 	Write16Word( &direct, RoQFile);
799 
800 	common->Printf("writeFrame: outputting %d bytes to RoQ_QUAD_VQ\n", j);
801 
802 	previousSize = j;
803 
804 	RoQFile->Write( cccList, onCCC );
805 
806 	Mem_Free( cccList );
807 	Mem_Free( use2 );
808 	Mem_Free( use4 );
809 }
810 
811 //
812 // load a frame, create a window (if neccesary) and display the frame
813 //
LoadAndDisplayImage(const char * filename)814 void roq::LoadAndDisplayImage( const char * filename )
815 {
816 	if (image) delete image;
817 
818 	common->Printf("loadAndDisplayImage: %s\n", filename);
819 
820 	currentFile = filename;
821 
822 	image = new NSBitmapImageRep( filename );
823 
824 	numQuadCels  = ((image->pixelsWide() & 0xfff0)*(image->pixelsHigh() & 0xfff0))/(MINSIZE*MINSIZE);
825 	numQuadCels += numQuadCels/4 + numQuadCels/16;
826 
827 //	if (paramFile->deltaFrames] == true && cleared == false && [image isPlanar] == false) {
828 //		cleared = true;
829 //		imageData = [image data];
830 //		memset( imageData, 0, image->pixelsWide()*image->pixelsHigh()*[image samplesPerPixel]);
831 //	}
832 
833 	if (!quietMode) common->Printf("loadAndDisplayImage: %dx%d\n", image->pixelsWide(), image->pixelsHigh());
834 }
835 
MarkQuadx(int xat,int yat,int size,float cerror,int choice)836 void roq::MarkQuadx( int xat, int yat, int size, float cerror, int choice ) {
837 }
838 
CurrentImage(void)839 NSBitmapImageRep* roq::CurrentImage( void )
840 {
841 	return	image;
842 }
843 
NumberOfFrames(void)844 int roq::NumberOfFrames( void ) {
845 	return numberOfFrames;
846 }
847 
RoQFileEncode_f(const idCmdArgs & args)848 void RoQFileEncode_f( const idCmdArgs &args ) {
849 	if ( args.Argc() != 2 ) {
850 		common->Printf( "Usage: roq <paramfile>\n" );
851 		return;
852 	}
853 	theRoQ = new roq;
854 	int		startMsec = Sys_Milliseconds();
855 	theRoQ->EncodeStream( args.Argv( 1 ) );
856 	int		stopMsec = Sys_Milliseconds();
857 	common->Printf( "total encoding time: %i second\n", ( stopMsec - startMsec ) / 1000 );
858 
859 }
860