]> icculus.org git repositories - taylor/freespace2.git/blob - src/ac/convert.cpp
use a better multi_sw_ok_to_commit() check
[taylor/freespace2.git] / src / ac / convert.cpp
1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/AC/convert.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
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.
17  *
18  * $Log$
19  * Revision 1.2  2002/06/09 04:41:15  relnev
20  * added copyright header
21  *
22  * Revision 1.1.1.1  2002/05/03 03:28:11  root
23  * Initial import.
24  *
25  * 
26  * 2     10/23/98 6:03p Dave
27  * 
28  * 1     10/23/98 5:34p Dave
29  * 
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
33  * 
34  * 2     10/07/98 10:52a Dave
35  * Initial checkin.
36  * 
37  * 1     10/07/98 10:48a Dave
38  * 
39  * 12    6/23/98 2:52p Hoffoss
40  * Changed code so AC compiles once again.
41  * 
42  * 11    7/20/97 6:57p Lawrance
43  * supporting new RLE format
44  * 
45  * 10    6/25/97 11:57a Lawrance
46  * forgot linefeed
47  * 
48  * 9     6/25/97 11:49a Lawrance
49  * don't assert if PCX read fails, print warning
50  * 
51  * 8     5/21/97 2:26p Lawrance
52  * bug fix: not using correct header size
53  * 
54  * 7     5/21/97 11:06a Lawrance
55  * enabling a user-defined transparent value
56  * 
57  * 6     5/19/97 3:21p Lawrance
58  * add fps parm, version num to anim header
59  * 
60  * 5     2/25/97 5:18p Lawrance
61  * force_key_frame now numbering from 1 for PCXs as well as AVIs
62  * 
63  * 4     2/20/97 1:47p Lawrance
64  * adding dots when making frames
65  * 
66  * 3     2/20/97 10:30a Hoffoss
67  * Added in support for forcing a key frame.
68  * 
69  * 2     2/19/97 9:26p Lawrance
70  * added force_key_frame global
71  * 
72  * 1     2/19/97 7:14p Lawrance
73  * 
74  * 14    2/19/97 4:21p Lawrance
75  * took out unnecessary #include BmpMan.h
76  * 
77  * 13    2/19/97 3:59p Lawrance
78  * using pcxutils to load bitmaps, not bmpman
79  * 
80  * 12    2/17/97 2:59p Lawrance
81  * integrating into game
82  * 
83  * 11    2/17/97 3:02p Hoffoss
84  * Added headers to files, and implemented key frame dialog stuff.
85  * 
86  * 10    2/14/97 10:38p Lawrance
87  * fixing bugs
88  * 
89  * 9     2/14/97 9:47p Hoffoss
90  * fixed bugs.
91  * 
92  * 8     2/14/97 8:44p Lawrance
93  * fixed bug with saving header
94  * 
95  * 7     2/14/97 8:04p Hoffoss
96  * Fixed bug.
97  * 
98  * 6     2/14/97 7:44p Lawrance
99  * fixed some bugs in loading an AVI
100  * 
101  * 5     2/14/97 7:33p Lawrance
102  * added convert_avi_to_anim() function
103  * 
104  * 4     2/14/97 5:38p Hoffoss
105  * Changes to get AnimCoverter project to compile and link.
106  * 
107  * 3     2/14/97 3:28p Hoffoss
108  * Wrote functions to save an anim file.
109  * 
110  * 2     2/13/97 5:55p Lawrance
111  * reading AVI / decompressing AVI functions in
112  *
113  * $NoKeywords: $
114  */
115
116
117 #include "pstypes.h"
118 #include "convert.h"
119 #include "pcxutils.h"
120 #include "animplay.h"
121 #include "packunpack.h"
122
123 #define AVI_STREAM_F_USED       ( 1 << 0 )
124
125 typedef struct _frame_index {
126         unsigned int offset;
127         unsigned int size;
128 } FRAMEINDEX;
129
130 typedef struct AVI_STREAM_TYPE {
131         FILE            *pfile;
132         FRAMEINDEX      *frame_index;
133         int                     num_frames;
134         int                     current_frame;
135         int                     w,h,bpp;
136         int                     min_compressed_buffer_size;
137         ubyte                   palette[768];
138         char                    filename[255];
139         //ubyte                 pal_translation[256];           // palette translation look-up table
140         int             flags;
141 }       AVI_STREAM_TYPE;
142
143 #define AVIF_HASINDEX 0x00000010
144
145 typedef struct _avimainheader {
146         unsigned int fcc;
147         unsigned int cb;
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];
159 } AVIMAINHEADER;
160
161 #define AVISF_VIDEO_PALCHANGES 0x00010000
162
163 typedef struct _avistreamheader {
164         unsigned int fcc;
165         unsigned int cb;
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;
173         unsigned int dwRate;
174         unsigned int dwStart;
175         unsigned int dwLength;
176         unsigned int dwSuggestedBufferSize;
177         unsigned int dwQuality;
178         unsigned int dwSampleSize;
179         struct {
180                 short left;
181                 short top;
182                 short right;
183                 short bottom;
184         } rcFrame;
185 } AVISTREAMHEADER;
186
187 #define BI_RLE8 0x00000001
188
189 typedef struct _bitmapinfo {
190         struct {
191                 unsigned int biSize;
192                 int biWidth;
193                 int biHeight;
194                 unsigned short biPlanes;
195                 unsigned short biBitCount;
196                 unsigned int biCompression;
197                 unsigned int biSizeImage;
198                 int biXPelsPerMeter;
199                 int biYPelsPerMeter;
200                 unsigned int biClrUsed;
201                 unsigned int biClrImportant;
202         } bmiHeader;
203
204         struct {
205                 ubyte b;
206                 ubyte g;
207                 ubyte r;
208                 ubyte p;
209         } bmiColors[256];
210 } BITMAPINFO;
211
212
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);
218
219 // Global to file
220 static          AVI_STREAM_TYPE AVI_stream;     
221 static int      AVI_stream_inited = 0;
222
223 // Globals 
224 char    *anim_save_filename;
225 ubyte *cur_frame, *last_frame;
226 ubyte   anim_buffer[ANIM_BUFFER_MAX];
227 int     key_frame_rate;
228 int     force_key_frame;
229 int     total_key_frames;
230 int     anim_offset;
231 int     cur_frame_num;
232 int     Default_fps;
233 int     Use_custom_xparent_color;
234 rgb_triple      Xparent_color;
235
236 int     Compression_type;               // what kind of RLE compression is going to be used 
237 int     Key_frame_compression, Regular_frame_compression;
238
239 key_frame *first_frame;
240 FILE *anim_fp = NULL;
241 anim Anim;
242
243 // AVI_stream_init() is called only to clear USED flag of the AVI_stream structure
244 // and reset the current frame.
245 //
246 //      This does not need to be called explicity, since it will be called by AVI_stream_open()
247 // anyways.
248 //
249 void AVI_stream_init()
250 {
251         AVI_stream.flags &= ~AVI_STREAM_F_USED;
252         AVI_stream.current_frame = 0;
253         AVI_stream_inited = 1;
254
255         AVI_stream.pfile = NULL;
256         AVI_stream.frame_index = NULL;
257 }
258
259 #define FREAD(a, b, c, d) do { if ( fread(a, b, c, d) != b ) { read_error = true; break; } } while (0);
260
261 // AVI_stream_open() will open the AVI file and prepare it for reading, but will not 
262 // store any of the frame data. 
263 //
264 //      returns:   0 ==> success
265 //           !0 ==> could not open the AVI stream
266 //
267 // The filename is expected to be an absolute pathname (or file in the current working directory)
268 //
269 int AVI_stream_open(char* filename)
270 {
271         if ( !AVI_stream_inited )
272                 AVI_stream_init();
273
274         FILE *pfile = NULL;
275         int id = 0;
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;
282
283         SDL_assert( !(AVI_stream.flags & AVI_STREAM_F_USED) );
284
285         SDL_zero(avi_header);
286         SDL_zero(stream_header);
287         SDL_zero(bitmap_header);
288
289         pfile = fopen(filename, "rb");
290
291         if (pfile == NULL) {
292                 printf("AVI ==> Unable to open %s", filename);
293                 return -1;
294         }
295
296         // get file size
297         fseek(pfile, 0, SEEK_END);
298         file_size = ftell(pfile);
299         fseek(pfile, 0, SEEK_SET);
300
301         // check for valid file type
302         if ( fread(&id, 1, 4, pfile) != 4 ) {
303                 printf("AVI => File read ERROR '%s'\n", filename);
304                 fclose(pfile);
305                 return -1;
306         }
307
308         id = INTEL_INT(id);
309
310         // 'RIFF'
311         if (id != 0x46464952) {
312                 printf("Not a RIFF file '%s'\n", filename);
313                 fclose(pfile);
314                 return -1;
315         }
316
317         // skip RIFF size
318         if ( fread(&id, 1, 4, pfile) != 4 ) {
319                 printf("AVI => File read ERROR '%s'\n", filename);
320                 fclose(pfile);
321                 return -1;
322         }
323
324         // check for valid RIFF type
325         if ( fread(&id, 1, 4, pfile) != 4 ) {
326                 printf("AVI => File read ERROR '%s'\n", filename);
327                 fclose(pfile);
328                 return -1;
329         }
330
331         id = INTEL_INT(id);
332
333         // 'AVI '
334         if (id != 0x20495641) {
335                 printf("Not an AVI file '%s'\n", filename);
336                 fclose(pfile);
337                 return -1;
338         }
339
340         // used for main 'LIST' chunks
341         long offset_tmp = 0;
342
343         // in case of error
344         bool read_error = false;
345
346         // parse WAVE tags
347         while ( ftell(pfile) < file_size ) {
348                 FREAD(&tag, 1, 4, pfile);
349                 FREAD(&size, 1, 4, pfile);
350
351                 tag = INTEL_INT(tag);
352                 size = INTEL_INT(size);
353
354                 next_chunk = ftell(pfile) + size;
355
356                 switch (tag) {
357                         // 'LIST'
358                         case 0x5453494c: {
359                                 // sub tag
360                                 FREAD(&s_tag, 1, 4, pfile);
361                                 s_tag = INTEL_INT(s_tag);
362
363                                 switch (s_tag) {
364                                         // 'hdrl'
365                                         case 0x6c726468: {
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);
379
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);
392
393                                                 // check for 'avih'
394                                                 SDL_assert(avi_header.fcc == 0x68697661);
395
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);
399                                                         fclose(pfile);
400                                                         return -1;
401                                                 }
402
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);
406                                                         fclose(pfile);
407                                                         return -1;
408                                                 }
409
410                                                 // update next_chunk offset for sub-chunk
411                                                 offset_tmp = next_chunk;
412                                                 next_chunk = ftell(pfile);
413
414                                                 break;
415                                         }
416
417                                         // 'strl' - subchunk of 'hdrl'
418                                         case 0x6c727473: {
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);
438
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);
458
459                                                 // check for 'strh'
460                                                 SDL_assert(stream_header.fcc == 0x68727473);
461
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);
465                                                         fclose(pfile);
466                                                         return -1;
467                                                 }
468                                                 SDL_assert(stream_header.fccType == 0x73646976);
469
470                                                 // only handle 'MRLE' encoding
471                                                 if (stream_header.fccHandler != 0x454c524d) {
472                                                         printf("AVI is not MRLE encoded '%s'\n", filename);
473                                                         fclose(pfile);
474                                                         return -1;
475                                                 }
476
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);
480                                                         fclose(pfile);
481                                                         return -1;
482                                                 }
483
484                                                 // next stream sub-chunk -------------------------------
485
486                                                 // check for 'strf'
487                                                 FREAD(&tmp, 1, 4, pfile);
488                                                 tmp = INTEL_INT(tmp);
489                                                 SDL_assert(tmp == 0x66727473);
490
491                                                 // size of 'strf'
492                                                 FREAD(&tmp, 1, 4, pfile);
493
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);
505
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);
517
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);
521                                                         fclose(pfile);
522                                                         return -1;
523                                                 }
524
525                                                 // palette
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);
531                                                 }
532
533                                                 // reset next_chunk back to main 'LIST'
534                                                 next_chunk = offset_tmp;
535
536                                                 break;
537                                         }
538
539                                         // 'movi'
540                                         case 0x69766f6d: {
541                                                 // need this for later
542                                                 movi_offset = ftell(pfile);
543
544                                                 // requiring an index, so don't mess with this anymore
545
546                                                 break;
547                                         }
548
549                                         default:
550                                                 printf("sub-something else: 0x%x\n", tag);
551                                                 break;
552                                 }
553
554                                 break;
555                         }
556
557                         // 'idx1'
558                         case 0x31786469: {
559                                 SDL_assert(AVI_stream.frame_index == NULL);
560
561                                 AVI_stream.frame_index = (FRAMEINDEX*) malloc(sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
562                                 SDL_assert(AVI_stream.frame_index != NULL);
563
564                                 memset(AVI_stream.frame_index, 0, sizeof(FRAMEINDEX) * avi_header.dwTotalFrames);
565
566                                 unsigned int c_id, c_flags, c_offset, c_size, i = 0;
567
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);
573
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);
578
579                                         // only interested in stream 0, compressed data: '00dc'
580                                         if (c_id == 0x63643030) {
581                                                 SDL_assert(i < avi_header.dwTotalFrames);
582
583                                                 AVI_stream.frame_index[i].offset = c_offset;
584                                                 AVI_stream.frame_index[i].size = c_size;
585                                                 i++;
586                                         }
587                                 }
588
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;
593                                 }
594
595                                 break;
596                         }
597
598                         // drop everything else
599                         default:
600                                 break;
601                 }
602
603                 if (read_error) {
604                         break;
605                 }
606
607                 fseek(pfile, next_chunk, SEEK_SET);
608         }
609
610         if (read_error) {
611                 printf("AVI => File read ERROR '%s'\n", filename);
612                 fclose(pfile);
613
614                 return -1;
615         }
616
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);
620                 fclose(pfile);
621                 return -1;
622         }
623
624         // fix up frame_index (assumes frame_index[0] is first frame in stream)
625         long base_offset = 0;
626
627         if (AVI_stream.frame_index[0].offset > (unsigned int)movi_offset) {
628                 base_offset = 0;
629         } else if (AVI_stream.frame_index[0].offset == (unsigned int)movi_offset) {
630                 base_offset = 4;
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;
635         } else {
636                 SDL_assert(0);
637         }
638
639         for (unsigned int i = 0; i < avi_header.dwTotalFrames; i++) {
640                 AVI_stream.frame_index[i].offset += base_offset;
641
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;
645                 }
646         }
647
648         // now set up AVI_stream
649
650         strcpy(AVI_stream.filename, filename);
651         AVI_stream.pfile = pfile;
652
653         AVI_stream.min_compressed_buffer_size = SDL_max(avi_header.dwSuggestedBufferSize, stream_header.dwSuggestedBufferSize);
654         SDL_assert(AVI_stream.min_compressed_buffer_size > 0);
655
656         AVI_stream.w = bitmap_header.bmiHeader.biWidth;
657         AVI_stream.h = bitmap_header.bmiHeader.biHeight;
658         AVI_stream.bpp = bitmap_header.bmiHeader.biBitCount;
659
660         // store the number of frames in the AVI_info[] structure
661         AVI_stream.num_frames = avi_header.dwTotalFrames;
662
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;
668         }
669
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;  
672
673         return 0;
674 }
675
676
677 // AVI_stream_close() should be called when you are finished reading all the frames of an AVI
678 //
679 void AVI_stream_close()
680 {       
681 //      SDL_assert( AVI_stream.flags & AVI_STREAM_F_USED);
682
683         if (AVI_stream.pfile) {
684                 fclose(AVI_stream.pfile);
685                 AVI_stream.pfile = NULL;
686         }
687
688         if (AVI_stream.frame_index) {
689                 free(AVI_stream.frame_index);
690                 AVI_stream.frame_index = NULL;
691         }
692
693         AVI_stream.flags &= ~AVI_STREAM_F_USED;                 // clear the used flag
694
695         AVI_stream_inited = 0;
696 }
697
698
699
700
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).
705 // 
706 // returns:    0 ==> success
707 //            !0 ==> error
708 //
709 int AVI_stream_get_frame(ubyte* buffer, int frame_number)
710 {
711         if ( frame_number > AVI_stream.num_frames ) {
712                 buffer = NULL;
713                 return -1;
714         }
715
716         SDL_assert( (frame_number - 1) >= 0 );
717
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);
721
722         fseek(AVI_stream.pfile, AVI_stream.frame_index[frame_number-1].offset, SEEK_SET);
723
724         size_t rsize = AVI_stream.frame_index[frame_number-1].size;
725
726         if ( fread(compressed_frame, 1, rsize, AVI_stream.pfile) == rsize ) {
727                 AVI_decompress_RLE8(compressed_frame, buffer, AVI_stream.w, AVI_stream.h);
728         } else {
729                 printf("AVI : ERROR => short read in get_frame()!\n");
730         }
731
732
733         free( compressed_frame );
734
735         return 0;
736 }
737
738
739
740 // -------------------------------------------------------------------------------------------------
741 // AVI_decompress_RLE8() will decompress the data pointed to by src, and store in dest.
742 //
743 //      NOTE:  1. memory for dest must be already allocated before calling function
744 //
745
746 void AVI_decompress_RLE8(ubyte* src, ubyte* dest, int w, int h)
747 {
748         int src_index = 0;
749         int dest_index = 0;
750         int i;
751
752         SDL_assert( src != NULL);
753         SDL_assert( dest != NULL);
754         SDL_assert( w > 0 );
755         SDL_assert( h > 0 );
756
757         ubyte count = 0;
758         ubyte run = 0;
759         ubyte control_code = 0;
760         ubyte x_off = 0;
761         ubyte y_off = 0;
762
763         int size_src = w * h + 1;
764
765         int scan_line = h-1;
766         int height_offset = scan_line * w;
767
768         while ( src_index < size_src ) {
769                 
770                 count = src[src_index];
771                 
772                 if ( count == 0 ) {     // control code follows
773                         src_index++;
774                         control_code = src[src_index];
775                         if ( control_code == 1 ) {
776                                 src_index++;
777 //                              nprintf(("AVI","AVI ==> Reached end of compressed image\n"));
778                                 break;
779                         }
780                         else if ( control_code == 0 ) {
781                                 src_index++;
782                                 scan_line--;
783                                 height_offset = scan_line * w;  // only need to calc once per scanline
784                                 dest_index = 0;
785                                 if (height_offset < 0) {
786                                         break;
787                                 }
788                                 //nprintf(("AVI","AVI ==> Reached end of line in compressed image\n"));
789                         }
790                         else if ( control_code == 2 ) {
791                                 // delta - horizontal and veritcal offsets
792                                 src_index++;
793                                 x_off = src[src_index];
794
795                                 if (x_off) {
796                                         dest_index += x_off;
797
798                                         if (dest_index >= w) {
799                                                 break;
800                                         }
801                                 }
802
803                                 src_index++;
804                                 y_off = src[src_index];
805
806                                 if (y_off) {
807                                         scan_line -= y_off;
808                                         height_offset = scan_line * w;
809
810                                         if (height_offset < 0) {
811                                                 break;
812                                         }
813                                 }
814
815                                 src_index++;
816                         }
817                         else {
818                                 // in absolute mode
819                                 src_index++;
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) {
823                                                 break;
824                                         }
825                                         dest[height_offset + dest_index] = src[src_index];
826                                         dest_index++;
827                                         src_index++;
828                                 }
829                                 // run must end on a word boundry
830                                 if ( control_code & 1 )
831                                         src_index++;
832                         }
833                 }
834                 else {
835                         src_index++;
836                         run = src[src_index];
837                         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) {
844                                         break;
845                                 }
846                                 dest[height_offset + dest_index] = run;
847                                 dest_index++;
848                         }
849                 }
850
851         }       // end while
852
853 }
854
855 int save_anim_header()
856 {
857         int i, new_format_id = 0;
858
859         SDL_assert(anim_fp);
860         fclose(anim_fp);
861         anim_fp = fopen(anim_save_filename, "r+b");
862
863         if (!fwrite(&new_format_id, 2, 1, anim_fp))
864                 return -1;
865         if (!fwrite(&Anim.version, 2, 1, anim_fp))
866                 return -1;
867         if (!fwrite(&Anim.fps, 2, 1, anim_fp))
868                 return -1;
869         if (!fwrite(&Anim.xparent_r, 1, 1, anim_fp))
870                 return -1;
871         if (!fwrite(&Anim.xparent_g, 1, 1, anim_fp))
872                 return -1;
873         if (!fwrite(&Anim.xparent_b, 1, 1, anim_fp))
874                 return -1;
875         if (!fwrite(&Anim.width, 2, 1, anim_fp))
876                 return -1;
877         if (!fwrite(&Anim.height, 2, 1, anim_fp))
878                 return -1;
879         if (!fwrite(&Anim.total_frames, 2, 1, anim_fp))
880                 return -1;
881         if (!fwrite(&Anim.packer_code, 1, 1, anim_fp))
882                 return -1;
883         if (fwrite(&Anim.palette, 3, 256, anim_fp) != 256)
884                 return -1;
885         if (!fwrite(&total_key_frames, 2, 1, anim_fp))
886                 return -1;
887
888         for (i=0; i<Anim.num_keys; i++) {
889                 if (!fwrite(&Anim.keys[i].frame_num, 2, 1, anim_fp))
890                         return -1;
891
892                 if (!fwrite(&Anim.keys[i].offset, 4, 1, anim_fp))
893                         return -1;
894         }
895
896         if (!fwrite(&anim_offset, 4, 1, anim_fp))
897                 return -1;
898
899         return 0;
900 }
901
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)
906 {
907         int count = 0, frame = 1, rate = key_frame_rate, last;
908
909         if (!rate)
910                 rate = total_frames;
911
912         while (frame <= total_frames) {
913                 count++;
914                 frame += rate;
915         }
916
917         if (force_key_frame >= 0)
918                 count++;
919
920         if (count)
921                 Anim.keys = (key_frame *) malloc(count * sizeof(key_frame));
922
923         count = 0;
924         frame = last = 1;
925         while (frame <= total_frames) {
926                 if ((force_key_frame > last) && (force_key_frame < frame))
927                         Anim.keys[count++].frame_num = force_key_frame;
928
929                 Anim.keys[count++].frame_num = frame;
930                 frame += rate;
931         }
932
933         if (force_key_frame > last)
934                 Anim.keys[count++].frame_num = force_key_frame;
935
936         Anim.num_keys = count;
937         return count;  // number of key frames
938 }
939
940 int anim_save_init(char *file, int width, int height, int frames)
941 {
942         SDL_assert(file);
943         anim_save_filename = file;
944         anim_fp = fopen(file, "wb");
945         if (!anim_fp)
946                 return -1;
947
948         Anim.version = ANIM_VERSION;
949         Anim.fps = Default_fps;
950         Anim.width = width;
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;
957         anim_offset = 0;
958         cur_frame_num = 0;
959         total_key_frames = allocate_key_frames(frames);
960         fseek(anim_fp, ANIM_HEADER_SIZE + total_key_frames * 6, SEEK_SET);
961
962         switch ( Compression_type ) {
963                 case CUSTOM_DELTA_RLE:
964                         Key_frame_compression = PACKING_METHOD_RLE_KEY;
965                         Regular_frame_compression = PACKING_METHOD_RLE;
966                         break;
967
968                 case STD_DELTA_RLE:
969                         Key_frame_compression = PACKING_METHOD_STD_RLE_KEY;
970                         Regular_frame_compression = PACKING_METHOD_STD_RLE;
971                         break;
972
973                 default:
974                         Int3();
975                         return -1;
976                         break;
977         } // end switch
978
979         return 0;
980 }
981
982 int anim_save_frame()
983 {
984         ubyte *temp;
985         int i, size;
986         key_frame *keyp = NULL;
987
988         SDL_assert(anim_fp);
989         cur_frame_num++;
990         SDL_assert(cur_frame_num <= Anim.total_frames);
991
992         for (i=0; i<Anim.num_keys; i++)
993                 if (Anim.keys[i].frame_num == cur_frame_num) {
994                         keyp = &Anim.keys[i];
995                         break;
996                 }
997
998         if (keyp) {
999                 fprintf(stdout, "*");
1000                 fflush(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);
1003
1004         } else {
1005                 fprintf(stdout, ".");
1006                 fflush(stdout);
1007                 size = pack_frame(cur_frame, last_frame, anim_buffer, Anim.width * Anim.height, ANIM_BUFFER_MAX, Regular_frame_compression);
1008         }
1009
1010         if (size < 0)
1011                 return -1;
1012
1013         if ((int) fwrite(anim_buffer, 1, size, anim_fp) != size)
1014                 return -1;
1015
1016         anim_offset += size;
1017         temp = cur_frame;
1018         cur_frame = last_frame;
1019         last_frame = temp;
1020         return 0;
1021 }
1022
1023
1024 // converts an avi file to an anim file
1025 //
1026 // returns:   0 ==> success
1027 //                !0 ==> failure
1028 //
1029 int convert_avi_to_anim(char* filename)
1030 {
1031         char ani_filename[255];
1032         int ret = 1;
1033         int rc, i, xparent_pal_index;
1034         int avi_stream_opened = 0;
1035
1036         rc = AVI_stream_open(filename);
1037         if ( rc != 0 ) {
1038                 // could not open the AVI stream
1039                 goto Finish;
1040         }
1041         avi_stream_opened = 1;
1042         
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);
1047
1048         strcpy(ani_filename, AVI_stream.filename);
1049         strcpy(ani_filename + strlen(ani_filename) - 3, "ani");
1050
1051         memset(&Anim, 0, sizeof(anim));
1052
1053         memcpy(Anim.palette, AVI_stream.palette, 768);
1054
1055         if (Use_custom_xparent_color) {
1056                 // Need to look at pixel in top-left 
1057                 rc = AVI_stream_get_frame(cur_frame, 1);
1058                 if ( rc != 0 )
1059                         goto Finish;
1060
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];
1065
1066         } else {
1067                 Xparent_color.r = 0;
1068                 Xparent_color.g = 255;
1069                 Xparent_color.b = 0;
1070         }
1071         
1072         rc = anim_save_init(ani_filename, AVI_stream.w, AVI_stream.h, AVI_stream.num_frames);
1073         if (rc == -1)
1074                 goto Finish;
1075
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);
1079                 if ( rc != 0 )
1080                         goto Finish;
1081
1082                 // pass to the anim compression
1083                 rc = anim_save_frame();
1084                 if ( rc != 0 )
1085                         goto Finish;
1086         }
1087
1088         rc = save_anim_header();
1089         if ( rc != 0 )
1090                 goto Finish;
1091
1092         ret = 0;
1093
1094         Finish:
1095         // done with the AVI.. close the stream
1096         if ( avi_stream_opened )
1097                 AVI_stream_close();
1098
1099         if ( anim_fp )
1100                 fclose(anim_fp);
1101
1102         if (Anim.keys)
1103                 free(Anim.keys);
1104
1105         free(cur_frame);
1106         free(last_frame);
1107         fprintf(stdout,"\n");
1108         fflush(stdout);
1109         return ret;
1110 }
1111
1112 int convert_frames_to_anim(char *filename)
1113 {
1114         int first, frame, pos, width, height, xparent_pal_index, r = -1;
1115         char ani_filename[255], name[255], temp[8];     
1116         int rc;
1117         FILE *fp;
1118
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 = atoi(&name[pos]);
1125         force_key_frame -= frame;
1126
1127         memset(&Anim, 0, sizeof(anim));
1128
1129         // first file
1130         fp = fopen(name, "rb");
1131         if(fp != NULL){
1132                 do {
1133                         fclose(fp);
1134                         frame++;
1135                         sprintf(temp, "%04d", frame);
1136                         strncpy(&name[pos], temp, 4);   
1137
1138                         // next file
1139                         fp = fopen(name, "rb");
1140                 } while(fp != NULL);    
1141         }
1142
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);
1146                 return -1;
1147         }
1148
1149         cur_frame = (ubyte *) malloc(width * height);
1150         last_frame = (ubyte *) malloc(width * height);
1151
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);
1155                 return -1;
1156         }
1157
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];
1164
1165         } else {
1166                 Xparent_color.r = 0;
1167                 Xparent_color.g = 255;
1168                 Xparent_color.b = 0;
1169         }
1170
1171         if (anim_save_init(ani_filename, width, height, frame - first))
1172                 goto done;
1173
1174         while (first < frame) {
1175                 sprintf(temp, "%04d", first);
1176                 strncpy(&name[pos], temp, 4);
1177                 rc = pcx_read_bitmap_8bpp(name, cur_frame, Anim.palette);
1178                 if (rc != PCX_ERROR_NONE)
1179                         goto done;
1180
1181                 if (anim_save_frame())
1182                         goto done;
1183
1184                 first++;
1185         }
1186
1187         if (save_anim_header())
1188                 goto done;
1189
1190         r = 0;
1191
1192 done:
1193         if (Anim.keys)
1194                 free(Anim.keys);
1195
1196         fclose(anim_fp);
1197         free(cur_frame);
1198         free(last_frame);
1199         fprintf(stdout, "\n");
1200         fflush(stdout);
1201         return r;
1202 }
1203