home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format 106 / af106sub.adf / datatypes.LZX / anim_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  2003-05-15  |  131KB  |  3,891 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.12 (12.11.97)
  5. **  anim.datatype 1.12
  6. **
  7. **  Dispatch routine for a DataTypes class
  8. **
  9. **  Written 1996/1997 by Roland 'Gizzy' Mainz
  10. **  Original example source from David N. Junod
  11. **
  12. */
  13.  
  14. /* Use asyncronous I/O below. Disabled due problems with Seek'ing */
  15. #if 0
  16. #define DOASYNCIO 1
  17. #endif
  18.  
  19. #if 0
  20. #define D( x ) x
  21. #else
  22. #define D( x )
  23. #endif
  24.  
  25. /* main includes */
  26. #include "classbase.h"
  27. #include "classdata.h"
  28. #include "asyncio.h"
  29.  
  30. /*****************************************************************************/
  31.  
  32. /* IFF errors to DOS errors */
  33. static const
  34. LONG ifferr2doserr[] =
  35. {
  36.   0L,                         /* End of file (not an error).                  */
  37.   0L,                         /* End of context (not an error).               */
  38.   DTERROR_INVALID_DATA,       /* No lexical scope.                            */
  39.   ERROR_NO_FREE_STORE,        /* Insufficient memory.                         */
  40.   ERROR_SEEK_ERROR,           /* Stream read error.                           */
  41.   ERROR_SEEK_ERROR,           /* Stream write error.                          */
  42.   ERROR_SEEK_ERROR,           /* Stream seek error.                           */
  43.   DTERROR_INVALID_DATA,       /* File is corrupt.                             */
  44.   DTERROR_INVALID_DATA,       /* IFF syntax error.                            */
  45.   ERROR_OBJECT_WRONG_TYPE,    /* Not an IFF file.                             */
  46.   ERROR_REQUIRED_ARG_MISSING, /* Required call-back hook missing.             */
  47.   0xDEADDEADUL                /* Return to client.  You should never see this */
  48. };
  49.  
  50. /*****************************************************************************/
  51.  
  52. /* local prototypes */
  53. static                 BOOL                 FreeAbleFrame( struct AnimInstData *, struct FrameNode * );
  54. static                 STRPTR               GetPrefsVar( struct ClassBase *, STRPTR );
  55. static                 void                 YouShouldRegister( struct ClassBase *, struct AnimInstData * );
  56. static                 BOOL                 matchstr( struct ClassBase *, STRPTR, STRPTR );
  57. static                 void                 ReadENVPrefs( struct ClassBase *, struct AnimInstData * );
  58. static                 LONG                 LoadFrames( struct ClassBase *, Object * );
  59. static                 struct FrameNode    *AllocFrameNode( struct ClassBase *, APTR );
  60. static                 struct FrameNode    *FindFrameNode( struct MinList *, ULONG );
  61. static                 void                 FreeFrameNodeResources( struct ClassBase *, struct MinList * );
  62. static                 void                 CopyBitMap( struct ClassBase *, struct BitMap *, struct BitMap * );
  63. static                 void                 XCopyMem( struct ClassBase *, APTR, APTR, ULONG );
  64. static                 void                 ClearBitMap( struct BitMap * );
  65. static                 void                 XORBitMaps( struct BitMap *, struct BitMap * );
  66. static                 struct BitMap       *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
  67. static                 BOOL                 CMAP2Object( struct ClassBase *, Object *, UBYTE *, ULONG );
  68. static                 struct ColorMap     *CMAP2ColorMap( struct ClassBase *, struct AnimInstData *, UBYTE *, ULONG );
  69. static                 struct ColorMap     *CopyColorMap( struct ClassBase *, struct ColorMap * );
  70. static                 APTR                 AllocVecPooled( struct ClassBase *, APTR, ULONG );
  71. static                 void                 FreeVecPooled( struct ClassBase *, APTR, APTR );
  72. static                 LONG                 DrawDLTA( struct ClassBase *, struct AnimInstData *, struct BitMap *, struct BitMap *, struct AnimHeader *, UBYTE *, ULONG );
  73. static                 void                 DumpAnimHeader( struct ClassBase *, struct AnimInstData *, ULONG, struct AnimHeader * );
  74. static                 struct FrameNode    *GetPrevFrameNode( struct FrameNode *, ULONG );
  75. static                 void                 OpenLogfile( struct ClassBase *, struct AnimInstData * );
  76. static                 void                 mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  77. static                 void                 verbose_printf( struct ClassBase *, struct AnimInstData *, STRPTR, ... );
  78. static                 void                 error_printf( struct ClassBase *, struct AnimInstData *, STRPTR, ... );
  79. static                 void                 AttachSample( struct ClassBase *, struct AnimInstData * );
  80.  
  81. static                 ULONG                SaveIFFAnim( struct ClassBase *, struct IClass *, Object *, struct dtWrite * );
  82. static                 struct IFFHandle    *CreateDOSIFFHandle( struct ClassBase *, BPTR );
  83. static                 LONG                 StartIFFAnim3( struct ClassBase *, struct AnimInstData *, struct IFFHandle *iff, struct AnimContext *, struct BitMapHeader *, ULONG, ULONG *, ULONG, ULONG, ULONG, struct BitMap * );
  84. static                 void                 EndIFFAnim3( struct ClassBase *, struct AnimInstData *, struct IFFHandle * );
  85. static                 LONG                 WriteIFFAnim3( struct ClassBase *, struct IFFHandle *, struct AnimContext *, ULONG, ULONG, struct BitMapHeader *, ULONG *, ULONG, struct BitMap * );
  86. static                 LONG                 PutAnim3Delta( struct ClassBase *, struct IFFHandle *, struct AnimContext *, struct BitMap *, struct BitMap * );
  87. static                 LONG                 PutILBMCMAP( struct ClassBase *, struct IFFHandle *, ULONG *, ULONG );
  88. static                 LONG                 PutILBMBody( struct ClassBase *, struct IFFHandle *, struct BitMap *, struct BitMapHeader * );
  89. static                 struct AnimContext  *CreateAnimContext( struct ClassBase *, ULONG, ULONG, ULONG );
  90. #if 0
  91. static                 struct BitMap       *PrevFrame( struct ClassBase *, struct AnimContext * );
  92. #endif
  93. static                 void                 SwapFrames( struct ClassBase *, struct AnimContext * );
  94. static                 struct BitMap       *CurrFrame( struct ClassBase *, struct AnimContext * );
  95. static                 void                 DeleteAnimContext( struct ClassBase *, struct AnimContext * );
  96.  
  97.  
  98. /*****************************************************************************/
  99.  
  100. /* Create "anim.datatype" BOOPSI class */
  101. struct IClass *initClass( struct ClassBase *cb )
  102. {
  103.     struct IClass *cl;
  104.  
  105.     /* Create our class... */
  106.     if( cl = MakeClass( ANIMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct AnimInstData ), 0UL ) )
  107.     {
  108. #define DTSTACKSIZE (16384UL)
  109.       cl -> cl_Dispatcher . h_Entry    = (HOOKFUNC)StackSwapDispatch; /* see stackswap.c */
  110.       cl -> cl_Dispatcher . h_SubEntry = (HOOKFUNC)Dispatch;          /* see stackswap.c */
  111.       cl -> cl_Dispatcher . h_Data     = (APTR)DTSTACKSIZE;           /* see stackswap.c */
  112.       cl -> cl_UserData                = (ULONG)cb;                   /* class library base as expected by datatypes.library */
  113.  
  114.       AddClass( cl );
  115.     }
  116.  
  117.     return( cl );
  118. }
  119.  
  120. /*****************************************************************************/
  121.  
  122. /* class dispatcher */
  123. DISPATCHERFLAGS
  124. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  125. {
  126.     struct ClassBase     *cb = (struct ClassBase *)(cl -> cl_UserData);
  127.     struct AnimInstData  *aid;
  128.     ULONG                 retval = 0UL;
  129.  
  130.     switch( msg -> MethodID )
  131.     {
  132. /****** anim.datatype/OM_NEW *************************************************
  133. *
  134. *    NAME
  135. *        OM_NEW -- Create a anim.datatype object.
  136. *
  137. *    FUNCTION
  138. *        The OM_NEW method is used to create an instance of the anim.datatype
  139. *        class.  This method is passed to the superclass first. After this,
  140. *        anim.datatype parses the prefs file and makes a scan through
  141. *        the data to get index information. Frame bitmaps are loaded if the
  142. *        input stream isn't seekable (e.g. IFF handle/clipboard),
  143. *        colormaps and the first frame are loaded immediately.
  144. *        If a sample was set in the prefs, it will be loaded and attached
  145. *        to the animation.
  146. *
  147. *    ATTRIBUTES
  148. *        The following attributes can be specified at creation time.
  149. *
  150. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  151. *            attribute. DTST_FILE, DTST_CLIPBOARD and DTST_RAM are supported.
  152. *            If any other type was set in a given DTA_SourceType,
  153. *            OM_NEW will be rejected.
  154. *            A sourcetype of DTST_CLIPBOARD forces the LOADALL prefs
  155. *            switch (can't seek on clipboard).
  156. *            Defaults to DTST_FILE.
  157. *
  158. *        DTA_Handle -- For both DTST_FILE and DTST_CLIPBOARD, a
  159. *            (struct IFFHandle *) is expected. This handle will be
  160. *            created by datatypesclass depeding on the DTF_#? flag, which
  161. *            is DTF_IFF here.  DTST_FILE, datatypesclass creates
  162. *            a IFF handle from the given DTA_Name and DTA_Handle (a
  163. *            BPTR returned by Lock), if DTST_CLIPBOARD, datatypesclass
  164. *            passes the given (IFF) handle through.
  165. *            A DTST_RAM (create empty object) source type requires a NULL
  166. *            handle.
  167. *
  168. *    RESULT
  169. *        If the object was created a pointer to the object is returned,
  170. *        otherwise NULL is returned.
  171. *
  172. ******************************************************************************
  173. *
  174. */
  175.       case OM_NEW:
  176.       {
  177.           struct TagItem *ti;
  178.  
  179.           /* We only support DTST_FILE, DTST_CLIPBOARD or DTST_RAM as source type */
  180.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  181.           {
  182.             if( ((ti -> ti_Data) != DTST_FILE)      &&
  183.                 ((ti -> ti_Data) != DTST_CLIPBOARD) &&
  184.                 ((ti -> ti_Data) != DTST_RAM) )
  185.             {
  186.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  187.  
  188.               break;
  189.             }
  190.           }
  191.  
  192.           /* Create object */
  193.           if( retval = DoSuperMethodA( cl, o, msg ) )
  194.           {
  195.             LONG error;
  196.  
  197.             /* Load frames... */
  198.             if( error = LoadFrames( cb, (Object *)retval ) )
  199.             {
  200.               /* Something went fatally wrong, dispose object */
  201.               CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  202.               retval = 0UL;
  203.             }
  204.  
  205.             SetIoErr( error );
  206.           }
  207.       }
  208.           break;
  209.  
  210. /****** anim.datatype/OM_DISPOSE *********************************************
  211. *
  212. *    NAME
  213. *        OM_DISPOSE -- Delete a anim.datatype object.
  214. *
  215. *    FUNCTION
  216. *        The OM_DISPOSE method is used to delete an instance of the
  217. *        anim.datatype class. This method is passed to the superclass when
  218. *        it has completed.
  219. *        This method frees all frame nodes and their contents (bitmaps,
  220. *        colormaps, samples etc.)
  221. *
  222. *    RESULT
  223. *        The object is deleted. 0UL is returned.
  224. *
  225. ******************************************************************************
  226. *
  227. */
  228.       case OM_DISPOSE:
  229.       {
  230.           LONG saved_ioerr = IoErr();
  231.  
  232.           /* Get a pointer to our object data */
  233.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  234.  
  235.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  236.           WaitBlit();
  237.  
  238.           /* Free colormaps etc. */
  239.           FreeFrameNodeResources( cb, (&(aid -> aid_FrameList)) );
  240.  
  241.           /* Free our key bitmap */
  242.           FreeBitMap( (aid -> aid_KeyBitMap) );
  243.  
  244.           /* Delete the pools */
  245.           DeletePool( (aid -> aid_FramePool) );
  246.           DeletePool( (aid -> aid_Pool) );
  247.  
  248.           /* Close input file */
  249.           if( aid -> aid_FH )
  250.           {
  251. #ifdef DOASYNCIO
  252.             CloseAsync( cb, (aid -> aid_FH) );
  253. #else
  254.             Close( (aid -> aid_FH) );
  255. #endif /* DOASYNCIO */
  256.           }
  257.  
  258.           /* Close verbose output file */
  259.           if( aid -> aid_VerboseOutput )
  260.           {
  261.             Close( (aid -> aid_VerboseOutput) );
  262.           }
  263.  
  264.           /* Dispose object */
  265.           DoSuperMethodA( cl, o, msg );
  266.           
  267.           SetIoErr( saved_ioerr );
  268.       }
  269.           break;
  270.  
  271.       case OM_UPDATE:
  272.       {
  273.           if( DoMethod( o, ICM_CHECKLOOP ) )
  274.           {
  275.             break;
  276.           }
  277.       }
  278.       case OM_SET:
  279.       {
  280.           /* Pass the attributes to the animation class and force a refresh if we need it */
  281.           if( retval = DoSuperMethodA( cl, o, msg ) )
  282.           {
  283.             /* Top instance ? */
  284.             if( OCLASS( o ) == cl )
  285.             {
  286.               struct RastPort *rp;
  287.  
  288.               /* Get a pointer to the rastport */
  289.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  290.               {
  291.                 struct gpRender gpr;
  292.  
  293.                 /* Force a redraw */
  294.                 gpr . MethodID   = GM_RENDER;
  295.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  296.                 gpr . gpr_RPort  = rp;
  297.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  298.  
  299.                 DoMethodA( o, (Msg)(&gpr) );
  300.  
  301.                 /* Release the temporary rastport */
  302.                 ReleaseGIRPort( rp );
  303.  
  304.                 /* We did a refresh... */
  305.                 retval = 0UL;
  306.               }
  307.             }
  308.           }
  309.       }
  310.           break;
  311.  
  312. /****** anim.datatype/DTM_WRITE **********************************************
  313. *
  314. *    NAME
  315. *        DTM_WRITE -- Save data
  316. *
  317. *    FUNCTION
  318. *        This method saves the object's contents to disk.
  319. *
  320. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  321. *        superclass, animation.datatype, which writes a single IFF ILBM
  322. *        picture.
  323. *
  324. *        If dtw_mode is DTWM_RAW, the object saved an IFF ANIM stream to
  325. *        the filehandle given, starting with the current frame until
  326. *        the end is reached.
  327. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames
  328. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  329. *
  330. *    TAGS
  331. *        When writing the local ("raw") format, IFF ANIM, the following
  332. *        attributes are recognized:
  333. *
  334. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  335. *            Defaults to the current frame displayed.
  336. *
  337. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  338. *            Defaults to (max_num_of_frames - curr_frame).
  339. *
  340. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  341. *            Defaults to 1, which means: "jump to next frame".
  342. *
  343. *    NOTE
  344. *        - Any sound attached to the animation will NOT be saved.
  345. *
  346. *        - A CTRL-D signal to the writing process aborts the save.
  347. *
  348. *    RESULT
  349. *        Returns 0 for failure (IoErr() returns result2), non-zero
  350. *        for success.
  351. *
  352. ******************************************************************************
  353. *
  354. */
  355.       case DTM_WRITE:
  356.       {
  357.           struct dtWrite *dtw;
  358.  
  359.           dtw = (struct dtWrite *)msg;
  360.  
  361.           /* Local data format not supported yet... */
  362.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  363.           {
  364.             retval = SaveIFFAnim( cb, cl, o, dtw );
  365.           }
  366.           else
  367.           {
  368.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  369.             retval = DoSuperMethodA( cl, o, msg );
  370.           }
  371.       }
  372.           break;
  373.  
  374. /****** anim.datatype/ADTM_START *********************************************
  375. *
  376. *    NAME
  377. *        ADTM_START -- Prepare for playback
  378. *
  379. *    FUNCTION
  380. *        ADTM_START tells the subclass (us) to prepare for continous
  381. *        playback. To avoid a long "search" for a full frame during the
  382. *        playback clock is running, we load here the given timestamp
  383. *        (asa_Frame) manually (and preseves it using a small trick, see
  384. *        source).
  385. *
  386. *        After all, the method is passed to superclass, which starts the
  387. *        playback (and the master clock).
  388. *
  389. *    RESULT
  390. *        Returns result from superclass (animation.datatype)
  391. *
  392. *    NOTE
  393. *
  394. ******************************************************************************
  395. *
  396. */
  397.  
  398.       case ADTM_START:
  399.       {
  400.           struct FrameNode *fn;
  401.           struct adtStart  *asa;
  402.           ULONG             timestamp;
  403.  
  404.           aid       = (struct AnimInstData *)INST_DATA( cl, o );
  405.           asa       = (struct adtStart *)msg;
  406.           timestamp = asa -> asa_Frame;
  407.  
  408.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  409.  
  410.           /* Turn on async IO */
  411.           aid -> aid_AsyncIO = TRUE;
  412.  
  413.           /* Find frame by timestamp */
  414.           if( fn = FindFrameNode( (&(aid -> aid_FrameList)), timestamp ) )
  415.           {
  416.             /* Load bitmaps only if we don't cache the whole anim and
  417.              * if we have a filehandle to load from (an empty object created using DTST_RAM don't have this)...
  418.              */
  419.             if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  420.             {
  421.               /* If no bitmap is loaded, load it... */
  422.               if( (fn -> fn_BitMap) == NULL )
  423.               {
  424.                 struct adtFrame alf;
  425.  
  426.                 /* reset method msg */
  427.                 memset( (void *)(&alf), 0, sizeof( struct adtFrame ) );
  428.  
  429.                 /* load frame */
  430.                 alf . MethodID      = ADTM_LOADFRAME;
  431.                 alf . alf_TimeStamp = timestamp;
  432.                 alf . alf_Frame     = timestamp;
  433.  
  434.                 /* Load frame */
  435.                 if( DoMethodA( o, (Msg)(&alf) ) )
  436.                 {
  437.                   /* Success ! */
  438.  
  439.                   /* The "trick" used here is to decrase the fn_UseCount
  440.                    * WITHOUT unloading the bitmap. The first following
  441.                    * ADTM_LOADFRAME triggered by animation.datatypes playback
  442.                    * clock gets this frame without any problems
  443.                    */
  444.                   fn -> fn_UseCount--;
  445.                 }
  446.                 else
  447.                 {
  448.                   /* Failure ! */
  449.                   error_printf( cb, aid, "ADTM_START load error %ld", IoErr() );
  450.  
  451.                   /* Unload frame... */
  452.                   alf . MethodID = ADTM_UNLOADFRAME;
  453.                   DoMethodA( o, (Msg)(&alf) );
  454.                 }
  455.               }
  456.             }
  457.           }
  458.  
  459.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  460.  
  461.           retval = DoSuperMethodA( cl, o, msg );
  462.       }
  463.           break;
  464.  
  465. /****** anim.datatype/ADTM_PAUSE **********************************************
  466. *
  467. *    NAME
  468. *        ADTM_PAUSE -- Pause playback
  469. *
  470. *    FUNCTION
  471. *        ADTM_PAUSE tells the subclass (use) to pause playback.
  472. *
  473. *        The method is passed to animation.datatype first, which pauses the
  474. *        playback clock.
  475. *
  476. *    RESULT
  477. *        Returns result from superclass (animation.datatype)
  478. *
  479. *    NOTE
  480. *
  481. ******************************************************************************
  482. *
  483. */
  484.  
  485.       case ADTM_PAUSE:
  486.       {
  487.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  488.  
  489.           /* Pass msg to superclass first ! */
  490.           retval = DoSuperMethodA( cl, o, msg );
  491.  
  492.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  493.  
  494.             /* Return to syncrounous IO */
  495.             aid -> aid_AsyncIO = FALSE;
  496.  
  497.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  498.       }
  499.           break;
  500.  
  501. /****** anim.datatype/ADTM_STOP **********************************************
  502. *
  503. *    NAME
  504. *        ADTM_STOP -- Stop playback
  505. *
  506. *    FUNCTION
  507. *        ADTM_STOP tells the subclass (use) to stop playback.
  508. *
  509. *        The method is passed to animation.datatype first, which stops the
  510. *        playback clock.
  511. *
  512. *        After clock has been stopped, we search for frames which have a
  513. *        0 UseCount and have not been unloaded yet (a small cleaup to get
  514. *        rid of frames which are loaded using the "trick" in ADTM_START
  515. *        code).
  516. *
  517. *    RESULT
  518. *        Returns result from superclass (animation.datatype)
  519. *
  520. *    NOTE
  521. *
  522. ******************************************************************************
  523. *
  524. */
  525.  
  526.  
  527.       case ADTM_STOP:
  528.       {
  529.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  530.  
  531.           /* Pass msg to superclass first ! */
  532.           retval = DoSuperMethodA( cl, o, msg );
  533.  
  534.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  535.  
  536. #if 0
  537.           if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  538.           {
  539.             struct FrameNode *worknode,
  540.                              *nextnode;
  541.  
  542.             worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  543.  
  544.             while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  545.             {
  546.               /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  547.               if( ((worknode -> fn_UseCount) == 0) && (worknode -> fn_BitMap) && (worknode != (struct FrameNode *)(aid -> aid_FrameList . mlh_Head)) )
  548.               {
  549.                 /* Don't free the current nor the previous nor the next bitmap (to avoid problems with delta frames) */
  550.                 if( (worknode != (aid -> aid_CurrFN)) &&
  551.                     (worknode != (struct FrameNode *)(aid -> aid_CurrFN -> fn_Node . mln_Succ)) &&
  552.                     (worknode != (struct FrameNode *)(aid -> aid_CurrFN -> fn_Node . mln_Pred)) )
  553.                 {
  554.                   FreeVecPooled( cb, (aid -> aid_FramePool), (worknode -> fn_BitMap) );
  555.                   worknode -> fn_BitMap = NULL;
  556.                 }
  557.               }
  558.  
  559.               worknode = nextnode;
  560.             }
  561.           }
  562. #endif
  563.  
  564.           /* Return to syncrounous IO */
  565.           aid -> aid_AsyncIO = FALSE;
  566.  
  567.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  568.       }
  569.           break;
  570.  
  571.  
  572. /****** anim.datatype/ADTM_LOADFRAME *****************************************
  573. *
  574. *    NAME
  575. *        ADTM_LOADFRAME -- Load frame
  576. *
  577. *    FUNCTION
  578. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  579. *        data of the animation.
  580. *        The given timestamp will be used to find a matching timestamp
  581. *        in the internal FrameNode list. If it was found, the corresponding
  582. *        timing, bitmap and colormap data are stored into the struct
  583. *        adtFrame. If the bitmap wasn't loaded at this time, this method 
  584. *        attempts to load it from disk.
  585. *
  586. *    RESULT
  587. *        Returns the bitmap ptr if a bitmap was found, 0UL otherwise;
  588. *        in case of failure Result2 contains the cause:
  589. *        ERROR_OBJECT_NOT_FOUND: Given timestamp does not exist
  590. *        ERROR_NO_FREE_STORE:    No memory
  591. *        and so on...
  592. *
  593. *    NOTE
  594. *        It is expected that a 0 return code (error) causes an
  595. *        ADTM_UNLOADFRAME that the invalid bitmap etc. will be freed.
  596. *
  597. ******************************************************************************
  598. *
  599. */
  600.       case ADTM_LOADFRAME:
  601.       {
  602.           struct FrameNode *fn;
  603.           struct adtFrame  *alf;
  604.  
  605.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  606.           alf = (struct adtFrame *)msg;
  607.  
  608.           ObtainSemaphore( (&(aid -> aid_SigSem)) );
  609.  
  610.           /* Like "realloc": Free any given frame here */
  611.           if( alf -> alf_UserData )
  612.           {
  613.             msg -> MethodID = ADTM_UNLOADFRAME;
  614.  
  615.               DoMethodA( o, msg );
  616.  
  617.             msg -> MethodID = ADTM_LOADFRAME;
  618.           }
  619.  
  620.           /* Find frame by timestamp */
  621.           if( fn = FindFrameNode( (&(aid -> aid_FrameList)), (alf -> alf_TimeStamp) ) )
  622.           {
  623.             LONG error = 0L;
  624.  
  625.             aid -> aid_CurrFN = fn;
  626.  
  627.             /* Load bitmaps only if we don't cache the whole anim and
  628.              * if we have a filehandle to load from (an empty object created using DTST_RAM don't have this)...
  629.              */
  630.             if( ((aid -> aid_LoadAll) == FALSE) && (aid -> aid_FH) )
  631.             {
  632.               /* If no bitmap is loaded, load it... */
  633.               if( (fn -> fn_BitMap) == NULL )
  634.               {
  635.                 if( fn -> fn_BitMap = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) ) )
  636.                 {
  637.                   struct FrameNode *worknode = fn;
  638.                   ULONG             rollback = 0UL;
  639.                   UBYTE            *buff;
  640.                   ULONG             buffsize;
  641.  
  642.                   /* Buffer to fill. Below we try to read some more bytes
  643.                    * (the size value is stored in worknode -> fn_LoadSize)
  644.                    * (ANHD chunk (~68 bytes), maybe a CMAP) to save
  645.                    * the Seek in the next cycle.
  646.                    * This makes only much sense when doing async io (during playback)...
  647.                    */
  648.  
  649.                   /* Not the last frame !
  650.                    * Note that this code is replicated in the loop below !!
  651.                    */
  652.  
  653.                   worknode -> fn_LoadSize = worknode -> fn_BMSize;
  654.  
  655.                   if( (worknode -> fn_Node . mln_Succ -> mln_Succ) && (aid -> aid_AsyncIO) )
  656.                   {
  657.                     ULONG nextpos = ((((struct FrameNode *)(worknode -> fn_Node . mln_Succ)) -> fn_BMOffset) + 8UL);
  658.  
  659.                     worknode -> fn_LoadSize = MAX( (worknode -> fn_LoadSize), (nextpos - ((worknode -> fn_BMOffset) + 8UL)) );
  660.  
  661.                     /* Don't alloc a too large buffer... */
  662.                     worknode -> fn_LoadSize = MIN( (worknode -> fn_LoadSize), ((worknode -> fn_BMSize) * 2UL) );
  663.                   }
  664.  
  665.                   buffsize = worknode -> fn_LoadSize;
  666.  
  667.                   do
  668.                   {
  669.                     worknode = worknode -> fn_PrevFrame;
  670.                     rollback++;
  671.  
  672.                     worknode -> fn_LoadSize = worknode -> fn_BMSize;
  673.  
  674.                     if( (worknode -> fn_Node . mln_Succ -> mln_Succ) && (aid -> aid_AsyncIO) )
  675.                     {
  676.                       ULONG nextpos = ((((struct FrameNode *)(worknode -> fn_Node . mln_Succ)) -> fn_BMOffset) + 8UL);
  677.  
  678.                       worknode -> fn_LoadSize = MAX( (worknode -> fn_LoadSize), (nextpos - ((worknode -> fn_BMOffset) + 8UL)) );
  679.  
  680.                       /* Don't alloc a too large buffer... */
  681.                       worknode -> fn_LoadSize = MIN( (worknode -> fn_LoadSize), ((worknode -> fn_BMSize) * 2UL) );
  682.                     }
  683.  
  684.                     buffsize = MAX( buffsize, (worknode -> fn_LoadSize) );
  685.                   } while( ((worknode -> fn_BitMap) == NULL) && ((worknode -> fn_TimeStamp) != 0UL) );
  686.  
  687.                   if( ((worknode -> fn_BitMap) == NULL) && ((worknode -> fn_TimeStamp) == 0UL) )
  688.                   {
  689.                     verbose_printf( cb, aid, "first frame without bitmap ... !\n" );
  690.                     ClearBitMap( (fn -> fn_BitMap) );
  691.                   }
  692.  
  693.                   /* Alloc buffer for compressed frame (DLTA) data */
  694.                   if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), (buffsize + 32UL) ) )
  695.                   {
  696.                     do
  697.                     {
  698.                       ULONG current = rollback;
  699.  
  700.                       worknode = fn;
  701.  
  702.                       while( current-- )
  703.                       {
  704.                         worknode = worknode -> fn_PrevFrame;
  705.                       }
  706.  
  707.                       if( (worknode -> fn_BitMap) && (worknode != fn) )
  708.                       {
  709.                         CopyBitMap( cb, (worknode -> fn_BitMap), (fn -> fn_BitMap) );
  710.                       }
  711.                       else
  712.                       {
  713.                         LONG seekdist; /* seeking distance (later Seek result, if Seek'ed) */
  714.  
  715.                         seekdist = (((worknode -> fn_BMOffset) + 8UL) - (aid -> aid_CurrFilePos));
  716.  
  717.                         /* Seek needed ? */
  718.                         if( seekdist != 0L )
  719.                         {
  720. #ifdef DOASYNCIO
  721.                           seekdist = SeekAsync( cb, (aid -> aid_FH), seekdist, OFFSET_CURRENT );
  722. #else
  723.                           seekdist = Seek( (aid -> aid_FH), seekdist, OFFSET_CURRENT );
  724. #endif /* DOASYNCIO */
  725.                         }
  726.  
  727.                         /* "Seek" success ? */
  728.                         if( seekdist != (-1L) )
  729.                         {
  730.                           LONG bytesread;
  731.  
  732. #ifdef DOASYNCIO
  733.                           bytesread = ReadAsync( cb, (aid -> aid_FH), buff, (worknode -> fn_LoadSize) );
  734. #else
  735.                           bytesread = Read( (aid -> aid_FH), buff, (worknode -> fn_LoadSize) );
  736. #endif /* DOASYNCIO */
  737.  
  738.                           /* No error during reading ? */
  739.                           if( (bytesread >= (worknode -> fn_BMSize)) && (bytesread != -1L) )
  740.                           {
  741.                             LONG ifferror;
  742.  
  743.                             if( ifferror = DrawDLTA( cb, aid, (fn -> fn_BitMap), (fn -> fn_BitMap), (&(worknode -> fn_AH)), buff, (worknode -> fn_BMSize) ) )
  744.                             {
  745.                               error_printf( cb, aid, "dlta unpacking error %lu\n", ifferror );
  746.  
  747.                               /* convert IFFParse error to DOS error */
  748.                               error = ifferr2doserr[ (-ifferror - 1) ];
  749.                             }
  750.  
  751.                             /* Bump file pos */
  752.                             aid -> aid_CurrFilePos = ((worknode -> fn_BMOffset) + 8UL) + bytesread;
  753.                           }
  754.                           else
  755.                           {
  756.                             /* Read error */
  757.                             error = IoErr();
  758.  
  759.                             /* Error, rewind stream */
  760. #ifdef DOASYNCIO
  761.                             SeekAsync( cb, (aid -> aid_FH), 0L, OFFSET_BEGINNING );
  762. #else
  763.                             Seek( (aid -> aid_FH), 0L, OFFSET_BEGINNING );
  764. #endif /* DOASYNCIO */
  765.                             aid -> aid_CurrFilePos = 0L;
  766.                           }
  767.  
  768.                           worknode -> fn_LoadSize = 0UL; /* destroy that this value won't affect anything else */
  769.                         }
  770.                         else
  771.                         {
  772.                           /* Seek error */
  773.                           error = IoErr();
  774.                         }
  775.                       }
  776.                     } while( rollback-- && (error == 0L) );
  777.  
  778.                     FreeVecPooled( cb, (aid -> aid_Pool), buff );
  779.                   }
  780.                   else
  781.                   {
  782.                     /* No memory for compressed frame data */
  783.                     error = ERROR_NO_FREE_STORE;
  784.                   }
  785.                 }
  786.                 else
  787.                 {
  788.                   /* No memory for frame bitmap */
  789.                   error = ERROR_NO_FREE_STORE;
  790.                 }
  791.               }
  792.             }
  793.  
  794.             /* Store frame/context information */
  795.             alf -> alf_Frame    = fn -> fn_Frame;
  796.             alf -> alf_Duration = fn -> fn_Duration;
  797.             alf -> alf_UserData = (APTR)fn;        /* Links back to this FrameNode (used by ADTM_UNLOADFRAME) */
  798.  
  799.             /* Store bitmap information */
  800.             alf -> alf_BitMap = fn -> fn_BitMap;
  801.             alf -> alf_CMap   = fn -> fn_CMap;
  802.  
  803.             /* Is there a sample to play ? */
  804.             if( fn -> fn_Sample )
  805.             {
  806.               /* Store sound information */
  807.               alf -> alf_Sample       = fn -> fn_Sample;
  808.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  809.               alf -> alf_Period       = fn -> fn_Period;
  810.             }
  811.             else
  812.             {
  813.               /* No sound */
  814.               alf -> alf_Sample       = NULL;
  815.               alf -> alf_SampleLength = 0UL;
  816.               alf -> alf_Period       = 0UL;
  817.             }
  818.  
  819.             /* Frame "in use", even for a unsuccessful result; on error
  820.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  821.              * allocated resources and decreases the "UseCount"...
  822.              */
  823.             fn -> fn_UseCount++;
  824.  
  825.             /* Is this node in the posted-free queue ? */
  826.             if( fn -> fn_PostedFree )
  827.             {
  828.               Remove( (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  829.               fn -> fn_PostedFree = FALSE;
  830.             }
  831.  
  832.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  833.             SetIoErr( error );                                   /* Result2 */
  834.           }
  835.           else
  836.           {
  837.             /* no matching frame found */
  838.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  839.           }
  840.  
  841.           ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  842.       }
  843.           break;
  844.  
  845. /****** anim.datatype/ADTM_UNLOADFRAME ***************************************
  846. *
  847. *    NAME
  848. *        ADTM_UNLOADFRAME -- Load frame contents
  849. *
  850. *    FUNCTION
  851. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  852. *        animation frame.
  853. *
  854. *        This method frees the bitmap data found in adtFrame.
  855. *
  856. *    RESULT
  857. *        Returns always 0UL.
  858. *
  859. ******************************************************************************
  860. *
  861. */
  862.       case ADTM_UNLOADFRAME:
  863.       {
  864.           struct FrameNode *fn;
  865.           struct adtFrame  *alf;
  866.  
  867.           aid = (struct AnimInstData *)INST_DATA( cl, o );
  868.           alf = (struct adtFrame *)msg;
  869.  
  870.           /* Free bitmaps only if we don't cache the whole anim */
  871.           if( (aid -> aid_LoadAll) == FALSE )
  872.           {
  873.             struct MinNode *pfn;
  874.             UWORD           i   = 10;
  875.  
  876.             ObtainSemaphore( (&(aid -> aid_SigSem)) );
  877.  
  878.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  879.             {
  880.               if( (fn -> fn_UseCount) > 0 )
  881.               {
  882.                 fn -> fn_UseCount--;
  883.  
  884.                 /* Free an existing bitmap if it isn't in use and if it is NOT the first bitmap */
  885.                 if( ((fn -> fn_UseCount) == 0) && (fn -> fn_BitMap) && (fn != (struct FrameNode *)(aid -> aid_FrameList . mlh_Head)) )
  886.                 {
  887.                   if( FALSE /*FreeAbleFrame( aid, fn )*/ )
  888.                   {
  889.                     /* Is this node in the posted-free queue ? */
  890.                     if( fn -> fn_PostedFree )
  891.                     {
  892.                       Remove( (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  893.                       fn -> fn_PostedFree = FALSE;
  894.  
  895.                       D( kprintf( "free posted 1 %lu\n", (fn -> fn_TimeStamp) ) );
  896.                     }
  897.  
  898.                     FreeVecPooled( cb, (aid -> aid_FramePool), (fn -> fn_BitMap) );
  899.                     fn -> fn_BitMap = NULL;
  900.                   }
  901.                   else
  902.                   {
  903.                     if( (fn -> fn_PostedFree) == FALSE )
  904.                     {
  905.                       D( kprintf( "posted free %lu\n", (fn -> fn_TimeStamp) ) );
  906.  
  907.                       AddTail( (struct List *)(&(aid -> aid_PostedFreeList)), (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  908.                       fn -> fn_PostedFree = TRUE;
  909.                     }
  910.                   }
  911.                 }
  912.               }
  913.             }
  914.  
  915.             while( pfn = (struct MinNode *)RemHead( (struct List *)(&(aid -> aid_PostedFreeList)) ) )
  916.             {
  917.               fn = POSTEDFREENODE2FN( pfn );
  918.               fn -> fn_PostedFree = FALSE;
  919.  
  920.               if( (fn -> fn_UseCount) == 0 )
  921.               {
  922.                 if( FreeAbleFrame( aid, fn ) )
  923.                 {
  924.                   D( kprintf( "free posted 2 %lu at %lu\n", (fn -> fn_TimeStamp), (((struct FrameNode *)(alf -> alf_UserData)) -> fn_TimeStamp) ) );
  925.  
  926.                   FreeVecPooled( cb, (aid -> aid_FramePool), (fn -> fn_BitMap) );
  927.                   fn -> fn_BitMap = NULL;
  928.                 }
  929.                 else
  930.                 {
  931.                   AddTail( (struct List *)(&(aid -> aid_PostedFreeList)), (struct Node *)(&(fn -> fn_PostedFreeNode)) );
  932.                   fn -> fn_PostedFree = TRUE;
  933.                 }
  934.  
  935.                 /* Don't process the list twice */
  936.                 if( fn == ((struct FrameNode *)(alf -> alf_UserData)) )
  937.                 {
  938.                   i = MIN( 1, i );
  939.  
  940.                   break;
  941.                 }
  942.  
  943.                 if( i-- == 0 )
  944.                 {
  945.                   D( kprintf( "pl overflow at %lu\n", (((struct FrameNode *)(alf -> alf_UserData)) -> fn_TimeStamp) ) );
  946.  
  947.                   break;
  948.                 }
  949.               }
  950.             }
  951.  
  952.             ReleaseSemaphore( (&(aid -> aid_SigSem)) );
  953.           }
  954.  
  955.           /* Indicate that the frame has been free'ed. */
  956.           alf -> alf_UserData = NULL;
  957.       }
  958.           break;
  959.  
  960.       /* Let the superclass handle everything else */
  961.       default:
  962.       {
  963.           retval = DoSuperMethodA( cl, o, msg );
  964.       }
  965.           break;
  966.     }
  967.  
  968.     return( retval );
  969. }
  970.  
  971.  
  972. static
  973. BOOL FreeAbleFrame( struct AnimInstData *aid, struct FrameNode *fn )
  974. {
  975.     struct FrameNode *currfn = aid -> aid_CurrFN;
  976.  
  977.     /* Don't free the current nor the previous nor the next bitmap (to avoid problems with delta frames) */
  978.     if( (fn == currfn) ||
  979.         (fn == (struct FrameNode *)(currfn -> fn_Node . mln_Succ)) ||
  980.         (fn == (struct FrameNode *)(currfn -> fn_Node . mln_Pred)) )
  981.     {
  982.       return( FALSE );
  983.     }
  984.  
  985.     if( ABS( ((LONG)(fn -> fn_TimeStamp)) - ((LONG)(currfn -> fn_TimeStamp)) ) < 5UL )
  986.     {
  987.       return( FALSE );
  988.     }
  989.  
  990.     return( TRUE );
  991. }
  992.  
  993.  
  994. /****** anim.datatype/preferences ********************************************
  995. *
  996. *   NAME
  997. *       preferences
  998. *
  999. *   DESCRIPTION
  1000. *       The "ENV:Classes/DataTypes/anim.prefs" file contains global
  1001. *       settings for the datatype.
  1002. *       The preferences file is an ASCII file containing one line where the
  1003. *       preferences can be set.
  1004. *       It can be superset by a local variable with the same name.
  1005. *
  1006. *       Each line can contain settings, special settings for some projects
  1007. *       can be set using the MATCHPROJECT option.
  1008. *       Lines beginning with a '#' or ';' chars are treated as comments.
  1009. *       Lines are limitted to 256 chars.
  1010. *
  1011. *   TEMPLATE
  1012. *       MATCHPROJECT/K,VERBOSE/S,MODEID/K/N,CMAPS/S,NOCMAPS/S,
  1013. *       DPAINTBRUSHPATCH/S,NODPAINTBRUSHPATCH/S,FPS/K/N,DYNAMICTIMING/S,
  1014. *       NODYNAMICTIMING/S,SAMPLE/K,SAMPLESPERFRAME=SPF/K/N,VOLUME/K/N,
  1015. *       LOADALL/S,NOLOADALL/S
  1016. *
  1017. *       MATCHPROJECT -- The settings in this line belongs only to this
  1018. *           project(s), e.g. if the case-insensitive pattern does not match,
  1019. *           this line is ignored.
  1020. *           The maximum length of the pattern is 128 chars.
  1021. *           Defaults to #?, which matches any project.
  1022. *
  1023. *       VERBOSE -- Print information about the animation. Currently
  1024. *          the frame numbers and the used compression are printed, after all
  1025. *          number of scanned/loaded frames, set FPS rate, dimensions (width/
  1026. *          height/depth), sample information etc.
  1027. *
  1028. *       MODEID -- Select screen mode id of datatype (will be stored in
  1029. *           ADTA_ModeID). Note that the DOS ReadArgs function used for parsing
  1030. *           fetches a SIGNED long. The bit 31 will be represented by minus
  1031. *           '-'. (example: "MODEID=266240" sets the mode to the A2024 screen
  1032. *           mode id)
  1033. *           Defaults to 0, which means: Use the screen mode from CAMG chunk,
  1034. *           if missing use the best screenmode available for the given width,
  1035. *           height and depth.
  1036. *
  1037. *       CMAPS -- Use colormaps per frame. This switch is set per default,
  1038. *           and can be turned off by the NOCMAPS option, later it can be
  1039. *           turned on again by this option.
  1040. *
  1041. *       NOCMAPS -- Don't load/use colormaps per frame. Only the initial
  1042. *           colormap will be used.
  1043. *           The current version of animation.datatype (V40.7 (28.09.93)) does
  1044. *           not implement per frame colormaps, it's output may look trashed.
  1045. *           Custom players like "DBufDTAnim" does support
  1046. *           "per frame colormaps",
  1047. *           animation.datatype V41 will implement "per frame colormaps".
  1048. *
  1049. *       DPAINTBRUSHPATCH -- If frames of ANIM-5 with an interleave of 1
  1050. *           occurs, the XOR mode is forced, even if the XOR bit is not set.
  1051. *           This fixes problems with some DPaint brush animations.
  1052. *           This option is ON per default and can be turned off by the 
  1053. *           NODPAINTBRUSHPATCH option.
  1054. *
  1055. *       NODPAINTBRUSHPATCH -- Turns off the DPaint brush patch. See 
  1056. *           DPAINTBRUSHPATCH option for details.
  1057. *
  1058. *       FPS -- Frames Per Second
  1059. *           Defaults to FPS set by DPAN chunk. If the DPAN chunk is missing
  1060. *           a fixed 5 fps rate is used.
  1061. *           A value of 0 here means: Use default FPS.
  1062. *
  1063. *       DYNAMICTIMING -- Turns dynamic timing on. Default if superclass
  1064. *           is animation.datatype V41, otherwise this option must
  1065. *           be explicitly set.
  1066. *
  1067. *       NODYNAMICTIMING -- Turn dynamic timing off. Default if superclass
  1068. *           is animation.datatype < V41 (e.g. V40.6).
  1069. *
  1070. *       SAMPLE -- Attach the given sample to the animation. The sample will
  1071. *           be loaded using datatypes (GID_SOUND).
  1072. *           Only one sample can be attached to one animationstream, any
  1073. *           following attempt to attach a sample will be ignored.
  1074. *
  1075. *       SAMPLESPERFRAME -- Set samples per frame rate for sound. This
  1076. *           overrides the own internal calculations to get rid of rounding
  1077. *           errors.
  1078. *
  1079. *       VOLUME -- Volume of the sound when playing.
  1080. *           Defaults to 64, which is the maximum. A value greater than 64 will
  1081. *           be set to 64.
  1082. *
  1083. *       LOADALL -- Load all frames into memory. If the source input is a
  1084. *           clipboard, this option is always set.
  1085. *
  1086. *       NOLOADALL -- Turns off the LOADALL flag, which may be set in a prefs-
  1087. *           line before. This switch is set per default, and can be turned off
  1088. *           by the LOADALL option, later it can be turned on again by this
  1089. *           option.
  1090. *
  1091. *       REGISTERED -- Turns off the shareware notice requester.
  1092. *
  1093. *   NOTE
  1094. *       An invalid prefs file line will be ignored and forces the VERBOSE
  1095. *       output.
  1096. *
  1097. *   BUGS
  1098. *       - Low memory may cause that the prefs file won't be parsed.
  1099. *
  1100. *       - Lines are limitted to 256 chars
  1101. *
  1102. *       - An invalid prefs file line will be ignored.
  1103. *
  1104. *       - The sample path length is limitted to 200 chars. A larger
  1105. *         value may crash the machine if an error occurs.
  1106. *
  1107. ******************************************************************************
  1108. *
  1109. */
  1110.  
  1111.  
  1112. static
  1113. STRPTR GetPrefsVar( struct ClassBase *cb, STRPTR name )
  1114. {
  1115.           STRPTR buff;
  1116.     const ULONG  buffsize = 16UL;
  1117.  
  1118.     if( buff = (STRPTR)AllocVec( (buffsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1119.     {
  1120.       if( GetVar( name, buff, buffsize, GVF_BINARY_VAR ) != (-1L) )
  1121.       {
  1122.         ULONG varsize = IoErr();
  1123.  
  1124.         varsize += 2UL;
  1125.  
  1126.         if( varsize > buffsize )
  1127.         {
  1128.           FreeVec( buff );
  1129.  
  1130.           if( buff = (STRPTR)AllocVec( (varsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  1131.           {
  1132.             if( GetVar( name, buff, varsize, GVF_BINARY_VAR ) != (-1L) )
  1133.             {
  1134.               return( buff );
  1135.             }
  1136.           }
  1137.         }
  1138.         else
  1139.         {
  1140.           return( buff );
  1141.         }
  1142.       }
  1143.  
  1144.       FreeVec( buff );
  1145.     }
  1146.  
  1147.     return( NULL );
  1148. }
  1149.  
  1150.  
  1151. static
  1152. BOOL matchstr( struct ClassBase *cb, STRPTR pat, STRPTR s )
  1153. {
  1154.     TEXT buff[ 512 ];
  1155.  
  1156.     if( pat && s )
  1157.     {
  1158.       if( ParsePatternNoCase( pat, buff, (sizeof( buff ) - 1) ) != (-1L) )
  1159.       {
  1160.         if( MatchPatternNoCase( buff, s ) )
  1161.         {
  1162.           return( TRUE );
  1163.         }
  1164.       }
  1165.     }
  1166.  
  1167.     return( FALSE );
  1168. }
  1169.  
  1170.  
  1171. static
  1172. void ReadENVPrefs( struct ClassBase *cb, struct AnimInstData *aid )
  1173. {
  1174.     struct RDArgs envvarrda =
  1175.     {
  1176.       NULL,
  1177.       256L,
  1178.       0L,
  1179.       0L,
  1180.       NULL,
  1181.       0L,
  1182.       NULL,
  1183.       RDAF_NOPROMPT
  1184.     };
  1185.  
  1186.     struct
  1187.     {
  1188.       STRPTR  matchproject;
  1189.       long   *verbose;
  1190.       long   *modeid;
  1191.       long   *cmaps;
  1192.       long   *nocmaps;
  1193.       long   *dpaintbrushpatch;
  1194.       long   *nodpaintbrushpatch;
  1195.       long   *fps;
  1196.       long   *dynamictiming;
  1197.       long   *nodynamictiming;
  1198.       STRPTR  sample;
  1199.       long   *samplesperframe;
  1200.       long   *volume;
  1201.       long   *loadall;
  1202.       long   *noloadall;
  1203.       long   *registered;
  1204.     } animargs;
  1205.  
  1206.     TEXT   varbuff[ 258 ];
  1207.     STRPTR var;
  1208.  
  1209.     if( var = GetPrefsVar( cb, "Classes/DataTypes/anim.prefs" ) )
  1210.     {
  1211.       STRPTR prefsline      = var,
  1212.              nextprefsline;
  1213.       ULONG  linecount      = 1UL;
  1214.  
  1215.       /* Be sure that "var" contains at least one break-char */
  1216.       strcat( var, "\n" );
  1217.  
  1218.       while( nextprefsline = strpbrk( prefsline, "\n" ) )
  1219.       {
  1220.         stccpy( varbuff, prefsline, (int)MIN( (sizeof( varbuff ) - 2UL), (((ULONG)(nextprefsline - prefsline)) + 1UL) ) );
  1221.  
  1222.         /* be sure that this line isn't a comment line or an empty line */
  1223.         if( (varbuff[ 0 ] != '#') && (varbuff[ 0 ] != ';') && (varbuff[ 0 ] != '\n') && (strlen( varbuff ) > 2UL) )
  1224.         {
  1225.           /* Prepare ReadArgs processing */
  1226.           strcat( varbuff, "\n" );                                       /* Add NEWLINE-char            */
  1227.           envvarrda . RDA_Source . CS_Buffer = varbuff;                  /* Buffer                      */
  1228.           envvarrda . RDA_Source . CS_Length = strlen( varbuff ) + 1UL;  /* Set up input buffer length  */
  1229.           envvarrda . RDA_Source . CS_CurChr = 0L;
  1230.           envvarrda . RDA_Buffer = NULL;
  1231.           envvarrda . RDA_BufSiz = 0L;
  1232.           memset( (void *)(&animargs), 0, sizeof( animargs ) );          /* Clear result array          */
  1233.  
  1234.           if( ReadArgs( "MATCHPROJECT/K,"
  1235.                         "VERBOSE/S,"
  1236.                         "MODEID/K/N,"
  1237.                         "CMAPS/S,"
  1238.                         "NOCMAPS/S,"
  1239.                         "DPAINTBRUSHPATCH/S,"
  1240.                         "NODPAINTBRUSHPATCH/S,"
  1241.                         "FPS/K/N,"
  1242.                         "DYNAMICTIMING/S,"
  1243.                         "NODYNAMICTIMING/S,"
  1244.                         "SAMPLE/K,"
  1245.                         "SAMPLESPERFRAME=SPF/K/N,"
  1246.                         "VOLUME/K/N,"
  1247.                         "LOADALL/S,"
  1248.                         "NOLOADALL/S,"
  1249.                         "REGISTERED/S", (LONG *)(&animargs), (&envvarrda) ) )
  1250.           {
  1251.             BOOL noignore = TRUE;
  1252.  
  1253.             if( (animargs . matchproject) && (aid -> aid_ProjectName) )
  1254.             {
  1255.               noignore = matchstr( cb, (animargs . matchproject), (aid -> aid_ProjectName) );
  1256.             }
  1257.  
  1258.             if( noignore )
  1259.             {
  1260.               if( animargs . verbose )
  1261.               {
  1262.                 OpenLogfile( cb, aid );
  1263.               }
  1264.  
  1265.               if( animargs . modeid )
  1266.               {
  1267.                 aid -> aid_ModeID = *(animargs . modeid);
  1268.               }
  1269.  
  1270.               if( animargs . cmaps )
  1271.               {
  1272.                 aid -> aid_NoCMAPs = FALSE;
  1273.               }
  1274.  
  1275.               if( animargs . nocmaps )
  1276.               {
  1277.                 aid -> aid_NoCMAPs = TRUE;
  1278.               }
  1279.  
  1280.               if( animargs . dpaintbrushpatch )
  1281.               {
  1282.                 aid -> aid_NoDPaintBrushPatch = FALSE;
  1283.               }
  1284.  
  1285.               if( animargs . nodpaintbrushpatch )
  1286.               {
  1287.                 aid -> aid_NoDPaintBrushPatch = TRUE;
  1288.               }
  1289.  
  1290.               if( animargs . fps )
  1291.               {
  1292.                 aid -> aid_FPS = *(animargs . fps);
  1293.               }
  1294.  
  1295.               if( animargs . dynamictiming )
  1296.               {
  1297.                 aid -> aid_NoDynamicTiming = FALSE;
  1298.               }
  1299.  
  1300.               if( animargs . nodynamictiming )
  1301.               {
  1302.                 aid -> aid_NoDynamicTiming = TRUE;
  1303.               }
  1304.  
  1305.               if( (animargs . sample) && ((aid -> aid_Sample) == NULL) )
  1306.               {
  1307.                 Object *so;
  1308.                 LONG    ioerr = 0L;
  1309.  
  1310.                 verbose_printf( cb, aid, "loading sample \"%s\"...\n", (animargs . sample) );
  1311.  
  1312.                 if( so = NewDTObject( (animargs . sample), DTA_GroupID, GID_SOUND, TAG_DONE ) )
  1313.                 {
  1314.                   BYTE  *sample;
  1315.                   ULONG  length;
  1316.                   ULONG  period;
  1317.  
  1318.                   /* Get sample data from object */
  1319.                   if( GetDTAttrs( so, SDTA_Sample,       (&sample),
  1320.                                       SDTA_SampleLength, (&length),
  1321.                                       SDTA_Period,       (&period),
  1322.                                       TAG_DONE ) == 3UL )
  1323.                   {
  1324.                     if( aid -> aid_Sample = (STRPTR)AllocPooled( (aid -> aid_Pool), (length + 1UL) ) )
  1325.                     {
  1326.                       /* Copy sample and context */
  1327.                       XCopyMem( cb, (APTR)sample, (APTR)(aid -> aid_Sample), length );
  1328.                       aid -> aid_SampleLength = length;
  1329.                       aid -> aid_Period       = period;
  1330.                     }
  1331.                     else
  1332.                     {
  1333.                       /* Can't alloc sample */
  1334.                       ioerr = ERROR_NO_FREE_STORE;
  1335.                     }
  1336.                   }
  1337.                   else
  1338.                   {
  1339.                     /* Object does not support the requested attributes */
  1340.                     ioerr = ERROR_OBJECT_WRONG_TYPE;
  1341.                   }
  1342.  
  1343.                   DisposeDTObject( so );
  1344.                 }
  1345.                 else
  1346.                 {
  1347.                   /* NewDTObjectA failed, cannot load sample... */
  1348.                   ioerr = IoErr();
  1349.                 }
  1350.  
  1351.                 if( (aid -> aid_Sample) == NULL )
  1352.                 {
  1353.                   TEXT errbuff[ 256 ];
  1354.  
  1355.                   if( ioerr >= DTERROR_UNKNOWN_DATATYPE )
  1356.                   {
  1357.                     mysprintf( cb, errbuff, GetDTString( ioerr ), (animargs . sample) );
  1358.                   }
  1359.                   else
  1360.                   {
  1361.                     Fault( ioerr, (animargs . sample), errbuff, sizeof( errbuff ) );
  1362.                   }
  1363.  
  1364.                   error_printf( cb, aid, "can't load sample: \"%s\" line %lu\n", errbuff, linecount );
  1365.                 }
  1366.               }
  1367.  
  1368.               if( animargs . samplesperframe )
  1369.               {
  1370.                 aid -> aid_SamplesPerFrame = (ULONG)(*(animargs . samplesperframe));
  1371.               }
  1372.  
  1373.               if( animargs . volume )
  1374.               {
  1375.                 aid -> aid_Volume = *(animargs . volume);
  1376.  
  1377.                 if( (aid -> aid_Volume) > 64UL )
  1378.                 {
  1379.                   aid -> aid_Volume = 64UL;
  1380.                 }
  1381.               }
  1382.  
  1383.               if( animargs . loadall )
  1384.               {
  1385.                 aid -> aid_LoadAll = TRUE;
  1386.               }
  1387.  
  1388.               if( animargs . noloadall )
  1389.               {
  1390.                 aid -> aid_LoadAll = FALSE;
  1391.               }
  1392.  
  1393.               if( animargs . registered )
  1394.               {
  1395.                 aid -> aid_Registered = TRUE;
  1396.               }
  1397.             }
  1398.             else
  1399.             {
  1400.               verbose_printf( cb, aid, "prefs line %lu ignored\n", linecount );
  1401.             }
  1402.  
  1403.             FreeArgs( (&envvarrda) );
  1404.           }
  1405.           else
  1406.           {
  1407.             LONG ioerr = IoErr();
  1408.             TEXT errbuff[ 256 ];
  1409.  
  1410.             Fault( ioerr, "Classes/DataTypes/anim.prefs", errbuff, (LONG)sizeof( errbuff ) );
  1411.  
  1412.             error_printf( cb, aid, "preferences \"%s\" line %lu\n", errbuff, linecount );
  1413.           }
  1414.         }
  1415.  
  1416.         prefsline = ++nextprefsline;
  1417.         linecount++;
  1418.       }
  1419.  
  1420.       FreeVec( var );
  1421.     }
  1422.  
  1423.     /* Notify the user that she/he is using shareware... */
  1424.     if( !(aid -> aid_Registered) )
  1425.     {
  1426.       YouShouldRegister( cb, aid );
  1427.     }
  1428. }
  1429.  
  1430.  
  1431. /* The shareware notify requester */
  1432. static
  1433. void YouShouldRegister( struct ClassBase *cb, struct AnimInstData *aid )
  1434. {
  1435.     struct EasyStruct SharewareES;
  1436.     ULONG             xa,
  1437.                       xb,
  1438.                       xc,
  1439.                       xd;
  1440.     ULONG             result;
  1441.     LONG              reqresult;
  1442.  
  1443.     TEXT              buffer[ 256 ],
  1444.                       cbuffer[ 256 ];
  1445. #define NUMCHOICES (6)
  1446.     ULONG             choices[ NUMCHOICES ];
  1447.  
  1448.     /* Create random values */
  1449.     CurrentTime( (&xb), (&xa) );
  1450.     xc = FastRand( xa );
  1451.     xd = FastRand( xb );
  1452.  
  1453.     /* Strip down to human-friendly values */
  1454.     xa %=  5;
  1455.     xb %=  7;
  1456.     xc %= 11;
  1457.     xd %= 13;
  1458.  
  1459.     /* calc */
  1460.     result = xa + xb * xc + xd;
  1461.  
  1462.     /* Build term */
  1463.     mysprintf( cb, buffer, "%lu + %lu * %lu + %lu = ???", xa, xb, xc, xd );
  1464.  
  1465.     /* Our choices */
  1466.     choices[ 0 ] = result;
  1467.     choices[ 1 ] = result + xb;
  1468.     choices[ 2 ] = result + xb + 1;
  1469.     choices[ 3 ] = result + xa / 2;
  1470.     choices[ 4 ] = result + 2 + xc;
  1471.     choices[ 5 ] = xa + xb + result / 2;
  1472.  
  1473.     mysprintf( cb, cbuffer, "%lu|%lu|%lu|%lu|%lu|%lu",
  1474.                choices[ (0 + xc) % NUMCHOICES ],
  1475.                choices[ (1 + xc) % NUMCHOICES ],
  1476.                choices[ (2 + xc) % NUMCHOICES ],
  1477.                choices[ (3 + xc) % NUMCHOICES ],
  1478.                choices[ (4 + xc) % NUMCHOICES ],
  1479.                choices[ (5 + xc) % NUMCHOICES ] );
  1480.  
  1481.     /* Prepare requester */
  1482.     SharewareES . es_StructSize   = sizeof( struct EasyStruct );
  1483.     SharewareES . es_Flags        = 0UL;
  1484.     SharewareES . es_Title        = "IFF ANIM DataType Shareware notice";
  1485.     SharewareES . es_TextFormat   = "Please register this DataType if you're using it more than 30 days\n"
  1486.                                     "See docs how to pay the shareware fee.\n"
  1487.                                     "To get rid of this requester forever, you must set the REGISTERED switch\n"
  1488.                                     "in the prefs-file \"ENVARC:Classes/DataTypes/anim.prefs\"\n"
  1489.                                     "then reboot the computer.\n"
  1490.                                     "To close the requester successfully, you must answer the following term:\n"
  1491.                                     "%s";
  1492.     SharewareES . es_GadgetFormat = cbuffer;
  1493.  
  1494.     /* The trial and error loop... */
  1495.     do
  1496.     {
  1497.       reqresult = EasyRequest( NULL, (&SharewareES), NULL, buffer );
  1498.  
  1499.       if( reqresult == 0L )
  1500.       {
  1501.         reqresult = NUMCHOICES;
  1502.       }
  1503.  
  1504.       reqresult--;
  1505.  
  1506.     } while( choices[ (reqresult + xc) % NUMCHOICES ] != result );
  1507. }
  1508.  
  1509.  
  1510. static
  1511. LONG LoadFrames( struct ClassBase *cb, Object *o )
  1512. {
  1513.     struct AnimInstData *aid   = (struct AnimInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  1514.     LONG                 error = 0L;
  1515.  
  1516.     /* Init */
  1517.     InitSemaphore( (&(aid -> aid_SigSem)) );
  1518.     NewList( (struct List *)(&(aid -> aid_FrameList)) );
  1519.     NewList( (struct List *)(&(aid -> aid_PostedFreeList)) );
  1520.  
  1521.     /* Create a memory pool for frame nodes and delta buffers */
  1522.     if( aid -> aid_Pool = CreatePool( MEMF_PUBLIC, 16384UL, 16384UL ) )
  1523.     {
  1524.       APTR                 fh;                              /* handle (IFF stream handle)      */
  1525.       ULONG                sourcetype;                      /* type of stream (either DTST_FILE or DTST_CLIPBOARD */
  1526.       ULONG                pos        = 0UL;                /* current file pos in IFF stream  */
  1527.       struct BitMapHeader *bmh;                             /* obj's bitmapheader              */
  1528.       ULONG                modeid     = (ULONG)INVALID_ID;  /* anim view mode                  */
  1529.       ULONG                animwidth  = 0UL,                /* anim width                      */
  1530.                            animheight = 0UL,                /* anim height                     */
  1531.                            animdepth  = 0UL;                /* anim depth                      */
  1532.       ULONG                timestamp  = 0UL;                /* timestamp                       */
  1533.       ULONG                minreltime = 1UL,                /* Maximum ah_RelTime value        */
  1534.                            maxreltime = 0UL;                /* Minimum ah_RelTime              */
  1535.       struct tPoint       *grabpoint  = NULL;               /* Grabbing point of animation     */
  1536.  
  1537.       /* Prefs defaults */
  1538.       aid -> aid_Volume          = 64UL;
  1539.       aid -> aid_NoDynamicTiming = MAKEBOOL( ((cb -> cb_SuperClassBase -> lib_Version) < 41U) );
  1540.       aid -> aid_ModeID          = (ULONG)INVALID_ID;
  1541.  
  1542.       /* Read prefs */
  1543.       ReadENVPrefs( cb, aid );
  1544.  
  1545.       /* Get file handle, handle type and BitMapHeader */
  1546.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  1547.                          DTA_Handle,        (&fh),
  1548.                          DTA_Name,          (&(aid -> aid_ProjectName)),
  1549.                          ADTA_BitMapHeader, (&bmh),
  1550.                          ADTA_Grab,         (&grabpoint), /* animation.datatype V41 */
  1551.                          TAG_DONE ) >= 4UL ) /* ADTA_Grab not supported in V40, e.g. 4 == V40, 5 == V41 */
  1552.       {
  1553.         struct IFFHandle *iff = NULL;
  1554.  
  1555.         aid -> aid_BMH = bmh; /* Store BitMapHeader */
  1556.  
  1557.         switch( sourcetype )
  1558.         {
  1559.           case DTST_CLIPBOARD:
  1560.           {
  1561.               aid -> aid_LoadAll = TRUE;
  1562.  
  1563.               iff = (struct IFFHandle *)fh;
  1564.           }
  1565.               break;
  1566.  
  1567.           case DTST_FILE:
  1568.           {
  1569.               BPTR iff_file_fh;
  1570.               BPTR cloned_fh    = NULL;
  1571.  
  1572.               iff = (struct IFFHandle *)fh;
  1573.  
  1574.               /* Attempt to open file from given stream (allows usage of virtual fs when using datatypes.library V45) */
  1575.               iff_file_fh = (BPTR)(iff -> iff_Stream); /* see iffparse.library/InitIFFasDOS autodoc */
  1576.  
  1577.               if( iff_file_fh )
  1578.               {
  1579.                 BPTR lock;
  1580.  
  1581.                 if( lock = DupLockFromFH( iff_file_fh ) )
  1582.                 {
  1583.                   /* Set up a filehandle for disk-based loading (random loading) */
  1584.                   if( !(cloned_fh = (LONG)OpenFromLock( lock )) )
  1585.                   {
  1586.                     /* failure */
  1587.                     UnLock( lock );
  1588.                   }
  1589.                 }
  1590.               }
  1591.  
  1592.               /* OpenFromLock failed ? - Then open by name :-( */
  1593.               if( cloned_fh == NULL )
  1594.               {
  1595.                 /* Set up a filehandle for disk-based loading (random loading) */
  1596.                 if( !(cloned_fh = (LONG)Open( (aid -> aid_ProjectName), MODE_OLDFILE )) )
  1597.                 {
  1598.                   /* Can't open file */
  1599.                   error = IoErr();
  1600.                 }
  1601.               }
  1602.  
  1603.               if( cloned_fh )
  1604.               {
  1605. #ifdef DOASYNCIO
  1606.                 if( !(aid -> aid_FH = OpenAsync( cb, cloned_fh, 8192L )) )
  1607.                 {
  1608.                   /* Can't get async access */
  1609.                   error = IoErr();
  1610.                 }
  1611. #else
  1612.                 aid -> aid_FH = cloned_fh;
  1613. #endif /* DOASYNCIO */
  1614.               }
  1615.           }
  1616.               break;
  1617.  
  1618.           case DTST_RAM:
  1619.           {
  1620.               /* do nothing */
  1621.           }
  1622.               break;
  1623.  
  1624.           default:
  1625.           {
  1626.               /* unsupported source type */
  1627.               error = ERROR_NOT_IMPLEMENTED;
  1628.           }
  1629.               break;
  1630.         }
  1631.  
  1632.         /* Any error ? */
  1633.         if( error == 0L )
  1634.         {
  1635.           if( iff )
  1636.           {
  1637.             struct StoredProperty *bmhdprop       = NULL, /* ILBM BMHD (struct BitMapHeader)        */
  1638.                                   *camgprop       = NULL, /* ILBM CAMG (amiga view mode id)         */
  1639.                                   *grabprop       = NULL, /* ILBM GRAB (grabbing point)             */
  1640.                                   *dpanprop       = NULL, /* DPaint DPAN chunk                      */
  1641.                                   *annoprop       = NULL, /* Generic IFF ANNO (annotation) chunk    */
  1642.                                   *authprop       = NULL, /* Generic IFF AUTH (author) chunk        */
  1643.                                   *copyrightprop  = NULL, /* Generic IFF (C)  (copyright) chunk     */
  1644.                                   *fverprop       = NULL, /* Generic IFF FVER (version) chunk       */
  1645.                                   *nameprop       = NULL; /* Generic IFF NAME (name) chunk          */
  1646.  
  1647. #define NUM_PROPCHUNKS (9L)
  1648.             const
  1649.             LONG propchunks[ (NUM_PROPCHUNKS * 2) ] =
  1650.             {
  1651.               ID_ILBM, ID_BMHD,
  1652.               ID_ILBM, ID_CAMG,
  1653.               ID_ILBM, ID_GRAB,
  1654.               ID_ILBM, ID_DPAN,
  1655.               ID_ILBM, ID_ANNO,
  1656.               ID_ILBM, ID_AUTH,
  1657.               ID_ILBM, ID_Copyright,
  1658.               ID_ILBM, ID_FVER,
  1659.               ID_ILBM, ID_NAME
  1660.             };
  1661.  
  1662.             if( !(error = PropChunks( iff, (LONG *)propchunks, NUM_PROPCHUNKS )) )
  1663.             {
  1664. #define NUM_STOPCHUNKS (5L)
  1665.               const
  1666.               LONG stopchunks[ (NUM_STOPCHUNKS * 2) ] =
  1667.               {
  1668.                 ID_ILBM, ID_FORM,
  1669.                 ID_ILBM, ID_ANHD,
  1670.                 ID_ILBM, ID_CMAP,
  1671.                 ID_ILBM, ID_BODY,
  1672.                 ID_ILBM, ID_DLTA
  1673.               };
  1674.  
  1675.               if( !(error = StopChunks( iff, (LONG *)stopchunks, NUM_STOPCHUNKS )) )
  1676.               {
  1677.                 struct FrameNode *fn         = NULL;
  1678.                 ULONG             numcmaps   = 0UL; /* number of created cmaps  */
  1679.  
  1680.                 /* Scan IFF stream until an error or an EOF occurs */
  1681.                 for( ;; )
  1682.                 {
  1683.                   struct ContextNode *cn;
  1684.  
  1685.                   if( error = ParseIFF( iff, IFFPARSE_SCAN ) )
  1686.                   {
  1687.                     /* EOF (End Of File) is no error here... */
  1688.                     if( error == IFFERR_EOF )
  1689.                     {
  1690.                       error = 0L;
  1691.                     }
  1692.  
  1693.                     break;
  1694.                   }
  1695.  
  1696.                   /* Get file position */
  1697.                   if( cn = CurrentChunk( iff ) )
  1698.                   {
  1699.                     pos = 0UL;
  1700.  
  1701.                     while( cn = ParentChunk( cn ) )
  1702.                     {
  1703.                       pos += cn -> cn_Scan;
  1704.                     }
  1705.                   }
  1706.  
  1707.                   /* bmhd header loaded ? */
  1708.                   if( bmhdprop == NULL )
  1709.                   {
  1710.                     if( bmhdprop = FindProp( iff, ID_ILBM, ID_BMHD ) )
  1711.                     {
  1712.                       ULONG poolsize,
  1713.                             availmem;
  1714.  
  1715.                       *bmh = *((struct BitMapHeader *)(bmhdprop -> sp_Data));
  1716.  
  1717.                       animwidth  = bmh -> bmh_Width;
  1718.                       animheight = bmh -> bmh_Height;
  1719.                       animdepth  = bmh -> bmh_Depth;
  1720.  
  1721.                       availmem = AvailMem( MEMF_PUBLIC );
  1722.  
  1723.                       /* Create a seperate pool for frames:
  1724.                        * (((width + 7) / 8) * height * depth + struct BitMapHeader + Padding) * 4 frames
  1725.                        */
  1726.                       poolsize = (((animwidth * animheight * animdepth) / 8UL) + 256UL) * 4UL;
  1727.  
  1728.                       /* Shrink pool to a fitting size */
  1729.                       while( (poolsize * 4) > availmem )
  1730.                       {
  1731.                         poolsize /= 2UL;
  1732.                       }
  1733.  
  1734.                       /* Create a memory pool for frame bitmaps */
  1735.                       if( !(aid -> aid_FramePool = CreatePool( MEMF_PUBLIC, poolsize, poolsize )) )
  1736.                       {
  1737.                         error = ERROR_NO_FREE_STORE;
  1738.                       }
  1739.                     }
  1740.                   }
  1741.  
  1742.                   /* camg loaded ? */
  1743.                   if( camgprop == NULL )
  1744.                   {
  1745.                     if( camgprop = FindProp( iff, ID_ILBM, ID_CAMG ) )
  1746.                     {
  1747.                       modeid = *(ULONG *)(camgprop -> sp_Data);
  1748.  
  1749.                       /* Check for invalid flags */
  1750.                       if( (!(modeid & MONITOR_ID_MASK)) ||
  1751.                           ((modeid & EXTENDED_MODE) &&
  1752.                           (!(modeid & 0xFFFF0000UL))) )
  1753.                       {
  1754.                         /* Remove invalid flags (see include31:graphics/view.h) */
  1755.                         modeid &= ~(GENLOCK_VIDEO | PFBA | GENLOCK_AUDIO | DUALPF | EXTENDED_MODE | VP_HIDE | SPRITES );
  1756.                       }
  1757.  
  1758.                       /* Be safe ! */
  1759.                       if( (modeid & 0xFFFF0000UL) && (!(modeid & 0x00001000UL)) )
  1760.                       {
  1761.                         modeid = (ULONG)INVALID_ID;
  1762.                       }
  1763.                     }
  1764.                   }
  1765.  
  1766.                   /* grab loaded ? */
  1767.                   if( grabprop == NULL )
  1768.                   {
  1769.                     if( grabprop = FindProp( iff, ID_ILBM, ID_GRAB ) )
  1770.                     {
  1771.                       /* Grab point only available in animation.datatype V41 */
  1772.                       if( grabpoint )
  1773.                       {
  1774.                         *grabpoint = *((struct tPoint *)(grabprop -> sp_Data));
  1775.                       }
  1776.  
  1777.                       verbose_printf( cb, aid, "animation GRAB point x=%ld, y=%ld\n",
  1778.                                       (long)(((struct tPoint *)(grabprop -> sp_Data)) -> x),
  1779.                                       (long)(((struct tPoint *)(grabprop -> sp_Data)) -> y) );
  1780.                     }
  1781.                   }
  1782.  
  1783.                   /* dpan loaded ? */
  1784.                   if( dpanprop == NULL )
  1785.                   {
  1786.                     if( dpanprop = FindProp( iff, ID_ILBM, ID_DPAN ) )
  1787.                     {
  1788.                       if( (aid -> aid_FPS) == 0UL )
  1789.                       {
  1790.                         struct DPAnimChunk *dpan = (struct DPAnimChunk *)(dpanprop -> sp_Data);
  1791.                         
  1792.                         if( (dpan -> dpan_FPS) <= 60UL )
  1793.                         {
  1794.                           aid -> aid_FPS = dpan -> dpan_FPS;
  1795.  
  1796.                           verbose_printf( cb, aid, "DPAN found, FPS set to %lu\n", (aid -> aid_FPS) );
  1797.                         }
  1798.                         else
  1799.                         {
  1800.                           verbose_printf( cb, aid, "DPAN found, ignoring invalid FPS value %lu\n", (ULONG)(dpan -> dpan_FPS) );
  1801.                         }
  1802.                       }
  1803.                     }
  1804.                   }
  1805.  
  1806.                   if( annoprop == NULL )
  1807.                   {
  1808.                     /* IFF ANNO found ? */
  1809.                     if( annoprop = FindProp( iff, ID_ILBM, ID_ANNO ) )
  1810.                     {
  1811.                       STRPTR buff;
  1812.  
  1813.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1814.                       if( buff = (STRPTR)AllocVec( ((annoprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1815.                       {
  1816.                         stccpy( buff, (annoprop -> sp_Data), (int)(annoprop -> sp_Size) );
  1817.  
  1818.                         verbose_printf( cb, aid, "ANNO annotation: \"%s\"\n", buff );
  1819.  
  1820.                         SetDTAttrs( o, NULL, NULL, DTA_ObjAnnotation, buff, TAG_DONE );
  1821.  
  1822.                         FreeVec( buff );
  1823.                       }
  1824.                       else
  1825.                       {
  1826.                         /* no temp. buffer */
  1827.                         error = ERROR_NO_FREE_STORE;
  1828.                       }
  1829.                     }
  1830.                   }
  1831.  
  1832.                   if( authprop == NULL )
  1833.                   {
  1834.                     /* IFF AUTH found ? */
  1835.                     if( authprop = FindProp( iff, ID_ILBM, ID_AUTH ) )
  1836.                     {
  1837.                       STRPTR buff;
  1838.  
  1839.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1840.                       if( buff = (STRPTR)AllocVec( ((authprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1841.                       {
  1842.                         stccpy( buff, (authprop -> sp_Data), (int)(authprop -> sp_Size) );
  1843.  
  1844.                         verbose_printf( cb, aid, "AUTH author: \"%s\"\n", buff );
  1845.  
  1846.                         SetDTAttrs( o, NULL, NULL, DTA_ObjAuthor, buff, TAG_DONE );
  1847.  
  1848.                         FreeVec( buff );
  1849.                       }
  1850.                       else
  1851.                       {
  1852.                         /* no temp. buffer */
  1853.                         error = ERROR_NO_FREE_STORE;
  1854.                       }
  1855.                     }
  1856.                   }
  1857.  
  1858.                   if( copyrightprop == NULL )
  1859.                   {
  1860.                     /* IFF (C) found ? */
  1861.                     if( copyrightprop = FindProp( iff, ID_ILBM, ID_Copyright ) )
  1862.                     {
  1863.                       STRPTR buff;
  1864.  
  1865.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1866.                       if( buff = (STRPTR)AllocVec( ((copyrightprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1867.                       {
  1868.                         stccpy( buff, (copyrightprop -> sp_Data), (int)(copyrightprop -> sp_Size) );
  1869.  
  1870.                         verbose_printf( cb, aid, "(C) copyright: \"%s\"\n", buff );
  1871.  
  1872.                         SetDTAttrs( o, NULL, NULL, DTA_ObjCopyright, buff, TAG_DONE );
  1873.  
  1874.                         FreeVec( buff );
  1875.                       }
  1876.                       else
  1877.                       {
  1878.                         /* no temp. buffer */
  1879.                         error = ERROR_NO_FREE_STORE;
  1880.                       }
  1881.                     }
  1882.                   }
  1883.  
  1884.                   if( fverprop == NULL )
  1885.                   {
  1886.                     /* IFF FVER found ? */
  1887.                     if( fverprop = FindProp( iff, ID_ILBM, ID_FVER ) )
  1888.                     {
  1889.                       STRPTR buff;
  1890.  
  1891.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1892.                       if( buff = (STRPTR)AllocVec( ((fverprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1893.                       {
  1894.                         stccpy( buff, (fverprop -> sp_Data), (int)(fverprop -> sp_Size) );
  1895.  
  1896.                         verbose_printf( cb, aid, "FVER version: \"%s\"\n", buff );
  1897.  
  1898.                         SetDTAttrs( o, NULL, NULL, DTA_ObjVersion, buff, TAG_DONE );
  1899.  
  1900.                         FreeVec( buff );
  1901.                       }
  1902.                       else
  1903.                       {
  1904.                         /* no temp. buffer */
  1905.                         error = ERROR_NO_FREE_STORE;
  1906.                       }
  1907.                     }
  1908.                   }
  1909.  
  1910.                   if( nameprop == NULL )
  1911.                   {
  1912.                     /* IFF NAME found ? */
  1913.                     if( nameprop = FindProp( iff, ID_ILBM, ID_NAME ) )
  1914.                     {
  1915.                       STRPTR buff;
  1916.  
  1917.                       /* Allocate a temp buffer so that stccpy can add a '\0'-terminator */
  1918.                       if( buff = (STRPTR)AllocVec( ((nameprop -> sp_Size) + 2UL), MEMF_ANY ) )
  1919.                       {
  1920.                         stccpy( buff, (nameprop -> sp_Data), (int)(nameprop -> sp_Size) );
  1921.  
  1922.                         verbose_printf( cb, aid, "NAME name: \"%s\"\n", buff );
  1923.  
  1924.                         SetDTAttrs( o, NULL, NULL, DTA_ObjName, buff, TAG_DONE );
  1925.  
  1926.                         FreeVec( buff );
  1927.                       }
  1928.                       else
  1929.                       {
  1930.                         /* no temp. buffer */
  1931.                         error = ERROR_NO_FREE_STORE;
  1932.                       }
  1933.                     }
  1934.                   }
  1935.  
  1936.                   if( cn = CurrentChunk( iff ) )
  1937.                   {
  1938.                     switch( (cn -> cn_Type) )
  1939.                     {
  1940.                       case ID_ILBM:
  1941.                       {
  1942.                           switch( (cn -> cn_ID) )
  1943.                           {
  1944.                             case ID_FORM:
  1945.                             {
  1946.                                 /* Create an prepare a new frame node */
  1947.                                 if( fn = AllocFrameNode( cb, (aid -> aid_Pool) ) )
  1948.                                 {
  1949.                                   AddTail( (struct List *)(&(aid -> aid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  1950.  
  1951.                                   fn -> fn_TimeStamp = timestamp++;
  1952.                                   fn -> fn_Frame     = fn -> fn_TimeStamp;
  1953.                                   
  1954.                                   fn -> fn_PrevFrame = fn;
  1955.                                 }
  1956.                                 else
  1957.                                 {
  1958.                                   /* can't alloc frame node */
  1959.                                   error = ERROR_NO_FREE_STORE;
  1960.                                 }
  1961.                             }
  1962.                                 break;
  1963.  
  1964.                             case ID_ANHD:
  1965.                             {
  1966.                                 if( fn )
  1967.                                 {
  1968.                                   ULONG interleave;
  1969.  
  1970.                                   /* Read struct AnimHeader */
  1971.                                   error = ReadChunkBytes( iff, (&(fn -> fn_AH)), (LONG)sizeof( struct AnimHeader ) );
  1972.                                   if( error == (LONG)sizeof( struct AnimHeader ) ) error = 0L;
  1973.  
  1974.                                   /* Info */
  1975.                                   DumpAnimHeader( cb, aid, (fn -> fn_TimeStamp), (&(fn -> fn_AH)) );
  1976.  
  1977.                                   /* Check if we have dynamic timing */
  1978.                                   maxreltime = MAX( maxreltime, (fn -> fn_AH . ah_RelTime) );
  1979.                                   minreltime = MIN( minreltime, (fn -> fn_AH . ah_RelTime) );
  1980.  
  1981.                                   interleave = (ULONG)(fn -> fn_AH . ah_Interleave);
  1982.  
  1983.                                   /* An interleave of 0 means two frames back */
  1984.                                   if( interleave == 0 )
  1985.                                   {
  1986.                                     interleave = 2;
  1987.                                   }
  1988.  
  1989.                                   /* Get previous frame */
  1990.                                   fn -> fn_PrevFrame = GetPrevFrameNode( fn, interleave );
  1991.                                 }
  1992.                             }
  1993.                                 break;
  1994.  
  1995.                             case ID_CMAP:
  1996.                             {
  1997.                                 if( fn )
  1998.                                 {
  1999.                                   UBYTE *buff;
  2000.  
  2001.                                   /* Allocate buffer */
  2002.                                   if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), ((cn -> cn_Size) + 16UL) ) )
  2003.                                   {
  2004.                                     /* Load CMAP data */
  2005.                                     error = ReadChunkBytes( iff, buff, (cn -> cn_Size) );
  2006.  
  2007.                                     /* All read ? */
  2008.                                     if( error == (cn -> cn_Size) )
  2009.                                     {
  2010.                                       error = 0L; /* Success ! */
  2011.  
  2012.                                       if( timestamp == 1UL )
  2013.                                       {
  2014.                                         if( !CMAP2Object( cb, o, buff, (cn -> cn_Size) ) )
  2015.                                         {
  2016.                                           /* can't alloc object's color table */
  2017.                                           error = ERROR_NO_FREE_STORE;
  2018.                                         }
  2019.                                       }
  2020.  
  2021.                                       /* Any failure ? */
  2022.                                       if( error == 0L )
  2023.                                       {
  2024.                                         if( aid -> aid_NoCMAPs )
  2025.                                         {
  2026.                                           error = 0L; /* Success ! */
  2027.                                         }
  2028.                                         else
  2029.                                         {
  2030.                                           if( fn -> fn_CMap = CMAP2ColorMap( cb, aid, buff, (cn -> cn_Size) ) )
  2031.                                           {
  2032.                                             error = 0L; /* Success ! */
  2033.                                             numcmaps++;
  2034.                                           }
  2035.                                           else
  2036.                                           {
  2037.                                             /* no colormap */
  2038.                                             error = ERROR_NO_FREE_STORE;
  2039.                                           }
  2040.                                         }
  2041.                                       }
  2042.                                     }
  2043.  
  2044.                                     FreeVecPooled( cb, (aid -> aid_Pool), buff );
  2045.                                   }
  2046.                                   else
  2047.                                   {
  2048.                                     /* no load buff */
  2049.                                     error = ERROR_NO_FREE_STORE;
  2050.                                   }
  2051.                                 }
  2052.                             }
  2053.                                 break;
  2054.  
  2055.                             case ID_BODY:
  2056.                             case ID_DLTA:
  2057.                             {
  2058.                                 if( fn )
  2059.                                 {
  2060.                                   /* Store position of DLTA (pos points to the DLTA ID) */
  2061.                                   fn -> fn_BMOffset = pos;
  2062.                                   fn -> fn_BMSize   = cn -> cn_Size;
  2063.  
  2064.                                   if( (fn -> fn_BitMap) == NULL )
  2065.                                   {
  2066.                                     /* Preload frames only if requested or if this is the key frame (first frame of anim) */
  2067.                                     if( (aid -> aid_LoadAll) || ((fn -> fn_TimeStamp) == 0UL) )
  2068.                                     {
  2069.                                       if( animwidth && animheight && animdepth )
  2070.                                       {
  2071.                                         if( fn -> fn_BitMap = AllocBitMapPooled( cb, animwidth, animheight, animdepth, (aid -> aid_FramePool) ) )
  2072.                                         {
  2073.                                           UBYTE *buff;
  2074.  
  2075.                                           /* Allocate buffer */
  2076.                                           if( buff = (UBYTE *)AllocVecPooled( cb, (aid -> aid_Pool), ((cn -> cn_Size) + 32UL) ) )
  2077.                                           {
  2078.                                             struct FrameNode *prevfn;
  2079.  
  2080.                                             /* Clear buffer to get rid of some problems with corrupted DLTAs */
  2081.                                             memset( (void *)buff, 0, (size_t)((cn -> cn_Size) + 31UL) );
  2082.  
  2083.                                             /* Get previous frame */
  2084.                                             prevfn = fn -> fn_PrevFrame;
  2085.  
  2086.                                             /* Load delta data */
  2087.                                             error = ReadChunkBytes( iff, buff, (cn -> cn_Size) );
  2088.  
  2089.                                             /* All bytes read ? */
  2090.                                             if( error == (cn -> cn_Size) )
  2091.                                             {
  2092.                                               error = DrawDLTA( cb, aid, (prevfn -> fn_BitMap), (fn -> fn_BitMap), (&(fn -> fn_AH)), buff, (cn -> cn_Size) );
  2093.  
  2094.                                               if( error )
  2095.                                               {
  2096.                                                 error_printf( cb, aid, "scan/load: dlta unpacking error %lu\n", error );
  2097.                                               }
  2098.                                             }
  2099.  
  2100.                                             FreeVecPooled( cb, (aid -> aid_Pool), buff );
  2101.                                           }
  2102.                                           else
  2103.                                           {
  2104.                                             /* no load buff */
  2105.                                             error = ERROR_NO_FREE_STORE;
  2106.                                           }
  2107.                                         }
  2108.                                         else
  2109.                                         {
  2110.                                           /* no bitmap */
  2111.                                           error = ERROR_NO_FREE_STORE;
  2112.                                         }
  2113.                                       }
  2114.                                       else
  2115.                                       {
  2116.                                         /* no dimensions for bitmap (possibly a missing bmhd) */
  2117.                                         error = DTERROR_NOT_ENOUGH_DATA;
  2118.                                       }
  2119.                                     }
  2120.                                   }
  2121.                                   else
  2122.                                   {
  2123.                                     error_printf( cb, aid, "scan/load: bitmap already loaded\n" );
  2124.                                   }
  2125.                                 }
  2126.                             }
  2127.                                 break;
  2128.                           }
  2129.                       }
  2130.                           break;
  2131.                     }
  2132.                   }
  2133.  
  2134.                   /* on error: leave for-loop */
  2135.                   if( error )
  2136.                   {
  2137.                     break;
  2138.                   }
  2139.                 }
  2140.  
  2141.                 /* Any frames ? */
  2142.                 if( timestamp && (error == 0L) && numcmaps )
  2143.                 {
  2144.                   if( numcmaps == 1UL )
  2145.                   {
  2146.                     /* We only have a global colormap and no colormap changes,
  2147.                      * delete first colormap (a colormap in the first frames indicates following colormap
  2148.                      * changes)
  2149.                      */
  2150.                     struct FrameNode *firstnode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2151.  
  2152.                     if( firstnode -> fn_CMap )
  2153.                     {
  2154.                       FreeColorMap( (firstnode -> fn_CMap) );
  2155.                       firstnode -> fn_CMap = NULL;
  2156.                     }
  2157.                   }
  2158.                   else
  2159.                   {
  2160.                     /* All frames must have a colormap, therefore we replicate the colormap
  2161.                      * from the previous colormap if one is missing
  2162.                      */
  2163.                     struct FrameNode *worknode,
  2164.                                      *nextnode;
  2165.                     struct ColorMap  *currcm = NULL;
  2166.  
  2167.                     verbose_printf( cb, aid, "Animation has palette changes per frame\n" );
  2168.  
  2169.                     worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2170.  
  2171.                     while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2172.                     {
  2173.                       if( worknode -> fn_CMap )
  2174.                       {
  2175.                         /* Current node contains colormap, this are the colors for the following frames... */
  2176.                         currcm = worknode -> fn_CMap;
  2177.                       }
  2178.                       else
  2179.                       {
  2180.                         if( currcm )
  2181.                         {
  2182.                           /* Copy colormap from previous one... */
  2183.                           if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
  2184.                           {
  2185.                             /* Can't copy/alloc colormap */
  2186.                             error = ERROR_NO_FREE_STORE;
  2187.                           }
  2188.                         }
  2189.                         else
  2190.                         {
  2191.                           verbose_printf( cb, aid, "scan/load: no colormap, can't copy it\n" );
  2192.                         }
  2193.                       }
  2194.  
  2195.                       worknode = nextnode;
  2196.                     }
  2197.                   }
  2198.                 }
  2199.               }
  2200.             }
  2201.  
  2202.             /* Check for required information */
  2203.             if( error == 0L )
  2204.             {
  2205.               /* bmh information available  ? */
  2206.               if( bmhdprop == NULL )
  2207.               {
  2208.                 verbose_printf( cb, aid, "scan: no bmhd found\n" );
  2209.  
  2210.                 /* BMHD missing */
  2211.                 error = DTERROR_INVALID_DATA;
  2212.               }
  2213.               else
  2214.               {
  2215.                 /* Any frames loaded ? */
  2216.                 if( timestamp == 0UL )
  2217.                 {
  2218.                   /* not enougth frames (at least one required) */
  2219.                   error = DTERROR_NOT_ENOUGH_DATA;
  2220.                 }
  2221.               }
  2222.             }
  2223.  
  2224.             /* Dynamic timing ? */
  2225.             if( (minreltime != maxreltime) && ((aid -> aid_NoDynamicTiming) == FALSE) )
  2226.             {
  2227.               struct FrameNode *worknode,
  2228.                                *nextnode;
  2229.               ULONG             shift = 0UL;    
  2230.               
  2231.               if( minreltime == 0UL )
  2232.               {
  2233.                 shift = 1UL;
  2234.               }
  2235.  
  2236.               verbose_printf( cb, aid, "using dynamic timing\n" );
  2237.  
  2238.               /* Renumber timestamps */
  2239.               timestamp = 0UL; /* again we count from 0 */
  2240.  
  2241.               worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  2242.  
  2243.               while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2244.               {
  2245.                 ULONG duration = (worknode -> fn_AH . ah_RelTime) + shift - 1UL;
  2246.  
  2247.                 worknode -> fn_TimeStamp = timestamp;
  2248.                 worknode -> fn_Frame     = timestamp;
  2249.                 worknode -> fn_Duration  = duration;
  2250.  
  2251.                 timestamp += (duration + 1UL);
  2252.  
  2253.                 worknode = nextnode;
  2254.               }
  2255.             }
  2256.  
  2257.             /* Any error ? */
  2258.             if( error == 0L )
  2259.             {
  2260.               /* Alloc bitmap as key bitmap  */
  2261.               if( aid -> aid_KeyBitMap = AllocBitMap( animwidth, animheight, animdepth, (BMF_CLEAR | BMF_MINPLANES), NULL ) )
  2262.               {
  2263.                 struct FrameNode *firstfn = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head); /* short cut to the first FrameNode */
  2264.                 
  2265.                 aid -> aid_CurrFN = firstfn;
  2266.  
  2267.                 if( (firstfn -> fn_BitMap) == NULL )
  2268.                 {
  2269.                   if( !(firstfn -> fn_BitMap = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) )) )
  2270.                   {
  2271.                     /* can't alloc first bitmap */
  2272.                     error = ERROR_NO_FREE_STORE;
  2273.                   }
  2274.                 }
  2275.  
  2276.                 if( error == 0L )
  2277.                 {
  2278.                   /* Copy first frame into key bitmap */
  2279.                   CopyBitMap( cb, (firstfn -> fn_BitMap), (aid -> aid_KeyBitMap) );
  2280.  
  2281.                   /* No name chunk ? */
  2282.                   if( nameprop == NULL )
  2283.                   {
  2284.                     STRPTR name;
  2285.  
  2286.                     GetDTAttrs( o, DTA_Name, (&name), TAG_DONE );
  2287.                     SetDTAttrs( o, NULL, NULL, DTA_ObjName, name, TAG_DONE );
  2288.                   }
  2289.  
  2290.                   /* ModeID... */
  2291.                   if( (aid -> aid_ModeID) != INVALID_ID )
  2292.                   {
  2293.                     modeid = aid -> aid_ModeID;
  2294.                   }
  2295.                   else
  2296.                   {
  2297.                     /* No mode id ? */
  2298.                     if( modeid == INVALID_ID )
  2299.                     {
  2300.                       /* BUG: Does currently not support SUPERHIRES modes */
  2301.                       if( animwidth >= 640UL )
  2302.                       {
  2303.                         if( animheight >= 400 )
  2304.                         {
  2305.                           modeid = HIRESLACE_KEY;
  2306.                         }
  2307.                         else
  2308.                         {
  2309.                           modeid = HIRES_KEY;
  2310.                         }
  2311.                       }
  2312.                       else
  2313.                       {
  2314.                         if( animheight >= 400 )
  2315.                         {
  2316.                           modeid = LORESLACE_KEY;
  2317.                         }
  2318.                         else
  2319.                         {
  2320.                           modeid = LORES_KEY;
  2321.                         }
  2322.                       }
  2323.                     }
  2324.                   }
  2325.  
  2326.                   /* No FPS rate found ? */
  2327.                   if( (aid -> aid_FPS) == 0UL )
  2328.                   {
  2329.                     ULONG adaptive;
  2330.  
  2331.                     aid -> aid_FPS = 10UL; /* should be 60 (e.g. 1/60 sec per frame) */
  2332.  
  2333.                     if( GetDTAttrs( o, ADTA_AdaptiveFPS, (&adaptive), TAG_DONE ) == 1UL )
  2334.                     {
  2335.                       if( adaptive )
  2336.                       {
  2337.                         verbose_printf( cb, aid, "animation.datatype uses adaptive playback rate selection\n" );
  2338.  
  2339.                         aid -> aid_FPS = 60UL; /* 1/60 sec per frame */
  2340.                       }
  2341.                     }
  2342.                   }
  2343.  
  2344.                   /* Attach external sound */
  2345.                   AttachSample( cb, aid );
  2346.  
  2347.                   /* Infos */
  2348.                   verbose_printf( cb, aid, "width %lu height %lu depth %lu frames %lu fps %lu\n",
  2349.                                 animwidth,
  2350.                                 animheight,
  2351.                                 animdepth,
  2352.                                 timestamp,
  2353.                                 (aid -> aid_FPS) );
  2354.  
  2355.                   /* Set misc attributes */
  2356.                   SetDTAttrs( o, NULL, NULL,
  2357.                               DTA_TotalHoriz,       animwidth,
  2358.                               DTA_TotalVert,        animheight,
  2359.                               ADTA_Width,           animwidth,
  2360.                               ADTA_Height,          animheight,
  2361.                               ADTA_Depth,           animdepth,
  2362.                               ADTA_ModeID,          modeid,
  2363.                               ADTA_Frames,          timestamp,
  2364.                               ADTA_FramesPerSecond, (aid -> aid_FPS),
  2365.                               ADTA_KeyFrame,        (aid -> aid_KeyBitMap),
  2366.                               ADTA_Sample,          (firstfn -> fn_Sample),
  2367.                               ADTA_SampleLength,    (firstfn -> fn_SampleLength),
  2368.                               ADTA_Period,          (firstfn -> fn_Period),
  2369.                               ADTA_Volume,          (aid -> aid_Volume),
  2370.                               ADTA_Cycles,          1UL,
  2371.                               TAG_DONE );
  2372.                 }
  2373.               }
  2374.               else
  2375.               {
  2376.                 /* can't alloc key bitmap */
  2377.                 error = ERROR_NO_FREE_STORE;
  2378.               }
  2379.             }
  2380.           }
  2381.           else
  2382.           {
  2383.             /* No iff handle ? - Be sure we got a DTST_RAM sourcetype */
  2384.             if( sourcetype != DTST_RAM )
  2385.             {
  2386.               /* No handle ! */
  2387.               error = ERROR_REQUIRED_ARG_MISSING;
  2388.             }
  2389.           }
  2390.         }
  2391.       }
  2392.       else
  2393.       {
  2394.         /* can't get required attributes from superclass */
  2395.         error = ERROR_OBJECT_WRONG_TYPE;
  2396.       }
  2397.     }
  2398.     else
  2399.     {
  2400.       /* no memory pool */
  2401.       error = ERROR_NO_FREE_STORE;
  2402.     }
  2403.  
  2404.     /* Error codes below 0 are related to the IFFParse.library functions */
  2405.     if( error < 0L )
  2406.     {
  2407.       verbose_printf( cb, aid, "iff error %ld\n", (long)error );
  2408.  
  2409.       /* convert IFFParse error to DOS error */
  2410.       error = ifferr2doserr[ (-error - 1) ];
  2411.     }
  2412.  
  2413.     return( error );
  2414. }
  2415.  
  2416.  
  2417. static
  2418. struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
  2419. {
  2420.     struct FrameNode *fn;
  2421.  
  2422.     if( fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) )
  2423.     {
  2424.       memset( fn, 0, sizeof( struct FrameNode ) );
  2425.     }
  2426.  
  2427.     return( fn );
  2428. }
  2429.  
  2430.  
  2431. static
  2432. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  2433. {
  2434.     if( fnl )
  2435.     {
  2436.       struct FrameNode *worknode,
  2437.                        *nextnode,
  2438.                        *prevnode;
  2439.  
  2440.       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  2441.  
  2442.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2443.       {
  2444.         if( (worknode -> fn_TimeStamp) > timestamp )
  2445.         {
  2446.           return( prevnode );
  2447.         }
  2448.  
  2449.         prevnode = worknode;
  2450.         worknode = nextnode;
  2451.       }
  2452.  
  2453.       if( !IsListEmpty( ((struct List *)fnl) ) )
  2454.       {
  2455.         return( prevnode );
  2456.       }  
  2457.     }
  2458.  
  2459.     return( NULL );
  2460. }
  2461.  
  2462.  
  2463. static
  2464. void FreeFrameNodeResources( struct ClassBase *cb, struct MinList *fnl )
  2465. {
  2466.     if( fnl )
  2467.     {
  2468.       struct FrameNode *worknode,
  2469.                        *nextnode;
  2470.  
  2471.       worknode = (struct FrameNode *)(fnl -> mlh_Head);
  2472.  
  2473.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  2474.       {
  2475.         if( worknode -> fn_CMap )
  2476.         {
  2477.           FreeColorMap( (worknode -> fn_CMap) );
  2478.           worknode -> fn_CMap = NULL;
  2479.         }
  2480.  
  2481.         worknode = nextnode;
  2482.       }
  2483.     }
  2484. }
  2485.  
  2486.  
  2487. /* Copy bm1 to bm2 */
  2488. static
  2489. void CopyBitMap( struct ClassBase *cb, struct BitMap *bm1, struct BitMap *bm2 )
  2490. {
  2491.     ULONG  bpr1 = bm1 -> BytesPerRow;
  2492.     ULONG  bpr2 = bm2 -> BytesPerRow;
  2493.  
  2494.     /* Same bitmap layout ? */
  2495.     if( bpr1 == bpr2 )
  2496.     {
  2497.       /* Interleaved BitMap ? */
  2498.       if( ((bm1 -> Planes[ 1 ]) - (bm1 -> Planes[ 0 ])) == (bpr1 / (ULONG)(bm1 -> Depth)) )
  2499.       {
  2500.         ULONG planesize = bpr2 * (ULONG)(bm2 -> Rows);
  2501.  
  2502.         XCopyMem( cb, (bm1 -> Planes[ 0 ]), (bm2 -> Planes[ 0 ]), planesize );
  2503.       }
  2504.       else
  2505.       {
  2506.         ULONG planesize = bpr2 * (ULONG)(bm2 -> Rows);
  2507.         UWORD i;
  2508.  
  2509.         for( i = 0U ; i < (bm2 -> Depth) ; i++ )
  2510.         {
  2511.           XCopyMem( cb, (bm1 -> Planes[ i ]), (bm2 -> Planes[ i ]), planesize );
  2512.         }
  2513.       }
  2514.     }
  2515.     else
  2516.     {
  2517.       register UBYTE *src;
  2518.       register UBYTE *dst;
  2519.       register LONG   r;
  2520.       register LONG   p;
  2521.                ULONG  width = bm1 -> BytesPerRow;
  2522.  
  2523.       /* Interleaved BitMap ? */
  2524.       if( ((bm1 -> Planes[ 1 ]) - (bm1 -> Planes[ 0 ])) == (bpr1 / (ULONG)(bm1 -> Depth)) )
  2525.       {
  2526.         width /= (bm1 -> Depth);
  2527.       }
  2528.  
  2529.       for( p = bm1 -> Depth - 1 ; p >= 0 ; p-- )
  2530.       {
  2531.         src = (BYTE *)bm1 -> Planes[ p ];
  2532.         dst = (BYTE *)bm2 -> Planes[ p ];
  2533.  
  2534.         for( r = bm1 -> Rows - 1 ; r >= 0 ; r-- )
  2535.         {
  2536.           CopyMem( src, dst, width );
  2537.           src += bpr1;
  2538.           dst += bpr2;
  2539.         }
  2540.       }
  2541.     }
  2542. }
  2543.  
  2544.  
  2545. static
  2546. void XCopyMem( struct ClassBase *cb, APTR src, APTR dest, ULONG size )
  2547. {
  2548.     /* Check if we can use the optimized CopyMemQuick */
  2549.     if( (ALIGN_LONG( src ) == src) && (ALIGN_LONG( dest ) == dest) )
  2550.     {
  2551.       register ULONG lsize = size & ~3UL,
  2552.                      cut   = size - lsize; /* remaining bytes (0-3) */
  2553.  
  2554.       CopyMemQuick( src, dest, lsize );
  2555.  
  2556.       if( cut )
  2557.       {
  2558.         src  = ((UBYTE *)src)  + lsize;
  2559.         dest = ((UBYTE *)dest) + lsize;
  2560.  
  2561.         CopyMem( src, dest, cut );
  2562.       }
  2563.     }
  2564.     else
  2565.     {
  2566.       CopyMem( src, dest, size );
  2567.     }
  2568. }
  2569.  
  2570.  
  2571. static
  2572. void ClearBitMap( struct BitMap *bm )
  2573. {
  2574.     if( bm )
  2575.     {
  2576.       ULONG planesize = (ULONG)(bm -> BytesPerRow) * (ULONG)(bm -> Rows);
  2577.       UWORD i;
  2578.  
  2579.       for( i = 0U ; i < (bm -> Depth) ; i++ )
  2580.       {
  2581.         memset( (bm -> Planes[ i ]), 0, (size_t)planesize );
  2582.       }
  2583.     }
  2584. }
  2585.  
  2586.  
  2587. /* XOR Bitmaps op1 ^= op2 */
  2588. static
  2589. void XORBitMaps( struct BitMap *op1, struct BitMap *op2 )
  2590. {
  2591.     if( op1 && op2 )
  2592.     {
  2593.                ULONG  planesize = (ULONG)(op1 -> BytesPerRow) * (ULONG)(op1 -> Rows);
  2594.                ULONG  missing;
  2595.                ULONG  i;
  2596.       register ULONG  j;
  2597.       register ULONG *op1p, /* op1 planes */
  2598.                      *op2p; /* op2 planes */
  2599.  
  2600.       planesize = planesize / sizeof( ULONG ); /* op1p and op2p are ULONGs, not BYTES... */
  2601.       missing   = planesize % sizeof( ULONG ); /* missing bytes */
  2602.  
  2603.       for( i = 0U ; i < (op1 -> Depth) ; i++ )
  2604.       {
  2605.         j = planesize;
  2606.  
  2607.         op1p = (ULONG *)(op1 -> Planes[ i ]);
  2608.         op2p = (ULONG *)(op2 -> Planes[ i ]);
  2609.  
  2610.         while( j-- )
  2611.         {
  2612.           *op1p++ ^= *op2p++;
  2613.         }
  2614.  
  2615.         if( missing )
  2616.         {
  2617.           register UBYTE *op1px = (UBYTE *)op1p;
  2618.           register UBYTE *op2px = (UBYTE *)op2p;
  2619.  
  2620.           j = missing;
  2621.  
  2622.           while( j-- )
  2623.           {
  2624.             *op1px++ ^= *op2px++;
  2625.           }
  2626.         }
  2627.       }
  2628.     }
  2629. }
  2630.  
  2631.  
  2632. static
  2633. struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
  2634. {
  2635.     struct BitMap *bm;
  2636.     ULONG          planesize,
  2637.                    moredepthsize,
  2638.                    size;
  2639.  
  2640.     planesize       = (ULONG)RASSIZE( ((width + 63UL) & ~63UL), height );
  2641.     moredepthsize   = (depth > 8UL)?((depth - 8UL) * sizeof( PLANEPTR )):(0UL);
  2642.     size            = ((ULONG)sizeof( struct BitMap )) + moredepthsize + (planesize * depth) + 31UL;
  2643.  
  2644.     if( bm = (struct BitMap *)AllocVecPooled( cb, pool, size ) )
  2645.     {
  2646.       UWORD    pl;
  2647.       PLANEPTR plane;
  2648.  
  2649.       InitBitMap( bm, depth, width, height );
  2650.  
  2651.       plane = ALIGN_QUADLONG( (PLANEPTR)(bm + 1) ); /* First plane follows struct BitMap */
  2652.  
  2653.       /* Set up plane data */
  2654.       pl = 0U;
  2655.  
  2656.       /* Set up plane ptrs */
  2657.       while( pl < depth )
  2658.       {
  2659.         bm -> Planes[ pl ] = plane;
  2660.  
  2661.         plane = ALIGN_QUADLONG( (PLANEPTR)(((UBYTE *)plane) + planesize) );
  2662.         pl++;
  2663.       }
  2664.  
  2665.       /* Clear the remaining plane ptrs (up to 8 planes) */
  2666.       while( pl < 8U )
  2667.       {
  2668.         bm -> Planes[ pl ] = NULL;
  2669.  
  2670.         pl++;
  2671.       }
  2672.     }
  2673.  
  2674.     return( bm );
  2675. }
  2676.  
  2677.  
  2678. static
  2679. BOOL CMAP2Object( struct ClassBase *cb, Object *o, UBYTE *rgb, ULONG rgbsize )
  2680. {
  2681.     struct ColorRegister *acm;
  2682.     ULONG                *acregs;
  2683.     ULONG                 nc;
  2684.  
  2685.     /* file has this many colors (e.g. each color has one byte per R,B,G-gun) */
  2686.     nc = rgbsize / 3UL;
  2687.  
  2688.     SetDTAttrs( o, NULL, NULL, ADTA_NumColors, nc, TAG_DONE );
  2689.  
  2690.     /* Get color context */
  2691.     if( GetDTAttrs( o,
  2692.                     ADTA_ColorRegisters, (&acm),
  2693.                     ADTA_CRegs,          (&acregs),
  2694.                     ADTA_NumColors,      (&nc),
  2695.                     TAG_DONE ) == 3UL )
  2696.     {
  2697.       /* All valid ? */
  2698.       if( acm && acregs && nc )
  2699.       {
  2700.         ULONG i;
  2701.  
  2702.         for( i = 0UL ; i < nc ; i++, acm++ )
  2703.         {
  2704.           acm -> red   =  *rgb++;
  2705.           acm -> green =  *rgb++;
  2706.           acm -> blue  =  *rgb++;
  2707.  
  2708.           /* Replicate the color information.
  2709.            * This surrounds an OS bug which uses the low-oreder bytes of the 32-bit colors
  2710.            * instead of the high order ones
  2711.            */
  2712.           acregs[ ((i * 3) + 0) ] = ((ULONG)(acm -> red))   * 0x01010101UL;
  2713.           acregs[ ((i * 3) + 1) ] = ((ULONG)(acm -> green)) * 0x01010101UL;
  2714.           acregs[ ((i * 3) + 2) ] = ((ULONG)(acm -> blue))  * 0x01010101UL;
  2715.         }
  2716.  
  2717.         return( TRUE );
  2718.       }
  2719.     }
  2720.  
  2721.     return( FALSE );
  2722. }
  2723.  
  2724.  
  2725. static
  2726. struct ColorMap *CMAP2ColorMap( struct ClassBase *cb, struct AnimInstData *aid, UBYTE *rgb, ULONG rgbsize )
  2727. {
  2728.     struct ColorMap *cm;
  2729.     ULONG            a_nc   = (1UL << (ULONG)(aid -> aid_BMH -> bmh_Depth)); /* Number of colors in animation */
  2730.     ULONG            rgb_nc = rgbsize / 3UL;                                 /* Number of colors in CMAP      */
  2731.  
  2732.     /* Get a colormap which hold all colors */
  2733.     if( cm = GetColorMap( (long)MAX( a_nc, rgb_nc ) ) )
  2734.     {
  2735.       ULONG i,
  2736.             r, g, b;
  2737.  
  2738.       for( i = 0UL ; i < rgb_nc ; i++ )
  2739.       {
  2740.         r = *rgb++;
  2741.         g = *rgb++;
  2742.         b = *rgb++;
  2743.  
  2744.         /* Replicate color information (see CMAP2Object for details) and store them into colormap */
  2745.         SetRGB32CM( cm, i, (r * 0x01010101UL), (g * 0x01010101UL), (b * 0x01010101UL) );
  2746.       }
  2747.  
  2748.       /* BUG: the remaining entries should be filled with colors from the last colormap */
  2749.       for( ; i < a_nc ; i++ )
  2750.       {
  2751.         SetRGB32CM( cm, i, 0UL, 0UL, 0UL ); /* fill remaining entries with black */
  2752.       }
  2753.     }
  2754.  
  2755.     return( cm );
  2756. }
  2757.  
  2758.  
  2759. static
  2760. struct ColorMap *CopyColorMap( struct ClassBase *cb, struct ColorMap *src )
  2761. {
  2762.     struct ColorMap *dest = NULL;
  2763.  
  2764.     if( src )
  2765.     {
  2766.       ULONG *ctable;
  2767.  
  2768.       if( ctable = (ULONG *)AllocVec( ((ULONG)(src -> Count) * sizeof( ULONG ) * 3UL), MEMF_PUBLIC ) )
  2769.       {
  2770.         if( dest = GetColorMap( (long)(src -> Count) ) )
  2771.         {
  2772.           ULONG i;
  2773.  
  2774.           GetRGB32( src, 0UL, (ULONG)(src -> Count), ctable );
  2775.  
  2776.           for( i = 0UL ; i < (src -> Count) ; i++ )
  2777.           {
  2778.             SetRGB32CM( dest, i, ctable[ ((i * 3) + 0) ], ctable[ ((i * 3) + 1) ], ctable[ ((i * 3) + 2) ] );
  2779.           }
  2780.         }
  2781.  
  2782.         FreeVec( ctable );
  2783.       }
  2784.     }
  2785.  
  2786.     return( dest );
  2787. }
  2788.  
  2789.  
  2790. /*****************************************************************************/
  2791.  
  2792. #define DEBUG_POOLS 1
  2793.  
  2794. #ifndef DEBUG_POOLS
  2795. static
  2796. APTR AllocVecPooled( struct ClassBase *cb, APTR pool, ULONG memsize )
  2797. {
  2798.     ULONG *memory = NULL;
  2799.  
  2800.     if( pool && memsize )
  2801.     {
  2802.       memsize += (ULONG)sizeof( ULONG );
  2803.  
  2804.       if( memory = (ULONG *)AllocPooled( pool, memsize ) )
  2805.       {
  2806.         (*memory) = memsize;
  2807.  
  2808.         memory++;
  2809.       }
  2810.     }
  2811.  
  2812.     return( (APTR)memory );
  2813. }
  2814.  
  2815.  
  2816. static
  2817. void FreeVecPooled( struct ClassBase *cb, APTR pool, APTR mem )
  2818. {
  2819.     if( pool && mem )
  2820.     {
  2821.       ULONG *memory;
  2822.  
  2823.       memory = (ULONG *)mem;
  2824.  
  2825.       memory--;
  2826.  
  2827.       FreePooled( pool, memory, (*memory) );
  2828.     }
  2829. }
  2830. #else
  2831. #define MY_MAGIC_MEMID (0xD0ADEAD0UL)
  2832.  
  2833. static
  2834. APTR AllocVecPooled( struct ClassBase *cb, APTR pool, ULONG memsize )
  2835. {
  2836.     ULONG *memory = NULL;
  2837.  
  2838.     if( pool && memsize )
  2839.     {
  2840.       memsize += (ULONG)sizeof( ULONG );
  2841.       memsize += (ULONG)sizeof( APTR );
  2842.  
  2843.       if( memory = (ULONG *)AllocPooled( pool, memsize ) )
  2844.       {
  2845.         (*memory) = memsize;
  2846.         memory++;
  2847.  
  2848.         (*memory) = (ULONG)pool;
  2849.         memory++;
  2850.  
  2851.         (*memory) = MY_MAGIC_MEMID;
  2852.         memory++;
  2853.       }
  2854.     }
  2855.  
  2856.     return( (APTR)memory );
  2857. }
  2858.  
  2859.  
  2860. static
  2861. void FreeVecPooled( struct ClassBase *cb, APTR pool, APTR mem )
  2862. {
  2863.     if( pool && mem )
  2864.     {
  2865.       ULONG *memory;
  2866.  
  2867.       memory = (ULONG *)mem;
  2868.  
  2869.       memory--;
  2870.  
  2871.       if( *memory != MY_MAGIC_MEMID )
  2872.       {
  2873.         D( kprintf( "wrong mem id\n" ) );
  2874.         return;
  2875.       }
  2876.  
  2877.       memory--;
  2878.  
  2879.       if( *memory != (ULONG)pool )
  2880.       {
  2881.         D( kprintf( "wrong pool %lx %lx\n", pool, *memory ) );
  2882.         return;
  2883.       }
  2884.  
  2885.       memory--;
  2886.  
  2887.       FreePooled( pool, memory, (*memory) );
  2888.     }
  2889. }
  2890. #endif /* DEBUG_POOLS */
  2891.  
  2892.  
  2893. static
  2894. LONG DrawDLTA( struct ClassBase *cb, struct AnimInstData *aid, struct BitMap *prevbm, struct BitMap *bm, struct AnimHeader *ah, UBYTE *dlta, ULONG dltasize )
  2895. {
  2896.     LONG error = 0L;
  2897.  
  2898.     if( bm && ah && dlta && dltasize )
  2899.     {
  2900.       struct BitMap       *unpackbm = bm,
  2901.                           *tempbm   = NULL;
  2902.       struct BitMapHeader *bmh      = aid -> aid_BMH;
  2903.       BOOL                 DoXOR;
  2904.  
  2905.       /* Handle acmpILBM, acmpXORILBM and acmpAnimJ explicitly */
  2906.       switch( ah -> ah_Operation )
  2907.       {
  2908.         case acmpILBM:    /*  0  */
  2909.         {
  2910.             /* unpack ILBM BODY */
  2911.             return( LoadILBMBody( cb, unpackbm, bmh, dlta, dltasize ) );
  2912.         }
  2913.  
  2914.         case acmpXORILBM: /*  1  */
  2915.         {
  2916.             error_printf( cb, aid, "\adlta: acmpXORILBM disabled, call author immediately\n" );
  2917.             return( ERROR_NOT_IMPLEMENTED );
  2918.         }
  2919.  
  2920.         case acmpAnimJ:   /* 'J' */
  2921.         {
  2922.             /* unpack ANIM-J  */
  2923.             return( unpackanimjdelta( cb, dlta, dltasize, prevbm, bm ) );
  2924.         }
  2925.       }
  2926.  
  2927.       /* XOR ? */
  2928.       DoXOR = ((ah -> ah_Flags) & ahfXOR);
  2929.  
  2930.       if( !DoXOR )
  2931.       {
  2932.         if( (aid -> aid_NoDPaintBrushPatch) == FALSE )
  2933.         {
  2934.           /* DPaint anim brush (compatibility hack) */
  2935.           if( ((ah -> ah_Operation) == acmpByteDelta) && ((ah -> ah_Interleave) == 1U) )
  2936.           {
  2937.             DoXOR = TRUE;
  2938.           }
  2939.         }
  2940.       }
  2941.  
  2942.       /* Prepare XOR (see below) */
  2943.       if( DoXOR && prevbm )
  2944.       {
  2945.         if( prevbm == bm )
  2946.         {
  2947.           if( !(tempbm = AllocBitMapPooled( cb, (ULONG)(aid -> aid_BMH -> bmh_Width), (ULONG)(aid -> aid_BMH -> bmh_Height), (ULONG)(aid -> aid_BMH -> bmh_Depth), (aid -> aid_FramePool) )) )
  2948.           {
  2949.             return( ERROR_NO_FREE_STORE );
  2950.           }
  2951.  
  2952.           unpackbm = prevbm = tempbm;
  2953.         }
  2954.  
  2955.         ClearBitMap( unpackbm );
  2956.       }
  2957.       else
  2958.       {
  2959.         if( prevbm )
  2960.         {
  2961.           if( prevbm != bm )
  2962.           {
  2963.             CopyBitMap( cb, prevbm, bm );
  2964.           }
  2965.         }
  2966.         else
  2967.         {
  2968.           ClearBitMap( bm );
  2969.         }
  2970.       }
  2971.  
  2972.       /* dispatch compression type, second attempt */
  2973.       switch( ah -> ah_Operation )
  2974.       {
  2975.         /* acmpILBM, acmpXORILBM and acmpAnimJ have been processed above */
  2976.  
  2977.         case acmpLongDelta:         /* 2 */
  2978.         {
  2979.             error = unpacklongdelta( unpackbm, dlta, dltasize );
  2980.         }
  2981.             break;
  2982.  
  2983.         case acmpShortDelta:        /* 3 */
  2984.         {
  2985.             error = unpackshortdelta( unpackbm, dlta, dltasize );
  2986.         }
  2987.             break;
  2988.  
  2989.         case acmpDelta:             /*  4 */
  2990.         {
  2991. #ifdef COMMENTED_OUT
  2992.             if( (ah -> ah_Flags) & ahfLongData )
  2993.             {
  2994.               error = unpackanim4longdelta( unpackbm, dlta, dltasize, (ah -> ah_Flags) );
  2995.             }
  2996.             else
  2997.             {
  2998.               error = unpackanim4worddelta( unpackbm, dlta, dltasize, (ah -> ah_Flags) );
  2999.             }
  3000. #else
  3001.             error_printf( cb, aid, "\adlta: acmpDelta disabled, call author (gisburn@w-specht.rhein-ruhr.de)\n"
  3002.                                    "immediately. If you are this FIRST user who send me a VALID IFF ANIM-4 compressed animation\n"
  3003.                                    "you'll get $10 US-Dollar !!\n THIS IS NO JOKE !!\n" );
  3004.             error = ERROR_NOT_IMPLEMENTED;
  3005. #endif /* COMMENTED_OUT */
  3006.         }
  3007.             break;
  3008.  
  3009.         case acmpByteDelta:         /* 5 */
  3010.         case acmpStereoByteDelta:   /* 6 */
  3011.         {
  3012.             error = unpackbytedelta( unpackbm, dlta, dltasize );
  3013.         }
  3014.             break;
  3015.  
  3016.         case acmpAnim7:             /* 7 */
  3017.         {
  3018.             if( (ah -> ah_Flags) & ahfLongData )
  3019.             {
  3020.               error = unpackanim7longdelta( unpackbm, dlta, dltasize );
  3021.             }
  3022.             else
  3023.             {
  3024.               error = unpackanim7worddelta( unpackbm, dlta, dltasize );
  3025.             }
  3026.         }
  3027.             break;
  3028.  
  3029.         case acmpAnim8:             /* 8 */
  3030.         {
  3031.             if( (ah -> ah_Flags) & ahfLongData )
  3032.             {
  3033.               error = unpackanim8longdelta( unpackbm, dlta, dltasize );
  3034.             }
  3035.             else
  3036.             {
  3037.               error = unpackanim8worddelta( unpackbm, dlta, dltasize );
  3038.             }
  3039.         }
  3040.             break;
  3041.  
  3042.         default:                    /* 'l' */
  3043.         {
  3044.             error_printf( cb, aid, "\adlta: anim compression %ld not implemented yet\n", (long)(ah -> ah_Operation) );
  3045.             error = ERROR_NOT_IMPLEMENTED;
  3046.         }
  3047.             break;
  3048.       }
  3049.  
  3050.       /* Handle XOR (see above) */
  3051.       if( DoXOR && prevbm )
  3052.       {
  3053.         XORBitMaps( bm, prevbm );
  3054.       }
  3055.  
  3056.       if( tempbm )
  3057.       {
  3058.         FreeVecPooled( cb, (aid -> aid_FramePool), tempbm );
  3059.       }
  3060.     }
  3061.  
  3062.     return( error );
  3063. }
  3064.  
  3065.  
  3066. static
  3067. void DumpAnimHeader( struct ClassBase *cb, struct AnimInstData *aid, ULONG ti, struct AnimHeader *anhd )
  3068. {
  3069.     if( anhd )
  3070.     {
  3071.       verbose_printf( cb, aid, "%4lu: ", ti );
  3072.  
  3073.       switch( anhd -> ah_Operation )
  3074.       {
  3075.         case acmpILBM:              verbose_printf( cb, aid, "Operation ILBM" );                  break;
  3076.         case acmpXORILBM:           verbose_printf( cb, aid, "Operation XORILBM" );               break;
  3077.         case acmpLongDelta:         verbose_printf( cb, aid, "Operation LongDelta" );             break;
  3078.         case acmpShortDelta:        verbose_printf( cb, aid, "Operation ShortDelta" );            break;
  3079.         case acmpDelta:             verbose_printf( cb, aid, "Operation Delta" );                 break;
  3080.         case acmpByteDelta:         verbose_printf( cb, aid, "Operation ByteDelta" );             break;
  3081.         case acmpStereoByteDelta:   verbose_printf( cb, aid, "Operation StereoByteDelta" );       break;
  3082.         case acmpAnim7:             verbose_printf( cb, aid, "Operation Anim7" );                 break;
  3083.         case acmpAnim8:             verbose_printf( cb, aid, "Operation Anim8" );                 break;
  3084.         case acmpAnimJ:             verbose_printf( cb, aid, "Operation AnimJ" );                 break;
  3085.         default:                    verbose_printf( cb, aid, "Operation <unknown compression>" ); break;
  3086.       }
  3087.  
  3088.       verbose_printf( cb, aid, " AbsTime %3lu RelTime %3lu Interleave %3lu", (anhd -> ah_AbsTime), (anhd -> ah_RelTime), (ULONG)(anhd -> ah_Interleave) );
  3089.  
  3090.       if( (anhd -> ah_Flags) & ahfLongData          ) verbose_printf( cb, aid, " LongData"          );
  3091.       if( (anhd -> ah_Flags) & ahfXOR               ) verbose_printf( cb, aid, " XOR"               );
  3092.       if( (anhd -> ah_Flags) & ahfOneInfoList       ) verbose_printf( cb, aid, " OneInfoList"       );
  3093.       if( (anhd -> ah_Flags) & ahfRLC               ) verbose_printf( cb, aid, " RLC"               );
  3094.       if( (anhd -> ah_Flags) & ahfVertical          ) verbose_printf( cb, aid, " Vertical"          );
  3095.       if( (anhd -> ah_Flags) & ahfLongInfoOffsets   ) verbose_printf( cb, aid, " LongInfoOffsets"   );
  3096.  
  3097.       verbose_printf( cb, aid, "\n" );
  3098.  
  3099.       if( (aid -> aid_NoDPaintBrushPatch) == FALSE )
  3100.       {
  3101.         /* DPaint anim brush (compatibility hack) */
  3102.         if( (anhd -> ah_Operation == acmpByteDelta) && ((anhd -> ah_Interleave) == 1U) && (!((anhd -> ah_Flags) & ahfXOR)) )
  3103.         {
  3104.           verbose_printf( cb, aid, "Assuming XOR mode for this frame (DPaint brush patch, see docs)\n" );
  3105.         }
  3106.       }
  3107.     }
  3108. }
  3109.  
  3110.  
  3111. static
  3112. struct FrameNode *GetPrevFrameNode( struct FrameNode *currfn, ULONG interleave )
  3113. {
  3114.     struct FrameNode *worknode,
  3115.                      *prevnode;
  3116.  
  3117.     /* Get previous frame */
  3118.     worknode = currfn;
  3119.  
  3120.     while( prevnode = (struct FrameNode *)(worknode -> fn_Node . mln_Pred) )
  3121.     {
  3122.       if( (interleave-- == 0U) || ((prevnode -> fn_Node . mln_Pred) == NULL) )
  3123.       {
  3124.         break;
  3125.       }
  3126.  
  3127.       worknode = prevnode;
  3128.     }
  3129.  
  3130.     return( worknode );
  3131. }
  3132.  
  3133.  
  3134. static
  3135. void OpenLogfile( struct ClassBase *cb, struct AnimInstData *aid )
  3136. {
  3137.     if( (aid -> aid_VerboseOutput) == NULL )
  3138.     {
  3139.       STRPTR confile;
  3140.  
  3141.       if( confile = (STRPTR)AllocVec( (((aid -> aid_ProjectName)?(strlen( (aid -> aid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  3142.       {
  3143.         mysprintf( cb, confile, "CON:////Anim DataType %s/auto/wait/close/inactive",
  3144.                    ((aid -> aid_ProjectName)?(FilePart( (aid -> aid_ProjectName) )):(NULL)) );
  3145.  
  3146.         aid -> aid_VerboseOutput = Open( confile, MODE_READWRITE );
  3147.  
  3148.         FreeVec( confile );
  3149.       }
  3150.     }
  3151. }
  3152.  
  3153.  
  3154. static
  3155. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  3156. {
  3157.     APTR args;
  3158.  
  3159.     args = (APTR)((&fmt) + 1);
  3160.  
  3161.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  3162. }
  3163.  
  3164.  
  3165. static
  3166. void error_printf( struct ClassBase *cb, struct AnimInstData *aid, STRPTR format, ... )
  3167. {
  3168.     OpenLogfile( cb, aid );
  3169.  
  3170.     if( aid -> aid_VerboseOutput )
  3171.     {
  3172.       VFPrintf( (aid -> aid_VerboseOutput), format, (APTR)((&format) + 1) );
  3173.     }
  3174. }
  3175.  
  3176.  
  3177. static
  3178. void verbose_printf( struct ClassBase *cb, struct AnimInstData *aid, STRPTR format, ... )
  3179. {
  3180.     if( aid -> aid_VerboseOutput )
  3181.     {
  3182.       VFPrintf( (aid -> aid_VerboseOutput), format, (APTR)((&format) + 1) );
  3183.     }
  3184. }
  3185.  
  3186.  
  3187. static
  3188. void AttachSample( struct ClassBase *cb, struct AnimInstData *aid )
  3189. {
  3190.     if( aid -> aid_Sample )
  3191.     {
  3192.       struct FrameNode *worknode,
  3193.                        *nextnode;
  3194.  
  3195.       ULONG             period          = aid -> aid_Period;
  3196.       ULONG             samplesperframe;
  3197.       BYTE             *sample          = aid -> aid_Sample;
  3198.  
  3199.       samplesperframe = (((SysBase -> ex_EClockFrequency) * 10UL) / (period * (aid -> aid_FPS) * 2UL));
  3200.  
  3201.       if( aid -> aid_SamplesPerFrame )
  3202.       {
  3203.         period = (period * samplesperframe) / (aid -> aid_SamplesPerFrame);
  3204.  
  3205.         samplesperframe = aid -> aid_SamplesPerFrame;
  3206.  
  3207.         verbose_printf( cb, aid, "period corrected from %lu to %lu to match spf=%lu with fps=%lu\n",
  3208.                         (aid -> aid_Period), period, samplesperframe, (aid -> aid_FPS) );
  3209.       }
  3210.  
  3211.       verbose_printf( cb, aid, "Attching samples (sysclock %lu period %lu fps %lu length %lu samplesperframe %lu)...\n",
  3212.                       (SysBase -> ex_EClockFrequency), period, (aid -> aid_FPS), (aid -> aid_SampleLength), samplesperframe );
  3213.  
  3214.       worknode = (struct FrameNode *)(aid -> aid_FrameList . mlh_Head);
  3215.  
  3216.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  3217.       {
  3218.         worknode -> fn_Sample       = sample;
  3219.         worknode -> fn_SampleLength = samplesperframe * ((worknode -> fn_Duration) + 1UL);
  3220.         worknode -> fn_Period       = period;
  3221.  
  3222.         sample += (samplesperframe * ((worknode -> fn_Duration) + 1UL));
  3223.  
  3224.         /* End of sample reached ? */
  3225.         if( (ULONG)(sample - (aid -> aid_Sample)) > (aid -> aid_SampleLength) )
  3226.         {
  3227.           /* Cut last size of sample to fit */
  3228.           worknode -> fn_SampleLength -= (ULONG)(sample - (aid -> aid_Sample));
  3229.  
  3230.           break;
  3231.         }
  3232.  
  3233.         worknode = nextnode;
  3234.       }
  3235.     }
  3236. }
  3237.  
  3238.  
  3239. static
  3240. ULONG SaveIFFAnim( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  3241. {
  3242.     ULONG retval = 0UL;
  3243.     LONG  error  = 0L;
  3244.  
  3245.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  3246.     if( dtw -> dtw_FileHandle )
  3247.     {
  3248.       struct AnimInstData *aid = (struct AnimInstData *)INST_DATA( cl, o );
  3249.  
  3250.       struct BitMapHeader *bmh;
  3251.       ULONG                modeid;
  3252.       ULONG               *cregs;
  3253.       ULONG                numcolors;
  3254.       ULONG                startframe = 0UL,
  3255.                            numframes  = 0UL,
  3256.                            framestep  = 1UL;
  3257.       ULONG                fps = 0UL;
  3258.       struct BitMap       *keyframe;
  3259.       ULONG                animwidth,
  3260.                            animheight,
  3261.                            animdepth;
  3262.  
  3263.       if( GetDTAttrs( o, ADTA_BitMapHeader,     (&bmh),
  3264.                          ADTA_ModeID,           (&modeid),
  3265.                          ADTA_CRegs,            (&cregs),
  3266.                          ADTA_NumColors,        (&numcolors),
  3267.                          ADTA_Width,            (&animwidth),
  3268.                          ADTA_Height,           (&animheight),
  3269.                          ADTA_Depth,            (&animdepth),
  3270.                          ADTA_Frame,            (&startframe),
  3271.                          ADTA_Frames,           (&numframes),
  3272.                          ADTA_FramesPerSecond,  (&fps),
  3273.                          ADTA_KeyFrame,         (&keyframe),
  3274.                          TAG_DONE ) == 11UL )
  3275.       {
  3276.         struct TagItem     *tstate,
  3277.                            *ti;
  3278.         struct AnimContext *ac;
  3279.         struct IFFHandle   *iff;
  3280.         struct BitMapHeader xbmh   = *bmh;
  3281.         BOOL                planar       = MAKEBOOL( GetBitMapAttr( keyframe, BMA_FLAGS ) & BMF_STANDARD );
  3282.         BOOL                interleaved  = MAKEBOOL( GetBitMapAttr( keyframe, BMA_FLAGS ) & BMF_INTERLEAVED );
  3283.  
  3284.         if( planar && (!interleaved) )
  3285.         {
  3286.           xbmh . bmh_Compression = cmpNone; /* Currently we only write an uncompressed key frame */
  3287.  
  3288.           numframes -= startframe;
  3289.  
  3290.           tstate = dtw -> dtw_AttrList;
  3291.  
  3292.           while( ti = NextTagItem( (&tstate) ) )
  3293.           {
  3294.             switch( ti -> ti_Tag )
  3295.             {
  3296.               case ADTA_Frame:            startframe = ti -> ti_Data; break;
  3297.               case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  3298.               case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  3299.             }
  3300.           }
  3301.  
  3302.           if( framestep == 0UL ) framestep = 1UL;
  3303.  
  3304.           verbose_printf( cb, aid, "saving iff anim %lu %lu %lu\n", startframe, numframes, framestep );
  3305.  
  3306.           if( numframes )
  3307.           {
  3308.             if( ac = CreateAnimContext( cb, animwidth, animheight, animdepth ) )
  3309.             {
  3310.               if( iff = CreateDOSIFFHandle( cb, (dtw -> dtw_FileHandle) ) )
  3311.               {
  3312.                 if( !(error = StartIFFAnim3( cb, aid, iff, ac, (&xbmh), modeid, cregs, numcolors, numframes, fps, keyframe )) )
  3313.                 {
  3314.                   struct adtFrame  alf;
  3315.                   ULONG            timestamp,
  3316.                                   *cmap_cregs = NULL;
  3317.  
  3318.                   /* Start scan through animation */
  3319.                   for( timestamp = startframe ; numframes > 0UL ; timestamp += framestep, numframes-- )
  3320.                   {
  3321.                     /* On error break */
  3322.                     if( error )
  3323.                     {
  3324.                       break;
  3325.                     }
  3326.  
  3327.                     /* Check for CTRL_D signal... */
  3328.                     if( SetSignal( 0UL, 0UL ) & SIGBREAKF_CTRL_D )
  3329.                     {
  3330.                       error = ERROR_BREAK;
  3331.  
  3332.                       break;
  3333.                     }
  3334.  
  3335.                     /* reset method msg */
  3336.                     memset( (void *)(&alf), 0, sizeof( struct adtFrame ) );
  3337.  
  3338.                     /* load frame */
  3339.                     alf . MethodID = ADTM_LOADFRAME;
  3340.                     alf . alf_TimeStamp = timestamp;
  3341.                     alf . alf_Frame     = timestamp;
  3342.  
  3343.                     if( DoMethodA( o, (Msg)(&alf) ) == 0UL )
  3344.                     {
  3345.                       error = IoErr();
  3346.  
  3347.                       if( error != ERROR_OBJECT_NOT_FOUND )
  3348.                       {
  3349.                         break;
  3350.                       }
  3351.                     }
  3352.                     else
  3353.                     {
  3354.                       /* print frame contents */
  3355.                       verbose_printf( cb, aid, "frame: timestamp %lu frame %lu duration %lu bitmap %lx cmap %lx sample %lx len %lu period %lu\n",
  3356.                               timestamp,
  3357.                               (alf . alf_Frame),
  3358.                               (alf . alf_Duration),
  3359.                               (alf . alf_BitMap),
  3360.                               (alf . alf_CMap),
  3361.                               (alf . alf_Sample),
  3362.                               (alf . alf_SampleLength),
  3363.                               (alf . alf_Period) );
  3364.  
  3365.                       if( alf . alf_CMap )
  3366.                       {
  3367.                         if( cmap_cregs = (ULONG *)AllocVec( (((sizeof( ULONG ) * 3UL) + 1UL) * numcolors), MEMF_PUBLIC ) )
  3368.                         {
  3369.                           GetRGB32( (alf . alf_CMap), 0UL, numcolors, cmap_cregs );
  3370.                         }
  3371.                         else
  3372.                         {
  3373.                           error_printf( cb, aid, "can't alloc dynamic palette buffer\n" );
  3374.                           error = ERROR_NO_FREE_STORE;
  3375.                         }
  3376.                       }
  3377.  
  3378.                       if( alf . alf_BitMap )
  3379.                       {
  3380.                         if( error = WriteIFFAnim3( cb, iff, ac, ((timestamp * 60UL) / fps), (60UL / fps), (&xbmh), cmap_cregs, numcolors, (alf . alf_BitMap) ) )
  3381.                         {
  3382.                           error_printf( cb, aid, "error while writing IFF ANIM-3, aborted\n" );
  3383.                         }
  3384.                       }
  3385.  
  3386.                       if( cmap_cregs )
  3387.                       {
  3388.                         FreeVec( cmap_cregs );
  3389.                         cmap_cregs = NULL;
  3390.                       }
  3391.                     }
  3392.  
  3393.                     alf . MethodID = ADTM_UNLOADFRAME;
  3394.                     DoMethodA( o, (Msg)(&alf) );
  3395.                   }
  3396.  
  3397.                   EndIFFAnim3( cb, aid, iff );
  3398.  
  3399.                   if( error == 0L )
  3400.                   {
  3401.                     retval = 1UL; /* success ! */
  3402.                   }
  3403.                 }
  3404.  
  3405.                 FreeIFF( iff );
  3406.               }
  3407.               else
  3408.               {
  3409.                 error = IoErr();
  3410.               }
  3411.  
  3412.               DeleteAnimContext( cb, ac );
  3413.             }
  3414.             else
  3415.             {
  3416.               /* Can't alloc animcontext */
  3417.               error = ERROR_NO_FREE_STORE;
  3418.             }
  3419.           }
  3420.         }  
  3421.         else
  3422.         {
  3423.           /* Does not support non-planar or planar interleaved bitmaps */
  3424.           error = ERROR_NOT_IMPLEMENTED;
  3425.         }
  3426.       }
  3427.       else
  3428.       {
  3429.         error_printf( cb, aid, "not enougth attributes\n" );
  3430.       }
  3431.     }
  3432.  
  3433.     /* Error codes below 0 are related to the IFFParse.library functions */
  3434.     if( error < 0L )
  3435.     {
  3436.       /* convert IFFParse error to DOS error */
  3437.       error = ifferr2doserr[ (-error - 1) ];
  3438.     }
  3439.  
  3440.     SetIoErr( error );
  3441.  
  3442.     return( retval );
  3443. }
  3444.  
  3445.  
  3446. static
  3447. struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *cb, BPTR fh )
  3448. {
  3449.     struct IFFHandle *iff;
  3450.  
  3451.     if( iff = AllocIFF() )
  3452.     {
  3453.       iff -> iff_Stream = (ULONG)fh;
  3454.  
  3455.       InitIFFasDOS( iff );
  3456.     }
  3457.  
  3458.     return( iff );
  3459. }
  3460.  
  3461.  
  3462. static
  3463. LONG StartIFFAnim3( struct ClassBase *cb, struct AnimInstData *aid, struct IFFHandle *iff, struct AnimContext *ac, struct BitMapHeader *bmh, ULONG modeid, ULONG *cregs, ULONG numcolors, ULONG numframes, ULONG fps, struct BitMap *bm )
  3464. {
  3465.     LONG error;
  3466.  
  3467.     if( !(error = OpenIFF( iff, IFFF_WRITE )) )
  3468.     {
  3469.       for( ;; ) /* not a loop, used as a jump table */
  3470.       {
  3471.         if( error = PushChunk( iff, ID_ANIM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3472.           break;
  3473.  
  3474.         /* write initial FORM ILBM */
  3475.         {
  3476.           if( error = PushChunk( iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3477.             break;
  3478.  
  3479.           /* write ILBM BMHD (BitMapHeader) */
  3480.           {
  3481.             if( error = PushChunk( iff, 0UL, ID_BMHD, IFFSIZE_UNKNOWN ) )
  3482.               break;
  3483.  
  3484.             if( WriteChunkBytes( iff, (APTR)bmh, sizeof( struct BitMapHeader ) ) != sizeof( struct BitMapHeader ) )
  3485.             {
  3486.               error = IFFERR_WRITE;
  3487.               break;
  3488.             }
  3489.  
  3490.             if( error = PopChunk( iff ) )
  3491.               break;
  3492.           }
  3493.  
  3494.           /* write ILBM CMAP (global color map) */
  3495.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  3496.             break;
  3497.  
  3498.           /* write ILBM DPAN chunk */
  3499.           {
  3500.             struct DPAnimChunk dpan;
  3501.  
  3502.             dpan . dpan_Version = 0U; /* ??? */
  3503.             dpan . dpan_nframes = numframes;
  3504.             dpan . dpan_FPS     = fps;
  3505.  
  3506.             if( error = PushChunk( iff, 0UL, ID_DPAN, IFFSIZE_UNKNOWN ) )
  3507.               break;
  3508.  
  3509.             if( WriteChunkBytes( iff, (APTR)(&dpan), sizeof( struct DPAnimChunk ) ) != sizeof( struct DPAnimChunk ) )
  3510.             {
  3511.               error = IFFERR_WRITE;
  3512.               break;
  3513.             }
  3514.  
  3515.             if( error = PopChunk( iff ) )
  3516.               break;
  3517.           }
  3518.  
  3519.           /* write ILBM CAMG (amiga view mode) */
  3520.           {
  3521.             if( error = PushChunk( iff, 0UL, ID_CAMG, IFFSIZE_UNKNOWN ) )
  3522.               break;
  3523.  
  3524.             if( WriteChunkBytes( iff, (APTR)(&modeid), sizeof( ULONG ) ) != sizeof( ULONG ) )
  3525.             {
  3526.               error = IFFERR_WRITE;
  3527.               break;
  3528.             }
  3529.  
  3530.             if( error = PopChunk( iff ) )
  3531.               break;
  3532.           }
  3533.  
  3534.           /* Write ILBM BODY (if there is one...) */
  3535.           if( bm )
  3536.           {
  3537.             if( error = PutILBMBody( cb, iff, bm, bmh ) )
  3538.               break;
  3539.  
  3540.             /* Copy current bitmap into both buffers */
  3541.             CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3542.             SwapFrames( cb, ac );
  3543.             CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3544.           }
  3545.  
  3546.           if( error = PopChunk( iff ) )
  3547.             break;
  3548.         }
  3549.  
  3550.         break; /* end of jump table */
  3551.       }
  3552.  
  3553.       /* All headers written successfully ? */
  3554.       if( error == 0L )
  3555.       {
  3556.         /* Success ! */
  3557.         return( 0L );
  3558.       }
  3559.  
  3560.       CloseIFF( iff );
  3561.     }
  3562.  
  3563.     return( error );
  3564. }
  3565.  
  3566.  
  3567. static
  3568. void EndIFFAnim3( struct ClassBase *cb, struct AnimInstData *aid, struct IFFHandle *iff )
  3569. {
  3570.     if( iff )
  3571.     {
  3572.       LONG error;
  3573.  
  3574.       if( error = PopChunk( iff ) )
  3575.       {
  3576.         error_printf( cb, aid, "error while popping IFF ANIM-3 FORM %ld\n", error );
  3577.       }
  3578.  
  3579.       CloseIFF( iff );
  3580.  
  3581.       verbose_printf( cb, aid, "IFF ANIM-3 sucessfully created\n" );
  3582.     }
  3583. }
  3584.  
  3585.  
  3586. static
  3587. LONG WriteIFFAnim3( struct ClassBase *cb, struct IFFHandle *iff, struct AnimContext *ac, ULONG abstime, ULONG reltime, struct BitMapHeader *bmh, ULONG *cregs, ULONG numcolors, struct BitMap *bm )
  3588. {
  3589.     LONG error = 0L;
  3590.  
  3591.     for( ;; ) /* not a loop, used as a jump-table */
  3592.     {
  3593.       /* write FORM ILBM */
  3594.       {
  3595.         if( error = PushChunk( iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN ) )
  3596.           break;
  3597.  
  3598.         /* write ILBM ANHD (AnimHeader) */
  3599.         {
  3600.           struct AnimHeader animheader = { 0 };
  3601.  
  3602.           animheader . ah_Operation  = acmpShortDelta;
  3603.           animheader . ah_AbsTime    = abstime;
  3604.           animheader . ah_RelTime    = reltime;
  3605.           animheader . ah_Interleave = 2U;
  3606.  
  3607.           if( error = PushChunk( iff, 0UL, ID_ANHD, IFFSIZE_UNKNOWN ) )
  3608.             break;
  3609.  
  3610.           if( WriteChunkBytes( iff, (APTR)(&animheader), sizeof( struct AnimHeader ) ) != sizeof( struct AnimHeader ) )
  3611.           {
  3612.             error = IFFERR_WRITE;
  3613.             break;
  3614.           }
  3615.  
  3616.           if( error = PopChunk( iff ) )
  3617.             break;
  3618.         }
  3619.  
  3620.         /* Palette change ? */
  3621.         if( cregs && numcolors )
  3622.         {
  3623.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  3624.             break;
  3625.         }
  3626.  
  3627.         /* Write ANIM-3 delta */
  3628.         if( error = PutAnim3Delta( cb, iff, ac, CurrFrame( cb, ac ), bm ) )
  3629.           break;
  3630.  
  3631.         /* Copy current bitmap into buffer, then swap to next frame */
  3632.         CopyBitMap( cb, bm, CurrFrame( cb, ac ) );
  3633.         SwapFrames( cb, ac );
  3634.  
  3635.         if( error = PopChunk( iff ) )
  3636.           break;
  3637.       }
  3638.  
  3639.       break; /* end of jump-table */
  3640.     }
  3641.  
  3642.     return( error );
  3643. }
  3644.  
  3645.  
  3646. static
  3647. LONG PutAnim3Delta( struct ClassBase *cb, struct IFFHandle *iff, struct AnimContext *ac, struct BitMap *prevbm, struct BitMap *bm )
  3648. {
  3649.     LONG    error;
  3650.     ULONG   len;
  3651.  
  3652.     ULONG  *ptrs = (ULONG *)(ac -> ac_WorkBuffer);
  3653.     WORD   *data = (WORD *)(ptrs + 8UL);  /* data space starts after the 8 byte pointers... */
  3654.     UBYTE   plane;
  3655.     ULONG   planesize = ((bm -> BytesPerRow) * (bm -> Rows)) / sizeof( WORD ); /* size of plane,
  3656.                                                                                 * in compression units (WORD).
  3657.                                                                                 */
  3658.  
  3659.     memset( (ac -> ac_WorkBuffer), 0, (size_t)(ac -> ac_WorkBufferSize) );
  3660.  
  3661.     for( plane = 0U ; plane < (bm -> Depth) ; plane++ )
  3662.     {
  3663.       WORD   distance = 0,
  3664.              i;
  3665.       WORD  *planedata     = (WORD *)(bm -> Planes[ plane ]),
  3666.             *prevplanedata = (WORD *)(prevbm -> Planes[ plane ]);
  3667.  
  3668.       ptrs[ plane ] = (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer));
  3669.  
  3670.       for( i = 0 ; i < planesize ; i++ )
  3671.       {
  3672.         if( (planedata[ i ] != prevplanedata[ i ]) || (distance > 30000) )
  3673.         {
  3674.           if( FALSE /*planedata[ (i + 1) ] != prevplanedata[ (i + 1) ]*/ )
  3675.           {
  3676.             WORD *len;
  3677.  
  3678.             *data++ = -distance - 1;
  3679.             len = data++;
  3680.  
  3681.             *len = 0;
  3682.  
  3683.             while( (planedata[ i ] != prevplanedata[ i ]) && (i < planesize) && (*len < 30000))
  3684.             {
  3685.               *data++ = planedata[ i ];
  3686.               i++;
  3687.               (*len)++;
  3688.             }
  3689.  
  3690.             i--;
  3691.           }
  3692.           else
  3693.           {
  3694.             *data++ = distance;
  3695.             *data++ = planedata[ i ];
  3696.           }
  3697.  
  3698.           distance = 1;
  3699.         }
  3700.         else
  3701.         {
  3702.           distance++;
  3703.         }
  3704.       }
  3705.  
  3706.       /* No changes ? */
  3707.       if( ptrs[ plane ] == (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer)) )
  3708.       {
  3709.         ptrs[ plane ] = 0UL;
  3710.       }
  3711.       else
  3712.       {
  3713.         *data++ = (WORD)0xFFFF; /* terminator */
  3714.       }
  3715.     }
  3716.  
  3717.     if( error = PushChunk( iff, 0UL, ID_DLTA, IFFSIZE_UNKNOWN ) )
  3718.       return( error );
  3719.  
  3720.     len = (ULONG)((UBYTE *)data - (UBYTE *)(ac -> ac_WorkBuffer));
  3721.  
  3722.     if( WriteChunkBytes( iff, (APTR)(ac -> ac_WorkBuffer), len ) != len )
  3723.     {
  3724.       return( IFFERR_WRITE );
  3725.     }
  3726.  
  3727.     error = PopChunk( iff );
  3728.  
  3729.     return( error );
  3730. }
  3731.  
  3732.  
  3733. /*****************************************************************************/
  3734.  
  3735. /* write ILBM CMAP  */
  3736. static
  3737. LONG PutILBMCMAP( struct ClassBase *cb, struct IFFHandle *iff, ULONG *cregs, ULONG numcolors )
  3738. {
  3739.     long                 error;
  3740.     ULONG                i;
  3741.     struct ColorRegister cm;
  3742.  
  3743.     if( error = PushChunk( iff, 0UL, ID_CMAP, IFFSIZE_UNKNOWN ) )
  3744.       return( error );
  3745.  
  3746.     for( i = 0UL ; i < numcolors ; i++ )
  3747.     {
  3748.       /* reduce colors from 32 bits to cmap's 8 bit-per-gun */
  3749.       cm . red   = (UBYTE)(cregs[ ((i * 3) + 0) ] >> 24UL);
  3750.       cm . green = (UBYTE)(cregs[ ((i * 3) + 1) ] >> 24UL);
  3751.       cm . blue  = (UBYTE)(cregs[ ((i * 3) + 2) ] >> 24UL);
  3752.  
  3753.       /* Write R, B, G bytes */
  3754.       if( WriteChunkBytes( iff, (APTR)(&cm), 3UL ) != 3UL )
  3755.       {
  3756.         return( IFFERR_WRITE );
  3757.       }
  3758.     }
  3759.  
  3760.     return( PopChunk( iff ) );
  3761. }
  3762.  
  3763.  
  3764. /*****************************************************************************/
  3765.  
  3766. /* from IFF example code ("iffp/ilbm.h") */
  3767. #define RowBytes( w )     ((((w) + 15) >> 4) << 1)
  3768. #define RowBits( w )      ((((w) + 15) >> 4) << 4)
  3769.  
  3770.  
  3771. static
  3772. LONG PutILBMBody( struct ClassBase *cb, struct IFFHandle *iff, struct BitMap *bitmap, struct BitMapHeader *bmh )
  3773. {
  3774.     LONG     error;
  3775.     LONG     rowBytes        = bitmap -> BytesPerRow;           /* for source modulo only  */
  3776.     LONG     FileRowBytes    = RowBytes( (bmh -> bmh_Width) );  /* width to write in bytes */
  3777.     ULONG    planeCnt        = bmh -> bmh_Depth;                /* number of bit planes including mask */
  3778.     ULONG    iPlane,
  3779.              iRow;
  3780.     BYTE    *planes[ 24 ]; /* array of ptrs to planes & mask */
  3781.  
  3782.     /* Copy the ptrs to bit & mask planes into local array "planes" */
  3783.     for( iPlane = 0 ; iPlane < planeCnt; iPlane++ )
  3784.        planes[ iPlane ] = (BYTE *)(bitmap -> Planes[ iPlane ]);
  3785.  
  3786.     /* Write out a BODY chunk header */
  3787.     if( error = PushChunk( iff, 0L, ID_BODY, IFFSIZE_UNKNOWN ) )
  3788.       return( error );
  3789.  
  3790.     /* Write out the BODY contents */
  3791.     for( iRow = bmh -> bmh_Height ; iRow > 0 ; iRow-- )
  3792.     {
  3793.       for( iPlane = 0 ; iPlane < planeCnt ; iPlane++ )
  3794.       {
  3795.         /* Write next row.*/
  3796.         if( WriteChunkBytes( iff, planes[ iPlane ], FileRowBytes ) != FileRowBytes )
  3797.           return( IFFERR_WRITE );
  3798.  
  3799.         planes[ iPlane ] += rowBytes; /* Possibly skipping unused bytes */
  3800.       }
  3801.     }
  3802.  
  3803.     /* Finish the chunk */
  3804.     error = PopChunk( iff );
  3805.  
  3806.     return( error );
  3807. }
  3808.  
  3809.  
  3810. static
  3811. struct AnimContext *CreateAnimContext( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth )
  3812. {
  3813.     APTR pool;
  3814.  
  3815.     if( pool = CreatePool( (MEMF_PUBLIC | MEMF_CLEAR), 1024UL, 1024UL ) )
  3816.     {
  3817.       struct AnimContext *ac;
  3818.  
  3819.       if( ac = (struct AnimContext *)AllocVecPooled( cb, pool, sizeof( struct AnimContext ) ) )
  3820.       {
  3821.         /* Alloc two bitmaps, used for interleaving */
  3822.         ac -> ac_BitMap[ 0 ] = AllocBitMapPooled( cb, width, height, depth, pool );
  3823.         ac -> ac_BitMap[ 1 ] = AllocBitMapPooled( cb, width, height, depth, pool );
  3824.  
  3825.         /* Alloc work buffer large enougth to hold fancy things... */
  3826.  
  3827.         ac -> ac_WorkBufferSize = (width * height * depth * 2UL) + 1024UL;
  3828.         ac -> ac_WorkBuffer     = (UBYTE *)AllocVecPooled( cb, pool, (ac -> ac_WorkBufferSize) );
  3829.  
  3830.         if( (ac -> ac_BitMap[ 0 ]) && (ac -> ac_BitMap[ 1 ]) && (ac -> ac_WorkBuffer) )
  3831.         {
  3832.           return( ac );
  3833.         }
  3834.       }
  3835.  
  3836.       /* Something goes wrong here, get rid of the resources allocated */
  3837.       DeletePool( pool );
  3838.     }
  3839.  
  3840.     return( NULL );
  3841. }
  3842.  
  3843.  
  3844. #if 0
  3845. static
  3846. struct BitMap *PrevFrame( struct ClassBase *cb, struct AnimContext *ac )
  3847. {
  3848.     if( ac )
  3849.     {
  3850.       return( (ac -> ac_BitMap[ ((ac -> ac_WhichBitMap) ^ 1) ]) );
  3851.     }
  3852.  
  3853.     return( NULL );
  3854. }
  3855. #endif
  3856.  
  3857.  
  3858. static
  3859. void SwapFrames( struct ClassBase *cb, struct AnimContext *ac )
  3860. {
  3861.     if( ac )
  3862.     {
  3863.       ac -> ac_WhichBitMap ^= 1; /* Toggle buffer */
  3864.     }
  3865. }
  3866.  
  3867.  
  3868. static
  3869. struct BitMap *CurrFrame( struct ClassBase *cb, struct AnimContext *ac )
  3870. {
  3871.     if( ac )
  3872.     {
  3873.       return( (ac -> ac_BitMap[ (ac -> ac_WhichBitMap) ]) );
  3874.     }
  3875.  
  3876.     return( NULL );
  3877. }
  3878.  
  3879.  
  3880. static
  3881. void DeleteAnimContext( struct ClassBase *cb, struct AnimContext *ac )
  3882. {
  3883.     if( ac )
  3884.     {
  3885.       DeletePool( (ac -> ac_Pool) );
  3886.     }
  3887. }
  3888.  
  3889.  
  3890.  
  3891.