home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / datatypes / anim_datatype / dispatch.c < prev   
Encoding:
C/C++ Source or Header  |  1997-05-22  |  108.8 KB  |  3,299 lines

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