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