2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
4 * All source code herein is the property of Volition, Inc. You may not sell
5 * or otherwise commercially exploit the source or things you created based on
10 * $Logfile: /Freespace2/code/AC/convert.cpp $
15 * C module for the conversion of standard animation files to our own ANIM format.
16 * This is where all the real code for this application is located really.
19 * Revision 1.2 2002/06/09 04:41:15 relnev
20 * added copyright header
22 * Revision 1.1.1.1 2002/05/03 03:28:11 root
26 * 2 10/23/98 6:03p Dave
28 * 1 10/23/98 5:34p Dave
30 * 3 10/22/98 6:14p Dave
31 * Optimized some #includes in Anim folder. Put in the beginnings of
32 * parse/localization support for externalized strings and tstrings.tbl
34 * 2 10/07/98 10:52a Dave
37 * 1 10/07/98 10:48a Dave
39 * 12 6/23/98 2:52p Hoffoss
40 * Changed code so AC compiles once again.
42 * 11 7/20/97 6:57p Lawrance
43 * supporting new RLE format
45 * 10 6/25/97 11:57a Lawrance
48 * 9 6/25/97 11:49a Lawrance
49 * don't assert if PCX read fails, print warning
51 * 8 5/21/97 2:26p Lawrance
52 * bug fix: not using correct header size
54 * 7 5/21/97 11:06a Lawrance
55 * enabling a user-defined transparent value
57 * 6 5/19/97 3:21p Lawrance
58 * add fps parm, version num to anim header
60 * 5 2/25/97 5:18p Lawrance
61 * force_key_frame now numbering from 1 for PCXs as well as AVIs
63 * 4 2/20/97 1:47p Lawrance
64 * adding dots when making frames
66 * 3 2/20/97 10:30a Hoffoss
67 * Added in support for forcing a key frame.
69 * 2 2/19/97 9:26p Lawrance
70 * added force_key_frame global
72 * 1 2/19/97 7:14p Lawrance
74 * 14 2/19/97 4:21p Lawrance
75 * took out unnecessary #include BmpMan.h
77 * 13 2/19/97 3:59p Lawrance
78 * using pcxutils to load bitmaps, not bmpman
80 * 12 2/17/97 2:59p Lawrance
81 * integrating into game
83 * 11 2/17/97 3:02p Hoffoss
84 * Added headers to files, and implemented key frame dialog stuff.
86 * 10 2/14/97 10:38p Lawrance
89 * 9 2/14/97 9:47p Hoffoss
92 * 8 2/14/97 8:44p Lawrance
93 * fixed bug with saving header
95 * 7 2/14/97 8:04p Hoffoss
98 * 6 2/14/97 7:44p Lawrance
99 * fixed some bugs in loading an AVI
101 * 5 2/14/97 7:33p Lawrance
102 * added convert_avi_to_anim() function
104 * 4 2/14/97 5:38p Hoffoss
105 * Changes to get AnimCoverter project to compile and link.
107 * 3 2/14/97 3:28p Hoffoss
108 * Wrote functions to save an anim file.
110 * 2 2/13/97 5:55p Lawrance
111 * reading AVI / decompressing AVI functions in
119 #include "pcxutils.h"
120 #include "animplay.h"
121 #include "packunpack.h"
123 #define AVI_STREAM_F_USED ( 1 << 0 )
125 typedef struct _frame_index {
130 typedef struct AVI_STREAM_TYPE {
132 FRAMEINDEX *frame_index;
136 int min_compressed_buffer_size;
139 //ubyte pal_translation[256]; // palette translation look-up table
143 #define AVIF_HASINDEX 0x00000010
145 typedef struct _avimainheader {
148 unsigned int dwMicroSecPerFrame;
149 unsigned int dwMaxBytesPerSec;
150 unsigned int dwPaddingGranularity;
151 unsigned int dwFlags;
152 unsigned int dwTotalFrames;
153 unsigned int dwInitialFrames;
154 unsigned int dwStreams;
155 unsigned int dwSuggestedBufferSize;
156 unsigned int dwWidth;
157 unsigned int dwHeight;
158 unsigned int dwReserved[4];
161 #define AVISF_VIDEO_PALCHANGES 0x00010000
163 typedef struct _avistreamheader {
166 unsigned int fccType;
167 unsigned int fccHandler;
168 unsigned int dwFlags;
169 unsigned short wPriority;
170 unsigned short wLanguage;
171 unsigned int dwInitialFrames;
172 unsigned int dwScale;
174 unsigned int dwStart;
175 unsigned int dwLength;
176 unsigned int dwSuggestedBufferSize;
177 unsigned int dwQuality;
178 unsigned int dwSampleSize;
187 #define BI_RLE8 0x00000001
189 typedef struct _bitmapinfo {
194 unsigned short biPlanes;
195 unsigned short biBitCount;
196 unsigned int biCompression;
197 unsigned int biSizeImage;
200 unsigned int biClrUsed;
201 unsigned int biClrImportant;
213 // Internal function prototypes
214 int AVI_stream_open(char* filename);
215 void AVI_stream_close();
216 int AVI_stream_get_frame(ubyte* buffer, int frame_number);
217 void AVI_decompress_RLE8(ubyte* src, ubyte* dest, int w, int h);
220 static AVI_STREAM_TYPE AVI_stream;
221 static int AVI_stream_inited = 0;
224 char *anim_save_filename;
225 ubyte *cur_frame, *last_frame;
226 ubyte anim_buffer[ANIM_BUFFER_MAX];
229 int total_key_frames;
233 int Use_custom_xparent_color;
234 rgb_triple Xparent_color;
236 int Compression_type; // what kind of RLE compression is going to be used
237 int Key_frame_compression, Regular_frame_compression;
239 key_frame *first_frame;
240 FILE *anim_fp = NULL;
243 // AVI_stream_init() is called only to clear USED flag of the AVI_stream structure
244 // and reset the current frame.
246 // This does not need to be called explicity, since it will be called by AVI_stream_open()
249 void AVI_stream_init()
251 AVI_stream.flags &= ~AVI_STREAM_F_USED;
252 AVI_stream.current_frame = 0;
253 AVI_stream_inited = 1;
255 AVI_stream.pfile = NULL;
256 AVI_stream.frame_index = NULL;
259 #define FREAD(a, b, c, d) do { if ( fread(a, b, c, d) != b ) { read_error = true; break; } } while (0);
261 // AVI_stream_open() will open the AVI file and prepare it for reading, but will not
262 // store any of the frame data.
264 // returns: 0 ==> success
265 // !0 ==> could not open the AVI stream
267 // The filename is expected to be an absolute pathname (or file in the current working directory)
269 int AVI_stream_open(char* filename)
271 if ( !AVI_stream_inited )
276 unsigned int tag = 0, size = 0;
277 unsigned int s_tag, tmp;
278 AVIMAINHEADER avi_header;
279 AVISTREAMHEADER stream_header;
280 BITMAPINFO bitmap_header;
281 long file_size = 0, movi_offset = 0, next_chunk;
283 SDL_assert( !(AVI_stream.flags & AVI_STREAM_F_USED) );
285 SDL_zero(avi_header);
286 SDL_zero(stream_header);
287 SDL_zero(bitmap_header);
289 pfile = fopen(filename, "rb");
292 printf("AVI ==> Unable to open %s", filename);
297 fseek(pfile, 0, SEEK_END);
298 file_size = ftell(pfile);
299 fseek(pfile, 0, SEEK_SET);
301 // check for valid file type
302 if ( fread(&id, 1, 4, pfile) != 4 ) {
303 printf("AVI => File read ERROR '%s'\n", filename);
311 if (id != 0x46464952) {
312 printf("Not a RIFF file '%s'\n", filename);
318 if ( fread(&id, 1, 4, pfile) != 4 ) {
319 printf("AVI => File read ERROR '%s'\n", filename);
324 // check for valid RIFF type
325 if ( fread(&id, 1, 4, pfile) != 4 ) {
326 printf("AVI => File read ERROR '%s'\n", filename);
334 if (id != 0x20495641) {
335 printf("Not an AVI file '%s'\n", filename);
340 // used for main 'LIST' chunks
344 bool read_error = false;
347 while ( ftell(pfile) < file_size ) {
348 FREAD(&tag, 1, 4, pfile);
349 FREAD(&size, 1, 4, pfile);
351 tag = INTEL_INT(tag);
352 size = INTEL_INT(size);
354 next_chunk = ftell(pfile) + size;
360 FREAD(&s_tag, 1, 4, pfile);
361 s_tag = INTEL_INT(s_tag);
366 FREAD(&avi_header.fcc, 1, sizeof(int), pfile);
367 FREAD(&avi_header.cb, 1, sizeof(int), pfile);
368 FREAD(&avi_header.dwMicroSecPerFrame, 1, sizeof(int), pfile);
369 FREAD(&avi_header.dwMaxBytesPerSec, 1, sizeof(int), pfile);
370 FREAD(&avi_header.dwPaddingGranularity, 1, sizeof(int), pfile);
371 FREAD(&avi_header.dwFlags, 1, sizeof(int), pfile);
372 FREAD(&avi_header.dwTotalFrames, 1, sizeof(int), pfile);
373 FREAD(&avi_header.dwInitialFrames, 1, sizeof(int), pfile);
374 FREAD(&avi_header.dwStreams, 1, sizeof(int), pfile);
375 FREAD(&avi_header.dwSuggestedBufferSize, 1, sizeof(int), pfile);
376 FREAD(&avi_header.dwWidth, 1, sizeof(int), pfile);
377 FREAD(&avi_header.dwHeight, 1, sizeof(int), pfile);
378 FREAD(&avi_header.dwReserved, 1, sizeof(avi_header.dwReserved), pfile);
380 avi_header.fcc = INTEL_INT(avi_header.fcc);
381 avi_header.cb = INTEL_INT(avi_header.cb);
382 avi_header.dwMicroSecPerFrame = INTEL_INT(avi_header.dwMicroSecPerFrame);
383 avi_header.dwMaxBytesPerSec = INTEL_INT(avi_header.dwMaxBytesPerSec);
384 avi_header.dwPaddingGranularity = INTEL_INT(avi_header.dwPaddingGranularity);
385 avi_header.dwFlags = INTEL_INT(avi_header.dwFlags);
386 avi_header.dwTotalFrames = INTEL_INT(avi_header.dwTotalFrames);
387 avi_header.dwInitialFrames = INTEL_INT(avi_header.dwInitialFrames);
388 avi_header.dwStreams = INTEL_INT(avi_header.dwStreams);
389 avi_header.dwSuggestedBufferSize = INTEL_INT(avi_header.dwSuggestedBufferSize);
390 avi_header.dwWidth = INTEL_INT(avi_header.dwWidth);
391 avi_header.dwHeight = INTEL_INT(avi_header.dwHeight);
394 SDL_assert(avi_header.fcc == 0x68697661);
396 // we're stupid, can only handle a single stream
397 if (avi_header.dwStreams != 1) {
398 printf("AVI has more than one stream '%s'\n", filename);
403 // require index chunk (should be flagged as availble)
404 if ( !(avi_header.dwFlags & AVIF_HASINDEX) ) {
405 printf("AVI does not have index '%s'\n", filename);
410 // update next_chunk offset for sub-chunk
411 offset_tmp = next_chunk;
412 next_chunk = ftell(pfile);
417 // 'strl' - subchunk of 'hdrl'
419 FREAD(&stream_header.fcc, 1, sizeof(int), pfile);
420 FREAD(&stream_header.cb, 1, sizeof(int), pfile);
421 FREAD(&stream_header.fccType, 1, sizeof(int), pfile);
422 FREAD(&stream_header.fccHandler, 1, sizeof(int), pfile);
423 FREAD(&stream_header.dwFlags, 1, sizeof(int), pfile);
424 FREAD(&stream_header.wPriority, 1, sizeof(short), pfile);
425 FREAD(&stream_header.wLanguage, 1, sizeof(short), pfile);
426 FREAD(&stream_header.dwInitialFrames, 1, sizeof(int), pfile);
427 FREAD(&stream_header.dwScale, 1, sizeof(int), pfile);
428 FREAD(&stream_header.dwRate, 1, sizeof(int), pfile);
429 FREAD(&stream_header.dwStart, 1, sizeof(int), pfile);
430 FREAD(&stream_header.dwLength, 1, sizeof(int), pfile);
431 FREAD(&stream_header.dwSuggestedBufferSize, 1, sizeof(int), pfile);
432 FREAD(&stream_header.dwQuality, 1, sizeof(int), pfile);
433 FREAD(&stream_header.dwSampleSize, 1, sizeof(int), pfile);
434 FREAD(&stream_header.rcFrame.left, 1, sizeof(short), pfile);
435 FREAD(&stream_header.rcFrame.top, 1, sizeof(short), pfile);
436 FREAD(&stream_header.rcFrame.right, 1, sizeof(short), pfile);
437 FREAD(&stream_header.rcFrame.bottom, 1, sizeof(short), pfile);
439 stream_header.fcc = INTEL_INT(stream_header.fcc);
440 stream_header.cb = INTEL_INT(stream_header.cb);
441 stream_header.fccType = INTEL_INT(stream_header.fccType);
442 stream_header.fccHandler = INTEL_INT(stream_header.fccHandler);
443 stream_header.dwFlags = INTEL_INT(stream_header.dwFlags);
444 stream_header.wPriority = INTEL_SHORT(stream_header.wPriority);
445 stream_header.wLanguage = INTEL_SHORT(stream_header.wLanguage);
446 stream_header.dwInitialFrames = INTEL_INT(stream_header.dwInitialFrames);
447 stream_header.dwScale = INTEL_INT(stream_header.dwScale);
448 stream_header.dwRate = INTEL_INT(stream_header.dwRate);
449 stream_header.dwStart = INTEL_INT(stream_header.dwStart);
450 stream_header.dwLength = INTEL_INT(stream_header.dwLength);
451 stream_header.dwSuggestedBufferSize = INTEL_INT(stream_header.dwSuggestedBufferSize);
452 stream_header.dwQuality = INTEL_INT(stream_header.dwQuality);
453 stream_header.dwSampleSize = INTEL_INT(stream_header.dwSampleSize);
454 stream_header.rcFrame.left = INTEL_SHORT(stream_header.rcFrame.left);
455 stream_header.rcFrame.top = INTEL_SHORT(stream_header.rcFrame.top);
456 stream_header.rcFrame.right = INTEL_SHORT(stream_header.rcFrame.right);
457 stream_header.rcFrame.bottom = INTEL_SHORT(stream_header.rcFrame.bottom);
460 SDL_assert(stream_header.fcc == 0x68727473);
462 // check stream type, can only handle 'vids'
463 if (stream_header.fccType != 0x73646976) {
464 printf("AVI => first stream must be video '%s'\n", filename);
468 SDL_assert(stream_header.fccType == 0x73646976);
470 // only handle 'MRLE' encoding
471 if (stream_header.fccHandler != 0x454c524d) {
472 printf("AVI is not MRLE encoded '%s'\n", filename);
477 // no pal changes for you cowboy
478 if (stream_header.dwFlags & AVISF_VIDEO_PALCHANGES) {
479 printf("AVI cannot have palette changes '%s'\n", filename);
484 // next stream sub-chunk -------------------------------
487 FREAD(&tmp, 1, 4, pfile);
488 tmp = INTEL_INT(tmp);
489 SDL_assert(tmp == 0x66727473);
492 FREAD(&tmp, 1, 4, pfile);
494 FREAD(&bitmap_header.bmiHeader.biSize, 1, sizeof(int), pfile);
495 FREAD(&bitmap_header.bmiHeader.biWidth, 1, sizeof(int), pfile);
496 FREAD(&bitmap_header.bmiHeader.biHeight, 1, sizeof(int), pfile);
497 FREAD(&bitmap_header.bmiHeader.biPlanes, 1, sizeof(short), pfile);
498 FREAD(&bitmap_header.bmiHeader.biBitCount, 1, sizeof(short), pfile);
499 FREAD(&bitmap_header.bmiHeader.biCompression, 1, sizeof(int), pfile);
500 FREAD(&bitmap_header.bmiHeader.biSizeImage, 1, sizeof(int), pfile);
501 FREAD(&bitmap_header.bmiHeader.biXPelsPerMeter, 1, sizeof(int), pfile);
502 FREAD(&bitmap_header.bmiHeader.biYPelsPerMeter, 1, sizeof(int), pfile);
503 FREAD(&bitmap_header.bmiHeader.biClrUsed, 1, sizeof(int), pfile);
504 FREAD(&bitmap_header.bmiHeader.biClrImportant, 1, sizeof(int), pfile);
506 bitmap_header.bmiHeader.biSize = INTEL_INT(bitmap_header.bmiHeader.biSize);
507 bitmap_header.bmiHeader.biWidth = INTEL_INT(bitmap_header.bmiHeader.biWidth);
508 bitmap_header.bmiHeader.biHeight = INTEL_INT(bitmap_header.bmiHeader.biHeight);
509 bitmap_header.bmiHeader.biPlanes = INTEL_SHORT(bitmap_header.bmiHeader.biPlanes);
510 bitmap_header.bmiHeader.biBitCount = INTEL_SHORT(bitmap_header.bmiHeader.biBitCount);
511 bitmap_header.bmiHeader.biCompression = INTEL_INT(bitmap_header.bmiHeader.biCompression);
512 bitmap_header.bmiHeader.biSizeImage = INTEL_INT(bitmap_header.bmiHeader.biSizeImage);
513 bitmap_header.bmiHeader.biXPelsPerMeter = INTEL_INT(bitmap_header.bmiHeader.biXPelsPerMeter);
514 bitmap_header.bmiHeader.biYPelsPerMeter = INTEL_INT(bitmap_header.bmiHeader.biYPelsPerMeter);
515 bitmap_header.bmiHeader.biClrUsed = INTEL_INT(bitmap_header.bmiHeader.biClrUsed);
516 bitmap_header.bmiHeader.biClrImportant = INTEL_INT(bitmap_header.bmiHeader.biClrImportant);
518 // verify bpp is 8 and compression is RLE8
519 if ( (bitmap_header.bmiHeader.biBitCount != 8) || (bitmap_header.bmiHeader.biCompression != BI_RLE8) ) {
520 printf("AVI has wrong bpp or compression '%s'\n", filename);
526 for (int i = 0; i < 256; i++) {
527 FREAD(&bitmap_header.bmiColors[i].b, 1, 1, pfile);
528 FREAD(&bitmap_header.bmiColors[i].g, 1, 1, pfile);
529 FREAD(&bitmap_header.bmiColors[i].r, 1, 1, pfile);
530 FREAD(&bitmap_header.bmiColors[i].p, 1, 1, pfile);
533 // reset next_chunk back to main 'LIST'
534 next_chunk = offset_tmp;
541 // need this for later
542 movi_offset = ftell(pfile);
544 // requiring an index, so don't mess with this anymore
550 printf("sub-something else: 0x%x\n", tag);
559 SDL_assert(AVI_stream.frame_index == NULL);
561 AVI_stream.frame_index = (FRAMEINDEX*) malloc(sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
562 SDL_assert(AVI_stream.frame_index != NULL);
564 memset(AVI_stream.frame_index, 0, sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
566 unsigned int c_id, c_flags, c_offset, c_size, i = 0;
568 while ( ftell(pfile) < next_chunk ) {
569 FREAD(&c_id, 1, sizeof(int), pfile);
570 FREAD(&c_flags, 1, sizeof(int), pfile);
571 FREAD(&c_offset, 1, sizeof(int), pfile);
572 FREAD(&c_size, 1, sizeof(int), pfile);
574 c_id = INTEL_INT(c_id);
575 c_flags = INTEL_INT(c_flags);
576 c_offset = INTEL_INT(c_offset);
577 c_size = INTEL_INT(c_size);
579 // only interested in stream 0, compressed data: '00dc'
580 if (c_id == 0x63643030) {
581 SDL_assert(i < avi_header.dwTotalFrames);
583 AVI_stream.frame_index[i].offset = c_offset;
584 AVI_stream.frame_index[i].size = c_size;
589 // if we didn't get good data then clear it out
590 if (i != avi_header.dwTotalFrames) {
591 free(AVI_stream.frame_index);
592 AVI_stream.frame_index = NULL;
598 // drop everything else
607 fseek(pfile, next_chunk, SEEK_SET);
611 printf("AVI => File read ERROR '%s'\n", filename);
617 // make sure we have a frame index
618 if (AVI_stream.frame_index == NULL) {
619 printf("AVI => No valid frame index found '%s'\n", filename);
624 // fix up frame_index (assumes frame_index[0] is first frame in stream)
625 long base_offset = 0;
627 if (AVI_stream.frame_index[0].offset > (unsigned int)movi_offset) {
629 } else if (AVI_stream.frame_index[0].offset == (unsigned int)movi_offset) {
631 } else if (AVI_stream.frame_index[0].offset == 0) {
632 base_offset = movi_offset + 4;
633 } else if (AVI_stream.frame_index[0].offset == 4) {
634 base_offset = movi_offset;
639 for (unsigned int i = 0; i < avi_header.dwTotalFrames; i++) {
640 AVI_stream.frame_index[i].offset += base_offset;
642 // maybe fix up size too
643 if (avi_header.dwSuggestedBufferSize < AVI_stream.frame_index[i].size) {
644 avi_header.dwSuggestedBufferSize = AVI_stream.frame_index[i].size;
648 // now set up AVI_stream
650 strcpy(AVI_stream.filename, filename);
651 AVI_stream.pfile = pfile;
653 AVI_stream.min_compressed_buffer_size = max(avi_header.dwSuggestedBufferSize, stream_header.dwSuggestedBufferSize);
654 SDL_assert(AVI_stream.min_compressed_buffer_size > 0);
656 AVI_stream.w = bitmap_header.bmiHeader.biWidth;
657 AVI_stream.h = bitmap_header.bmiHeader.biHeight;
658 AVI_stream.bpp = bitmap_header.bmiHeader.biBitCount;
660 // store the number of frames in the AVI_info[] structure
661 AVI_stream.num_frames = avi_header.dwTotalFrames;
663 // Store the palette in the AVI stream structure
664 for (int i = 0; i < 256; i++) {
665 AVI_stream.palette[i*3] = bitmap_header.bmiColors[i].r;
666 AVI_stream.palette[i*3+1] = bitmap_header.bmiColors[i].g;
667 AVI_stream.palette[i*3+2] = bitmap_header.bmiColors[i].b;
670 // set the flag to used, so to make sure we only process one AVI stream at a time
671 AVI_stream.flags |= AVI_STREAM_F_USED;
677 // AVI_stream_close() should be called when you are finished reading all the frames of an AVI
679 void AVI_stream_close()
681 // SDL_assert( AVI_stream.flags & AVI_STREAM_F_USED);
683 if (AVI_stream.pfile) {
684 fclose(AVI_stream.pfile);
685 AVI_stream.pfile = NULL;
688 if (AVI_stream.frame_index) {
689 free(AVI_stream.frame_index);
690 AVI_stream.frame_index = NULL;
693 AVI_stream.flags &= ~AVI_STREAM_F_USED; // clear the used flag
695 AVI_stream_inited = 0;
701 // AVI_stream_get_next_frame() will take the next RLE'd AVI frame and return the
702 // uncompressed data in the buffer pointer supplied as a parameter. The caller is
703 // responsible for allocating the memory before-hand (the memory required is easily
704 // calculated by looking at the w and h members in AVI_stream).
706 // returns: 0 ==> success
709 int AVI_stream_get_frame(ubyte* buffer, int frame_number)
711 if ( frame_number > AVI_stream.num_frames ) {
716 SDL_assert( (frame_number - 1) >= 0 );
718 ubyte* compressed_frame = (ubyte*)malloc(AVI_stream.min_compressed_buffer_size);
719 SDL_assert( compressed_frame != NULL );
720 memset(compressed_frame, 0, AVI_stream.min_compressed_buffer_size);
722 fseek(AVI_stream.pfile, AVI_stream.frame_index[frame_number-1].offset, SEEK_SET);
724 size_t rsize = AVI_stream.frame_index[frame_number-1].size;
726 if ( fread(compressed_frame, 1, rsize, AVI_stream.pfile) == rsize ) {
727 AVI_decompress_RLE8(compressed_frame, buffer, AVI_stream.w, AVI_stream.h);
729 printf("AVI : ERROR => short read in get_frame()!\n");
733 free( compressed_frame );
740 // -------------------------------------------------------------------------------------------------
741 // AVI_decompress_RLE8() will decompress the data pointed to by src, and store in dest.
743 // NOTE: 1. memory for dest must be already allocated before calling function
746 void AVI_decompress_RLE8(ubyte* src, ubyte* dest, int w, int h)
752 SDL_assert( src != NULL);
753 SDL_assert( dest != NULL);
759 ubyte control_code = 0;
763 int size_src = w * h + 1;
766 int height_offset = scan_line * w;
768 while ( src_index < size_src ) {
770 count = src[src_index];
772 if ( count == 0 ) { // control code follows
774 control_code = src[src_index];
775 if ( control_code == 1 ) {
777 // nprintf(("AVI","AVI ==> Reached end of compressed image\n"));
780 else if ( control_code == 0 ) {
783 height_offset = scan_line * w; // only need to calc once per scanline
785 if (height_offset < 0) {
788 //nprintf(("AVI","AVI ==> Reached end of line in compressed image\n"));
790 else if ( control_code == 2 ) {
791 // delta - horizontal and veritcal offsets
793 x_off = src[src_index];
798 if (dest_index >= w) {
804 y_off = src[src_index];
808 height_offset = scan_line * w;
810 if (height_offset < 0) {
820 //SDL_assert( (height_offset + dest_index) < (AVI_stream.w * AVI_stream.h) );
821 for ( i = 0; i < control_code; i++ ) {
822 if (dest_index >= w) {
825 dest[height_offset + dest_index] = src[src_index];
829 // run must end on a word boundry
830 if ( control_code & 1 )
836 run = src[src_index];
838 // nprintf(("AVI","AVI ==> Got %d pixel run of %d\n", src[src_index], count));
839 //SDL_assert( (height_offset + dest_index + count) <= (w * h) );
840 //memset(&dest[height_offset+dest_index], run, count);
841 //dest_index += count;
842 for ( i = 0; i < count; i++ ) {
843 if (dest_index >= w) {
846 dest[height_offset + dest_index] = run;
855 int save_anim_header()
857 int i, new_format_id = 0;
861 anim_fp = fopen(anim_save_filename, "r+b");
863 if (!fwrite(&new_format_id, 2, 1, anim_fp))
865 if (!fwrite(&Anim.version, 2, 1, anim_fp))
867 if (!fwrite(&Anim.fps, 2, 1, anim_fp))
869 if (!fwrite(&Anim.xparent_r, 1, 1, anim_fp))
871 if (!fwrite(&Anim.xparent_g, 1, 1, anim_fp))
873 if (!fwrite(&Anim.xparent_b, 1, 1, anim_fp))
875 if (!fwrite(&Anim.width, 2, 1, anim_fp))
877 if (!fwrite(&Anim.height, 2, 1, anim_fp))
879 if (!fwrite(&Anim.total_frames, 2, 1, anim_fp))
881 if (!fwrite(&Anim.packer_code, 1, 1, anim_fp))
883 if (fwrite(&Anim.palette, 3, 256, anim_fp) != 256)
885 if (!fwrite(&total_key_frames, 2, 1, anim_fp))
888 for (i=0; i<Anim.num_keys; i++) {
889 if (!fwrite(&Anim.keys[i].frame_num, 2, 1, anim_fp))
892 if (!fwrite(&Anim.keys[i].offset, 4, 1, anim_fp))
896 if (!fwrite(&anim_offset, 4, 1, anim_fp))
902 // This function allocates a linked list of key frame headers.
903 // It is responsible for determining which frames in an anim
904 // should be key frames.
905 int allocate_key_frames(int total_frames)
907 int count = 0, frame = 1, rate = key_frame_rate, last_frame;
912 while (frame <= total_frames) {
917 if (force_key_frame >= 0)
921 Anim.keys = (key_frame *) malloc(count * sizeof(key_frame));
924 frame = last_frame = 1;
925 while (frame <= total_frames) {
926 if ((force_key_frame > last_frame) && (force_key_frame < frame))
927 Anim.keys[count++].frame_num = force_key_frame;
929 Anim.keys[count++].frame_num = frame;
933 if (force_key_frame > last_frame)
934 Anim.keys[count++].frame_num = force_key_frame;
936 Anim.num_keys = count;
937 return count; // number of key frames
940 int anim_save_init(char *file, int width, int height, int frames)
943 anim_save_filename = file;
944 anim_fp = fopen(file, "wb");
948 Anim.version = ANIM_VERSION;
949 Anim.fps = Default_fps;
951 Anim.height = height;
952 Anim.packer_code = PACKER_CODE;
953 Anim.xparent_r = Xparent_color.r;
954 Anim.xparent_g = Xparent_color.g;
955 Anim.xparent_b = Xparent_color.b;
956 Anim.total_frames = frames;
959 total_key_frames = allocate_key_frames(frames);
960 fseek(anim_fp, ANIM_HEADER_SIZE + total_key_frames * 6, SEEK_SET);
962 switch ( Compression_type ) {
963 case CUSTOM_DELTA_RLE:
964 Key_frame_compression = PACKING_METHOD_RLE_KEY;
965 Regular_frame_compression = PACKING_METHOD_RLE;
969 Key_frame_compression = PACKING_METHOD_STD_RLE_KEY;
970 Regular_frame_compression = PACKING_METHOD_STD_RLE;
982 int anim_save_frame()
986 key_frame *keyp = NULL;
990 SDL_assert(cur_frame_num <= Anim.total_frames);
992 for (i=0; i<Anim.num_keys; i++)
993 if (Anim.keys[i].frame_num == cur_frame_num) {
994 keyp = &Anim.keys[i];
999 fprintf(stdout, "*");
1001 keyp->offset = anim_offset;
1002 size = pack_key_frame(cur_frame, anim_buffer, Anim.width * Anim.height, ANIM_BUFFER_MAX, Key_frame_compression);
1005 fprintf(stdout, ".");
1007 size = pack_frame(cur_frame, last_frame, anim_buffer, Anim.width * Anim.height, ANIM_BUFFER_MAX, Regular_frame_compression);
1013 if ((int) fwrite(anim_buffer, 1, size, anim_fp) != size)
1016 anim_offset += size;
1018 cur_frame = last_frame;
1024 // converts an avi file to an anim file
1026 // returns: 0 ==> success
1029 int convert_avi_to_anim(char* filename)
1031 char ani_filename[255];
1033 int rc, i, xparent_pal_index;
1034 int avi_stream_opened = 0;
1036 rc = AVI_stream_open(filename);
1038 // could not open the AVI stream
1041 avi_stream_opened = 1;
1043 SDL_assert(AVI_stream.bpp == 8);
1044 cur_frame = (ubyte*) malloc(AVI_stream.w * AVI_stream.h);
1045 last_frame = (ubyte*) malloc(AVI_stream.w * AVI_stream.h);
1046 SDL_assert(cur_frame && last_frame);
1048 strcpy(ani_filename, AVI_stream.filename);
1049 strcpy(ani_filename + strlen(ani_filename) - 3, "ani");
1051 memset(&Anim, 0, sizeof(anim));
1053 memcpy(Anim.palette, AVI_stream.palette, 768);
1055 if (Use_custom_xparent_color) {
1056 // Need to look at pixel in top-left
1057 rc = AVI_stream_get_frame(cur_frame, 1);
1061 xparent_pal_index = cur_frame[0];
1062 Xparent_color.r = Anim.palette[xparent_pal_index * 3];
1063 Xparent_color.g = Anim.palette[xparent_pal_index * 3 + 1];
1064 Xparent_color.b = Anim.palette[xparent_pal_index * 3 + 2];
1067 Xparent_color.r = 0;
1068 Xparent_color.g = 255;
1069 Xparent_color.b = 0;
1072 rc = anim_save_init(ani_filename, AVI_stream.w, AVI_stream.h, AVI_stream.num_frames);
1076 for ( i=1; i <= AVI_stream.num_frames; i++ ) {
1077 // get uncompressed frame from the AVI
1078 rc = AVI_stream_get_frame(cur_frame, i);
1082 // pass to the anim compression
1083 rc = anim_save_frame();
1088 rc = save_anim_header();
1095 // done with the AVI.. close the stream
1096 if ( avi_stream_opened )
1107 fprintf(stdout,"\n");
1112 int convert_frames_to_anim(char *filename)
1114 int first_frame, frame, pos, width, height, xparent_pal_index, r = -1;
1115 char ani_filename[255], name[255], temp[8];
1119 SDL_assert(strlen(filename) < 254);
1120 strcpy(name, filename);
1121 strcpy(ani_filename, filename);
1122 strcpy(ani_filename + strlen(ani_filename) - 8, ".ani");
1123 pos = strlen(name) - 8;
1124 frame = first_frame = atoi(&name[pos]);
1125 force_key_frame -= frame;
1127 memset(&Anim, 0, sizeof(anim));
1130 fp = fopen(name, "rb");
1135 sprintf(temp, "%04d", frame);
1136 strncpy(&name[pos], temp, 4);
1139 fp = fopen(name, "rb");
1140 } while(fp != NULL);
1143 rc = pcx_read_header(filename, &width, &height, NULL);
1144 if (rc != PCX_ERROR_NONE) {
1145 fprintf(stdout, "An error reading the PCX file %s. It may not exist.\n", filename);
1149 cur_frame = (ubyte *) malloc(width * height);
1150 last_frame = (ubyte *) malloc(width * height);
1152 rc = pcx_read_bitmap_8bpp(filename, cur_frame, Anim.palette);
1153 if (rc != PCX_ERROR_NONE) {
1154 fprintf(stdout, "An error reading the PCX file %s. It may not exist.\n", filename);
1158 if (Use_custom_xparent_color) {
1159 // Need to look at pixel in top-left
1160 xparent_pal_index = ((ubyte *) cur_frame)[0];
1161 Xparent_color.r = Anim.palette[xparent_pal_index * 3];
1162 Xparent_color.g = Anim.palette[xparent_pal_index * 3 + 1];
1163 Xparent_color.b = Anim.palette[xparent_pal_index * 3 + 2];
1166 Xparent_color.r = 0;
1167 Xparent_color.g = 255;
1168 Xparent_color.b = 0;
1171 if (anim_save_init(ani_filename, width, height, frame - first_frame))
1174 while (first_frame < frame) {
1175 sprintf(temp, "%04d", first_frame);
1176 strncpy(&name[pos], temp, 4);
1177 rc = pcx_read_bitmap_8bpp(name, cur_frame, Anim.palette);
1178 if (rc != PCX_ERROR_NONE)
1181 if (anim_save_frame())
1187 if (save_anim_header())
1199 fprintf(stdout, "\n");