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;
133 unsigned int movi_offset;
137 int min_compressed_buffer_size;
140 //ubyte pal_translation[256]; // palette translation look-up table
144 #define AVIF_HASINDEX 0x00000010
146 typedef struct _avimainheader {
149 unsigned int dwMicroSecPerFrame;
150 unsigned int dwMaxBytesPerSec;
151 unsigned int dwPaddingGranularity;
152 unsigned int dwFlags;
153 unsigned int dwTotalFrames;
154 unsigned int dwInitialFrames;
155 unsigned int dwStreams;
156 unsigned int dwSuggestedBufferSize;
157 unsigned int dwWidth;
158 unsigned int dwHeight;
159 unsigned int dwReserved[4];
162 #define AVISF_VIDEO_PALCHANGES 0x00010000
164 typedef struct _avistreamheader {
167 unsigned int fccType;
168 unsigned int fccHandler;
169 unsigned int dwFlags;
170 unsigned short wPriority;
171 unsigned short wLanguage;
172 unsigned int dwInitialFrames;
173 unsigned int dwScale;
175 unsigned int dwStart;
176 unsigned int dwLength;
177 unsigned int dwSuggestedBufferSize;
178 unsigned int dwQuality;
179 unsigned int dwSampleSize;
188 #define BI_RLE8 0x00000001
190 typedef struct _bitmapinfo {
195 unsigned short biPlanes;
196 unsigned short biBitCount;
197 unsigned int biCompression;
198 unsigned int biSizeImage;
201 unsigned int biClrUsed;
202 unsigned int biClrImportant;
214 // Internal function prototypes
215 int AVI_stream_open(char* filename);
216 void AVI_stream_close();
217 int AVI_stream_get_frame(ubyte* buffer, int frame_number);
218 void AVI_decompress_RLE8(ubyte* src, ubyte* dest, unsigned int srcSize);
221 static AVI_STREAM_TYPE AVI_stream;
222 static int AVI_stream_inited = 0;
225 char *anim_save_filename;
226 ubyte *cur_frame, *last_frame;
227 ubyte anim_buffer[ANIM_BUFFER_MAX];
230 int total_key_frames;
234 int Use_custom_xparent_color;
235 rgb_triple Xparent_color;
237 int Compression_type; // what kind of RLE compression is going to be used
238 int Key_frame_compression, Regular_frame_compression;
240 key_frame *first_frame;
241 FILE *anim_fp = NULL;
244 // AVI_stream_init() is called only to clear USED flag of the AVI_stream structure
245 // and reset the current frame.
247 // This does not need to be called explicity, since it will be called by AVI_stream_open()
250 void AVI_stream_init()
252 AVI_stream.flags &= ~AVI_STREAM_F_USED;
253 AVI_stream.current_frame = 0;
254 AVI_stream_inited = 1;
256 AVI_stream.pfile = NULL;
257 AVI_stream.frame_index = NULL;
260 // AVI_stream_open() will open the AVI file and prepare it for reading, but will not
261 // store any of the frame data.
263 // returns: 0 ==> success
264 // !0 ==> could not open the AVI stream
266 // The filename is expected to be an absolute pathname (or file in the current working directory)
268 int AVI_stream_open(char* filename)
270 if ( !AVI_stream_inited )
275 unsigned int tag = 0, size = 0, next_chunk;
276 unsigned int s_tag, tmp;
277 AVIMAINHEADER avi_header;
278 AVISTREAMHEADER stream_header;
279 BITMAPINFO bitmap_header;
280 unsigned int file_size = 0;
282 SDL_assert( !(AVI_stream.flags & AVI_STREAM_F_USED) );
284 pfile = fopen(filename, "rb");
287 printf("AVI ==> Unable to open %s", filename);
292 fseek(pfile, 0, SEEK_END);
293 file_size = ftell(pfile);
294 fseek(pfile, 0, SEEK_SET);
296 // check for valid file type
297 fread(&id, 1, 4, pfile);
300 if (id != 0x46464952) {
301 printf("Not a RIFF file '%s'\n", filename);
307 fread(&id, 1, 4, pfile);
309 // check for valid RIFF type
310 fread(&id, 1, 4, pfile);
313 if (id != 0x20495641) {
314 printf("Not an AVI file '%s'\n", filename);
319 // used for main 'LIST' chunks
320 unsigned int offset_tmp = 0;
323 while ( ftell(pfile) < file_size ) {
324 fread(&tag, 1, 4, pfile);
325 fread(&size, 1, 4, pfile);
327 next_chunk = ftell(pfile) + size;
333 fread(&s_tag, 1, 4, pfile);
338 fread(&avi_header.fcc, 1, sizeof(int), pfile);
339 fread(&avi_header.cb, 1, sizeof(int), pfile);
340 fread(&avi_header.dwMicroSecPerFrame, 1, sizeof(int), pfile);
341 fread(&avi_header.dwMaxBytesPerSec, 1, sizeof(int), pfile);
342 fread(&avi_header.dwPaddingGranularity, 1, sizeof(int), pfile);
343 fread(&avi_header.dwFlags, 1, sizeof(int), pfile);
344 fread(&avi_header.dwTotalFrames, 1, sizeof(int), pfile);
345 fread(&avi_header.dwInitialFrames, 1, sizeof(int), pfile);
346 fread(&avi_header.dwStreams, 1, sizeof(int), pfile);
347 fread(&avi_header.dwSuggestedBufferSize, 1, sizeof(int), pfile);
348 fread(&avi_header.dwWidth, 1, sizeof(int), pfile);
349 fread(&avi_header.dwHeight, 1, sizeof(int), pfile);
350 fread(&avi_header.dwReserved, 1, sizeof(avi_header.dwReserved), pfile);
353 SDL_assert(avi_header.fcc == 0x68697661);
355 // we're stupid, can only handle a single stream
356 // if (avi_header.dwStreams != 1) {
357 // printf("AVI has more than one stream '%s'\n", filename);
362 // update next_chunk offset for sub-chunk
363 offset_tmp = next_chunk;
364 next_chunk = ftell(pfile);
369 // 'strl' - subchunk of 'hdrl'
371 fread(&stream_header.fcc, 1, sizeof(int), pfile);
372 fread(&stream_header.cb, 1, sizeof(int), pfile);
373 fread(&stream_header.fccType, 1, sizeof(int), pfile);
374 fread(&stream_header.fccHandler, 1, sizeof(int), pfile);
375 fread(&stream_header.dwFlags, 1, sizeof(int), pfile);
376 fread(&stream_header.wPriority, 1, sizeof(short), pfile);
377 fread(&stream_header.wLanguage, 1, sizeof(short), pfile);
378 fread(&stream_header.dwInitialFrames, 1, sizeof(int), pfile);
379 fread(&stream_header.dwScale, 1, sizeof(int), pfile);
380 fread(&stream_header.dwRate, 1, sizeof(int), pfile);
381 fread(&stream_header.dwStart, 1, sizeof(int), pfile);
382 fread(&stream_header.dwLength, 1, sizeof(int), pfile);
383 fread(&stream_header.dwSuggestedBufferSize, 1, sizeof(int), pfile);
384 fread(&stream_header.dwQuality, 1, sizeof(int), pfile);
385 fread(&stream_header.dwSampleSize, 1, sizeof(int), pfile);
386 fread(&stream_header.rcFrame.left, 1, sizeof(short), pfile);
387 fread(&stream_header.rcFrame.top, 1, sizeof(short), pfile);
388 fread(&stream_header.rcFrame.right, 1, sizeof(short), pfile);
389 fread(&stream_header.rcFrame.bottom, 1, sizeof(short), pfile);
392 SDL_assert(stream_header.fcc == 0x68727473);
394 // check stream type, can only handle 'vids'
395 if (stream_header.fccType != 0x73646976) {
396 printf("AVI => first stream must be video '%s'\n", filename);
400 SDL_assert(stream_header.fccType == 0x73646976);
402 // only handle 'MRLE' encoding (or 'mrle' if wrong)
403 if ( (stream_header.fccHandler != 0x454c524d) && (stream_header.fccHandler != 0x656c726d) ) {
404 printf("AVI is not MRLE encoded '%s'\n", filename);
409 // no pal changes for you cowboy
410 if (stream_header.dwFlags & AVISF_VIDEO_PALCHANGES) {
411 printf("AVI cannot have palette changes '%s'\n", filename);
416 // next stream sub-chunk -------------------------------
419 fread(&tmp, 1, 4, pfile);
420 SDL_assert(tmp == 0x66727473);
423 fread(&tmp, 1, 4, pfile);
425 fread(&bitmap_header.bmiHeader.biSize, 1, sizeof(int), pfile);
426 fread(&bitmap_header.bmiHeader.biWidth, 1, sizeof(int), pfile);
427 fread(&bitmap_header.bmiHeader.biHeight, 1, sizeof(int), pfile);
428 fread(&bitmap_header.bmiHeader.biPlanes, 1, sizeof(short), pfile);
429 fread(&bitmap_header.bmiHeader.biBitCount, 1, sizeof(short), pfile);
430 fread(&bitmap_header.bmiHeader.biCompression, 1, sizeof(int), pfile);
431 fread(&bitmap_header.bmiHeader.biSizeImage, 1, sizeof(int), pfile);
432 fread(&bitmap_header.bmiHeader.biXPelsPerMeter, 1, sizeof(int), pfile);
433 fread(&bitmap_header.bmiHeader.biYPelsPerMeter, 1, sizeof(int), pfile);
434 fread(&bitmap_header.bmiHeader.biClrUsed, 1, sizeof(int), pfile);
435 fread(&bitmap_header.bmiHeader.biClrImportant, 1, sizeof(int), pfile);
437 // verify bpp is 8 and compression is RLE8
438 if ( (bitmap_header.bmiHeader.biBitCount != 8) || (bitmap_header.bmiHeader.biCompression != BI_RLE8) ) {
439 printf("AVI has wrong bpp or compression '%s'\n", filename);
445 for (int i = 0; i < 256; i++) {
446 fread(&bitmap_header.bmiColors[i].b, 1, 1, pfile);
447 fread(&bitmap_header.bmiColors[i].g, 1, 1, pfile);
448 fread(&bitmap_header.bmiColors[i].r, 1, 1, pfile);
449 fread(&bitmap_header.bmiColors[i].p, 1, 1, pfile);
452 // reset next_chunk back to main 'LIST'
453 next_chunk = offset_tmp;
460 // need this for later
461 AVI_stream.movi_offset = ftell(pfile);
464 // TODO: this crap is broken and unsafe!
466 if ( !(avi_header.dwFlags & AVIF_HASINDEX) ) {
467 // printf("AVI => Building index... (%d)", avi_header.dwTotalFrames);
469 SDL_assert(AVI_stream.frame_index == NULL);
471 AVI_stream.frame_index = (FRAMEINDEX*) malloc(sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
472 SDL_assert(AVI_stream.frame_index != NULL);
474 memset(AVI_stream.frame_index, 0, sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
476 unsigned short b1, b2;
479 while ( ftell(pfile) < next_chunk ) {
480 fread(&b1, 1, 2, pfile);
481 fread(&b2, 1, 2, pfile);
483 // check for compressed DIB on first stream '00dc'
484 if ( (b1 == 0x3030) && (b2 == 0x6364) ) {
485 SDL_assert(i < avi_header.dwTotalFrames);
487 // printf("\rAVI => Building index... %d / %d", i+1, avi_header.dwTotalFrames);
489 AVI_stream.frame_index[i].offset = ftell(pfile) - AVI_stream.movi_offset;
492 AVI_stream.frame_index[i-1].size = AVI_stream.frame_index[i].offset - AVI_stream.frame_index[i-1].offset - 4;
493 } else if (i == avi_header.dwTotalFrames-1) {
494 AVI_stream.frame_index[i].size = next_chunk - ftell(pfile);
495 printf("HERERERERERERE\n");
497 // printf("%d, %d, %d\n", ftell(pfile), AVI_stream.movi_offset, i);
502 // printf("\rAVI => Building index... done \n");
510 printf("sub-something else: 0x%x\n", tag);
519 SDL_assert(AVI_stream.frame_index == NULL);
521 AVI_stream.frame_index = (FRAMEINDEX*) malloc(sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
522 SDL_assert(AVI_stream.frame_index != NULL);
524 memset(AVI_stream.frame_index, 0, sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
526 unsigned int c_id, c_flags, c_offset, c_size, i = 0;
528 while ( ftell(pfile) < next_chunk ) {
529 fread(&c_id, 1, sizeof(int), pfile);
530 fread(&c_flags, 1, sizeof(int), pfile);
531 fread(&c_offset, 1, sizeof(int), pfile);
532 fread(&c_size, 1, sizeof(int), pfile);
534 // only interested in stream 0, compressed data: '00dc'
535 if (c_id == 0x63643030) {
536 SDL_assert(i < avi_header.dwTotalFrames);
538 AVI_stream.frame_index[i].offset = c_offset;
539 AVI_stream.frame_index[i].size = c_size;
547 // drop everything else
552 fseek(pfile, next_chunk, SEEK_SET);
555 // make sure we have a frame index
556 if (AVI_stream.frame_index == NULL) {
557 printf("No frame index found or created '%s'\n", filename);
562 strcpy(AVI_stream.filename, filename);
563 AVI_stream.pfile = pfile;
565 AVI_stream.min_compressed_buffer_size = max(avi_header.dwSuggestedBufferSize, stream_header.dwSuggestedBufferSize);
566 AVI_stream.min_compressed_buffer_size = max(AVI_stream.min_compressed_buffer_size, bitmap_header.bmiHeader.biWidth*bitmap_header.bmiHeader.biHeight);
568 AVI_stream.w = bitmap_header.bmiHeader.biWidth;
569 AVI_stream.h = bitmap_header.bmiHeader.biHeight;
570 AVI_stream.bpp = bitmap_header.bmiHeader.biBitCount;
572 // store the number of frames in the AVI_info[] structure
573 AVI_stream.num_frames = avi_header.dwTotalFrames;
575 // Store the palette in the AVI stream structure
576 for (int i = 0; i < 256; i++) {
577 AVI_stream.palette[i*3] = bitmap_header.bmiColors[i].r;
578 AVI_stream.palette[i*3+1] = bitmap_header.bmiColors[i].g;
579 AVI_stream.palette[i*3+2] = bitmap_header.bmiColors[i].b;
582 printf("filename: %s\n", filename);
583 printf("w: %d, h: %d, bpp: %d\n", AVI_stream.w, AVI_stream.h, AVI_stream.bpp);
584 printf("num frames: %d\n", AVI_stream.num_frames);
586 // set the flag to used, so to make sure we only process one AVI stream at a time
587 AVI_stream.flags |= AVI_STREAM_F_USED;
593 // AVI_stream_close() should be called when you are finished reading all the frames of an AVI
595 void AVI_stream_close()
597 // SDL_assert( AVI_stream.flags & AVI_STREAM_F_USED);
599 if (AVI_stream.pfile && fi) {
600 fclose(AVI_stream.pfile);
601 AVI_stream.pfile = NULL;
604 if (AVI_stream.frame_index) {
605 free(AVI_stream.frame_index);
606 AVI_stream.frame_index = NULL;
609 AVI_stream.flags &= ~AVI_STREAM_F_USED; // clear the used flag
611 AVI_stream_inited = 0;
617 // AVI_stream_get_next_frame() will take the next RLE'd AVI frame and return the
618 // uncompressed data in the buffer pointer supplied as a parameter. The caller is
619 // responsible for allocating the memory before-hand (the memory required is easily
620 // calculated by looking at the w and h members in AVI_stream).
622 // returns: 0 ==> success
625 int AVI_stream_get_frame(ubyte* buffer, int frame_number)
628 if ( frame_number > AVI_stream.num_frames ) {
633 SDL_assert( (frame_number - 1) >= 0 );
635 ubyte* compressed_frame = (ubyte*)malloc(AVI_stream.min_compressed_buffer_size);
636 SDL_assert( compressed_frame != NULL );
640 if (AVI_stream.frame_index[frame_number-1].offset > AVI_stream.movi_offset) {
641 offset = AVI_stream.frame_index[frame_number-1].offset;
642 } else if (AVI_stream.frame_index[frame_number-1].offset == AVI_stream.movi_offset) {
643 offset = AVI_stream.frame_index[frame_number-1].offset + sizeof(int);
645 offset = AVI_stream.movi_offset + AVI_stream.frame_index[frame_number-1].offset;
648 fseek(AVI_stream.pfile, offset, SEEK_SET);
649 fread(compressed_frame, 1, AVI_stream.frame_index[frame_number-1].size, AVI_stream.pfile);
651 AVI_decompress_RLE8(compressed_frame, buffer, AVI_stream.frame_index[frame_number-1].size);
653 free( compressed_frame );
660 // -------------------------------------------------------------------------------------------------
661 // AVI_decompress_RLE8() will decompress the data pointed to by src, and store in dest.
663 // NOTE: 1. memory for dest must be already allocated before calling function
666 void AVI_decompress_RLE8(ubyte* src, ubyte* dest, unsigned int srcSize)
672 SDL_assert( src != NULL);
673 SDL_assert( dest != NULL);
674 SDL_assert( srcSize > 0 );
682 int size_src = srcSize;
684 int scan_line = AVI_stream.h-1;
685 int height_offset = scan_line * AVI_stream.w;
687 while ( src_index < size_src ) {
689 count = src[src_index];
691 if ( count == 0 ) { // control code follows
693 control_code = src[src_index];
694 if ( control_code == 1 ) {
696 // nprintf(("AVI","AVI ==> Reached end of compressed image\n"));
699 else if ( control_code == 0 ) {
702 height_offset = scan_line * AVI_stream.w; // only need to calc once per scanline
704 //nprintf(("AVI","AVI ==> Reached end of line in compressed image\n"));
706 else if ( control_code == 2 ) {
707 // delta - horizontal and veritcal offsets
709 x_off = src[src_index];
716 y_off = src[src_index];
720 height_offset = scan_line * AVI_stream.w;
728 for ( i = 0; i < control_code; i++ ) {
729 SDL_assert( (height_offset + dest_index) < (AVI_stream.w * AVI_stream.h) );
730 dest[height_offset + dest_index] = src[src_index];
734 // run must end on a word boundry
735 if ( control_code & 1 )
741 run = src[src_index];
742 // nprintf(("AVI","AVI ==> Got %d pixel run of %d\n", src[src_index], count));
743 if (dest_index+count > AVI_stream.w) count = AVI_stream.w - dest_index;
744 SDL_assert( (height_offset + dest_index + count) <= (AVI_stream.w * AVI_stream.h) );
745 memset( &dest[height_offset + dest_index], run, count );
753 int save_anim_header()
755 int i, new_format_id = 0;
759 anim_fp = fopen(anim_save_filename, "r+b");
761 if (!fwrite(&new_format_id, 2, 1, anim_fp))
763 if (!fwrite(&Anim.version, 2, 1, anim_fp))
765 if (!fwrite(&Anim.fps, 2, 1, anim_fp))
767 if (!fwrite(&Anim.xparent_r, 1, 1, anim_fp))
769 if (!fwrite(&Anim.xparent_g, 1, 1, anim_fp))
771 if (!fwrite(&Anim.xparent_b, 1, 1, anim_fp))
773 if (!fwrite(&Anim.width, 2, 1, anim_fp))
775 if (!fwrite(&Anim.height, 2, 1, anim_fp))
777 if (!fwrite(&Anim.total_frames, 2, 1, anim_fp))
779 if (!fwrite(&Anim.packer_code, 1, 1, anim_fp))
781 if (fwrite(&Anim.palette, 3, 256, anim_fp) != 256)
783 if (!fwrite(&total_key_frames, 2, 1, anim_fp))
786 for (i=0; i<Anim.num_keys; i++) {
787 if (!fwrite(&Anim.keys[i].frame_num, 2, 1, anim_fp))
790 if (!fwrite(&Anim.keys[i].offset, 4, 1, anim_fp))
794 if (!fwrite(&anim_offset, 4, 1, anim_fp))
800 // This function allocates a linked list of key frame headers.
801 // It is responsible for determining which frames in an anim
802 // should be key frames.
803 int allocate_key_frames(int total_frames)
805 int count = 0, frame = 1, rate = key_frame_rate, last_frame;
810 while (frame <= total_frames) {
815 if (force_key_frame >= 0)
819 Anim.keys = (key_frame *) malloc(count * sizeof(key_frame));
822 frame = last_frame = 1;
823 while (frame <= total_frames) {
824 if ((force_key_frame > last_frame) && (force_key_frame < frame))
825 Anim.keys[count++].frame_num = force_key_frame;
827 Anim.keys[count++].frame_num = frame;
831 if (force_key_frame > last_frame)
832 Anim.keys[count++].frame_num = force_key_frame;
834 Anim.num_keys = count;
835 return count; // number of key frames
838 int anim_save_init(char *file, int width, int height, int frames)
841 anim_save_filename = file;
842 anim_fp = fopen(file, "wb");
846 Anim.version = ANIM_VERSION;
847 Anim.fps = Default_fps;
849 Anim.height = height;
850 Anim.packer_code = PACKER_CODE;
851 Anim.xparent_r = Xparent_color.r;
852 Anim.xparent_g = Xparent_color.g;
853 Anim.xparent_b = Xparent_color.b;
854 Anim.total_frames = frames;
857 total_key_frames = allocate_key_frames(frames);
858 fseek(anim_fp, ANIM_HEADER_SIZE + total_key_frames * 6, SEEK_SET);
860 switch ( Compression_type ) {
861 case CUSTOM_DELTA_RLE:
862 Key_frame_compression = PACKING_METHOD_RLE_KEY;
863 Regular_frame_compression = PACKING_METHOD_RLE;
867 Key_frame_compression = PACKING_METHOD_STD_RLE_KEY;
868 Regular_frame_compression = PACKING_METHOD_STD_RLE;
880 int anim_save_frame()
884 key_frame *keyp = NULL;
888 SDL_assert(cur_frame_num <= Anim.total_frames);
890 for (i=0; i<Anim.num_keys; i++)
891 if (Anim.keys[i].frame_num == cur_frame_num) {
892 keyp = &Anim.keys[i];
897 fprintf(stdout, "*");
899 keyp->offset = anim_offset;
900 size = pack_key_frame(cur_frame, anim_buffer, Anim.width * Anim.height, ANIM_BUFFER_MAX, Key_frame_compression);
903 fprintf(stdout, ".");
905 size = pack_frame(cur_frame, last_frame, anim_buffer, Anim.width * Anim.height, ANIM_BUFFER_MAX, Regular_frame_compression);
911 if ((int) fwrite(anim_buffer, 1, size, anim_fp) != size)
916 cur_frame = last_frame;
922 // converts an avi file to an anim file
924 // returns: 0 ==> success
927 int convert_avi_to_anim(char* filename)
929 char ani_filename[255];
931 int rc, i, xparent_pal_index;
932 int avi_stream_opened = 0;
934 rc = AVI_stream_open(filename);
936 // could not open the AVI stream
939 avi_stream_opened = 1;
941 SDL_assert(AVI_stream.bpp == 8);
942 cur_frame = (ubyte*) malloc(AVI_stream.w * AVI_stream.h);
943 last_frame = (ubyte*) malloc(AVI_stream.w * AVI_stream.h);
944 SDL_assert(cur_frame && last_frame);
946 strcpy(ani_filename, AVI_stream.filename);
947 strcpy(ani_filename + strlen(ani_filename) - 3, "ani");
949 memcpy(Anim.palette, AVI_stream.palette, 768);
951 if (Use_custom_xparent_color) {
952 // Need to look at pixel in top-left
953 rc = AVI_stream_get_frame(cur_frame, 1);
957 xparent_pal_index = cur_frame[0];
958 Xparent_color.r = Anim.palette[xparent_pal_index * 3];
959 Xparent_color.g = Anim.palette[xparent_pal_index * 3 + 1];
960 Xparent_color.b = Anim.palette[xparent_pal_index * 3 + 2];
964 Xparent_color.g = 255;
968 rc = anim_save_init(ani_filename, AVI_stream.w, AVI_stream.h, AVI_stream.num_frames);
972 for ( i=1; i <= AVI_stream.num_frames; i++ ) {
973 // get uncompressed frame from the AVI
974 rc = AVI_stream_get_frame(cur_frame, i);
978 // pass to the anim compression
979 rc = anim_save_frame();
984 rc = save_anim_header();
991 // done with the AVI.. close the stream
992 if ( avi_stream_opened )
1000 fprintf(stdout,"\n");
1005 int convert_frames_to_anim(char *filename)
1007 int first_frame, frame, pos, width, height, xparent_pal_index, r = -1;
1008 char ani_filename[255], name[255], temp[8];
1012 SDL_assert(strlen(filename) < 254);
1013 strcpy(name, filename);
1014 strcpy(ani_filename, filename);
1015 strcpy(ani_filename + strlen(ani_filename) - 8, ".ani");
1016 pos = strlen(name) - 8;
1017 frame = first_frame = atoi(&name[pos]);
1018 force_key_frame -= frame;
1021 fp = fopen(name, "rb");
1026 sprintf(temp, "%04d", frame);
1027 strncpy(&name[pos], temp, 4);
1030 fp = fopen(name, "rb");
1031 } while(fp != NULL);
1034 rc = pcx_read_header(filename, &width, &height, NULL);
1035 if (rc != PCX_ERROR_NONE) {
1036 fprintf(stdout, "An error reading the PCX file %s. It may not exist.\n", filename);
1040 cur_frame = (ubyte *) malloc(width * height);
1041 last_frame = (ubyte *) malloc(width * height);
1043 rc = pcx_read_bitmap_8bpp(filename, cur_frame, Anim.palette);
1044 if (rc != PCX_ERROR_NONE) {
1045 fprintf(stdout, "An error reading the PCX file %s. It may not exist.\n", filename);
1049 if (Use_custom_xparent_color) {
1050 // Need to look at pixel in top-left
1051 xparent_pal_index = ((ubyte *) cur_frame)[0];
1052 Xparent_color.r = Anim.palette[xparent_pal_index * 3];
1053 Xparent_color.g = Anim.palette[xparent_pal_index * 3 + 1];
1054 Xparent_color.b = Anim.palette[xparent_pal_index * 3 + 2];
1057 Xparent_color.r = 0;
1058 Xparent_color.g = 255;
1059 Xparent_color.b = 0;
1062 if (anim_save_init(ani_filename, width, height, frame - first_frame))
1065 while (first_frame < frame) {
1066 sprintf(temp, "%04d", first_frame);
1067 strncpy(&name[pos], temp, 4);
1068 rc = pcx_read_bitmap_8bpp(name, cur_frame, Anim.palette);
1069 if (rc != PCX_ERROR_NONE)
1072 if (anim_save_frame())
1078 if (save_anim_header())
1087 fprintf(stdout, "\n");