Import the current wip animation datatype and subclasses. further development will...
[AROS.git] / workbench / classes / datatypes / gifanim / dispatch.c
blob6d1055bc3cab1d7f95f36bbcf7546a3eeb870e22
2 /*
3 **
4 ** $VER: dispatch.c 2.4 (24.5.98)
5 ** gifanim.datatype 2.4
6 **
7 ** Dispatch routine for a DataTypes class
8 **
9 ** Written 1997/1998 by Roland 'Gizzy' Mainz
10 ** Original example source from David N. Junod
14 #ifndef DEBUG
15 # define DEBUG 0
16 #endif
17 #include <aros/debug.h>
19 struct MyStackSwapStruct;
20 struct GIFAnimInstData;
21 struct GIFEncoder;
23 /* main includes */
24 #include "classbase.h"
25 #include "classdata.h"
27 #include "dispatch.h"
29 /* ansi includes */
30 #include <limits.h>
31 #include <stdio.h>
33 /*****************************************************************************/
35 /* decoder related local prototypes */
36 static BOOL ReadColorMap( struct ClassBase *, struct GIFAnimInstData *, UWORD, struct ColorRegister * );
37 static int DoExtension( struct ClassBase *, Object *, struct GIFAnimInstData *, TEXT );
38 static int GetDataBlock( struct ClassBase *, struct GIFAnimInstData *, UBYTE * );
39 static int GetCode( struct ClassBase *, struct GIFAnimInstData *, int, BOOL );
40 static int LWZReadByte( struct ClassBase *, struct GIFAnimInstData *, BOOL, int );
41 static int getbase2( int );
43 /*****************************************************************************/
45 /* local prototypes */
46 static struct FrameNode *AllocFrameNode( struct ClassBase *, APTR );
47 static struct BitMap *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
48 static void AttachSample( struct ClassBase *, struct GIFAnimInstData * );
50 /*****************************************************************************/
52 #if !defined (__AROS__)
53 /* Create "gifanim.datatype" BOOPSI class */
54 struct IClass *initClass( struct ClassBase *cb )
56 struct IClass *cl;
58 /* Create our class... */
59 if( cl = MakeClass( GIFANIMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct GIFAnimInstData ), 0UL ) )
61 cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)Dispatch;
62 #define DTSTACKSIZE (16384UL)
63 cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
64 cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch; /* see stackswap.c */
65 cl -> cl_Dispatcher . h_Data = (APTR)DTSTACKSIZE; /* see stackswap.c */
66 cl -> cl_UserData = cb;
67 AddClass( cl );
70 return( cl );
73 #include "methods.h"
75 /* class dispatcher */
76 DISPATCHERFLAGS
77 ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
79 struct ClassBase *cb = (struct ClassBase *)(cl -> cl_UserData);
80 struct GIFAnimInstData *gaid;
81 ULONG retval = 0UL;
83 switch( msg -> MethodID )
85 case OM_NEW:
86 retval = DT_NewMethod( cl, o, msg );
87 break;
89 case OM_DISPOSE:
90 retval = DT_DisposeMethod( cl, o, msg );
91 break;
93 /* TEST TEST / Support for format change "on-the-fly" disabled here / TEST TEST
94 * DO NOT make any assumptions on this EXPERIMENTAL code !
96 #ifdef COMMENTED_OUT
97 case DTM_FRAMEBOX:
98 retval = DT_FrameBoxMethod( cl, o, msg );
99 break;
100 #endif /* COMMENTED_OUT */
102 case OM_UPDATE:
103 case OM_SET:
104 retval = DT_SetMethod( cl, o, msg );
105 break;
107 case DTM_WRITE:
108 retval = DT_WriteMethod( cl, o, msg );
109 break;
111 case ADTM_LOADFRAME:
112 retval = DT_LoadFrameMethod( cl, o, msg );
113 break;
115 case ADTM_UNLOADFRAME:
116 retval = DT_UnLoadFrameMethod( cl, o, msg );
117 break;
119 /* Let the superclass handle everything else */
120 default:
122 retval = DoSuperMethodA( cl, o, msg );
124 break;
127 return( retval );
129 #endif
131 BOOL ScanFrames( struct ClassBase *cb, Object *o )
133 struct GIFAnimInstData *gaid = (struct GIFAnimInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
134 LONG error = 0L;
135 BOOL success = FALSE;
137 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
139 InitSemaphore( (&(gaid -> gaid_SigSem)) );
140 NewList( (struct List *)(&(gaid -> gaid_FrameList)) );
142 /* Create a memory pool for frame nodes */
143 if ((gaid -> gaid_Pool = CreatePool( MEMF_PUBLIC, 8192UL, 8192UL ) ) != NULL)
145 BPTR fh; /* handle (file handle) */
146 IPTR sourcetype; /* type of stream (either DTST_FILE or DTST_RAM) */
147 ULONG modeid /*= (ULONG)INVALID_ID*/; /* anim view mode */
148 ULONG animwidth, /* anim width */
149 animheight, /* anim height */
150 animdepth; /* anim depth */
151 ULONG timestamp = 0UL; /* timestamp */
153 D(bug("[gifanim.datatype] %s: pool @ 0x%p\n", __PRETTY_FUNCTION__, gaid -> gaid_Pool));
155 /* Prefs defaults */
156 gaid -> gaid_LoadAll = TRUE; /* The decoder is too slow to allow realtime decoding of a
157 * 576 * 124 * 8 GIF Image, even on a mc68040 :-((
159 gaid -> gaid_ModeID = (ULONG)INVALID_ID; /* no screen mode selected yet */
160 gaid -> gaid_Volume = 64UL;
162 /* Read prefs */
163 ReadENVPrefs( cb, gaid, NULL );
165 /* Get file handle, handle type and BitMapHeader */
166 if( GetDTAttrs( o, DTA_SourceType, (&sourcetype),
167 DTA_Handle, (&fh),
168 DTA_Name, (&(gaid -> gaid_ProjectName)),
169 TAG_DONE ) == 3UL )
171 switch( sourcetype )
173 case DTST_FILE:
175 D(bug("[gifanim.datatype] %s: DTST_FILE (0x%p)\n", __PRETTY_FUNCTION__, fh));
177 if( fh )
179 BPTR lock;
181 if ((lock = DupLockFromFH( fh ) ) != BNULL)
183 /* Set up a filehandle for disk-based loading (random loading) */
184 if ((gaid -> gaid_FH = (BPTR)OpenFromLock( lock ) ) != BNULL)
186 success = TRUE;
188 else
190 /* failure */
191 UnLock( lock );
196 /* OpenFromLock failed ? - Then open by name :-( */
197 if( (gaid -> gaid_FH) == BNULL )
199 /* Set up a filehandle for disk-based loading (random loading) */
200 if ((gaid -> gaid_FH = (BPTR)Open( (gaid -> gaid_ProjectName), MODE_OLDFILE ) ) != BNULL)
202 success = TRUE;
204 else
206 /* Can't open file */
207 error = IoErr();
211 break;
213 case DTST_RAM: /* empty object */
215 D(bug("[gifanim.datatype] %s: DTST_RAM\n", __PRETTY_FUNCTION__));
217 success = TRUE;
219 break;
221 default:
223 /* unsupported source type */
224 error = ERROR_NOT_IMPLEMENTED;
226 break;
229 /* Any error ? */
230 if( success )
232 /* Now we enter the next stage of testing... */
233 success = FALSE;
235 if( fh )
237 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
238 struct FrameNode *fn;
239 ULONG numcmaps = 0UL; /* number of created cmaps */
240 UBYTE buf[ 16 ];
241 struct ColorRegister localColorMap[ MAXCOLORMAPSIZE ] = { 0 };
242 struct ColorRegister savedTransparentColor = { 0 };
243 UBYTE c;
244 BOOL useGlobalColormap;
245 UWORD bitPixel;
247 gifdec -> file = fh;
248 gifdec -> Gif89 . transparent = (UWORD)~0U; /* means: no transparent color */
250 D(bug("[gifanim.datatype] %s: checking sig..\n", __PRETTY_FUNCTION__));
252 /* Read "GIF" indentifer and version */
253 if( ReadOK( cb, gifdec, buf, 6 ) )
255 /* Is there the GIF signature ? */
256 if( !strncmp( (char *)buf, "GIF", 3 ) )
258 STRPTR version = (STRPTR)(buf + 3);
260 D(bug("[gifanim.datatype] %s: checking gif version..\n", __PRETTY_FUNCTION__));
262 /* Check if we support this GIF version */
263 if( (!strncmp( version, "87a", 3 )) ||
264 (!strncmp( version, "89a", 3 )) )
266 D(bug("[gifanim.datatype]: %s: read gif screen..\n", __PRETTY_FUNCTION__));
268 /* Read GIF Screen */
269 if( ReadOK( cb, gifdec, buf, 7 ) )
271 struct FrameNode *prevnode = NULL;
272 UBYTE *deltamap = NULL;
274 gifdec -> GifScreen . Width = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
275 gifdec -> GifScreen . Height = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
276 gifdec -> GifScreen . BitPixel = 2 << (buf[ 4 ] & 0x07);
277 gifdec -> GifScreen . ColorResolution = (((buf[ 4 ] & 0x70) >> 3) + 1);
278 gifdec -> GifScreen . Background = buf[ 5 ];
279 gifdec -> GifScreen . AspectRatio = buf[ 6 ];
281 gaid -> gaid_Width = gifdec -> GifScreen . Width;
282 animwidth = gaid -> gaid_PaddedWidth = (gaid -> gaid_UseChunkyMap)?(gaid -> gaid_Width):(((gaid -> gaid_Width) + 15UL) & ~15UL); /* align for c2p-wpa (c2c does not need padding) */
283 animheight = gaid -> gaid_Height = gifdec -> GifScreen . Height;
284 animdepth = gaid -> gaid_Depth = (gaid -> gaid_UseChunkyMap)?(DIRECTRGB_DEPTH):((ULONG)getbase2( (gifdec -> GifScreen . BitPixel) ));
286 D(bug("[gifanim.datatype] %s: %dx%dx%d\n", __PRETTY_FUNCTION__, animwidth, animheight, animdepth));
288 /* Global Colormap ? */
289 if( BitSet( buf[ 4 ], LOCALCOLORMAP ) )
291 D(bug("[gifanim.datatype]: %s: reading global colormap..\n", __PRETTY_FUNCTION__));
293 numcmaps++;
295 if( ReadColorMap( cb, gaid, (gifdec -> GifScreen . BitPixel), (gifdec -> GifScreen . ColorMap) ) )
297 D(bug("[gifanim.datatype]: %s: failed!\n", __PRETTY_FUNCTION__));
298 error = IoErr();
299 error_printf( cb, gaid, "error %d reading global colormap\n", error);
302 else
304 /* No global colormap ? - Then the background color in the GifScreen is a NOP */
305 gifdec -> GifScreen . Background = 0U;
308 while (TRUE)
310 D(bug("[gifanim.datatype]: %s: reading chunk..\n", __PRETTY_FUNCTION__));
311 /* Read chunk ID char */
312 if( !ReadOK( cb, gifdec, (&c), 1 ) )
314 error = IoErr();
315 error_printf( cb, gaid, "EOF / read error on image data (%x)\n", error);
316 break;
319 switch( c )
321 case ';': /* GIF terminator ? */
323 D(bug("[gifanim.datatype]: %s: ## terminator\n", __PRETTY_FUNCTION__));
325 goto scandone;
328 case '!': /* Extension ? */
330 D(bug("[gifanim.datatype]: %s: ## extension\n", __PRETTY_FUNCTION__));
332 if( ReadOK( cb, gifdec, (&c), 1 ) )
334 if( DoExtension( cb, o, gaid, c ) == -1 )
336 error = IoErr();
337 error_printf( cb, gaid, "error %x in extension\n", error);
338 goto scandone;
341 else
343 error = IoErr();
344 error_printf( cb, gaid, "OF / read error on extension function code (%x)\n", error);
345 goto scandone;
348 break;
350 case ',': /* Raster data start ? */
352 D(bug("[gifanim.datatype]: %s: ## rast data\n", __PRETTY_FUNCTION__));
354 /* Create an prepare a new frame node */
355 if ((fn = AllocFrameNode( cb, (gaid -> gaid_Pool) )) != NULL)
357 D(bug("[gifanim.datatype]: %s: frame node @ 0x%p\n", __PRETTY_FUNCTION__, fn));
358 if( (gaid -> gaid_LoadAll) || (timestamp == 0UL) )
360 if( !(fn -> fn_BitMap = AllocFrameBitMap( cb, gaid ) ) )
362 D(bug("[gifanim.datatype]: %s: failed to allocate bitmap!\n", __PRETTY_FUNCTION__));
363 error = ERROR_NO_FREE_STORE;
366 /* Allocate array for chunkypixel data */
367 if ((fn -> fn_ChunkyMap = (UBYTE *)AllocPooledVec( cb, (gaid -> gaid_Pool), ((animwidth * animheight) + 256) )) != NULL)
369 /* Get a clean background to avoid that rubbish shows througth transparent parts */
370 memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
372 else
374 D(bug("[gifanim.datatype]: %s: failed to allocate chunky data!\n", __PRETTY_FUNCTION__));
375 error = ERROR_NO_FREE_STORE;
379 if( error == 0L )
381 ULONG duration;
383 /* Get position of bitmap */
384 fn -> fn_BMOffset = Seek( fh, 0L, OFFSET_CURRENT ); /* BUG: does not check for failure */
386 D(bug("[gifanim.datatype]: %s: bitmap offset %lu\n", __PRETTY_FUNCTION__, fn->fn_BMOffset));
388 if( !ReadOK( cb, gifdec, buf, 9 ) )
390 error = IoErr();
391 error_printf( cb, gaid, "couldn't read left/top/width/height (%x)\n", error);
392 goto scandone;
395 /* Local color map ? */
396 useGlobalColormap = !BitSet( buf[ 8 ], LOCALCOLORMAP );
398 /* Size of local color map */
399 bitPixel = 1 << ((buf[ 8 ] & 0x07) + 1);
401 /* Store GIF89a related attributes */
402 fn -> fn_GIF89aDisposal = gifdec -> Gif89 . disposal; /* Store disposal mode for current frame */
403 fn -> fn_GIF89aTransparent = gifdec -> Gif89 . transparent; /* Store currents frame transparent color */
405 if( fn -> fn_ChunkyMap )
407 D(bug("[gifanim.datatype]: %s: chunky\n", __PRETTY_FUNCTION__));
409 /* disposal method */
410 switch( fn -> fn_GIF89aDisposal )
412 case GIF89A_DISPOSE_NOP:
414 D(bug("[gifanim.datatype]: %s: GIF89A_DISPOSE_NOP\n", __PRETTY_FUNCTION__));
415 /* Background not transparent ? */
416 if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
417 ((fn -> fn_GIF89aTransparent) != 0U) )
419 /* restore to color 0 */
420 memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
423 break;
425 case GIF89A_DISPOSE_NODISPOSE:
427 D(bug("[gifanim.datatype]: %s: GIF89A_DISPOSE_NODISPOSE\n", __PRETTY_FUNCTION__));
428 /* do not dispose prev image */
430 /* If we have a previous frame, copy it */
431 if( prevnode )
433 CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
434 #ifdef DELTAWPA8
435 CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
436 deltamap = prevnode -> fn_ChunkyMap;
437 #endif /* DELTAWPA8 */
439 else
441 /* Background not transparent ? */
442 if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
443 ((fn -> fn_GIF89aTransparent) != 0U) )
445 /* restore to color 0 */
446 memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
448 #ifdef DELTAWPA8
449 deltamap = NULL;
450 #endif /* DELTAWPA8 */
453 break;
455 case GIF89A_DISPOSE_RESTOREBACKGROUND:
457 D(bug("[gifanim.datatype]: %s: GIF89A_DISPOSE_RESTOREBACKGROUND\n", __PRETTY_FUNCTION__));
458 /* Background not transparent ? */
459 if( ((fn -> fn_GIF89aTransparent) == ~0U) ||
460 ((fn -> fn_GIF89aTransparent) != (gaid -> gaid_GIFDec . GifScreen . Background)) )
462 /* Restore to background color */
463 memset( (fn -> fn_ChunkyMap), (gifdec -> GifScreen . Background), (size_t)(animwidth * animheight) );
466 break;
468 case GIF89A_DISPOSE_RESTOREPREVIOUS:
470 D(bug("[gifanim.datatype]: %s: GIF89A_DISPOSE_RESTOREPREVIOUS\n", __PRETTY_FUNCTION__));
471 /* restore previous image */
473 /* If we have a previous frame, copy it */
474 if( prevnode )
476 CopyMem( (prevnode -> fn_ChunkyMap), (fn -> fn_ChunkyMap), (animwidth * animheight) );
477 #ifdef DELTAWPA8
478 CopyBitMap( cb, (fn -> fn_BitMap), (prevnode -> fn_BitMap), animwidth, animheight );
479 deltamap = prevnode -> fn_ChunkyMap;
480 #endif /* DELTAWPA8 */
482 else
484 /* restore to color 0 */
485 memset( (fn -> fn_ChunkyMap), 0, (size_t)(animwidth * animheight) );
486 #ifdef DELTAWPA8
487 deltamap = NULL;
488 #endif /* DELTAWPA8 */
491 break;
493 default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
495 error_printf( cb, gaid, "unsupported disposal method %lu\n", (ULONG)(gifdec -> Gif89 . disposal) );
497 break;
501 /* Save transparent color (if we have one) */
502 if( ((fn -> fn_GIF89aTransparent) != ~0U) && (timestamp != 0UL) )
504 D(bug("[gifanim.datatype]: %s: save transp\n", __PRETTY_FUNCTION__));
505 savedTransparentColor = localColorMap[ (fn -> fn_GIF89aTransparent) ];
508 /* Get colormap */
509 if( useGlobalColormap )
511 /* use global colormap and depth */
512 bitPixel = gifdec -> GifScreen . BitPixel;
513 memcpy( localColorMap, (gifdec -> GifScreen . ColorMap), (sizeof( struct ColorRegister ) * bitPixel) );
515 else
517 D(bug("[gifanim.datatype]: %s: reading colormap...\n", __PRETTY_FUNCTION__));
518 numcmaps++;
520 if( ReadColorMap( cb, gaid, bitPixel, localColorMap ) )
522 error = IoErr();
523 error_printf( cb, gaid, "error %x reading local colormap\n", error);
524 goto scandone;
528 /* Restore transparent color (if we have one) */
529 if( (fn -> fn_GIF89aTransparent) != ~0U )
531 D(bug("[gifanim.datatype]: %s: restore transp\n", __PRETTY_FUNCTION__));
532 localColorMap[ (fn -> fn_GIF89aTransparent) ] = savedTransparentColor;
535 if( !(gaid -> gaid_UseChunkyMap) )
537 /* The first palette must be moved to the object's palette */
538 if( timestamp == 0UL )
540 if( !CMAP2Object( cb, o, (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) ) )
542 D(bug("[gifanim.datatype]: %s: failed to allocate object cmap!\n", __PRETTY_FUNCTION__));
543 /* can't alloc object's color table */
544 error = ERROR_NO_FREE_STORE;
548 /* Create a palette-per-frame colormap here */
549 if( !(fn -> fn_CMap = CMAP2ColorMap( cb, (1UL << (ULONG)(gaid -> gaid_Depth)), (UBYTE *)localColorMap, (ULONG)(bitPixel * 3UL) )) )
551 D(bug("[gifanim.datatype]: %s: failed to allocate frame cmap!\n", __PRETTY_FUNCTION__));
552 /* can't alloc colormap */
553 error = ERROR_NO_FREE_STORE;
557 D(bug("[gifanim.datatype]: %s: copying colormap\n", __PRETTY_FUNCTION__));
558 /* Copy colormap for 24 bit output */
559 memcpy( (void *)(fn -> fn_ColorMap), (void *)localColorMap, (size_t)(sizeof( struct ColorRegister ) * bitPixel) );
561 D(bug("[gifanim.datatype]: %s: reading image ...\n", __PRETTY_FUNCTION__));
562 (void)ReadImage( cb, gaid,
563 (fn -> fn_ChunkyMap),
564 (UWORD)animwidth,
565 LOHI2UINT16( buf[ 0 ], buf[ 1 ] ),
566 LOHI2UINT16( buf[ 2 ], buf[ 3 ] ),
567 LOHI2UINT16( buf[ 4 ], buf[ 5 ] ),
568 LOHI2UINT16( buf[ 6 ], buf[ 7 ] ),
569 BitSet( buf[ 8 ], INTERLACE ),
570 ((fn -> fn_BitMap) == NULL),
571 (fn -> fn_GIF89aTransparent) );
573 /* Get size of bitmap (curr_pos - start_of_bm) */
574 fn -> fn_BMSize = Seek( fh, 0L, OFFSET_CURRENT ) - (fn -> fn_BMOffset); /* BUG: does not check for failure */
576 D(bug("[gifanim.datatype]: %s: bitmap = %d bytes\n", __PRETTY_FUNCTION__, fn->fn_BMSize));
578 if( fn -> fn_BitMap )
580 D(bug("[gifanim.datatype]: %s: rendering to bitmap @ 0x%p\n", __PRETTY_FUNCTION__, fn->fn_BitMap));
581 if( gaid -> gaid_UseChunkyMap )
583 WriteRGBPixelArray8( cb, (fn -> fn_BitMap), animwidth, animheight, (fn -> fn_ColorMap), (fn -> fn_ChunkyMap) );
585 else
587 WriteDeltaPixelArray8Fast( (fn -> fn_BitMap), (fn -> fn_ChunkyMap), deltamap );
591 /* Bump timestamp... */
592 if( ((gifdec -> Gif89 . delayTime) != ~0U) &&
593 ((gifdec -> Gif89 . delayTime) > 1U) &&
594 ((gifdec -> Gif89 . delayTime) < 2000U) )
596 duration = (gifdec -> Gif89 . delayTime);
598 else
600 duration = 0;
603 fn -> fn_TimeStamp = timestamp;
604 fn -> fn_Frame = timestamp;
605 fn -> fn_Duration = duration;
607 D(bug("[gifanim.datatype]: %s: %08p:%08p\n", __PRETTY_FUNCTION__, fn->fn_TimeStamp, fn->fn_Duration));
609 AddTail( (struct List *)(&(gaid -> gaid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
611 prevnode = fn;
613 /* Next frame starts at timestamp... */
614 timestamp += (fn -> fn_Duration) + 1UL;
618 break;
620 case 0x00: /* padding byte ? */
622 /* Padding bytes are not part of the Compuserve documents, but... */
623 if( !(gaid -> gaid_StrictSyntax) )
625 break;
628 /* fall througth */
629 default: /* Not a valid raster data start character ? */
631 error_printf( cb, gaid, "invalid character 0x%02x, ignoring\n", (int)c );
633 break;
636 /* on error break */
637 if( error )
639 D(bug("[gifanim.datatype]: %s: ERROR!\n", __PRETTY_FUNCTION__));
640 break;
644 scandone:
645 D(bug("[gifanim.datatype]: %s: scan done\n", __PRETTY_FUNCTION__));
647 /* Any frames ? */
648 if( timestamp && (error == 0L) && numcmaps )
650 if( numcmaps == 1UL )
652 /* We only have a global colormap and no colormap changes (or a direct RGB bitmap),
653 * delete first colormap (a colormap in the first frames indicates following colormap
654 * changes)
656 struct FrameNode *firstnode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
658 if( firstnode -> fn_CMap )
660 FreeColorMap( (firstnode -> fn_CMap) );
661 firstnode -> fn_CMap = NULL;
664 else
666 /* All frames must have a colormap, therefore we replicate the colormap
667 * from the previous colormap if one is missing
669 struct FrameNode *worknode,
670 *nextnode;
671 struct ColorMap *currcm = NULL;
673 verbose_printf( cb, gaid, "Animation has palette changes per frame\n" );
675 worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
677 while ((nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) ) != NULL)
679 if( worknode -> fn_CMap )
681 /* Current node contains colormap, this are the colors for the following frames... */
682 currcm = worknode -> fn_CMap;
684 else
686 if( currcm )
688 /* Copy colormap from previous one... */
689 if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
691 /* Can't copy/alloc colormap */
692 error = ERROR_NO_FREE_STORE;
695 else
697 verbose_printf( cb, gaid, "scan/load: no colormap, can't copy it\n" );
701 worknode = nextnode;
706 /* Check for required information */
707 if( error == 0L )
709 /* Any frames loaded ? */
710 if( timestamp == 0UL )
712 /* not enougth frames (at least one required) */
713 error = DTERROR_NOT_ENOUGH_DATA;
717 /* Any error ? */
718 if( error == 0L )
720 struct FrameNode *firstfn = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head); /* short cut to the first FrameNode */
722 /* Alloc bitmap as key bitmap */
723 if( gaid -> gaid_UseChunkyMap )
725 gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL );
727 else
729 gaid -> gaid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, BMF_CLEAR, NULL );
732 if( gaid -> gaid_KeyBitMap )
734 if( (firstfn -> fn_BitMap) == NULL )
736 /* can't alloc first bitmap */
737 error = ERROR_NO_FREE_STORE;
740 if( error == 0L )
742 /* Copy first frame into key bitmap */
743 CopyBitMap( cb, (gaid -> gaid_KeyBitMap), (firstfn -> fn_BitMap), animwidth, animheight );
745 /* No screen mode id set by prefs ? */
746 if( (gaid -> gaid_ModeID) != (ULONG)INVALID_ID )
748 modeid = gaid -> gaid_ModeID;
750 else
752 if( gaid -> gaid_UseChunkyMap )
754 /* We don't have fixed values for cybergfx mode id's, therefore we have to ask for them */
755 if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth, animwidth,
756 CYBRBIDTG_NominalHeight, animheight,
757 CYBRBIDTG_Depth, animdepth,
758 TAG_DONE )) == INVALID_ID )
760 #if 0
761 error = 1L; /* inducate an error here :-( */
762 #else
763 /* Workaround for CyberGFX bug :-( */
764 if( (modeid = BestCModeIDTags( CYBRBIDTG_NominalWidth, 640UL,
765 CYBRBIDTG_NominalHeight, 480UL,
766 CYBRBIDTG_Depth, animdepth,
767 TAG_DONE )) == INVALID_ID )
769 modeid = 0UL;
771 error_printf( cb, gaid, "'CyberGFX bug' workaround failed, too ! Using modeid=%x.\n", modeid);
773 #endif
775 error_printf( cb, gaid, "No screenmode available for %lu/%lu/%lu\n", animwidth, animheight, animdepth );
778 else
780 /* BUG: Does currently not support SUPERHIRES modes */
781 if( animwidth >= 640UL )
783 if( animheight >= 400 )
785 modeid = HIRESLACE_KEY;
787 else
789 modeid = HIRES_KEY;
792 else
794 if( animheight >= 400 )
796 modeid = LORESLACE_KEY;
798 else
800 modeid = LORES_KEY;
806 /* No fps set by prefs ? */
807 if( (gaid -> gaid_FPS) == 0UL )
809 gaid -> gaid_FPS = 100; /* defaults to 100 fps. GIF 89a delay values counts in
810 * 1/100 sec steps. We set the alf_Duration field
811 * to this value (got from the GIF 89a extension).
815 AttachSample( cb, gaid );
817 verbose_printf( cb, gaid, "width %lu height %lu depth %lu frames %lu fps %lu\n",
818 animwidth,
819 animheight,
820 animdepth,
821 timestamp,
822 (gaid -> gaid_FPS) );
824 /* Set misc. attributes */
825 SetDTAttrs( o, NULL, NULL,
826 DTA_ObjName, (gaid -> gaid_ProjectName),
827 DTA_TotalHoriz, animwidth,
828 DTA_TotalVert, animheight,
829 ADTA_Width, (gaid -> gaid_Width),
830 ADTA_Height, animheight,
831 ADTA_Depth, animdepth,
832 ADTA_Frames, timestamp,
833 ADTA_FramesPerSecond, (gaid -> gaid_FPS),
834 ADTA_ModeID, modeid,
835 ADTA_KeyFrame, (gaid -> gaid_KeyBitMap),
836 XTAG( (firstfn -> fn_Sample), ADTA_Sample ), (firstfn -> fn_Sample),
837 XTAG( (firstfn -> fn_Sample), ADTA_SampleLength ), ((firstfn -> fn_SampleLength) / ((firstfn -> fn_Duration) + 1UL)),
838 XTAG( (firstfn -> fn_Sample), ADTA_Period ), (firstfn -> fn_Period),
839 XTAG( (firstfn -> fn_Sample), ADTA_Volume ), (gaid -> gaid_Volume),
840 TAG_DONE );
842 /* All done for now... */
843 success = TRUE;
846 else
848 /* can't alloc key bitmap */
849 error = ERROR_NO_FREE_STORE;
853 else
855 error = IoErr();
856 error_printf( cb, gaid, "failed to read gif screen descriptor (%x)\n", error);
859 else
861 /* unsupported GIF version number */
862 error = DTERROR_UNKNOWN_COMPRESSION;
863 error_printf( cb, gaid, "error %x bad version number, not '87a' or '89a'\n", error);
866 else
868 /* no GIF signature */
869 error = ERROR_OBJECT_WRONG_TYPE;
870 error_printf( cb, gaid, "error %x not a GIF file\n", error);
873 else
875 error = IoErr();
876 error_printf( cb, gaid, "error %x reading magic number\n", error);
879 /* Prepare decoder for dynamic frame access */
880 gifdec -> file = gaid -> gaid_FH;
882 else
884 /* No file handle ? - Be sure we got a DTST_RAM sourcetype */
885 if( sourcetype == DTST_RAM )
887 /* The object is used without any input file.
888 * This "empty" object is used to run the encoder only...
890 success = TRUE;
892 else
894 /* No handle ! */
895 error = ERROR_REQUIRED_ARG_MISSING;
900 else
902 /* can't get required attributes from superclass */
903 error = ERROR_OBJECT_WRONG_TYPE;
906 else
908 /* no memory pool */
909 error = ERROR_NO_FREE_STORE;
912 SetIoErr( error );
914 return( success );
918 static
919 struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
921 struct FrameNode *fn;
923 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
925 if ((fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) ) != NULL)
927 memset( fn, 0, sizeof( struct FrameNode ) );
930 return( fn );
934 struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
937 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
939 if( fnl )
941 struct FrameNode *worknode,
942 *nextnode,
943 *prevnode;
945 prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
947 while ((nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) ) != NULL)
949 if( (worknode -> fn_TimeStamp) > timestamp )
951 return( prevnode );
954 prevnode = worknode;
955 worknode = nextnode;
958 if( !IsListEmpty( ((struct List *)fnl) ) )
960 return( prevnode );
964 return( NULL );
968 void FreeFrameNodeResources( struct ClassBase *cb, struct GIFAnimInstData *gaid )
970 struct FrameNode *worknode;
972 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
974 /* The follwoing was used for debugging */
975 /* #define FREE_LIST_IN_REVERSE_ORDER 1 */
977 #ifdef FREE_LIST_IN_REVERSE_ORDER
978 struct FrameNode *nextnode;
980 worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
982 while ((nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) ) != NULL)
983 #else
984 while ((worknode = (struct FrameNode *)RemTail( (struct List *)(&(gaid -> gaid_FrameList)) ) ) != NULL)
985 #endif /* FREE_LIST_IN_REVERSE_ORDER */
987 if( worknode -> fn_CMap )
989 FreeColorMap( (worknode -> fn_CMap) );
990 worknode -> fn_CMap = NULL;
993 if( worknode -> fn_BitMap )
995 FreeFrameBitMap( cb, gaid, (worknode -> fn_BitMap) );
996 worknode -> fn_BitMap = NULL;
999 #ifdef FREE_LIST_IN_REVERSE_ORDER
1000 worknode = nextnode;
1001 #endif /* FREE_LIST_IN_REVERSE_ORDER */
1006 struct BitMap *AllocFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid )
1008 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1010 if( gaid -> gaid_UseChunkyMap )
1012 return( AllocBitMap( (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth),
1013 (BMF_SPECIALFMT | SHIFT_PIXFMT( DIRECTRGB_PIXFMT )), NULL ) );
1015 else
1017 return( AllocBitMapPooled( cb, (ULONG)(gaid -> gaid_PaddedWidth), (ULONG)(gaid -> gaid_Height), (ULONG)(gaid -> gaid_Depth), (gaid -> gaid_Pool) ) );
1022 void FreeFrameBitMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, struct BitMap *bm )
1024 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1026 if( bm )
1028 if( gaid -> gaid_UseChunkyMap )
1030 FreeBitMap( bm );
1032 else
1034 FreePooledVec( cb, (gaid -> gaid_Pool), bm );
1040 /* This function assumes (0UL < depth) && (depth <= 8UL) */
1041 static
1042 struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
1044 struct BitMap *bm;
1046 ULONG planesize,
1047 size;
1049 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1051 planesize = (ULONG)RASSIZE( width, height ) + 16UL;
1052 size = ((ULONG)sizeof( struct BitMap )) + (planesize * depth) + width;
1054 if ((bm = (struct BitMap *)AllocPooledVec( cb, pool, size ) ) != NULL)
1056 UWORD pl;
1057 PLANEPTR plane;
1059 InitBitMap( bm, depth, width, height );
1061 plane = (PLANEPTR)(bm + 1); /* First plane follows struct BitMap */
1063 /* Set up plane data */
1064 pl = 0U;
1066 /* Set up plane ptrs */
1067 while( pl < depth )
1069 bm -> Planes[ pl ] = plane;
1071 plane = (PLANEPTR)(((UBYTE *)plane) + planesize + 8);
1072 pl++;
1075 /* Clear the remaining plane ptrs */
1076 while( pl < 8U )
1078 bm -> Planes[ pl ] = NULL;
1080 pl++;
1084 return( bm );
1088 void OpenLogfile( struct ClassBase *cb, struct GIFAnimInstData *gaid )
1090 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1092 if( ((gaid -> gaid_VerboseOutput) == NULL) || ((gaid -> gaid_VerboseOutput) == (APTR)-1L) )
1094 STRPTR confile;
1096 if ((confile = (STRPTR)AllocVec( (((gaid -> gaid_ProjectName)?(strlen( (gaid -> gaid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) ) != NULL)
1098 mysprintf( cb, confile, "CON:////GIF Anim DataType %s/auto/wait/close/inactive",
1099 ((gaid -> gaid_ProjectName)?(FilePart( (gaid -> gaid_ProjectName) )):(NULL)) );
1101 gaid -> gaid_VerboseOutput = Open( confile, MODE_READWRITE );
1103 FreeVec( confile );
1109 #if !defined(__AROS__)
1110 void error_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
1112 va_list args;
1114 if( (gaid -> gaid_VerboseOutput) != (BPTR)-1L )
1116 OpenLogfile( cb, gaid );
1118 if( gaid -> gaid_VerboseOutput )
1120 va_start (args, format);
1121 VFPrintf( (gaid -> gaid_VerboseOutput), format, args);
1122 va_end (args);
1128 void verbose_printf( struct ClassBase *cb, struct GIFAnimInstData *gaid, STRPTR format, ... )
1130 va_list args;
1132 if( (gaid -> gaid_VerboseOutput) && ((gaid -> gaid_VerboseOutput) != (BPTR)-1L) )
1134 va_start (args, format);
1135 VFPrintf( (gaid -> gaid_VerboseOutput), format, args);
1136 va_end (args);
1139 #endif
1141 static
1142 void AttachSample( struct ClassBase *cb, struct GIFAnimInstData *gaid )
1144 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1146 if( gaid -> gaid_Sample )
1148 struct FrameNode *worknode,
1149 *nextnode;
1151 ULONG period = gaid -> gaid_Period;
1152 ULONG samplesperframe;
1153 BYTE *sample = gaid -> gaid_Sample;
1155 samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (gaid -> gaid_FPS) * 2UL));
1157 if( gaid -> gaid_SamplesPerFrame )
1159 period = (period * samplesperframe) / (gaid -> gaid_SamplesPerFrame);
1161 samplesperframe = gaid -> gaid_SamplesPerFrame;
1163 verbose_printf( cb, gaid, "period corrected from %lu to %lu to match spf=%lu with fps=%lu\n",
1164 (gaid -> gaid_Period), period, samplesperframe, (gaid -> gaid_FPS) );
1167 verbose_printf( cb, gaid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
1168 (SysBase -> ex_EClockFrequency), period, (gaid -> gaid_FPS), (gaid -> gaid_SampleLength), samplesperframe );
1170 worknode = (struct FrameNode *)(gaid -> gaid_FrameList . mlh_Head);
1172 while ((nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) ) != NULL)
1174 worknode -> fn_Sample = sample;
1175 worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
1176 worknode -> fn_Period = period;
1178 sample += worknode -> fn_SampleLength;
1180 /* End of sample reached ? */
1181 if( (IPTR)(sample - (gaid -> gaid_Sample)) > (gaid -> gaid_SampleLength) )
1183 /* Cut last size of sample to fit */
1184 worknode -> fn_SampleLength -= (IPTR)(sample - (gaid -> gaid_Sample));
1186 break;
1189 worknode = nextnode;
1195 /* Read a GIF colormap info a struct ColorRegister */
1196 static
1197 BOOL ReadColorMap( struct ClassBase *cb, struct GIFAnimInstData *gaid, UWORD numcolors, struct ColorRegister *color )
1199 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1201 return( (BOOL)(!ReadOK( cb, (&(gaid -> gaid_GIFDec)), color, (ULONG)(GIFCMAPENTRYSIZE * numcolors) )) );
1205 static
1206 int DoExtension( struct ClassBase *cb, Object *o, struct GIFAnimInstData *gaid, TEXT label )
1208 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
1209 UBYTE buf[ 257 ] = { 0 };
1210 STRPTR str;
1211 int count;
1213 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1215 switch( (int)label )
1217 case 0x01: /* Plain Text Extension */
1219 UWORD lpos,
1220 tpos,
1221 width,
1222 height,
1223 cellw,
1224 cellh,
1225 foreground,
1226 background;
1228 error_printf( cb, gaid, "'Plain text extension' (%d) not supported yet. Please send this animation to the author that"
1229 "this can be implemented\n", (int)label );
1231 if( GetDataBlock( cb, gaid, buf ) == -1 )
1233 return( -1 );
1236 lpos = LOHI2UINT16( buf[ 0 ], buf[ 1 ] );
1237 tpos = LOHI2UINT16( buf[ 2 ], buf[ 3 ] );
1238 width = LOHI2UINT16( buf[ 4 ], buf[ 5 ] );
1239 height = LOHI2UINT16( buf[ 6 ], buf[ 7 ] );
1240 cellw = buf[ 8 ];
1241 cellh = buf[ 9 ];
1242 foreground = buf[ 10 ];
1243 background = buf[ 11 ];
1245 verbose_printf( cb, gaid, "Plain text: "
1246 "left %lu top %lu width %lu height %lu "
1247 "cell width %lu cell height %lu"
1248 "foreground %lu background %lu", lpos, tpos, width, height, cellw, cellh, foreground, background );
1250 while( (count = GetDataBlock( cb, gaid, buf )), ((count != 0) && (count != -1)) )
1252 #if 0
1253 PPM_ASSIGN( image[ ypos ][ xpos ], cmap[ CM_RED ][ v ], cmap[ CM_GREEN ][ v ], cmap[ CM_BLUE ][ v ] );
1255 index++;
1256 #endif
1258 /* Clear buffer for next cycle */
1259 memset( (void *)buf, 0, sizeof( buf ) );
1262 return( 0 );
1265 case 0xf9: /* Graphic Control Extension */
1267 STRPTR fmt; /* Format string for verbose output (fmt changes if transparent color is set) */
1269 if( GetDataBlock( cb, gaid, buf ) == -1 )
1271 return( -1 );
1274 /* Get "delta" mode (disposal of previous frame), input flag and the delay time in 1/100 sec) */
1275 gifdec -> Gif89 . disposal = (buf[ 0 ] >> 2) & 0x7;
1276 gifdec -> Gif89 . inputFlag = (buf[ 0 ] >> 1) & 0x1;
1277 gifdec -> Gif89 . delayTime = LOHI2UINT16( buf[ 1 ], buf[ 2 ] );
1279 /* Any transparent color ? */
1280 if( buf[ 0 ] & 0x01 )
1282 gifdec -> Gif89 . transparent = buf[ 3 ];
1284 fmt = "Graphic Control Extension: disposal %s (%lu)%s transparent %lu\n";
1286 else
1288 fmt = "Graphic Control Extension: disposal %s (%lu)%s\n";
1291 /* Verbose output ? */
1292 if( (gaid -> gaid_VerboseOutput) && ((gaid -> gaid_VerboseOutput) != (BPTR)-1L) )
1294 STRPTR user_input = ((gifdec -> Gif89 . inputFlag)?(" user input requested"):(""));
1295 STRPTR disposal;
1297 switch( gifdec -> Gif89 . disposal )
1299 case GIF89A_DISPOSE_NOP: disposal = "nop"; break;
1300 case GIF89A_DISPOSE_NODISPOSE: disposal = "no dispose"; break;
1301 case GIF89A_DISPOSE_RESTOREBACKGROUND: disposal = "restore background"; break;
1302 case GIF89A_DISPOSE_RESTOREPREVIOUS: disposal = "restore previous"; break;
1303 default: disposal = "reserved"; break;
1306 verbose_printf( cb, gaid, fmt,
1307 disposal,
1308 (ULONG)(gifdec -> Gif89 . disposal),
1309 user_input,
1310 (gifdec -> Gif89 . transparent) );
1313 /* Ignore remaining data... */
1314 while( (count = GetDataBlock( cb, gaid, (UBYTE *)buf )), ((count != 0) && (count != -1)) )
1317 /* Return 0 (success) or -1 (error) */
1318 return( count );
1321 case 0xfe: /* Comment Extension */
1323 STRPTR annotation;
1325 /* Get all comment extension chunks, and append them on the DTA_ObjAnnotation string we've created before */
1326 while( (count = GetDataBlock( cb, gaid, buf )), ((count != 0) && (count != -1)) )
1328 ULONG size;
1329 STRPTR oldannotation;
1331 buf[ 255 ] = '\0'; /* terminate explicitly */
1333 size = (ULONG)strlen( buf ) + 2UL;
1335 (void)GetDTAttrs( o, DTA_ObjAnnotation, (&oldannotation), TAG_DONE );
1337 if( oldannotation )
1339 size += (ULONG)strlen( oldannotation ) + 2UL;
1342 /* Allocate a temp. buffer */
1343 if ((annotation = (STRPTR)AllocMem( size, MEMF_ANY ) ) != NULL)
1345 if( oldannotation )
1347 strcpy( annotation, oldannotation );
1349 else
1351 annotation[ 0 ] = '\0'; /* terminate */
1354 /* Append the new buffer */
1355 IBMPC2ISOLatin1( buf, (annotation + strlen( annotation )) );
1357 /* Store the comment */
1358 SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, annotation, TAG_DONE );
1360 /* Free temp string */
1361 FreeMem( annotation, size );
1364 /* Clear buffer for next cycle */
1365 memset( (void *)buf, 0, sizeof( buf ) );
1368 /* After all, prompt the annotation to the user */
1369 (void)GetDTAttrs( o, DTA_ObjAnnotation, (&annotation), TAG_DONE );
1371 verbose_printf( cb, gaid, "Comment Extension: '%s'\n", annotation );
1373 return( 0 );
1376 case 0xff: /* Application Extension */
1378 str = "Application Extension";
1380 break;
1382 default:
1384 mysprintf( cb, buf, "UNKNOWN (0x%02lx)", (long)label );
1385 str = buf;
1387 break;
1390 verbose_printf( cb, gaid, "got a '%s' extension\n", ((str)?(str):(STRPTR)"") );
1392 /* skip extension data */
1393 while( (count = GetDataBlock( cb, gaid, buf )), ((count != 0) && (count != -1)) )
1396 /* Returns 0 (success) or -1 (error) */
1397 return( count );
1401 static
1402 int GetDataBlock( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *buf )
1404 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
1405 UBYTE count;
1407 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1409 if( !ReadOK( cb, gifdec, &count, 1 ) )
1411 error_printf( cb, gaid, "error %d in getting DataBlock size\n", -1);
1413 return( -1 );
1416 gifdec -> ZeroDataBlock = (count == 0);
1418 if( (count != 0) && (!ReadOK( cb, gifdec, buf, (ULONG)count ) ) )
1420 error_printf( cb, gaid, "error %d in reading DataBlock\n", -1);
1422 return( -1 );
1425 return( count );
1429 /* returns -1 for error */
1430 static
1431 int GetCode( struct ClassBase *cb, struct GIFAnimInstData *gaid, int code_size, BOOL flag )
1433 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec));
1434 int i,
1436 ret;
1437 UBYTE count;
1439 if( flag )
1441 gifdec -> GetCode . curbit = 0;
1442 gifdec -> GetCode . lastbit = 0;
1443 gifdec -> GetCode . done = FALSE;
1445 return( 0 );
1448 if( (gifdec -> GetCode . curbit + code_size) >= (gifdec -> GetCode . lastbit) )
1450 if( gifdec -> GetCode . done )
1452 if( (gifdec -> GetCode . curbit) >= (gifdec -> GetCode . lastbit) )
1453 error_printf( cb, gaid, "GetCode: ran past the end of code bits (%d)\n", gifdec->GetCode.lastbit);
1455 return( -1 );
1458 gifdec -> GetCode . buf[ 0 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 2 ];
1459 gifdec -> GetCode . buf[ 1 ] = gifdec -> GetCode . buf[ gifdec -> GetCode . last_byte - 1 ];
1461 if( (count = GetDataBlock( cb, gaid, (&(gifdec -> GetCode . buf[ 2 ])) )) == 0 )
1462 gifdec -> GetCode . done = TRUE;
1464 gifdec -> GetCode . last_byte = 2 + count;
1465 gifdec -> GetCode . curbit = (gifdec -> GetCode . curbit - gifdec -> GetCode . lastbit) + 16;
1466 gifdec -> GetCode . lastbit = (2 + count) * 8 ;
1469 ret = 0;
1471 for( i = gifdec -> GetCode . curbit, j = 0; j < code_size ; i++, j++ )
1472 ret |= ((gifdec -> GetCode . buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
1474 gifdec -> GetCode . curbit += code_size;
1476 return( ret );
1480 static
1481 int LWZReadByte( struct ClassBase *cb, struct GIFAnimInstData *gaid, BOOL flag, int input_code_size )
1483 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec)); /* shortcut */
1484 int code,
1485 incode;
1486 register int i;
1488 if( flag )
1490 gifdec -> LWZReadByte . set_code_size = input_code_size;
1491 gifdec -> LWZReadByte . code_size = gifdec -> LWZReadByte . set_code_size + 1;
1492 gifdec -> LWZReadByte . clear_code = 1 << gifdec -> LWZReadByte . set_code_size ;
1493 gifdec -> LWZReadByte . end_code = gifdec -> LWZReadByte . clear_code + 1;
1494 gifdec -> LWZReadByte . max_code_size = 2 * gifdec -> LWZReadByte . clear_code;
1495 gifdec -> LWZReadByte . max_code = gifdec -> LWZReadByte . clear_code + 2;
1497 (void)GetCode( cb, gaid, 0, TRUE );
1499 gifdec -> LWZReadByte . fresh = TRUE;
1501 /* Fill table with the codes... */
1502 for( i = 0 ; i < (gifdec -> LWZReadByte . clear_code) ; i++ )
1504 gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
1505 gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
1508 /* ... and clear the remaining part */
1509 for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
1511 gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
1514 gifdec -> LWZReadByte . table[ 1 ][ 0 ] = 0;
1516 /* Reset stack ptr */
1517 gifdec -> LWZReadByte . sp = gifdec -> LWZReadByte . stack;
1519 return( 0 );
1521 else
1523 if( gifdec -> LWZReadByte . fresh )
1525 gifdec -> LWZReadByte . fresh = FALSE;
1529 gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . oldcode = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
1530 } while( (gifdec -> LWZReadByte . firstcode) == (gifdec -> LWZReadByte . clear_code) );
1532 return( gifdec -> LWZReadByte . firstcode );
1536 if( (gifdec -> LWZReadByte . sp) > (gifdec -> LWZReadByte . stack) )
1538 return( *--gifdec -> LWZReadByte . sp );
1541 while( (code = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE )) >= 0 )
1543 if( code == gifdec -> LWZReadByte . clear_code )
1545 for( i = 0 ; i < gifdec -> LWZReadByte . clear_code ; i++ )
1547 gifdec -> LWZReadByte . table[ 0 ][ i ] = 0;
1548 gifdec -> LWZReadByte . table[ 1 ][ i ] = i;
1551 for( ; i < (1 << MAX_LWZ_BITS) ; i++ )
1553 gifdec -> LWZReadByte . table[ 0 ][ i ] =
1554 gifdec -> LWZReadByte . table[ 1 ][ i ] = 0;
1557 gifdec -> LWZReadByte . code_size = gifdec -> LWZReadByte . set_code_size + 1;
1558 gifdec -> LWZReadByte . max_code_size = 2 * gifdec -> LWZReadByte . clear_code;
1559 gifdec -> LWZReadByte . max_code = gifdec -> LWZReadByte . clear_code + 2;
1560 gifdec -> LWZReadByte . sp = gifdec -> LWZReadByte . stack;
1561 gifdec -> LWZReadByte . firstcode =
1562 gifdec -> LWZReadByte . oldcode = GetCode( cb, gaid, gifdec -> LWZReadByte . code_size, FALSE );
1564 return( gifdec -> LWZReadByte . firstcode );
1566 else
1568 if( code == gifdec -> LWZReadByte . end_code )
1570 int count;
1571 UBYTE buf[ 260 ];
1573 if( gifdec -> ZeroDataBlock )
1574 return( -2 );
1576 while( (count = GetDataBlock( cb, gaid, buf )) > 0 )
1579 if( count != 0 )
1580 error_printf( cb, gaid, "missing EOD in data stream (common occurence) (count=%d)\n", count);
1582 return( -2 );
1586 incode = code;
1588 if( code >= (gifdec -> LWZReadByte . max_code) )
1590 *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode;
1591 code = gifdec -> LWZReadByte . oldcode;
1594 while( code >= gifdec -> LWZReadByte . clear_code )
1596 *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . table[ 1 ][ code ];
1598 if( code == gifdec -> LWZReadByte . table[ 0 ][ code ] )
1599 error_printf( cb, gaid, "circular table entry (code=%d) BIG ERROR\n", code);
1601 code = gifdec -> LWZReadByte . table[ 0 ][ code ];
1604 *gifdec -> LWZReadByte . sp++ = gifdec -> LWZReadByte . firstcode = gifdec -> LWZReadByte . table[ 1 ][ code ];
1606 if( (code = gifdec -> LWZReadByte . max_code) < (1 << MAX_LWZ_BITS ) )
1608 gifdec -> LWZReadByte . table[ 0 ][ code ] = gifdec -> LWZReadByte . oldcode;
1609 gifdec -> LWZReadByte . table[ 1 ][ code ] = gifdec -> LWZReadByte . firstcode;
1610 gifdec -> LWZReadByte . max_code++;
1612 if( (gifdec -> LWZReadByte . max_code >= gifdec -> LWZReadByte . max_code_size) && (gifdec -> LWZReadByte . max_code_size < (1 << MAX_LWZ_BITS)) )
1614 gifdec -> LWZReadByte . max_code_size *= 2;
1615 gifdec -> LWZReadByte . code_size++;
1619 gifdec -> LWZReadByte . oldcode = incode;
1621 if( gifdec -> LWZReadByte . sp > gifdec -> LWZReadByte . stack )
1623 return( *--gifdec -> LWZReadByte . sp );
1627 return( code );
1631 int ReadImage( struct ClassBase *cb, struct GIFAnimInstData *gaid, UBYTE *image,
1632 UWORD imagewidth, UWORD left, UWORD top, UWORD len, UWORD height,
1633 BOOL interlace, BOOL ignore, UWORD transparent )
1635 struct GIFDecoder *gifdec = (&(gaid -> gaid_GIFDec)); /* shortcut */
1636 UBYTE c;
1638 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1640 /* Initialize the Compression routines */
1641 if( !ReadOK( cb, gifdec, &c, 1 ) )
1643 return( -1 );
1646 /* If this is an "uninteresting picture" ignore it. */
1647 if( ignore )
1649 D(bug("[gifanim.datatype]: %s: skipping gif image...\n", __PRETTY_FUNCTION__ ) );
1651 /* Loop until end of raster data */
1652 while(TRUE)
1654 if( !ReadOK( cb, gifdec, &c, 1 ) )
1656 error_printf( cb, gaid, "EOF (%d) / reading block byte count\n", -1);
1657 return( -1 );
1660 if( c == 0 )
1662 D(bug("[gifanim.datatype]: %s: gif image done\n", __PRETTY_FUNCTION__ ) );
1663 break;
1666 /* Skip... */
1667 if( Seek( (gifdec -> file), (long)c, OFFSET_CURRENT ) == -1L )
1669 return( -1 );
1673 else
1675 WORD v;
1676 ULONG xpos = 0UL,
1677 ypos = 0UL,
1678 offset = (top * imagewidth) + left, /* "ypos" position in image (byte offset) */
1679 pass = 0UL; /* interlace pass */
1681 if( LWZReadByte( cb, gaid, TRUE, c ) < 0 )
1682 error_printf( cb, gaid, "error (<%d) reading image\n", 0);
1684 D(bug("[gifanim.datatype]: %s: reading %lx %ld.%ld / %ld by %ld%s GIF image\n", __PRETTY_FUNCTION__, image, left, top, len, height, interlace ? " interlaced" : "" ) );
1686 while( (v = LWZReadByte( cb, gaid, FALSE, c )) >= 0 )
1688 /* Pixel transparent ? */
1689 if( (transparent == ~0U) || (transparent != v) )
1691 /* Store pixel */
1692 image[ offset + xpos ] = v;
1695 xpos++;
1697 if( xpos == len )
1699 xpos = 0UL;
1701 if( interlace )
1703 switch( pass )
1705 case 0UL:
1706 case 1UL: ypos += 8UL; break;
1707 case 2UL: ypos += 4UL; break;
1708 case 3UL: ypos += 2UL; break;
1711 if( ypos >= height )
1713 pass++;
1715 switch( pass )
1717 case 1UL: ypos = 4UL; break;
1718 case 2UL: ypos = 2UL; break;
1719 case 3UL: ypos = 1UL; break;
1720 default: goto fini;
1724 else
1726 ypos++;
1729 offset = ((ypos + top) * imagewidth) + left;
1732 if( ypos >= height )
1733 break;
1736 fini:
1737 if( (v = LWZReadByte( cb, gaid, FALSE, c )) >= 0 )
1739 /* 0x00-bytes are treated here as padding bytes unless the STRICTSYNTAX option is set... */
1740 if( (v != 0) || (gaid -> gaid_StrictSyntax) )
1742 verbose_printf( cb, gaid, "too much input data %ld, ignoring extra...\n", (long)v );
1747 return( 0 );
1751 /* got from my anim.datatype (IFF ANIM) */
1752 struct FrameNode *GetPrevFrameNode( struct FrameNode *currfn, ULONG interleave )
1754 struct FrameNode *worknode,
1755 *prevnode;
1757 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1759 /* Get previous frame */
1760 worknode = currfn;
1762 while ((prevnode = (struct FrameNode *)(worknode -> fn_Node . mln_Pred) ) != NULL)
1764 if( (interleave-- == 0U) || ((prevnode -> fn_Node . mln_Pred) == NULL) )
1766 break;
1769 worknode = prevnode;
1772 return( worknode );
1776 /* WritePixelArray8 replacement by Peter McGavin (p.mcgavin@irl.cri.nz),
1777 * slightly adapted to fit here...
1780 void WriteDeltaPixelArray8Fast( struct BitMap *dest, UBYTE *source, UBYTE *prev )
1782 ULONG *plane[ 8 ] = { 0 };
1783 register ULONG *chunky = (ULONG *)source, /* fetch 32 bits per cycle */
1784 *prevchunky = (ULONG *)prev;
1785 ULONG numcycles = ((dest -> Rows) * (dest -> BytesPerRow)) / sizeof( ULONG ),
1788 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__));
1790 /* Copy plane ptrs */
1791 for( i = 0UL ; i < (dest -> Depth) ; i++ )
1793 D(bug("[gifanim.datatype] %s: plane %d @ 0x%p\n", __PRETTY_FUNCTION__, i, dest -> Planes[ i ]));
1794 plane[ i ] = (ULONG *)(dest -> Planes[ i ]);
1797 /* Fill unused planes with plane 0, which will be written last, all previous accesses
1798 * will be droped (assumes that a cache hides this "dummy" writes)
1800 for( ; i < 8UL ; i++ )
1802 plane[ i ] = (ULONG *)(dest -> Planes[ 0 ]);
1805 #define merge( a, b, mask, shift ) \
1806 tmp = mask & (a ^ (b >> shift)); \
1807 a ^= tmp; \
1808 b ^= (tmp << shift)
1810 /* Check if we have to do the "delta" test */
1811 if( prevchunky )
1813 /* Process bitmaps */
1814 for( i = 0UL ; i < numcycles ; i++ )
1816 ULONG curr0, curr1, curr2, curr3, curr4, curr5, curr6, curr7;
1817 ULONG prev0, prev1, prev2, prev3, prev4, prev5, prev6, prev7;
1818 ULONG tmp;
1820 /* process 32 pixels */
1822 curr0 = AROS_BE2LONG(*chunky++); curr4 = AROS_BE2LONG(*chunky++);
1823 curr1 = AROS_BE2LONG(*chunky++); curr5 = AROS_BE2LONG(*chunky++);
1824 curr2 = AROS_BE2LONG(*chunky++); curr6 = AROS_BE2LONG(*chunky++);
1825 curr3 = AROS_BE2LONG(*chunky++); curr7 = AROS_BE2LONG(*chunky++);
1827 prev0 = AROS_BE2LONG(*prevchunky++); prev4 = AROS_BE2LONG(*prevchunky++);
1828 prev1 = AROS_BE2LONG(*prevchunky++); prev5 = AROS_BE2LONG(*prevchunky++);
1829 prev2 = AROS_BE2LONG(*prevchunky++); prev6 = AROS_BE2LONG(*prevchunky++);
1830 prev3 = AROS_BE2LONG(*prevchunky++); prev7 = AROS_BE2LONG(*prevchunky++);
1832 /* I use the '+' here to avoid that the compiler skips an expression.
1833 * WARNING: The code assumes that the code is executed in the sequence as it occurs here
1835 if ( (curr0 != prev0) || (curr4 != prev4) ||
1836 (curr1 != prev1) || (curr5 != prev5) ||
1837 (curr2 != prev2) || (curr6 != prev6) ||
1838 (curr3 != prev3) || (curr7 != prev7))
1840 merge( curr0, curr2, 0x0000ffff, 16 );
1841 merge( curr1, curr3, 0x0000ffff, 16 );
1842 merge( curr4, curr6, 0x0000ffff, 16 );
1843 merge( curr5, curr7, 0x0000ffff, 16 );
1845 merge( curr0, curr1, 0x00ff00ff, 8 );
1846 merge( curr2, curr3, 0x00ff00ff, 8 );
1847 merge( curr4, curr5, 0x00ff00ff, 8 );
1848 merge( curr6, curr7, 0x00ff00ff, 8 );
1850 merge( curr0, curr4, 0x0f0f0f0f, 4 );
1851 merge( curr1, curr5, 0x0f0f0f0f, 4 );
1852 merge( curr2, curr6, 0x0f0f0f0f, 4 );
1853 merge( curr3, curr7, 0x0f0f0f0f, 4 );
1855 merge( curr0, curr2, 0x33333333, 2 );
1856 merge( curr1, curr3, 0x33333333, 2 );
1857 merge( curr4, curr6, 0x33333333, 2 );
1858 merge( curr5, curr7, 0x33333333, 2 );
1860 merge( curr0, curr1, 0x55555555, 1 );
1861 merge( curr2, curr3, 0x55555555, 1 );
1862 merge( curr4, curr5, 0x55555555, 1 );
1863 merge( curr6, curr7, 0x55555555, 1 );
1865 *plane[ 7 ]++ = AROS_LONG2BE(curr0);
1866 *plane[ 6 ]++ = AROS_LONG2BE(curr1);
1867 *plane[ 5 ]++ = AROS_LONG2BE(curr2);
1868 *plane[ 4 ]++ = AROS_LONG2BE(curr3);
1869 *plane[ 3 ]++ = AROS_LONG2BE(curr4);
1870 *plane[ 2 ]++ = AROS_LONG2BE(curr5);
1871 *plane[ 1 ]++ = AROS_LONG2BE(curr6);
1872 *plane[ 0 ]++ = AROS_LONG2BE(curr7);
1874 else
1876 plane[ 7 ]++;
1877 plane[ 6 ]++;
1878 plane[ 5 ]++;
1879 plane[ 4 ]++;
1880 plane[ 3 ]++;
1881 plane[ 2 ]++;
1882 plane[ 1 ]++;
1883 plane[ 0 ]++;
1887 else
1889 /* Process bitmaps */
1890 for( i = 0UL ; i < numcycles ; i++ )
1892 register ULONG b0, b1, b2, b3, b4, b5, b6, b7,
1893 tmp;
1895 /* process 32 pixels */
1896 b0 = AROS_BE2LONG(*chunky++); b4 = AROS_BE2LONG(*chunky++);
1897 b1 = AROS_BE2LONG(*chunky++); b5 = AROS_BE2LONG(*chunky++);
1898 b2 = AROS_BE2LONG(*chunky++); b6 = AROS_BE2LONG(*chunky++);
1899 b3 = AROS_BE2LONG(*chunky++); b7 = AROS_BE2LONG(*chunky++);
1901 merge( b0, b2, 0x0000ffff, 16 );
1902 merge( b1, b3, 0x0000ffff, 16 );
1903 merge( b4, b6, 0x0000ffff, 16 );
1904 merge( b5, b7, 0x0000ffff, 16 );
1906 merge( b0, b1, 0x00ff00ff, 8 );
1907 merge( b2, b3, 0x00ff00ff, 8 );
1908 merge( b4, b5, 0x00ff00ff, 8 );
1909 merge( b6, b7, 0x00ff00ff, 8 );
1911 merge( b0, b4, 0x0f0f0f0f, 4 );
1912 merge( b1, b5, 0x0f0f0f0f, 4 );
1913 merge( b2, b6, 0x0f0f0f0f, 4 );
1914 merge( b3, b7, 0x0f0f0f0f, 4 );
1916 merge( b0, b2, 0x33333333, 2 );
1917 merge( b1, b3, 0x33333333, 2 );
1918 merge( b4, b6, 0x33333333, 2 );
1919 merge( b5, b7, 0x33333333, 2 );
1921 merge( b0, b1, 0x55555555, 1 );
1922 merge( b2, b3, 0x55555555, 1 );
1923 merge( b4, b5, 0x55555555, 1 );
1924 merge( b6, b7, 0x55555555, 1 );
1926 *plane[ 7 ]++ = AROS_LONG2BE(b0);
1927 *plane[ 6 ]++ = AROS_LONG2BE(b1);
1928 *plane[ 5 ]++ = AROS_LONG2BE(b2);
1929 *plane[ 4 ]++ = AROS_LONG2BE(b3);
1930 *plane[ 3 ]++ = AROS_LONG2BE(b4);
1931 *plane[ 2 ]++ = AROS_LONG2BE(b5);
1932 *plane[ 1 ]++ = AROS_LONG2BE(b6);
1933 *plane[ 0 ]++ = AROS_LONG2BE(b7);
1939 static
1940 int getbase2( int x )
1942 int i = 0,
1943 j = 1;
1945 while( x > j )
1947 j *= 2;
1948 i++;
1951 return( i );
1956 /* Read and test */
1957 BOOL ReadOK( struct ClassBase *cb, struct GIFDecoder *gifdec, void *buffer, ULONG len )
1959 if( (gifdec -> which_fh) == WHICHFH_FILE )
1961 return( (BOOL)(Read( (gifdec -> file), buffer, len ) == len) );
1963 else
1965 /* Check if the request fit in out buffer... */
1966 if( (((gifdec -> buffer) - (gifdec -> file_buffer)) + len) <= (gifdec -> buffersize) )
1968 CopyMem( (gifdec -> buffer), buffer, len );
1969 gifdec -> buffer += len;
1971 return( TRUE );
1975 return( FALSE );