4 ** $VER: dispatch.c 2.4 (24.5.98)
5 ** gifanim.datatype 2.4
7 ** Dispatch routine for a DataTypes class
9 ** Written 1997/1998 by Roland 'Gizzy' Mainz
10 ** Original example source from David N. Junod
17 #include <aros/debug.h>
19 struct MyStackSwapStruct
;
20 struct GIFAnimInstData
;
24 #include "classbase.h"
25 #include "classdata.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
)
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
;
75 /* class dispatcher */
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
;
83 switch( msg
-> MethodID
)
86 retval
= DT_NewMethod( cl
, o
, msg
);
90 retval
= DT_DisposeMethod( cl
, o
, msg
);
93 /* TEST TEST / Support for format change "on-the-fly" disabled here / TEST TEST
94 * DO NOT make any assumptions on this EXPERIMENTAL code !
98 retval
= DT_FrameBoxMethod( cl
, o
, msg
);
100 #endif /* COMMENTED_OUT */
104 retval
= DT_SetMethod( cl
, o
, msg
);
108 retval
= DT_WriteMethod( cl
, o
, msg
);
112 retval
= DT_LoadFrameMethod( cl
, o
, msg
);
115 case ADTM_UNLOADFRAME
:
116 retval
= DT_UnLoadFrameMethod( cl
, o
, msg
);
119 /* Let the superclass handle everything else */
122 retval
= DoSuperMethodA( cl
, o
, msg
);
131 BOOL
ScanFrames( struct ClassBase
*cb
, Object
*o
)
133 struct GIFAnimInstData
*gaid
= (struct GIFAnimInstData
*)INST_DATA( (cb
-> cb_Lib
. cl_Class
), o
);
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
));
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;
163 ReadENVPrefs( cb
, gaid
, NULL
);
165 /* Get file handle, handle type and BitMapHeader */
166 if( GetDTAttrs( o
, DTA_SourceType
, (&sourcetype
),
168 DTA_Name
, (&(gaid
-> gaid_ProjectName
)),
175 D(bug("[gifanim.datatype] %s: DTST_FILE (0x%p)\n", __PRETTY_FUNCTION__
, fh
));
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
)
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
)
206 /* Can't open file */
213 case DTST_RAM
: /* empty object */
215 D(bug("[gifanim.datatype] %s: DTST_RAM\n", __PRETTY_FUNCTION__
));
223 /* unsupported source type */
224 error
= ERROR_NOT_IMPLEMENTED
;
232 /* Now we enter the next stage of testing... */
237 struct GIFDecoder
*gifdec
= (&(gaid
-> gaid_GIFDec
));
238 struct FrameNode
*fn
;
239 ULONG numcmaps
= 0UL; /* number of created cmaps */
241 struct ColorRegister localColorMap
[ MAXCOLORMAPSIZE
] = { 0 };
242 struct ColorRegister savedTransparentColor
= { 0 };
244 BOOL useGlobalColormap
;
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__
));
295 if( ReadColorMap( cb
, gaid
, (gifdec
-> GifScreen
. BitPixel
), (gifdec
-> GifScreen
. ColorMap
) ) )
297 D(bug("[gifanim.datatype]: %s: failed!\n", __PRETTY_FUNCTION__
));
299 error_printf( cb
, gaid
, "error %d reading global colormap\n", error
);
304 /* No global colormap ? - Then the background color in the GifScreen is a NOP */
305 gifdec
-> GifScreen
. Background
= 0U;
310 D(bug("[gifanim.datatype]: %s: reading chunk..\n", __PRETTY_FUNCTION__
));
311 /* Read chunk ID char */
312 if( !ReadOK( cb
, gifdec
, (&c
), 1 ) )
315 error_printf( cb
, gaid
, "EOF / read error on image data (%x)\n", error
);
321 case ';': /* GIF terminator ? */
323 D(bug("[gifanim.datatype]: %s: ## terminator\n", __PRETTY_FUNCTION__
));
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 )
337 error_printf( cb
, gaid
, "error %x in extension\n", error
);
344 error_printf( cb
, gaid
, "OF / read error on extension function code (%x)\n", error
);
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
) );
374 D(bug("[gifanim.datatype]: %s: failed to allocate chunky data!\n", __PRETTY_FUNCTION__
));
375 error
= ERROR_NO_FREE_STORE
;
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 ) )
391 error_printf( cb
, gaid
, "couldn't read left/top/width/height (%x)\n", error
);
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
) );
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 */
433 CopyMem( (prevnode
-> fn_ChunkyMap
), (fn
-> fn_ChunkyMap
), (animwidth
* animheight
) );
435 CopyBitMap( cb
, (fn
-> fn_BitMap
), (prevnode
-> fn_BitMap
), animwidth
, animheight
);
436 deltamap
= prevnode
-> fn_ChunkyMap
;
437 #endif /* DELTAWPA8 */
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
) );
450 #endif /* DELTAWPA8 */
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
) );
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 */
476 CopyMem( (prevnode
-> fn_ChunkyMap
), (fn
-> fn_ChunkyMap
), (animwidth
* animheight
) );
478 CopyBitMap( cb
, (fn
-> fn_BitMap
), (prevnode
-> fn_BitMap
), animwidth
, animheight
);
479 deltamap
= prevnode
-> fn_ChunkyMap
;
480 #endif /* DELTAWPA8 */
484 /* restore to color 0 */
485 memset( (fn
-> fn_ChunkyMap
), 0, (size_t)(animwidth
* animheight
) );
488 #endif /* DELTAWPA8 */
493 default: /* GIF89A_DISPOSE_RESERVED4 - GIF89A_DISPOSE_RESERVED7 */
495 error_printf( cb
, gaid
, "unsupported disposal method %lu\n", (ULONG
)(gifdec
-> Gif89
. disposal
) );
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
) ];
509 if( useGlobalColormap
)
511 /* use global colormap and depth */
512 bitPixel
= gifdec
-> GifScreen
. BitPixel
;
513 memcpy( localColorMap
, (gifdec
-> GifScreen
. ColorMap
), (sizeof( struct ColorRegister
) * bitPixel
) );
517 D(bug("[gifanim.datatype]: %s: reading colormap...\n", __PRETTY_FUNCTION__
));
520 if( ReadColorMap( cb
, gaid
, bitPixel
, localColorMap
) )
523 error_printf( cb
, gaid
, "error %x reading local colormap\n", error
);
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
),
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
) );
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
);
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
)) );
613 /* Next frame starts at timestamp... */
614 timestamp
+= (fn
-> fn_Duration
) + 1UL;
620 case 0x00: /* padding byte ? */
622 /* Padding bytes are not part of the Compuserve documents, but... */
623 if( !(gaid
-> gaid_StrictSyntax
) )
629 default: /* Not a valid raster data start character ? */
631 error_printf( cb
, gaid
, "invalid character 0x%02x, ignoring\n", (int)c
);
639 D(bug("[gifanim.datatype]: %s: ERROR!\n", __PRETTY_FUNCTION__
));
645 D(bug("[gifanim.datatype]: %s: scan done\n", __PRETTY_FUNCTION__
));
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
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
;
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
,
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
;
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
;
697 verbose_printf( cb
, gaid
, "scan/load: no colormap, can't copy it\n" );
706 /* Check for required information */
709 /* Any frames loaded ? */
710 if( timestamp
== 0UL )
712 /* not enougth frames (at least one required) */
713 error
= DTERROR_NOT_ENOUGH_DATA
;
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
);
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
;
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
;
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
)
761 error
= 1L; /* inducate an error here :-( */
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
)
771 error_printf( cb
, gaid
, "'CyberGFX bug' workaround failed, too ! Using modeid=%x.\n", modeid
);
775 error_printf( cb
, gaid
, "No screenmode available for %lu/%lu/%lu\n", animwidth
, animheight
, animdepth
);
780 /* BUG: Does currently not support SUPERHIRES modes */
781 if( animwidth
>= 640UL )
783 if( animheight
>= 400 )
785 modeid
= HIRESLACE_KEY
;
794 if( animheight
>= 400 )
796 modeid
= LORESLACE_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",
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
),
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
),
842 /* All done for now... */
848 /* can't alloc key bitmap */
849 error
= ERROR_NO_FREE_STORE
;
856 error_printf( cb
, gaid
, "failed to read gif screen descriptor (%x)\n", error
);
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
);
868 /* no GIF signature */
869 error
= ERROR_OBJECT_WRONG_TYPE
;
870 error_printf( cb
, gaid
, "error %x not a GIF file\n", error
);
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
;
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...
895 error
= ERROR_REQUIRED_ARG_MISSING
;
902 /* can't get required attributes from superclass */
903 error
= ERROR_OBJECT_WRONG_TYPE
;
909 error
= ERROR_NO_FREE_STORE
;
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
) );
934 struct FrameNode
*FindFrameNode( struct MinList
*fnl
, ULONG timestamp
)
937 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__
));
941 struct FrameNode
*worknode
,
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
)
958 if( !IsListEmpty( ((struct List
*)fnl
) ) )
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
)
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
) );
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__
));
1028 if( gaid
-> gaid_UseChunkyMap
)
1034 FreePooledVec( cb
, (gaid
-> gaid_Pool
), bm
);
1040 /* This function assumes (0UL < depth) && (depth <= 8UL) */
1042 struct BitMap
*AllocBitMapPooled( struct ClassBase
*cb
, ULONG width
, ULONG height
, ULONG depth
, APTR pool
)
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
)
1059 InitBitMap( bm
, depth
, width
, height
);
1061 plane
= (PLANEPTR
)(bm
+ 1); /* First plane follows struct BitMap */
1063 /* Set up plane data */
1066 /* Set up plane ptrs */
1069 bm
-> Planes
[ pl
] = plane
;
1071 plane
= (PLANEPTR
)(((UBYTE
*)plane
) + planesize
+ 8);
1075 /* Clear the remaining plane ptrs */
1078 bm
-> Planes
[ pl
] = NULL
;
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) )
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
);
1109 #if !defined(__AROS__)
1110 void error_printf( struct ClassBase
*cb
, struct GIFAnimInstData
*gaid
, STRPTR format
, ... )
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
);
1128 void verbose_printf( struct ClassBase
*cb
, struct GIFAnimInstData
*gaid
, STRPTR format
, ... )
1132 if( (gaid
-> gaid_VerboseOutput
) && ((gaid
-> gaid_VerboseOutput
) != (BPTR
)-1L) )
1134 va_start (args
, format
);
1135 VFPrintf( (gaid
-> gaid_VerboseOutput
), format
, args
);
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
,
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
));
1189 worknode
= nextnode
;
1195 /* Read a GIF colormap info a struct ColorRegister */
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
) )) );
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 };
1213 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__
));
1215 switch( (int)label
)
1217 case 0x01: /* Plain Text Extension */
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 )
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 ] );
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)) )
1253 PPM_ASSIGN( image
[ ypos
][ xpos
], cmap
[ CM_RED
][ v
], cmap
[ CM_GREEN
][ v
], cmap
[ CM_BLUE
][ v
] );
1258 /* Clear buffer for next cycle */
1259 memset( (void *)buf
, 0, sizeof( buf
) );
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 )
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";
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"):(""));
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
,
1308 (ULONG
)(gifdec
-> Gif89
. disposal
),
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) */
1321 case 0xfe: /* Comment Extension */
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)) )
1329 STRPTR oldannotation
;
1331 buf
[ 255 ] = '\0'; /* terminate explicitly */
1333 size
= (ULONG
)strlen( buf
) + 2UL;
1335 (void)GetDTAttrs( o
, DTA_ObjAnnotation
, (&oldannotation
), TAG_DONE
);
1339 size
+= (ULONG
)strlen( oldannotation
) + 2UL;
1342 /* Allocate a temp. buffer */
1343 if ((annotation
= (STRPTR
)AllocMem( size
, MEMF_ANY
) ) != NULL
)
1347 strcpy( annotation
, oldannotation
);
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
);
1376 case 0xff: /* Application Extension */
1378 str
= "Application Extension";
1384 mysprintf( cb
, buf
, "UNKNOWN (0x%02lx)", (long)label
);
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) */
1402 int GetDataBlock( struct ClassBase
*cb
, struct GIFAnimInstData
*gaid
, UBYTE
*buf
)
1404 struct GIFDecoder
*gifdec
= (&(gaid
-> gaid_GIFDec
));
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);
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);
1429 /* returns -1 for error */
1431 int GetCode( struct ClassBase
*cb
, struct GIFAnimInstData
*gaid
, int code_size
, BOOL flag
)
1433 struct GIFDecoder
*gifdec
= (&(gaid
-> gaid_GIFDec
));
1441 gifdec
-> GetCode
. curbit
= 0;
1442 gifdec
-> GetCode
. lastbit
= 0;
1443 gifdec
-> GetCode
. done
= FALSE
;
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
);
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 ;
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
;
1481 int LWZReadByte( struct ClassBase
*cb
, struct GIFAnimInstData
*gaid
, BOOL flag
, int input_code_size
)
1483 struct GIFDecoder
*gifdec
= (&(gaid
-> gaid_GIFDec
)); /* shortcut */
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
;
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
);
1568 if( code
== gifdec
-> LWZReadByte
. end_code
)
1573 if( gifdec
-> ZeroDataBlock
)
1576 while( (count
= GetDataBlock( cb
, gaid
, buf
)) > 0 )
1580 error_printf( cb
, gaid
, "missing EOD in data stream (common occurence) (count=%d)\n", count
);
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
);
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 */
1638 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__
));
1640 /* Initialize the Compression routines */
1641 if( !ReadOK( cb
, gifdec
, &c
, 1 ) )
1646 /* If this is an "uninteresting picture" ignore it. */
1649 D(bug("[gifanim.datatype]: %s: skipping gif image...\n", __PRETTY_FUNCTION__
) );
1651 /* Loop until end of raster data */
1654 if( !ReadOK( cb
, gifdec
, &c
, 1 ) )
1656 error_printf( cb
, gaid
, "EOF (%d) / reading block byte count\n", -1);
1662 D(bug("[gifanim.datatype]: %s: gif image done\n", __PRETTY_FUNCTION__
) );
1667 if( Seek( (gifdec
-> file
), (long)c
, OFFSET_CURRENT
) == -1L )
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
) )
1692 image
[ offset
+ xpos
] = v
;
1706 case 1UL: ypos
+= 8UL; break;
1707 case 2UL: ypos
+= 4UL; break;
1708 case 3UL: ypos
+= 2UL; break;
1711 if( ypos
>= height
)
1717 case 1UL: ypos
= 4UL; break;
1718 case 2UL: ypos
= 2UL; break;
1719 case 3UL: ypos
= 1UL; break;
1729 offset
= ((ypos
+ top
) * imagewidth
) + left
;
1732 if( ypos
>= height
)
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
);
1751 /* got from my anim.datatype (IFF ANIM) */
1752 struct FrameNode
*GetPrevFrameNode( struct FrameNode
*currfn
, ULONG interleave
)
1754 struct FrameNode
*worknode
,
1757 D(bug("[gifanim.datatype]: %s()\n", __PRETTY_FUNCTION__
));
1759 /* Get previous frame */
1762 while ((prevnode
= (struct FrameNode
*)(worknode
-> fn_Node
. mln_Pred
) ) != NULL
)
1764 if( (interleave
-- == 0U) || ((prevnode
-> fn_Node
. mln_Pred
) == NULL
) )
1769 worknode
= prevnode
;
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)); \
1810 /* Check if we have to do the "delta" test */
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
;
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
);
1889 /* Process bitmaps */
1890 for( i
= 0UL ; i
< numcycles
; i
++ )
1892 register ULONG b0
, b1
, b2
, b3
, b4
, b5
, b6
, b7
,
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
);
1940 int getbase2( int x
)
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
) );
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
;