home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 2 / MECOMP-CD-II.iso / amiga / datatypes / film_datatype / dispatch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-27  |  78.5 KB  |  2,407 lines

  1.  
  2. /*
  3. **
  4. **  $VER: dispatch.c 1.6 (27.8.97)
  5. **  film.datatype 1.6
  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. #include "classdata.h"
  17.  
  18. /*****************************************************************************/
  19.  
  20. /* local prototypes */
  21. static                 STRPTR            GetPrefsVar( struct ClassBase *, STRPTR );
  22. static                 BOOL              matchstr( struct ClassBase *, STRPTR, STRPTR );
  23. static                 void              ReadENVPrefs( struct ClassBase *, struct FilmInstData * );
  24. static                 LONG              LoadFrames( struct ClassBase *, Object * );
  25. static                 struct FrameNode *AllocFrameNode( struct ClassBase *, APTR );
  26. static                 struct FrameNode *FindFrameNode( struct MinList *, ULONG );
  27. static                 void              FreeFrameNodeResources( struct ClassBase *, struct MinList * );
  28. static                 void              CopyBitMap( struct ClassBase *, struct BitMap *, struct BitMap * );
  29. static                 struct BitMap    *AllocBitMapPooled( struct ClassBase *, ULONG, ULONG, ULONG, APTR );
  30. static                 BOOL              CMAP2Object( struct ClassBase *, Object *, UBYTE *, ULONG );
  31. static                 struct ColorMap  *CMAP2ColorMap( struct ClassBase *, struct FilmInstData *, UBYTE *, ULONG );
  32. static                 struct ColorMap  *CopyColorMap( struct ClassBase *, struct ColorMap * );
  33. static                 APTR              AllocVecPooled( struct ClassBase *, APTR, ULONG );
  34. static                 void              FreeVecPooled( struct ClassBase *, APTR, APTR );
  35. static                 void              verbose_printf( struct ClassBase *, struct FilmInstData *, STRPTR, ... );
  36. static                 void              OpenLogfile( struct ClassBase *, struct FilmInstData * );
  37. static                 void              mysprintf( struct ClassBase *, STRPTR, STRPTR, ... );
  38. static                 ULONG             SaveIFFFilm( struct ClassBase *, struct IClass *, Object *, struct dtWrite * );
  39.  
  40. static                 struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *, BPTR );
  41. static                 LONG              StartIFFFilm( struct ClassBase *, struct FilmInstData *, struct IFFHandle *, struct BitMapHeader *, ULONG, ULONG *, ULONG, struct VoiceHeader * );
  42. static                 void              EndIFFFilm( struct ClassBase *, struct FilmInstData *, struct IFFHandle * );
  43. static                 LONG              WriteIFFFilmCell( struct ClassBase *, struct IFFHandle *, struct BitMapHeader *, ULONG *, ULONG, struct BitMap *, BYTE *, ULONG );
  44. static                 LONG              PutILBMCMAP( struct ClassBase *, struct IFFHandle *, ULONG *, ULONG );
  45. static                 LONG              PutILBMBody( struct ClassBase *, struct IFFHandle *, struct BitMap *, struct BitMapHeader * );
  46. static                 LONG              Put8SVXBody( struct ClassBase *, struct IFFHandle *, BYTE *, ULONG );
  47.  
  48.  
  49.  
  50. /*****************************************************************************/
  51.  
  52. /* Create "film.datatype" BOOPSI class */
  53. struct IClass *initClass( struct ClassBase *cb )
  54. {
  55.     struct IClass *cl;
  56.  
  57.     /* Create our class... */
  58.     if( cl = MakeClass( FILMDTCLASS, ANIMATIONDTCLASS, NULL, (ULONG)sizeof( struct FilmInstData ), 0UL ) )
  59.     {
  60.       cl -> cl_Dispatcher . h_Entry = (HOOKFUNC)Dispatch;
  61.       cl -> cl_UserData             = (ULONG)cb;
  62.  
  63.       AddClass( cl );
  64.     }
  65.  
  66.     return( cl );
  67. }
  68.  
  69. /*****************************************************************************/
  70.  
  71. /* IFF errors to DOS errors */
  72. const
  73. LONG ifferr2doserr[] =
  74. {
  75.     0L,                         /* End of file (not an error).                   */
  76.     0L,                         /* End of context (not an error).                */
  77.     DTERROR_INVALID_DATA,       /* No lexical scope.                             */
  78.     ERROR_NO_FREE_STORE,        /* Insufficient memory.                          */
  79.     ERROR_SEEK_ERROR,           /* Stream read error.                            */
  80.     ERROR_SEEK_ERROR,           /* Stream write error.                           */
  81.     ERROR_SEEK_ERROR,           /* Stream seek error.                            */
  82.     DTERROR_INVALID_DATA,       /* File is corrupt.                              */
  83.     DTERROR_INVALID_DATA,       /* IFF syntax error.                             */
  84.     ERROR_OBJECT_WRONG_TYPE,    /* Not an IFF file.                              */
  85.     ERROR_REQUIRED_ARG_MISSING, /* Required call-back hook missing.              */
  86.     0xDEADDEAD                  /* Return to client. You should never see this ! */
  87. };
  88.  
  89. /*****************************************************************************/
  90.  
  91.  
  92. struct MyStackSwapStruct
  93. {
  94.     struct StackSwapStruct  stk;
  95.     struct IClass          *cl;
  96.     Object                 *o;
  97.     Msg                     msg;
  98. };
  99.  
  100. /*****************************************************************************/
  101.  
  102. DISPATCHERFLAGS
  103. ULONG Dispatch( REGA0 struct IClass *cl, REGA2 Object *o, REGA1 Msg msg )
  104. {
  105.     struct ClassBase         *cb = (struct ClassBase *)(cl -> cl_UserData);
  106.     ULONG                     retval;
  107.     struct MyStackSwapStruct  mystk;
  108.     UBYTE                    *lower,
  109.                              *upper,
  110.                              *sp;
  111.     struct Task              *ThisTask;
  112.     ULONG                     stacksize;
  113.  
  114.     mystk . cl                = cl;
  115.     mystk . o                 = o;
  116.     mystk . msg               = msg;
  117.  
  118.     ThisTask = FindTask( NULL );
  119.     stacksize = (ULONG)(((UBYTE *)(ThisTask -> tc_SPReg)) - ((UBYTE *)(ThisTask -> tc_SPLower)));
  120.  
  121. #define DTSTACKSIZE (16384UL)
  122.  
  123.     /* Enougth stack ? */
  124.     if( stacksize > (DTSTACKSIZE / 2UL) )
  125.     {
  126.       retval = MyDispatch( (&mystk) );
  127.     }
  128.     else
  129.     {
  130.       /* Alloc a new stack frame... */
  131.       while( !(lower = (UBYTE *)AllocMem( DTSTACKSIZE, (MEMF_PUBLIC | MEMF_CLEAR) )) );
  132.  
  133.       sp = upper = lower + DTSTACKSIZE;
  134.  
  135.       mystk . stk . stk_Lower   = lower;
  136.       mystk . stk . stk_Upper   = (ULONG)upper;
  137.       mystk . stk . stk_Pointer = sp;
  138.  
  139.       retval = SwapMe( (&mystk) );
  140.  
  141.       FreeMem( lower, DTSTACKSIZE );
  142.     }
  143.  
  144.     return( retval );
  145. }
  146.  
  147.  
  148. DISPATCHERFLAGS
  149. ULONG SwapMe( REGA0 struct MyStackSwapStruct *mystk )
  150. {
  151.     register ULONG retval;
  152.  
  153. #define cb ((struct ClassBase *)(mystk -> cl -> cl_UserData))
  154.  
  155.     StackSwap( (&(mystk -> stk)) );
  156.  
  157.       retval = MyDispatch( mystk );
  158.  
  159.     StackSwap( (&(mystk -> stk)) );
  160.  
  161. #undef cb
  162.  
  163.     return( retval );
  164. }
  165.  
  166.  
  167. /* class dispatcher */
  168. DISPATCHERFLAGS
  169. ULONG MyDispatch( REGA0 struct MyStackSwapStruct *mystk )
  170. {
  171.     struct IClass        *cl  = mystk -> cl;
  172.     Object               *o   = mystk -> o;
  173.     Msg                   msg = mystk -> msg;
  174.  
  175.     struct ClassBase     *cb = (struct ClassBase *)(cl -> cl_UserData);
  176.     struct FilmInstData  *fid;
  177.     ULONG                 retval = 0UL;
  178.  
  179.     switch( msg -> MethodID )
  180.     {
  181. /****** film.datatype/OM_NEW *************************************************
  182. *
  183. *    NAME
  184. *        OM_NEW -- Create a film.datatype object.
  185. *
  186. *    FUNCTION
  187. *        The OM_NEW method is used to create an instance of the film.datatype
  188. *        class.  This method is passed to the superclass first. After this,
  189. *        film.datatype parses the description file and makes a scan through
  190. *        the data to get index information. The samples are loaded directly
  191. *        (due their small size), frame bitmaps are loaded if the input
  192. *        stream isn't seekable (e.g. IFF handle/clipboard).
  193. *
  194. *    ATTRIBUTES
  195. *        The following attributes can be specified at creation time.
  196. *
  197. *        DTA_SourceType (ULONG) -- Determinates the type of DTA_Handle
  198. *            attribute. DTST_FILE, DTST_CLIPBOARD and DTST_RAM are supported.
  199. *            If any other type was set in a given DTA_SourceType,
  200. *            OM_NEW will be rejected.
  201. *            Defaults to DTST_FILE.
  202. *
  203. *        DTA_Handle -- For both supported DTST_FILE and DTST_CLIPBOARD, a
  204. *            (struct IFFHandle *) is expected.
  205. *            (DTST_FILE expects a IFF Stream handle because this is a IFF
  206. *            type DataType (DTF_IFF)).
  207. *            A DTST_RAM (create empty object) source type requires a NULL
  208. *            handle.
  209. *
  210. *    BUGS
  211. *        Before V1.3, this autodoc described that a DTA_Handle with a
  212. *        DTA_SourceType of DTST_FILE takes a DOS filehandle as an argument.
  213. *        This was WRONG ! Because this is a DTF_IFF type datatype, DTST_FILE
  214. *        takes also an IFF Stream handle as an argument.
  215. *
  216. *    RESULT
  217. *        If the object was created a pointer to the object is returned,
  218. *        otherwise NULL is returned.
  219. *
  220. ******************************************************************************
  221. *
  222. */
  223.       case OM_NEW:
  224.       {
  225.           struct TagItem *ti;
  226.  
  227.           /* We only support DTST_FILE, DTST_CLIPBOARD or DTST_RAM as source type */
  228.           if( ti = FindTagItem( DTA_SourceType, (((struct opSet *)msg) -> ops_AttrList) ) )
  229.           {
  230.             if( ((ti -> ti_Data) != DTST_FILE)      &&
  231.                 ((ti -> ti_Data) != DTST_CLIPBOARD) &&
  232.                 ((ti -> ti_Data) != DTST_RAM) )
  233.             {
  234.               SetIoErr( ERROR_OBJECT_WRONG_TYPE );
  235.  
  236.               break;
  237.             }
  238.           }
  239.  
  240.           if( retval = DoSuperMethodA( cl, o, msg ) )
  241.           {
  242.             LONG error;
  243.  
  244.             /* Load frames... */
  245.             if( error = LoadFrames( cb, (Object *)retval ) )
  246.             {
  247.               /* Something went fatally wrong, dispose object */
  248.               CoerceMethod( cl, (Object *)retval, OM_DISPOSE );
  249.               retval = 0UL;
  250.             }
  251.  
  252.             SetIoErr( error );
  253.           }
  254.       }
  255.           break;
  256.  
  257. /****** film.datatype/OM_DISPOSE *********************************************
  258. *
  259. *    NAME
  260. *        OM_DISPOSE -- Delete a film.datatype object.
  261. *
  262. *    FUNCTION
  263. *        The OM_DISPOSE method is used to delete an instance of the
  264. *        film.datatype class. This method is pass to the superclass when
  265. *        it has completed.
  266. *        This method frees all frame nodes and their contents (bitmaps,
  267. *        sounds etc.).
  268. *
  269. *    RESULT
  270. *        The object is deleted. 0UL is returned.
  271. *
  272. ******************************************************************************
  273. *
  274. */
  275.       case OM_DISPOSE:
  276.       {
  277.           /* Get a pointer to our object data */
  278.           fid = (struct FilmInstData *)INST_DATA( cl, o );
  279.  
  280.           /* Wait for any outstanding blitter usage (which may use one of our bitmaps) */
  281.           WaitBlit();
  282.  
  283.           /* Free colormaps etc. */
  284.           FreeFrameNodeResources( cb, (&(fid -> fid_FrameList)) );
  285.  
  286.           /* Free our key bitmap */
  287.           FreeBitMap( (fid -> fid_KeyBitMap) );
  288.  
  289.           /* Delete the frame pool */
  290.           DeletePool( (fid -> fid_Pool) );
  291.  
  292.           if( fid -> fid_FH )
  293.           {
  294.             Close( (fid -> fid_FH) );
  295.           }
  296.  
  297.            /* Close verbose output file */
  298.           if( fid -> fid_VerboseOutput )
  299.           {
  300.             Close( (fid -> fid_VerboseOutput) );
  301.           }
  302.  
  303.           /* Dispose object */
  304.           DoSuperMethodA( cl, o, msg );
  305.       }
  306.           break;
  307.  
  308.       case OM_UPDATE:
  309.       {
  310.           if( DoMethod( o, ICM_CHECKLOOP ) )
  311.           {
  312.             break;
  313.           }
  314.       }
  315.       case OM_SET:
  316.       {
  317.           /* Pass the attributes to the animation class and force a refresh if we need it */
  318.           if( retval = DoSuperMethodA( cl, o, msg ) )
  319.           {
  320.             /* Top instance ? */
  321.             if( OCLASS( o ) == cl )
  322.             {
  323.               struct RastPort *rp;
  324.  
  325.               /* Get a pointer to the rastport */
  326.               if( rp = ObtainGIRPort( (((struct opSet *)msg) -> ops_GInfo) ) )
  327.               {
  328.                 struct gpRender gpr;
  329.  
  330.                 /* Force a redraw */
  331.                 gpr . MethodID   = GM_RENDER;
  332.                 gpr . gpr_GInfo  = ((struct opSet *)msg) -> ops_GInfo;
  333.                 gpr . gpr_RPort  = rp;
  334.                 gpr . gpr_Redraw = GREDRAW_UPDATE;
  335.  
  336.                 DoMethodA( o, (Msg)(&gpr) );
  337.  
  338.                 /* Release the temporary rastport */
  339.                 ReleaseGIRPort( rp );
  340.  
  341.                 retval = 0UL;
  342.               }
  343.             }
  344.           }
  345.       }
  346.           break;
  347.  
  348.  
  349. /****** film.datatype/DTM_WRITE **********************************************
  350. *
  351. *    NAME
  352. *        DTM_WRITE -- Save data
  353. *
  354. *    FUNCTION
  355. *        This method saves the object's contents to disk.
  356. *
  357. *        If dtw_Mode is DTWM_IFF, the method is passed unchanged to the
  358. *        superclass, animation.datatype, which writes a single IFF ILBM
  359. *        picture.
  360. *
  361. *        If dtw_mode is DTWM_RAW, the object saved an IFF FILM stream to
  362. *        the filehandle given, starting with the current frame until
  363. *        the end is reached.
  364. *        The sequence saved can be controlled by the ADTA_Frame, ADTA_Frames 
  365. *        and ADTA_FrameIncrement attributes (see TAGS section below).
  366. *
  367. *    TAGS
  368. *        When writing the local ("raw") format, IFF FILM, the following
  369. *        attributes are recognized:
  370. *
  371. *        ADTA_Frame (ULONG) - start frame, saving starts here.
  372. *            Defaults to the current frame displayed.
  373. *
  374. *        ADTA_Frames (ULONG) - the number of frames to be saved,
  375. *            Defaults to (max_num_of_frames - curr_frame).
  376. *
  377. *        ADTA_FrameIncrement (ULONG) - frame increment when saving.
  378. *            Defaults to 1, which means: "jump to next frame".
  379. *
  380. *    BUGS
  381. *        Any other ADTA_FrameIncrement value than 1 causes that
  382. *        the sound of the skipped frames got lost. A recommened way would be
  383. *        to append their sound to the next frame(s).
  384. *
  385. *    RESULT
  386. *        Returns 0 for failure (IoErr() returns result2), non-zero
  387. *        for success.
  388. *
  389. ******************************************************************************
  390. *
  391. */
  392.       case DTM_WRITE:
  393.       {
  394.           struct dtWrite *dtw;
  395.  
  396.           dtw = (struct dtWrite *)msg;
  397.  
  398.           /* Local data format not supported yet... */
  399.           if( (dtw -> dtw_Mode) == DTWM_RAW )
  400.           {
  401.             retval = SaveIFFFilm( cb, cl, o, dtw );
  402.           }
  403.           else
  404.           {
  405.             /* Pass msg to superclass (which writes a single frame as an IFF ILBM picture)... */
  406.             retval = DoSuperMethodA( cl, o, msg );
  407.           }
  408.       }
  409.           break;
  410.  
  411.  
  412. /****** film.datatype/ADTM_LOADFRAME *****************************************
  413. *
  414. *    NAME
  415. *        ADTM_LOADFRAME -- Load frame
  416. *
  417. *    FUNCTION
  418. *        The ADTM_LOADFRAME method is used to obtain the bitmap and timing
  419. *        data of the animation.
  420. *        The given timestamp will be used to find a matching timestamp
  421. *        in the internal FrameNode list. If it was found, the corresponding
  422. *        timing, bitmap and colormap data are stored into the struct
  423. *        adtFrame. If the bitmap wasn't loaded at this time, this method 
  424. *        attempts to load it from disk.
  425. *
  426. *    RESULT
  427. *        Returns the bitmap ptr if a bitmap was found, 0UL otherwise;
  428. *        in case of failure Result2 contains the cause:
  429. *        ERROR_OBJECT_NOT_FOUND: Given timestamp does not exist
  430. *        ERROR_NO_FREE_STORE:    No memory
  431. *        and so on...
  432. *
  433. *    NOTE
  434. *        It is expected that a 0 return code (error) causes an
  435. *        ADTM_UNLOADFRAME that the invalid bitmap etc. will be freed.
  436. *
  437. ******************************************************************************
  438. *
  439. */
  440.  
  441.       case ADTM_LOADFRAME:
  442.       {
  443.           struct FrameNode *fn;
  444.           struct adtFrame  *alf;
  445.  
  446.           fid = (struct FilmInstData *)INST_DATA( cl, o );
  447.           alf = (struct adtFrame *)msg;
  448.  
  449.           ObtainSemaphore( (&(fid -> fid_SigSem)) );
  450.  
  451.           /* Find frame by timestamp */
  452.           if( fn = FindFrameNode( (&(fid -> fid_FrameList)), (alf -> alf_TimeStamp) ) )
  453.           {
  454.             LONG error = 0L;
  455.  
  456.             /* Load bitmaps only if we don't cache the whole anim and
  457.              * if we have a filehandle to load from (an empty object created using DTST_RAM)...
  458.              */
  459.             if( (fid -> fid_LoadAll) == FALSE && (fid -> fid_FH) )
  460.             {
  461.               /* If no bitmap is loaded, load it... */
  462.               if( (fn -> fn_BitMap) == NULL )
  463.               {
  464.                 if( fn -> fn_BitMap = AllocBitMapPooled( cb, (ULONG)(fid -> fid_BMH -> bmh_Width), (ULONG)(fid -> fid_BMH -> bmh_Height), (ULONG)(fid -> fid_BMH -> bmh_Depth), (fid -> fid_Pool) ) )
  465.                 {
  466.                   if( Seek( (fid -> fid_FH), (((fn -> fn_BMOffset) + 8UL) - (fid -> fid_CurrFilePos)), OFFSET_CURRENT ) != (-1L) )
  467.                   {
  468.                     /* Load ILBM BODY directly into bitmap, assuming an interleaved bitmap */
  469.                     if( Read( (fid -> fid_FH), (fn -> fn_BitMap -> Planes[ 0 ]), (fn -> fn_BMSize) ) == (fn -> fn_BMSize) )
  470.                     {
  471.                       /* Bump file pos */
  472.                       fid -> fid_CurrFilePos = ((fn -> fn_BMOffset) + 8UL) + (fn -> fn_BMSize);
  473.  
  474.                       /* Success ! */
  475.                       retval = 1UL;
  476.                     }
  477.                   }
  478.  
  479.                   if( retval == 0UL )
  480.                   {
  481.                     error = IoErr(); /* seek or read error */
  482.  
  483.                     /* Error, rewind stream */
  484.                     Seek( (fid -> fid_FH), 0L, OFFSET_BEGINNING );
  485.                     fid -> fid_CurrFilePos = 0L;
  486.                   }
  487.                 }
  488.                 else
  489.                 {
  490.                   /* no bitmap memory */
  491.                   error = ERROR_NO_FREE_STORE;
  492.                 }
  493.               }
  494.             }
  495.  
  496.             /* Store frame/context information */
  497.             alf -> alf_Frame    = fn -> fn_Frame;
  498.             alf -> alf_Duration = 0UL;             /* we don't have dynamic timing (a NOP here because alf_Duration is 0 by default */
  499.             alf -> alf_UserData = (APTR)fn;        /* Links back to this FrameNode (used by ADTM_UNLOADFRAME) */
  500.  
  501.             /* Store bitmap/colormap information */
  502.             alf -> alf_BitMap = fn -> fn_BitMap;
  503.             alf -> alf_CMap   = fn -> fn_CMap;
  504.  
  505.             /* Is there a sample to play ? */
  506.             if( fn -> fn_Sample )
  507.             {
  508.               /* Store sound information */
  509.               alf -> alf_Sample       = fn -> fn_Sample;
  510.               alf -> alf_SampleLength = fn -> fn_SampleLength;
  511.               alf -> alf_Period       = fid -> fid_Period;
  512.             }
  513.             else
  514.             {
  515.               /* No sound */
  516.               alf -> alf_Sample       = NULL;
  517.               alf -> alf_SampleLength = 0UL;
  518.               alf -> alf_Period       = 0UL;
  519.             }
  520.  
  521.             /* Frame "in use", even for a unsuccessful result; on error
  522.              * animation.datatype send an ADTM_UNLOADFRAME which frees
  523.              * allocated resources and decreases the "UseCount"...
  524.              */
  525.             fn -> fn_UseCount++;
  526.  
  527.             /* Return bitmap ptr on success, 0UL otherwise (and set result2) */
  528.             retval = ((error)?(0UL):(ULONG)(alf -> alf_BitMap)); /* Result  */
  529.             SetIoErr( error );                                   /* Result2 */
  530.           }
  531.           else
  532.           {
  533.             /* no matching frame found */
  534.             SetIoErr( ERROR_OBJECT_NOT_FOUND );
  535.           }
  536.  
  537.           ReleaseSemaphore( (&(fid -> fid_SigSem)) );
  538.       }
  539.           break;
  540.  
  541. /****** film.datatype/ADTM_UNLOADFRAME ***************************************
  542. *
  543. *    NAME
  544. *        ADTM_UNLOADFRAME -- Load frame contents
  545. *
  546. *    FUNCTION
  547. *        The ADTM_UNLOADFRAME method is used to release the contents of a
  548. *        animation frame.
  549. *
  550. *        This method frees the bitmap data found in adtFrame.
  551. *
  552. *    RESULT
  553. *        Returns always 0UL.
  554. *
  555. ******************************************************************************
  556. *
  557. */
  558.       case ADTM_UNLOADFRAME:
  559.       {
  560.           struct adtFrame *alf;
  561.  
  562.           fid = (struct FilmInstData *)INST_DATA( cl, o );
  563.           alf = (struct adtFrame *)msg;
  564.  
  565.           /* Free bitmaps only if we don't cache the whole anim */
  566.           if( (fid -> fid_LoadAll) == FALSE )
  567.           {
  568.             struct FrameNode *fn;
  569.  
  570.             if( fn = (struct FrameNode *)(alf -> alf_UserData) )
  571.             {
  572.               ObtainSemaphore( (&(fid -> fid_SigSem)) );
  573.  
  574.               /* Decrease use-count */
  575.               if( (fn -> fn_UseCount) > 0 )
  576.               {
  577.                 fn -> fn_UseCount--;
  578.  
  579.                 /* No one use the bitmap ? */
  580.                 if( ((fn -> fn_UseCount) == 0) && (fn -> fn_BitMap) )
  581.                 {
  582.                   FreeVecPooled( cb, (fid -> fid_Pool), (fn -> fn_BitMap) );
  583.                   fn -> fn_BitMap = NULL;
  584.                 }
  585.               }
  586.  
  587.               ReleaseSemaphore( (&(fid -> fid_SigSem)) );
  588.             }
  589.           }
  590.  
  591.           /* This isn't neccesary because Msg (struct alfFrame) should not be used after ADTM_UNLOADFRAME
  592.            * (e.g. it must be cleared with ZEROs before using it again).
  593.            * This is only for those BRAIN-DEAD programmers which don't follow this rule...
  594.            */
  595.           alf -> alf_UserData = NULL;
  596.       }
  597.           break;
  598.  
  599.       /* Let the superclass handle everything else */
  600.       default:
  601.       {
  602.           retval = DoSuperMethodA( cl, o, msg );
  603.       }
  604.           break;
  605.     }
  606.  
  607.     return( retval );
  608. }
  609.  
  610.  
  611. /****** film.datatype/preferences ********************************************
  612. *
  613. *   NAME
  614. *       preferences
  615. *
  616. *   DESCRIPTION
  617. *       The "ENV:Classes/DataTypes/film.prefs" file contains global
  618. *       settings for the datatype.
  619. *       The preferences file is an ASCII file containing one line where the
  620. *       preferences can be set.
  621. *       It can be superset by a local variable with the same name.
  622. *
  623. *       Each line can contain settings, special settings for some projects
  624. *       can be set using the MATCHPROJECT option.
  625. *       Lines beginning with a '#' or ';' chars are treated as comments.
  626. *       Lines are limitted to 256 chars.
  627. *
  628. *   TEMPLATE
  629. *       MATCHPROJECT/K,VERBOSE/S,MODEID/K/N,FPS/K/N,VOLUME/K/N,LOADALL/S,
  630. *       NOLOADALL/S,
  631. *
  632. *
  633. *       MATCHPROJECT -- The settings in this line belongs only to this
  634. *           project(s), e.g. if the case-insensitive pattern does not match,
  635. *           this line is ignored.
  636. *           The maximum length of the pattern is 256 chars.
  637. *           Defaults to #?, which matches any project.
  638. *
  639. *       VERBOSE -- Print out verbose information about the movie like
  640. *           width, height, depth, number of frames, FPS-Rate etc.
  641. *
  642. *       MODEID -- Select screen mode id of datatype (will be stored in
  643. *           ADTA_ModeID). Note that the DOS ReadArgs function used for parsing
  644. *           fetches a SIGNED long. The bit 31 will be represented by minus
  645. *           '-'. (example: "MODEID=266240" sets the mode to the A2024 screen
  646. *           mode id)
  647. *           Defaults to 0, which means: Use the best screenmode available
  648. *           for the given width, height and depth.
  649. *
  650. *       FPS -- frames per second
  651. *           Defaults to 0, which means: overtake fps rate from video stream.
  652. *           Setting the FPS value also affects an attched sound. The period
  653. *           of the sample (e.g. the playback speed) will everytimes as long
  654. *           as the frame is displayed.
  655. *
  656. *       VOLUME -- Volume of the sound when playing.
  657. *           Defaults to 64, which is the maximum. A value greater than 64 will
  658. *           be set to 64.
  659. *
  660. *       LOADALL -- Load all frames into memory.
  661. *
  662. *       NOLOADALL -- Load frames dynamically from disk. This is the default.
  663. *
  664. *   NOTE
  665. *       An invalid prefs file line will be ignored.
  666. *
  667. *   BUGS
  668. *       - Low memory may cause that the prefs file won't be parsed.
  669. *
  670. *       - Lines are limitted to 256 chars
  671. *
  672. ******************************************************************************
  673. *
  674. */
  675.  
  676.  
  677. static
  678. STRPTR GetPrefsVar( struct ClassBase *cb, STRPTR name )
  679. {
  680.           STRPTR buff;
  681.     const ULONG  buffsize = 16UL;
  682.  
  683.     if( buff = (STRPTR)AllocVec( (buffsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  684.     {
  685.       if( GetVar( name, buff, buffsize, GVF_BINARY_VAR ) != (-1L) )
  686.       {
  687.         ULONG varsize = IoErr();
  688.  
  689.         varsize += 2UL;
  690.  
  691.         if( varsize > buffsize )
  692.         {
  693.           FreeVec( buff );
  694.  
  695.           if( buff = (STRPTR)AllocVec( (varsize + 2UL), (MEMF_PUBLIC | MEMF_CLEAR) ) )
  696.           {
  697.             if( GetVar( name, buff, varsize, GVF_BINARY_VAR ) != (-1L) )
  698.             {
  699.               return( buff );
  700.             }
  701.           }
  702.         }
  703.         else
  704.         {
  705.           return( buff );
  706.         }
  707.       }
  708.  
  709.       FreeVec( buff );
  710.     }
  711.  
  712.     return( NULL );
  713. }
  714.  
  715.  
  716. static
  717. BOOL matchstr( struct ClassBase *cb, STRPTR pat, STRPTR s )
  718. {
  719.     TEXT buff[ 516 ];
  720.  
  721.     if( pat && s )
  722.     {
  723.       if( ParsePatternNoCase( pat, buff, (ULONG)(sizeof( buff ) - 1) ) != (-1L) )
  724.       {
  725.         if( MatchPatternNoCase( buff, s ) )
  726.         {
  727.           return( TRUE );
  728.         }
  729.       }
  730.     }
  731.  
  732.     return( FALSE );
  733. }
  734.  
  735.  
  736. static
  737. void ReadENVPrefs( struct ClassBase *cb, struct FilmInstData *fid )
  738. {
  739.     struct RDArgs envvarrda =
  740.     {
  741.       NULL,
  742.       256L,
  743.       0L,
  744.       0L,
  745.       NULL,
  746.       0L,
  747.       NULL,
  748.       RDAF_NOPROMPT
  749.     };
  750.  
  751.     struct
  752.     {
  753.       STRPTR  matchproject;
  754.       long   *verbose;
  755.       long   *modeid;
  756.       long   *fps;
  757.       long   *volume;
  758.       long   *loadall;
  759.       long   *noloadall;
  760.     } animargs;
  761.  
  762.     TEXT   varbuff[ 258 ];
  763.     STRPTR var;
  764.  
  765.     if( var = GetPrefsVar( cb, "Classes/DataTypes/film.prefs" ) )
  766.     {
  767.       STRPTR prefsline      = var,
  768.              nextprefsline;
  769.       ULONG  linecount      = 1UL;
  770.  
  771.       /* Be sure that "var" contains at least one break-char */
  772.       strcat( var, "\n" );
  773.  
  774.       while( nextprefsline = strpbrk( prefsline, "\n" ) )
  775.       {
  776.         stccpy( varbuff, prefsline, MIN( (sizeof( varbuff ) - 2UL), (((ULONG)(nextprefsline - prefsline)) + 1UL) ) );
  777.  
  778.         /* be sure that this line isn't a comment line or an empty line */
  779.         if( (varbuff[ 0 ] != '#') && (varbuff[ 0 ] != ';') && (varbuff[ 0 ] != '\n') && (strlen( varbuff ) > 2UL) )
  780.         {
  781.           /* Prepare ReadArgs processing */
  782.           strcat( varbuff, "\n" );                                       /* Add NEWLINE-char            */
  783.           envvarrda . RDA_Source . CS_Buffer = varbuff;                  /* Buffer                      */
  784.           envvarrda . RDA_Source . CS_Length = strlen( varbuff ) + 1UL;  /* Set up input buffer length  */
  785.           envvarrda . RDA_Source . CS_CurChr = 0L;
  786.           envvarrda . RDA_Buffer = NULL;
  787.           envvarrda . RDA_BufSiz = 0L;
  788.           memset( (void *)(&animargs), 0, sizeof( animargs ) );          /* Clear result array          */
  789.  
  790.           if( ReadArgs( "MATCHPROJECT/K,"
  791.                         "VERBOSE/S,"
  792.                         "MODEID/K/N,"
  793.                         "FPS/K/N,"
  794.                         "VOLUME/K/N,"
  795.                         "LOADALL/S,"
  796.                         "NOLOADALL/S", (LONG *)(&animargs), (&envvarrda) ) )
  797.           {
  798.             BOOL noignore = TRUE;
  799.  
  800.             if( (animargs . matchproject) && (fid -> fid_ProjectName) )
  801.             {
  802.               noignore = matchstr( cb, (animargs . matchproject), (fid -> fid_ProjectName) );
  803.             }
  804.  
  805.             if( noignore )
  806.             {
  807.               if( animargs . verbose )
  808.               {
  809.                 OpenLogfile( cb, fid );
  810.               }
  811.  
  812.               if( animargs . modeid )
  813.               {
  814.                 fid -> fid_ModeID = *(animargs . modeid);
  815.               }
  816.  
  817.               if( animargs . fps )
  818.               {
  819.                 fid -> fid_FPS = *(animargs . fps);
  820.               }
  821.  
  822.               if( animargs . volume )
  823.               {
  824.                 fid -> fid_Volume = *(animargs . volume);
  825.  
  826.                 if( (fid -> fid_Volume) > 64UL )
  827.                 {
  828.                   fid -> fid_Volume = 64UL;
  829.                 }
  830.               }
  831.               else
  832.               {
  833.                 fid -> fid_Volume = 64UL;
  834.               }
  835.  
  836.               if( animargs . loadall )
  837.               {
  838.                 fid -> fid_LoadAll = TRUE;
  839.               }
  840.  
  841.               if( animargs . noloadall )
  842.               {
  843.                 fid -> fid_LoadAll = FALSE;
  844.               }
  845.             }
  846.             else
  847.             {
  848.               verbose_printf( cb, fid, "prefs line %lu ignored\n", linecount );
  849.             }
  850.  
  851.             FreeArgs( (&envvarrda) );
  852.           }
  853.           else
  854.           {
  855.             LONG ioerr = IoErr();
  856.             TEXT errbuff[ 256 ];
  857.  
  858.             Fault( ioerr, "Classes/DataTypes/film.prefs", errbuff, sizeof( errbuff ) );
  859.  
  860.             verbose_printf( cb, fid, "preferences \"%s\" line %lu\n", errbuff, linecount );
  861.           }
  862.         }
  863.  
  864.         prefsline = ++nextprefsline;
  865.         linecount++;
  866.       }
  867.  
  868.       FreeVec( var );
  869.     }
  870. }
  871.  
  872.  
  873. static
  874. LONG LoadFrames( struct ClassBase *cb, Object *o )
  875. {
  876.     struct FilmInstData *fid  = (struct FilmInstData *)INST_DATA( (cb -> cb_Lib . cl_Class), o );
  877.     LONG                 error = 0L;
  878.  
  879.     InitSemaphore( (&(fid -> fid_SigSem)) );
  880.     NewList( (struct List *)(&(fid -> fid_FrameList)) );
  881.  
  882.     /* Create a memory pool for frame nodes */
  883.     if( fid -> fid_Pool = CreatePool( MEMF_PUBLIC, 16384UL, 16384UL ) )
  884.     {
  885.       APTR                 fh;               /* IFF stream handle               */
  886.       ULONG                sourcetype;       /* type of stream (either DTST_FILE, DTST_CLIPBOARD or DTST_RAM */
  887.       ULONG                pos        = 0UL; /* current file pos in IFF stream  */
  888.       struct BitMapHeader *bmh;              /* obj's bitmapheader              */
  889.       ULONG                modeid     = 0UL; /* anim view mode                  */
  890.       ULONG                animwidth  = 0UL, /* anim width                      */
  891.                            animheight = 0UL, /* anim height                     */
  892.                            animdepth  = 0UL; /* anim depth                      */
  893.       ULONG                timestamp  = 0UL; /* timestamp                       */
  894.       ULONG                sps        = 0UL; /* samples per second              */
  895.       ULONG                spf        = 0UL; /* samples per frame               */
  896.  
  897.       /* Prefs defaults */
  898.       fid -> fid_Volume = 64U;
  899.  
  900.       /* Read prefs */
  901.       ReadENVPrefs( cb, fid );
  902.  
  903.       /* Get file handle, handle type and BitMapHeader */
  904.       if( GetDTAttrs( o, DTA_SourceType,    (&sourcetype),
  905.                          DTA_Handle,        (&fh),
  906.                          DTA_Name,          (&(fid -> fid_ProjectName)),
  907.                          PDTA_BitMapHeader, (&bmh),
  908.                          TAG_DONE ) == 4UL )
  909.       {
  910.         struct IFFHandle *iff      = NULL;
  911.         ULONG             numcmaps = 0UL; /* number of loaded colormaps */
  912.  
  913.         fid -> fid_BMH = bmh; /* Store BitMapHeader */
  914.  
  915.         switch( sourcetype )
  916.         {
  917.           case DTST_CLIPBOARD:
  918.           {
  919.               fid -> fid_LoadAll = TRUE; /* Cache all frames because we cannot load randomly from stream */
  920.  
  921.               iff = (struct IFFHandle *)fh;
  922.           }
  923.               break;
  924.  
  925.           case DTST_FILE:
  926.           {
  927.               BPTR iff_file_fh;
  928.  
  929.               iff = (struct IFFHandle *)fh;
  930.  
  931.               /* Attempt to open file from given stream (allows usage of virtual fs when using datatypes.library V45) */
  932.               iff_file_fh = (BPTR)(iff -> iff_Stream); /* see iffparse.library/InitIFFasDOS autodoc */
  933.  
  934.               if( iff_file_fh )
  935.               {
  936.                 BPTR lock;
  937.  
  938.                 if( lock = DupLockFromFH( iff_file_fh ) )
  939.                 {
  940.                   /* Set up a filehandle for disk-based loading (random loading) */
  941.                   if( !(fid -> fid_FH = (LONG)OpenFromLock( lock )) )
  942.                   {
  943.                     /* failure */
  944.                     UnLock( lock );
  945.                   }
  946.                 }
  947.               }
  948.  
  949.               /* OpenFromLock failed ? - Then open by name :-( */
  950.               if( (fid -> fid_FH) == NULL )
  951.               {
  952.                 /* Set up a filehandle for disk-based loading (random loading) */
  953.                 if( !(fid -> fid_FH = (LONG)Open( (fid -> fid_ProjectName), MODE_OLDFILE )) )
  954.                 {
  955.                   /* Can't open file */
  956.                   error = IoErr();
  957.                 }
  958.               }
  959.           }
  960.               break;
  961.  
  962.           case DTST_RAM:
  963.           {
  964.               /* No nothing... */
  965.           }
  966.               break;
  967.  
  968.           default:
  969.           {
  970.               /* unsupported source type */
  971.               error = ERROR_NOT_IMPLEMENTED;
  972.           }
  973.               break;
  974.         }
  975.  
  976.         /* Any error ? */
  977.         if( error == 0L )
  978.         {
  979.           /* Any handle to proccess ? */
  980.           if( iff )
  981.           {
  982.             struct StoredProperty *bmhdprop = NULL, /* ILBM BMHD (struct BitMapHeader)        */
  983.                                   *camgprop = NULL, /* ILBM CAMG (amiga view mode id)         */
  984.                                   *vhdrprop = NULL, /* 8SVX VHDR (struct VoiceHeader)         */
  985.                                   *chanprop = NULL; /* 8SVX CHAN (left/right/stereo channel)  */
  986.  
  987.             ULONG chan_channel = CHAN_RIGHT; /* or CHAN_LEFT - whatever you want, but only ONE channel */
  988.  
  989. #define NUM_PROPCHUNKS (4L)
  990.             const
  991.             LONG propchunks[ (NUM_PROPCHUNKS * 2) ] =
  992.             {
  993.               ID_ILBM, ID_BMHD,
  994.               ID_ILBM, ID_CAMG,
  995.               ID_8SVX, ID_VHDR,
  996.               ID_8SVX, ID_CHAN
  997.             };
  998.  
  999.             if( !(error = PropChunks( iff, (LONG *)propchunks, NUM_PROPCHUNKS )) )
  1000.             {
  1001. #define NUM_STOPCHUNKS (4L)
  1002.               const
  1003.               LONG stopchunks[ (NUM_STOPCHUNKS * 2) ] =
  1004.               {
  1005.                 ID_CELL, ID_CAT,
  1006.                 ID_ILBM, ID_BODY,
  1007.                 ID_ILBM, ID_CMAP,
  1008.                 ID_8SVX, ID_BODY
  1009.               };
  1010.  
  1011.               if( !(error = StopChunks( iff, (LONG *)stopchunks, NUM_STOPCHUNKS )) )
  1012.               {
  1013.                 struct FrameNode *fn = NULL;
  1014.  
  1015.                 /* Scan IFF stream until an error or an EOF occurs */
  1016.                 for( ;; )
  1017.                 {
  1018.                   struct ContextNode *cn;
  1019.  
  1020.                   if( error = ParseIFF( iff, IFFPARSE_SCAN ) )
  1021.                   {
  1022.                     /* EOF (End Of File) is no error here... */
  1023.                     if( error == IFFERR_EOF )
  1024.                     {
  1025.                       error = 0L;
  1026.                     }
  1027.  
  1028.                     break;
  1029.                   }
  1030.  
  1031.                   /* Get file position */
  1032.                   if( cn = CurrentChunk( iff ) )
  1033.                   {
  1034.                     pos = 0UL;
  1035.  
  1036.                     while( cn = ParentChunk( cn ) )
  1037.                     {
  1038.                       pos += cn -> cn_Scan;
  1039.                     }
  1040.                   }
  1041.  
  1042.                   /* bmhd header loaded ? */
  1043.                   if( bmhdprop == NULL )
  1044.                   {
  1045.                     if( bmhdprop = FindProp( iff, ID_ILBM, ID_BMHD ) )
  1046.                     {
  1047.                       *bmh = *((struct BitMapHeader *)(bmhdprop -> sp_Data));
  1048.  
  1049.                       animwidth  = bmh -> bmh_Width;
  1050.                       animheight = bmh -> bmh_Height;
  1051.                       animdepth  = bmh -> bmh_Depth;
  1052.  
  1053.                       /* ILBM BODY __must__ not be compressed for IFF FILM */
  1054.                       if( (bmh -> bmh_Compression) != cmpNone )
  1055.                       {
  1056.                         error = DTERROR_INVALID_DATA;
  1057.                       }
  1058.                     }
  1059.                   }
  1060.  
  1061.                   /* camg loaded ? */
  1062.                   if( camgprop == NULL )
  1063.                   {
  1064.                     if( camgprop = FindProp( iff, ID_ILBM, ID_CAMG ) )
  1065.                     {
  1066.                       modeid = *(ULONG *)(camgprop -> sp_Data);
  1067.  
  1068.                       /* Check for invalid flags */
  1069.                       if( (!(modeid & MONITOR_ID_MASK)) ||
  1070.                           ((modeid & EXTENDED_MODE) && (!(modeid & 0xFFFF0000UL))) )
  1071.                       {
  1072.                         /* Remove invalid flags (see include31:graphics/view.h) */
  1073.                         modeid &= ~(GENLOCK_VIDEO | PFBA | GENLOCK_AUDIO | DUALPF | EXTENDED_MODE | VP_HIDE | SPRITES);
  1074.                       }
  1075.  
  1076.                       /* Be safe ! */
  1077.                       if( (modeid & 0xFFFF0000UL) && (!(modeid & 0x00001000UL)) )
  1078.                       {
  1079.                         modeid = 0UL;
  1080.                       }
  1081.                     }
  1082.                   }
  1083.  
  1084.                   /* vhdr loaded ? */
  1085.                   if( vhdrprop == NULL )
  1086.                   {
  1087.                     if( vhdrprop = FindProp( iff, ID_8SVX, ID_VHDR ) )
  1088.                     {
  1089.                       struct VoiceHeader *vhdr = (struct VoiceHeader *)(vhdrprop -> sp_Data);
  1090.  
  1091.                       if( (vhdr -> vh_SamplesPerSec) == 0UL )
  1092.                       {
  1093.                         /* vh_SamplesPerSec must not be 0 */
  1094.                         error = DTERROR_INVALID_DATA;
  1095.                         break;
  1096.                       }
  1097.  
  1098.                       sps = vhdr -> vh_SamplesPerSec;
  1099.                     }
  1100.                   }
  1101.  
  1102.                   /* chan loaded ? */
  1103.                   if( chanprop == NULL )
  1104.                   {
  1105.                     if( chanprop = FindProp( iff, ID_8SVX, ID_CHAN ) )
  1106.                     {
  1107.                       chan_channel = *(ULONG *)(chanprop -> sp_Data);
  1108.  
  1109.                       if( (chan_channel != CHAN_RIGHT) &&
  1110.                           (chan_channel != CHAN_LEFT)  &&
  1111.                           (chan_channel != CHAN_STEREO) )
  1112.                       {
  1113.                         /* unsupported 8SVX/CHAN channel ID, use the default */
  1114.                         chan_channel = CHAN_RIGHT; /* or CHAN_LEFT, see upstairs */
  1115.                       }
  1116.                     }
  1117.                   }
  1118.  
  1119.                   if( cn = CurrentChunk( iff ) )
  1120.                   {
  1121.                     switch( (cn -> cn_Type) )
  1122.                     {
  1123.                       /* New IFF FILM CELL found */
  1124.                       case ID_CELL:
  1125.                       {
  1126.                           if( (cn -> cn_ID) == ID_CAT )
  1127.                           {
  1128.                             /* Move previous cell into frame list */
  1129.                             if( fn )
  1130.                             {
  1131.                               AddTail( (struct List *)(&(fid -> fid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  1132.                             }
  1133.  
  1134.                             /* Create an prepare a new frame node */
  1135.                             if( fn = AllocFrameNode( cb, (fid -> fid_Pool) ) )
  1136.                             {
  1137.                               fn -> fn_TimeStamp = timestamp++;
  1138.                               fn -> fn_Frame     = fn -> fn_TimeStamp;
  1139.                             }
  1140.                             else
  1141.                             {
  1142.                               /* can't alloc frame node */
  1143.                               error = ERROR_NO_FREE_STORE;
  1144.                             }
  1145.                           }
  1146.                       }
  1147.                           break;
  1148.  
  1149.                       case ID_ILBM:
  1150.                       {
  1151.                           switch( cn -> cn_ID )
  1152.                           {
  1153.                             case ID_CMAP:
  1154.                             {
  1155.                                 UBYTE *buff;
  1156.  
  1157.                                 /* Allocate buffer */
  1158.                                 if( buff = (UBYTE *)AllocVecPooled( cb, (fid -> fid_Pool), ((cn -> cn_Size) + 16UL) ) )
  1159.                                 {
  1160.                                   /* Load CMAP data */
  1161.                                   error = ReadChunkBytes( iff, buff, (cn -> cn_Size) );
  1162.  
  1163.                                   /* All read ? */
  1164.                                   if( error == (cn -> cn_Size) )
  1165.                                   {
  1166.                                     error = 0L; /* Success ! */
  1167.  
  1168.                                     if( timestamp == 0UL )
  1169.                                     {
  1170.                                       if( !CMAP2Object( cb, o, buff, (cn -> cn_Size) ) )
  1171.                                       {
  1172.                                         /* can't alloc object's color table */
  1173.                                         error = ERROR_NO_FREE_STORE;
  1174.                                       }
  1175.                                     }
  1176.  
  1177.                                     /* Any failure ? */
  1178.                                     if( error == 0L )
  1179.                                     {
  1180.                                       if( fn )
  1181.                                       {
  1182.                                         if( fn -> fn_CMap = CMAP2ColorMap( cb, fid, buff, (cn -> cn_Size) ) )
  1183.                                         {
  1184.                                           numcmaps++;
  1185.                                         }
  1186.                                         else
  1187.                                         {
  1188.                                           /* no colormap */
  1189.                                           error = ERROR_NO_FREE_STORE;
  1190.                                         }
  1191.                                       }
  1192.                                     }
  1193.                                   }
  1194.  
  1195.                                   FreeVecPooled( cb, (fid -> fid_Pool), buff );
  1196.                                 }
  1197.                                 else
  1198.                                 {
  1199.                                   /* no load buff */
  1200.                                   error = ERROR_NO_FREE_STORE;
  1201.                                 }
  1202.                             }
  1203.                                 break;
  1204.  
  1205.                             case ID_BODY:
  1206.                             {
  1207.                                 if( fn )
  1208.                                 {
  1209.                                   /* Store position of BODY (pos points to the BODY ID) */
  1210.                                   fn -> fn_BMOffset = pos;
  1211.                                   fn -> fn_BMSize   = cn -> cn_Size;
  1212.  
  1213.                                   if( (fn -> fn_BitMap) == NULL )
  1214.                                   {
  1215.                                     /* Preload frames only if requested or if this is the key frame (first frame of anim) */
  1216.                                     if( (fid -> fid_LoadAll) || IsListEmpty( (struct List *)(&(fid -> fid_FrameList)) ) )
  1217.                                     {
  1218.                                       if( animwidth && animheight && animdepth )
  1219.                                       {
  1220.                                         if( fn -> fn_BitMap = AllocBitMapPooled( cb, animwidth, animheight, animdepth, (fid -> fid_Pool) ) )
  1221.                                         {
  1222.                                           (void)ReadChunkBytes( iff, (fn -> fn_BitMap -> Planes[ 0 ]), (cn -> cn_Size) );
  1223.                                         }
  1224.                                         else
  1225.                                         {
  1226.                                           /* no bitmap */
  1227.                                           error = ERROR_NO_FREE_STORE;
  1228.                                         }
  1229.                                       }
  1230.                                       else
  1231.                                       {
  1232.                                         /* no dimensions for bitmap (possibly a missing bmhd) */
  1233.                                         error = DTERROR_NOT_ENOUGH_DATA;
  1234.                                       }
  1235.                                     }
  1236.                                   }
  1237.                                   else
  1238.                                   {
  1239.                                     /* bitmap already loaded */
  1240.                                     error = DTERROR_INVALID_DATA;
  1241.                                   }
  1242.                                 }
  1243.                             }
  1244.                                 break;
  1245.                           }
  1246.                       }
  1247.                           break;
  1248.  
  1249.                       case ID_8SVX:
  1250.                       {
  1251.                           if( (cn -> cn_ID) == ID_BODY )
  1252.                           {
  1253.                             if( fn )
  1254.                             {
  1255.                               BYTE *buff;
  1256.                               ULONG bufflength = cn -> cn_Size;
  1257.  
  1258.                               /* Calc samples per frame (if not set previously)
  1259.                                * If sample data represents mono audio,
  1260.                                *     spf = length of sample data
  1261.                                * If sample data represents stereo audio (2 channels),
  1262.                                *     spf = (length of sample data) / 2
  1263.                                */
  1264.                               if( spf == 0UL )
  1265.                               {
  1266.                                 spf = ((chan_channel != CHAN_STEREO)?(cn -> cn_Size):((cn -> cn_Size) / 2UL));
  1267.                               }
  1268.  
  1269.                               if( buff = (BYTE *)AllocPooled( (fid -> fid_Pool), bufflength ) )
  1270.                               {
  1271.                                 (void)ReadChunkBytes( iff, buff, bufflength );
  1272.  
  1273.                                 if( chan_channel != CHAN_STEREO )
  1274.                                 {
  1275.                                   fn -> fn_Sample       = buff;
  1276.                                   fn -> fn_SampleLength = bufflength;
  1277.                                 }
  1278.                                 else
  1279.                                 {
  1280.                                   BYTE *sample;
  1281.                                   ULONG samplelength = bufflength / 2UL;
  1282.  
  1283.                                   if( sample = (BYTE *)AllocPooled( (fid -> fid_Pool), (samplelength + 4UL) ) )
  1284.                                   {
  1285.                                     UBYTE *left   = buff,
  1286.                                           *right  = buff + samplelength,
  1287.                                           *dest   = sample;
  1288.  
  1289.                                     ULONG  i = samplelength;
  1290.  
  1291.                                     /* Merge the two stereo channels together (quality loss !) */
  1292.                                     while( i-- )
  1293.                                     {
  1294.                                       *dest++ = (BYTE)((((WORD)(*left++)) + ((WORD)(*right++))) / 2);
  1295.                                     }
  1296.  
  1297.                                     fn -> fn_Sample       = sample;
  1298.                                     fn -> fn_SampleLength = samplelength;
  1299.                                   }
  1300.                                   else
  1301.                                   {
  1302.                                     /* no sample mem (stereo) */
  1303.                                     error = ERROR_NO_FREE_STORE;
  1304.                                   }
  1305.  
  1306.                                   FreePooled( (fid -> fid_Pool), buff, bufflength );
  1307.                                 }
  1308.                               }
  1309.                               else
  1310.                               {
  1311.                                 /* no sample mem mono (or stereo temp buffer) */
  1312.                                 error = ERROR_NO_FREE_STORE;
  1313.                               }
  1314.                             }
  1315.                             else
  1316.                             {
  1317.                               /* no fn while reading a 8SVX BODY */
  1318.                               error = ERROR_NO_FREE_STORE;
  1319.                             }
  1320.                           }
  1321.                       }
  1322.                           break;
  1323.                     }
  1324.                   }
  1325.  
  1326.                   /* on error: leave for-loop */
  1327.                   if( error )
  1328.                   {
  1329.                     break;
  1330.                   }
  1331.                 }
  1332.  
  1333.                 if( fn )
  1334.                 {
  1335.                   /* Move last cell into frame list */
  1336.                   AddTail( (struct List *)(&(fid -> fid_FrameList)), (struct Node *)(&(fn -> fn_Node)) );
  1337.                 }
  1338.               }
  1339.             }
  1340.  
  1341.             /* bmh, vh and all other required information available  ? */
  1342.             if( (bmhdprop == NULL) || (vhdrprop == NULL) || (sps == 0UL) || (spf == 0UL) )
  1343.             {
  1344.               error = DTERROR_INVALID_DATA;
  1345.             }
  1346.  
  1347.             /* Process colormaps */
  1348.             if( timestamp && (error == 0L) && numcmaps )
  1349.             {
  1350.               if( numcmaps == 1UL )
  1351.               {
  1352.                 /* We only have a global colormap and no colormap changes,
  1353.                  * delete first colormap (a colormap in the first frames indicates following
  1354.                  * colormap/palette changes)
  1355.                  */
  1356.                 struct FrameNode *firstnode = (struct FrameNode *)(fid -> fid_FrameList . mlh_Head);
  1357.  
  1358.                 if( firstnode -> fn_CMap )
  1359.                 {
  1360.                   FreeColorMap( (firstnode -> fn_CMap) );
  1361.                   firstnode -> fn_CMap = NULL;
  1362.                 }
  1363.               }
  1364.               else
  1365.               {
  1366.                 /* All frames must have a colormap, therefore we replicate the colormap
  1367.                  * from the previous colormap if one is missing
  1368.                  */
  1369.                 struct FrameNode *worknode,
  1370.                                  *nextnode;
  1371.                 struct ColorMap  *currcm = NULL;
  1372.  
  1373.                 verbose_printf( cb, fid, "Movie has a palette-per-frame\n" );
  1374.  
  1375.                 worknode = (struct FrameNode *)(fid -> fid_FrameList . mlh_Head);
  1376.  
  1377.                 while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1378.                 {
  1379.                   if( worknode -> fn_CMap )
  1380.                   {
  1381.                     /* Current node contains colormap, this are the colors for the following frames... */
  1382.                     currcm = worknode -> fn_CMap;
  1383.                   }
  1384.                   else
  1385.                   {
  1386.                     if( currcm )
  1387.                     {
  1388.                       /* Copy colormap from previous one... */
  1389.                       if( !(worknode -> fn_CMap = CopyColorMap( cb, currcm )) )
  1390.                       {
  1391.                         /* Can't copy/alloc colormap */
  1392.                         error = ERROR_NO_FREE_STORE;
  1393.                       }
  1394.                     }
  1395.                     else
  1396.                     {
  1397.                       verbose_printf( cb, fid, "scan/load: no colormap, can't copy it\n" );
  1398.                     }
  1399.                   }
  1400.  
  1401.                   worknode = nextnode;
  1402.                 }
  1403.               }
  1404.             }
  1405.  
  1406.             /* Any error ? */
  1407.             if( error == 0L )
  1408.             {
  1409.               struct FrameNode *firstfn; /* short cut to the first FrameNode */
  1410.  
  1411.               /* Set up fid_FirstFrameNode */
  1412.               if( firstfn = (struct FrameNode *)(fid -> fid_FrameList . mlh_Head) )
  1413.               {
  1414.                 /* Alloc interleaved bitmap as key bitmap  */
  1415.                 if( (fid -> fid_KeyBitMap) = AllocBitMap( animwidth, animheight, animdepth, (BMF_CLEAR | BMF_MINPLANES | BMF_INTERLEAVED), NULL ) )
  1416.                 {
  1417.                   /* Be sure that this is an interleaved bitmap */
  1418.                   if( GetBitMapAttr( (fid -> fid_KeyBitMap), BMA_FLAGS ) & BMF_INTERLEAVED )
  1419.                   {
  1420.                     ULONG clock = ((SysBase -> ex_EClockFrequency) * 5UL); /* amiga clock        */
  1421.                     ULONG fps;                                             /* frames per second  */
  1422.                     ULONG ticksperframe;
  1423.                     ULONG period;
  1424.  
  1425.                     /* Calc sample period (clock / samples_per_second) */
  1426.                     period = clock / sps;
  1427.  
  1428.                     /* Calc samples per second */
  1429.                     sps = clock / period;
  1430.  
  1431.                     /* Calc FPS */
  1432.                     fps = (sps + (spf / 2UL)) / spf; /* (samples per second) / (samples per frame) = (frames per second) (rounded !) */
  1433.  
  1434.                     /* Calc tickspersecond (in RealTime.library's 1200 units)  */
  1435.                     ticksperframe = (TICK_FREQ * spf) / (sps + (spf / 2UL));
  1436.  
  1437.                     /* Other FPS set by prefs ? */
  1438.                     if( fid -> fid_FPS )
  1439.                     {
  1440.                       period = (period * fps) / (fid -> fid_FPS);
  1441.                     }
  1442.                     else
  1443.                     {
  1444.                       fid -> fid_FPS = fps;
  1445.                     }
  1446.  
  1447.                     fid -> fid_Period = period; /* Store period */
  1448.  
  1449.                     /* Assert: Be sure our FPS and period values are valid ! */
  1450.                     if( ((fid -> fid_FPS) == 0UL) || (period == 0UL) )
  1451.                     {
  1452.                       /* invalid fps or period */
  1453.                       error = DTERROR_INVALID_DATA;
  1454.                     }
  1455.                     else
  1456.                     {
  1457.                       if( firstfn -> fn_BitMap )
  1458.                       {
  1459.                         /* Copy first frame into key bitmap */
  1460.                         CopyBitMap( cb, (fid -> fid_KeyBitMap), (firstfn -> fn_BitMap) );
  1461.                       }
  1462.  
  1463.                       if( fid -> fid_ModeID )
  1464.                       {
  1465.                         modeid = fid -> fid_ModeID;
  1466.                       }
  1467.                       else
  1468.                       {
  1469.                         /* No mode id ? */
  1470.                         if( modeid == 0UL )
  1471.                         {
  1472.                           /* Get best modeid for this dimensions */
  1473.                           modeid = BestModeID( BIDTAG_NominalWidth,      animwidth,
  1474.                                                BIDTAG_NominalHeight,     animheight,
  1475.                                                BIDTAG_Depth,             animdepth,
  1476.                                                BIDTAG_DIPFMustNotHave,   (DIPF_IS_DUALPF | DIPF_IS_PF2PRI),
  1477.                                                TAG_DONE );
  1478.                         }
  1479.                       }
  1480.  
  1481.                       verbose_printf( cb, fid, "width %lu height %lu depth %lu frames %lu sps %lu spf %lu tpf %lu fps %lu volume %lu\n",
  1482.                                       animwidth,
  1483.                                       animheight,
  1484.                                       animdepth,
  1485.                                       timestamp,
  1486.                                       sps,
  1487.                                       spf,
  1488.                                       ticksperframe,
  1489.                                       (fid -> fid_FPS),
  1490.                                       (ULONG)(fid -> fid_Volume) );
  1491.  
  1492.                       /* Set misc attributes */
  1493.                       SetDTAttrs( o, NULL, NULL,
  1494.                                   DTA_ObjName,          (fid -> fid_ProjectName), /* BUG: Should be IFF NAME chunk, if available */
  1495.                                   DTA_TotalHoriz,       animwidth,
  1496.                                   DTA_TotalVert,        animheight,
  1497.                                   ADTA_ModeID,          modeid,
  1498.                                   ADTA_Width,           animwidth,
  1499.                                   ADTA_Height,          animheight,
  1500.                                   ADTA_Depth,           animdepth,
  1501.                                   ADTA_Frames,          timestamp,
  1502.                                   ADTA_FramesPerSecond, (fid -> fid_FPS),
  1503.                                   ADTA_KeyFrame,        (fid -> fid_KeyBitMap),
  1504.                                   ADTA_Sample,          (firstfn -> fn_Sample),
  1505.                                   ADTA_SampleLength,    (firstfn -> fn_SampleLength),
  1506.                                   ADTA_Period,          (fid -> fid_Period),
  1507.                                   ADTA_Volume,          (fid -> fid_Volume),
  1508.                                   ADTA_Cycles,          1UL,
  1509.                                   TAG_DONE );
  1510.                     }
  1511.                   }
  1512.                   else
  1513.                   {
  1514.                     /* can't alloc interleaved key bitmap
  1515.                      * (not enought memory to allocate continous memory, AllocBitMap allocated a non-interleaved one)
  1516.                      */
  1517.                     error = ERROR_NO_FREE_STORE;
  1518.                   }
  1519.                 }
  1520.                 else
  1521.                 {
  1522.                   /* can't alloc key bitmap */
  1523.                   error = ERROR_NO_FREE_STORE;
  1524.                 }
  1525.               }
  1526.               else
  1527.               {
  1528.                 /* not enougth frames (at least one required) */
  1529.                 error = DTERROR_NOT_ENOUGH_DATA;
  1530.               }
  1531.             }
  1532.           }
  1533.           else
  1534.           {
  1535.             /* No iff handle ? - Be sure we got a DTST_RAM sourcetype */
  1536.             if( sourcetype != DTST_RAM )
  1537.             {
  1538.               /* No handle ! */
  1539.               error = ERROR_REQUIRED_ARG_MISSING;
  1540.             }
  1541.           }
  1542.         }
  1543.       }
  1544.       else
  1545.       {
  1546.         /* can't get required attributes from superclass */
  1547.         error = ERROR_OBJECT_WRONG_TYPE;
  1548.       }
  1549.     }
  1550.     else
  1551.     {
  1552.       /* no memory pool */
  1553.       error = ERROR_NO_FREE_STORE;
  1554.     }
  1555.  
  1556.     /* Error codes below 0 are related to the IFFParse.library functions */
  1557.     if( error < 0L )
  1558.     {
  1559.       /* convert IFFParse error to DOS error */
  1560.       error = ifferr2doserr[ (-error - 1) ];
  1561.     }
  1562.  
  1563.     return( error );
  1564. }
  1565.  
  1566.  
  1567. static
  1568. struct FrameNode *AllocFrameNode( struct ClassBase *cb, APTR pool )
  1569. {
  1570.     struct FrameNode *fn;
  1571.  
  1572.     if( fn = (struct FrameNode *)AllocPooled( pool, (ULONG)sizeof( struct FrameNode ) ) )
  1573.     {
  1574.       memset( fn, 0, sizeof( struct FrameNode ) );
  1575.     }
  1576.  
  1577.     return( fn );
  1578. }
  1579.  
  1580.  
  1581. /* Find a frame node with exact matching by timestamp
  1582.  * We would need here the nearest-match method if we have dynamic timing
  1583.  * (IFF FILM does not have dynamic timing, therefore this is not needed).
  1584.  *
  1585.  * The follwoing code (from anim.datatype V1.11) does this nearest-timestamp
  1586.  * search:
  1587.  *
  1588.  *     if( fnl )
  1589.  *     {
  1590.  *       struct FrameNode *worknode,
  1591.  *                        *nextnode,
  1592.  *                        *prevnode;
  1593.  *
  1594.  *       prevnode = worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1595.  *
  1596.  *       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1597.  *       {
  1598.  *         if( (worknode -> fn_TimeStamp) > timestamp )
  1599.  *         {
  1600.  *           return( prevnode );
  1601.  *         }
  1602.  *
  1603.  *         prevnode = worknode;
  1604.  *         worknode = nextnode;
  1605.  *       }
  1606.  *
  1607.  *       if( !IsListEmpty( ((struct List *)fnl) ) )
  1608.  *       {
  1609.  *         return( prevnode );
  1610.  *       }
  1611.  *     }
  1612.  */
  1613.  
  1614. static
  1615. struct FrameNode *FindFrameNode( struct MinList *fnl, ULONG timestamp )
  1616. {
  1617.     if( fnl )
  1618.     {
  1619.       struct FrameNode *worknode,
  1620.                        *nextnode;
  1621.  
  1622.       worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1623.  
  1624.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1625.       {
  1626.         if( (worknode -> fn_TimeStamp) == timestamp )
  1627.         {
  1628.           return( worknode );
  1629.         }
  1630.  
  1631.         worknode = nextnode;
  1632.       }
  1633.     }
  1634.  
  1635.     return( NULL );
  1636. }
  1637.  
  1638.  
  1639. /* Free resources attached to a list of struct FrameNode's */
  1640. static
  1641. void FreeFrameNodeResources( struct ClassBase *cb, struct MinList *fnl )
  1642. {
  1643.     if( fnl )
  1644.     {
  1645.       struct FrameNode *worknode,
  1646.                        *nextnode;
  1647.  
  1648.       worknode = (struct FrameNode *)(fnl -> mlh_Head);
  1649.  
  1650.       while( nextnode = (struct FrameNode *)(worknode -> fn_Node . mln_Succ) )
  1651.       {
  1652.         if( worknode -> fn_CMap )
  1653.         {
  1654.           FreeColorMap( (worknode -> fn_CMap) );
  1655.           worknode -> fn_CMap = NULL;
  1656.         }
  1657.  
  1658.         worknode = nextnode;
  1659.       }
  1660.     }
  1661. }
  1662.  
  1663.  
  1664. /* Copy interleaved source to an interleaved destination */
  1665. static
  1666. void CopyBitMap( struct ClassBase *cb, struct BitMap *dest, struct BitMap *src )
  1667. {
  1668.     if( dest && src )
  1669.     {
  1670.       ULONG planesize = (ULONG)(dest -> BytesPerRow) * (ULONG)(dest -> Rows);
  1671.  
  1672.       CopyMem( (src -> Planes[ 0 ]), (dest -> Planes[ 0 ]), planesize );
  1673.     }
  1674. }
  1675.  
  1676.  
  1677. /* Create an interleaved bitmap, which matches the layout of a single IFF ILBM BODY, 
  1678.  * that we can load the frame directly into this bitmap
  1679.  */
  1680. static
  1681. struct BitMap *AllocBitMapPooled( struct ClassBase *cb, ULONG width, ULONG height, ULONG depth, APTR pool )
  1682. {
  1683.     struct BitMap *bm;
  1684.     ULONG          planesize,
  1685.                    moredepthsize,
  1686.                    size;
  1687.  
  1688.     planesize      = (ULONG)RASSIZE( width, height );
  1689.     moredepthsize  = (depth > 8UL)?((depth - 8UL) * sizeof( PLANEPTR )):(0UL);
  1690.     size           = ((ULONG)sizeof( struct BitMap )) + moredepthsize + (planesize * depth) + 128UL;
  1691.  
  1692.     if( bm = (struct BitMap *)AllocVecPooled( cb, pool, size ) )
  1693.     {
  1694.       UWORD    pl;
  1695.       PLANEPTR plane;
  1696.       ULONG    BytesPerRow;
  1697.  
  1698.       InitBitMap( bm, depth, width, height );
  1699.  
  1700.       /* Modify bitmap's BytesPerRow to be an interleaved bitmap (BytesPerRow = BytesPerRow * Depth,
  1701.        * plane ptr's follows with old BytesPerRow offset)
  1702.        */
  1703.       BytesPerRow = bm -> BytesPerRow;
  1704.       bm -> BytesPerRow *= bm -> Depth;
  1705.  
  1706.       plane = ALIGN_QUADLONG( ((PLANEPTR)(bm + 1)) ); /* First plane follows struct BitMap */
  1707.  
  1708.       /* Set up plane data */
  1709.       pl = 0U;
  1710.  
  1711.       /* Set up plane ptrs */
  1712.       while( pl < depth )
  1713.       {
  1714.         bm -> Planes[ pl ] = plane;
  1715.  
  1716.         plane = (PLANEPTR)(((UBYTE *)plane) + BytesPerRow);
  1717.         pl++;
  1718.       }
  1719.  
  1720.       /* Clear the remaining plane ptrs */
  1721.       while( pl < 8U )
  1722.       {
  1723.         bm -> Planes[ pl ] = NULL;
  1724.  
  1725.         pl++;
  1726.       }
  1727.     }
  1728.  
  1729.     return( bm );
  1730. }
  1731.  
  1732.  
  1733. /* Store IFF ILBM CMAP into picture.datatype / animation.dataype object
  1734.  * (Does currently NOT check if the RGB-values are right-shifted (e.g. 4-bits-per-gun))
  1735.  */
  1736. static
  1737. BOOL CMAP2Object( struct ClassBase *cb, Object *o, UBYTE *rgb, ULONG rgbsize )
  1738. {
  1739.     struct ColorRegister *acm;
  1740.     ULONG                *acregs;
  1741.     ULONG                 nc;
  1742.  
  1743.     /* file has this many colors (e.g. each color has one byte per R,B,G-gun) */
  1744.     nc = rgbsize / 3UL;
  1745.  
  1746.     SetDTAttrs( o, NULL, NULL, ADTA_NumColors, nc, TAG_DONE );
  1747.  
  1748.     /* Get color context */
  1749.     if( GetDTAttrs( o,
  1750.                     ADTA_ColorRegisters, (&acm),
  1751.                     ADTA_CRegs,          (&acregs),
  1752.                     ADTA_NumColors,      (&nc),
  1753.                     TAG_DONE ) == 3UL )
  1754.     {
  1755.       /* All valid ? */
  1756.       if( acm && acregs && nc )
  1757.       {
  1758.         ULONG i;
  1759.  
  1760.         for( i = 0UL ; i < nc ; i++, acm++ )
  1761.         {
  1762.           acm -> red   =  *rgb++;
  1763.           acm -> green =  *rgb++;
  1764.           acm -> blue  =  *rgb++;
  1765.  
  1766.           /* Replicate the color information.
  1767.            * This surrounds an OS bug which uses the low-oreder bytes of the 32-bit colors
  1768.            * instead of the high order ones
  1769.            */
  1770.           acregs[ ((i * 3) + 0) ] = ((ULONG)(acm -> red))   * 0x01010101UL;
  1771.           acregs[ ((i * 3) + 1) ] = ((ULONG)(acm -> green)) * 0x01010101UL;
  1772.           acregs[ ((i * 3) + 2) ] = ((ULONG)(acm -> blue))  * 0x01010101UL;
  1773.         }
  1774.  
  1775.         return( TRUE );
  1776.       }
  1777.     }
  1778.  
  1779.     return( FALSE );
  1780. }
  1781.  
  1782.  
  1783. /* Store IFF ILBM CMAP into a ColorMap structure
  1784.  * (Does currently NOT check if the RGB-values are right-shifted (e.g. 4-bits-per-gun))
  1785.  */
  1786. static
  1787. struct ColorMap *CMAP2ColorMap( struct ClassBase *cb, struct FilmInstData *fid, UBYTE *rgb, ULONG rgbsize )
  1788. {
  1789.     struct ColorMap *cm;
  1790.     ULONG            a_nc   = (1UL << (ULONG)(fid -> fid_BMH -> bmh_Depth)); /* Number of colors in animation */
  1791.     ULONG            rgb_nc = rgbsize / 3UL;                                 /* Number of colors in CMAP      */
  1792.  
  1793.     /* Get a colormap which hold all colors */
  1794.     if( cm = GetColorMap( (long)MAX( a_nc, rgb_nc ) ) )
  1795.     {
  1796.       ULONG i,
  1797.             r, g, b;
  1798.  
  1799.       for( i = 0UL ; i < rgb_nc ; i++ )
  1800.       {
  1801.         r = *rgb++;
  1802.         g = *rgb++;
  1803.         b = *rgb++;
  1804.  
  1805.         /* Replicate color information (see CMAP2Object for details) and store them into colormap */
  1806.         SetRGB32CM( cm, i, (r * 0x01010101UL), (g * 0x01010101UL), (b * 0x01010101UL) );
  1807.       }
  1808.  
  1809.       /* BUG: the remaining entries should be filled with colors from the last colormap */
  1810.       for( ; i < a_nc ; i++ )
  1811.       {
  1812.         SetRGB32CM( cm, i, 0UL, 0UL, 0UL ); /* fill remaining entries with black */
  1813.       }
  1814.     }
  1815.  
  1816.     return( cm );
  1817. }
  1818.  
  1819.  
  1820. static
  1821. struct ColorMap *CopyColorMap( struct ClassBase *cb, struct ColorMap *src )
  1822. {
  1823.     struct ColorMap *dest = NULL;
  1824.  
  1825.     if( src )
  1826.     {
  1827.       ULONG *ctable;
  1828.  
  1829.       if( ctable = (ULONG *)AllocVec( ((ULONG)(src -> Count) * sizeof( ULONG ) * 3UL), MEMF_PUBLIC ) )
  1830.       {
  1831.         if( dest = GetColorMap( (long)(src -> Count) ) )
  1832.         {
  1833.           ULONG i;
  1834.  
  1835.           GetRGB32( src, 0UL, (ULONG)(src -> Count), ctable );
  1836.  
  1837.           for( i = 0UL ; i < (src -> Count) ; i++ )
  1838.           {
  1839.             SetRGB32CM( dest, i, ctable[ ((i * 3) + 0) ], ctable[ ((i * 3) + 1) ], ctable[ ((i * 3) + 2) ] );
  1840.           }
  1841.         }
  1842.  
  1843.         FreeVec( ctable );
  1844.       }
  1845.     }
  1846.  
  1847.     return( dest );
  1848. }
  1849.  
  1850.  
  1851. static
  1852. APTR AllocVecPooled( struct ClassBase *cb, APTR pool, ULONG memsize )
  1853. {
  1854.     ULONG *memory = NULL;
  1855.  
  1856.     if( pool && memsize )
  1857.     {
  1858.       memsize += (ULONG)sizeof( ULONG );
  1859.  
  1860.       if( memory = (ULONG *)AllocPooled( pool, memsize ) )
  1861.       {
  1862.         (*memory) = memsize;
  1863.  
  1864.         memory++;
  1865.       }
  1866.     }
  1867.  
  1868.     return( (APTR)memory );
  1869. }
  1870.  
  1871.  
  1872. static
  1873. void FreeVecPooled( struct ClassBase *cb, APTR pool, APTR mem )
  1874. {
  1875.     if( pool && mem )
  1876.     {
  1877.       ULONG *memory;
  1878.  
  1879.       memory = (ULONG *)mem;
  1880.  
  1881.       memory--;
  1882.  
  1883.       FreePooled( pool, memory, (*memory) );
  1884.     }
  1885. }
  1886.  
  1887.  
  1888. static
  1889. void verbose_printf( struct ClassBase *cb, struct FilmInstData *fid, STRPTR format, ... )
  1890. {
  1891.     if( fid -> fid_VerboseOutput )
  1892.     {
  1893.       VFPrintf( (fid -> fid_VerboseOutput), format, (APTR)((&format) + 1) );
  1894.     }
  1895. }
  1896.  
  1897.  
  1898. static
  1899. void OpenLogfile( struct ClassBase *cb, struct FilmInstData *fid )
  1900. {
  1901.     if( (fid -> fid_VerboseOutput) == NULL )
  1902.     {
  1903.       STRPTR confile;
  1904.  
  1905.       if( confile = (STRPTR)AllocVec( (((fid -> fid_ProjectName)?(strlen((fid -> fid_ProjectName) )):(0UL)) + 100UL), MEMF_PUBLIC ) )
  1906.       {
  1907.         mysprintf( cb, confile, "CON:////Film DataType %s/auto/wait/close/inactive",
  1908.                    ((fid -> fid_ProjectName)?(FilePart( (fid -> fid_ProjectName) )):(NULL)) );
  1909.  
  1910.         fid -> fid_VerboseOutput = Open( confile, MODE_READWRITE );
  1911.  
  1912.         FreeVec( confile );
  1913.       }
  1914.     }
  1915. }
  1916.  
  1917.  
  1918. static
  1919. void mysprintf( struct ClassBase *cb, STRPTR buffer, STRPTR fmt, ... )
  1920. {
  1921.     APTR args;
  1922.  
  1923.     args = (APTR)((&fmt) + 1);
  1924.  
  1925.     RawDoFmt( fmt, args, (void (*))"\x16\xc0\x4e\x75", buffer );
  1926. }
  1927.  
  1928.  
  1929. /* encoder entry */
  1930. static
  1931. ULONG SaveIFFFilm( struct ClassBase *cb, struct IClass *cl, Object *o, struct dtWrite *dtw )
  1932. {
  1933.     ULONG retval = 0UL;
  1934.     LONG  error  = 0L;
  1935.  
  1936.     /* A NULL file handle is a nop (GMultiView uses this to test if a datatype supports RAW writing) */
  1937.     if( dtw -> dtw_FileHandle )
  1938.     {
  1939.       struct FilmInstData *fid = (struct FilmInstData *)INST_DATA( cl, o );
  1940.  
  1941.       struct BitMapHeader *bmh;
  1942.       struct BitMap       *keyframe;
  1943.       ULONG                modeid;
  1944.       ULONG               *cregs;
  1945.       ULONG                numcolors;
  1946.       ULONG                samplelength,
  1947.                            period;
  1948.       ULONG                startframe = 0UL,
  1949.                            numframes  = 0UL,
  1950.                            framestep  = 1UL;
  1951.  
  1952.       if( GetDTAttrs( o, PDTA_BitMapHeader, (&bmh),
  1953.                          ADTA_ModeID,       (&modeid),
  1954.                          ADTA_CRegs,        (&cregs),
  1955.                          ADTA_NumColors,    (&numcolors),
  1956.                          ADTA_SampleLength, (&samplelength),
  1957.                          ADTA_Period,       (&period),
  1958.                          ADTA_Frame,        (&startframe),
  1959.                          ADTA_Frames,       (&numframes),
  1960.                          ADTA_KeyFrame,     (&keyframe),
  1961.                          TAG_DONE ) == 9UL )
  1962.       {
  1963.         struct TagItem *tstate,
  1964.                        *ti;
  1965.         BOOL            planar  = MAKEBOOL( GetBitMapAttr( keyframe, BMA_FLAGS ) & BMF_STANDARD );
  1966.  
  1967.         /* We only support planar planes as input */
  1968.         if( planar )
  1969.         {
  1970.           numframes -= startframe;
  1971.  
  1972.           tstate = dtw -> dtw_AttrList;
  1973.  
  1974.           while( ti = NextTagItem( (&tstate) ) )
  1975.           {
  1976.             switch( ti -> ti_Tag )
  1977.             {
  1978.               case ADTA_Frame:            startframe = ti -> ti_Data; break;
  1979.               case ADTA_Frames:           numframes  = ti -> ti_Data; break;
  1980.               case ADTA_FrameIncrement:   framestep  = ti -> ti_Data; break;
  1981.             }
  1982.           }
  1983.  
  1984.           if( framestep == 0UL ) framestep = 1UL;
  1985.  
  1986.           if( samplelength && period )
  1987.           {
  1988.             struct IFFHandle   *iff;
  1989.             struct VoiceHeader  vh;
  1990.  
  1991.             /* Set up voice header */
  1992.             vh . vh_OneShotHiSamples     = samplelength;
  1993.             vh . vh_RepeatHiSamples      = 0UL;
  1994.             vh . vh_SamplesPerHiCycle    = 0UL;
  1995.             vh . vh_SamplesPerSec        = ((SysBase -> ex_EClockFrequency) * 5UL) / period;
  1996.             vh . vh_Octaves              = 1UL;
  1997.             vh . vh_Compression          = CMP_NONE;
  1998.             vh . vh_Volume               = 0x10000UL; /* maximum volume */
  1999.  
  2000.             verbose_printf( cb, fid, "saving iff film %lu %lu %lu\n", startframe, numframes, framestep );
  2001.  
  2002.             if( iff = CreateDOSIFFHandle( cb, (dtw -> dtw_FileHandle) ) )
  2003.             {
  2004.               if( !(error = StartIFFFilm( cb, fid, iff, bmh, modeid, cregs, numcolors, (&vh) )) )
  2005.               {
  2006.                 struct adtFrame  alf;
  2007.                 ULONG            timestamp,
  2008.                                 *cmap_cregs = NULL;
  2009.  
  2010.                 /* Start scan through animation */
  2011.                 for( timestamp = startframe ; numframes > 0UL ; timestamp += framestep, numframes-- )
  2012.                 {
  2013.                   /* On error break */
  2014.                   if( error )
  2015.                   {
  2016.                     break;
  2017.                   }
  2018.  
  2019.                   /* Check for CTRL_C signal... */
  2020.                   if( SetSignal( 0UL, 0UL ) & SIGBREAKF_CTRL_C )
  2021.                   {
  2022.                     error = ERROR_BREAK;
  2023.  
  2024.                     break;
  2025.                   }
  2026.  
  2027.                   /* reset method msg */
  2028.                   memset( (void *)(&alf), 0, sizeof( struct adtFrame ) );
  2029.  
  2030.                   /* load frame */
  2031.                   alf . MethodID = ADTM_LOADFRAME;
  2032.                   alf . alf_TimeStamp = timestamp;
  2033.                   alf . alf_Frame     = timestamp;
  2034.  
  2035.                   if( DoMethodA( o, (Msg)(&alf) ) == 0UL )
  2036.                   {
  2037.                     error = IoErr();
  2038.                     break;
  2039.                   }
  2040.  
  2041.                   /* print frame contents */
  2042.                   verbose_printf( cb, fid, "frame: timestamp %lu frame %lu duration %lu bitmap %lx cmap %lx sample %lx len %lu period %lu\n",
  2043.                           timestamp,
  2044.                           (alf . alf_Frame),
  2045.                           (alf . alf_Duration),
  2046.                           (alf . alf_BitMap),
  2047.                           (alf . alf_CMap),
  2048.                           (alf . alf_Sample),
  2049.                           (alf . alf_SampleLength),
  2050.                           (alf . alf_Period) );
  2051.  
  2052.                   if( alf . alf_CMap )
  2053.                   {
  2054.                     if( cmap_cregs = (ULONG *)AllocVec( (((sizeof( ULONG ) * 3UL) + 1UL) * numcolors), MEMF_PUBLIC ) )
  2055.                     {
  2056.                       GetRGB32( (alf . alf_CMap), 0UL, (numcolors - 1UL), cmap_cregs );
  2057.                     }
  2058.                     else
  2059.                     {
  2060.                       verbose_printf( cb, fid, "can't alloc dynamic palette buffer\n" );
  2061.                       error = ERROR_NO_FREE_STORE;
  2062.                     }
  2063.                   }
  2064.  
  2065.                   if( (alf . alf_BitMap) && (alf . alf_Sample) )
  2066.                   {
  2067.                     if( error = WriteIFFFilmCell( cb, iff, bmh, cmap_cregs, numcolors, (alf . alf_BitMap), (alf . alf_Sample), (alf . alf_SampleLength) ) )
  2068.                     {
  2069.                       verbose_printf( cb, fid, "error while writing IFF FILM, aborted\n" );
  2070.                     }
  2071.                   }
  2072.  
  2073.                   if( cmap_cregs )
  2074.                   {
  2075.                     FreeVec( cmap_cregs );
  2076.                     cmap_cregs = NULL;
  2077.                   }
  2078.  
  2079.                   alf . MethodID = ADTM_UNLOADFRAME;
  2080.                   DoMethodA( o, (Msg)(&alf) );
  2081.                 }
  2082.  
  2083.                 EndIFFFilm( cb, fid, iff );
  2084.  
  2085.                 if( error == 0L )
  2086.                 {
  2087.                   retval = 1UL; /* success ! */
  2088.                 }
  2089.               }
  2090.  
  2091.               FreeIFF( iff );
  2092.             }
  2093.           }
  2094.           else
  2095.           {
  2096.             verbose_printf( cb, fid, "no sound, can't save iff film\n" );
  2097.           }
  2098.         }
  2099.         else
  2100.         {
  2101.           /* Does not support non-planar bitmaps */
  2102.           error = ERROR_NOT_IMPLEMENTED;
  2103.         }
  2104.       }
  2105.       else
  2106.       {
  2107.         verbose_printf( cb, fid, "not enougth attributes\n" );
  2108.       }
  2109.     }
  2110.  
  2111.     /* Error codes below 0 are related to the IFFParse.library functions */
  2112.     if( error < 0L )
  2113.     {
  2114.       /* convert IFFParse error to DOS error */
  2115.       error = ifferr2doserr[ (-error - 1) ];
  2116.     }
  2117.     
  2118.     SetIoErr( error );
  2119.  
  2120.     return( retval );
  2121. }
  2122.  
  2123.  
  2124. static
  2125. struct IFFHandle *CreateDOSIFFHandle( struct ClassBase *cb, BPTR fh )
  2126. {
  2127.     struct IFFHandle *iff;
  2128.  
  2129.     if( iff = AllocIFF() )
  2130.     {
  2131.       iff -> iff_Stream = (ULONG)fh;
  2132.  
  2133.       InitIFFasDOS( iff );
  2134.     }
  2135.  
  2136.     return( iff );
  2137. }
  2138.  
  2139.  
  2140. static
  2141. LONG StartIFFFilm( struct ClassBase *cb, struct FilmInstData *fid, struct IFFHandle *iff, struct BitMapHeader *bmh, ULONG modeid, ULONG *cregs, ULONG numcolors, struct VoiceHeader *vh )
  2142. {
  2143.     LONG error;
  2144.  
  2145.     if( !(error = OpenIFF( iff, IFFF_WRITE )) )
  2146.     {
  2147.       for( ;; ) /* not a loop, used as a jump table */
  2148.       {
  2149.         if( error = PushChunk( iff, ID_FILM, ID_LIST, IFFSIZE_UNKNOWN ) )
  2150.           break;
  2151.  
  2152.         /* write ILBM props */
  2153.         {
  2154.           if( error = PushChunk( iff, ID_ILBM, ID_PROP, IFFSIZE_UNKNOWN ) )
  2155.             break;
  2156.  
  2157.           /* write ILBM BMHD (BitMapHeader) */
  2158.           {
  2159.             if( error = PushChunk( iff, 0UL, ID_BMHD, IFFSIZE_UNKNOWN ) )
  2160.              break;
  2161.  
  2162.             if( WriteChunkBytes( iff, (APTR)bmh, sizeof( struct BitMapHeader ) ) != sizeof( struct BitMapHeader ) )
  2163.             {
  2164.               error = IFFERR_WRITE;
  2165.               break;
  2166.             }
  2167.  
  2168.             if( error = PopChunk( iff ) )
  2169.               break;
  2170.           }
  2171.  
  2172.           /* write ILBM CMAP (global color map) */
  2173.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  2174.             break;
  2175.  
  2176.           /* write ILBM CAMG (amiga view mode) */
  2177.           {
  2178.             if( error = PushChunk( iff, 0UL, ID_CAMG, IFFSIZE_UNKNOWN ) )
  2179.               break;
  2180.  
  2181.             if( WriteChunkBytes( iff, (APTR)(&modeid), sizeof( ULONG ) ) != sizeof( ULONG ) )
  2182.             {
  2183.               error = IFFERR_WRITE;
  2184.               break;
  2185.             }
  2186.  
  2187.             if( error = PopChunk( iff ) )
  2188.               break;
  2189.           }
  2190.  
  2191.           if( error = PopChunk( iff ) )
  2192.             break;
  2193.         }
  2194.  
  2195.         /* write 8SVX props */
  2196.         {
  2197.           if( error = PushChunk( iff, ID_8SVX, ID_PROP, IFFSIZE_UNKNOWN ) )
  2198.             break;
  2199.  
  2200.           {
  2201.             /* write 8SVX VHDR (VoiceHeader) */
  2202.             {
  2203.               if( error = PushChunk( iff, 0UL, ID_VHDR, IFFSIZE_UNKNOWN ) )
  2204.                 break;
  2205.  
  2206.               if( WriteChunkBytes( iff, (APTR)vh, sizeof( struct VoiceHeader ) ) != sizeof( struct VoiceHeader ) )
  2207.               {
  2208.                 error = IFFERR_WRITE;
  2209.                 break;
  2210.               }
  2211.  
  2212.               if( error = PopChunk( iff ) )
  2213.                 break;
  2214.             }
  2215.           }
  2216.  
  2217.           /* a 8SVX CHAN chunk is missing here (animation.datatype does currently not support stereo sound)
  2218.            * subclasses like "film.datatype" may create "interleaved samples" to support this, maybe we've to
  2219.            * add a de-interleave-code here...
  2220.            */
  2221.           if( error = PopChunk( iff ) )
  2222.             break;
  2223.         }
  2224.  
  2225.         break; /* end of jump table */
  2226.       }
  2227.  
  2228.       /* All headers written successfully ? */
  2229.       if( error == 0L )
  2230.       {
  2231.         /* Success ! */
  2232.         return( 0L );
  2233.       }
  2234.  
  2235.       CloseIFF( iff );
  2236.     }
  2237.  
  2238.     return( error );
  2239. }
  2240.  
  2241.  
  2242. static
  2243. void EndIFFFilm( struct ClassBase *cb, struct FilmInstData *fid, struct IFFHandle *iff )
  2244. {
  2245.     if( iff )
  2246.     {
  2247.       LONG error;
  2248.  
  2249.       if( error = PopChunk( iff ) )
  2250.       {
  2251.         verbose_printf( cb, fid, "error while popping IFF FILM LIST %ld\n", error );
  2252.       }
  2253.  
  2254.       CloseIFF( iff );
  2255.  
  2256.       verbose_printf( cb, fid, "IFF FILM sucessfully created\n" );
  2257.     }
  2258. }
  2259.  
  2260.  
  2261. static
  2262. LONG WriteIFFFilmCell( struct ClassBase *cb, struct IFFHandle *iff, struct BitMapHeader *bmh, ULONG *cregs, ULONG numcolors, struct BitMap *bm, BYTE *sample, ULONG samplelength )
  2263. {
  2264.     LONG error;
  2265.  
  2266.     for( ;; ) /* not a loop, used as a jump-table */
  2267.     {
  2268.       if( error = PushChunk( iff, ID_CELL, ID_CAT, IFFSIZE_UNKNOWN ) )
  2269.         break;
  2270.  
  2271.       /* write FORM ILBM */
  2272.       {
  2273.         if( error = PushChunk( iff, ID_ILBM, ID_FORM, IFFSIZE_UNKNOWN ) )
  2274.           break;
  2275.  
  2276.         /* Palette change */
  2277.         if( cregs && numcolors )
  2278.         {
  2279.           if( error = PutILBMCMAP( cb, iff, cregs, numcolors ) )
  2280.             break;
  2281.         }
  2282.  
  2283.         /* Write ILBM BODY */
  2284.         if( error = PutILBMBody( cb, iff, bm, bmh ) )
  2285.           break;
  2286.  
  2287.         if( error = PopChunk( iff ) )
  2288.           break;
  2289.       }
  2290.  
  2291.       /* write FORM 8SVX */
  2292.       {
  2293.         if( error = PushChunk( iff, ID_8SVX, ID_FORM, IFFSIZE_UNKNOWN ) )
  2294.           break;
  2295.  
  2296.         /* Write 8SVX BODY */
  2297.         if( error = Put8SVXBody( cb, iff, sample, samplelength ) )
  2298.           break;
  2299.  
  2300.         if( error = PopChunk( iff ) )
  2301.           break;
  2302.       }
  2303.  
  2304.       if( error = PopChunk( iff ) )
  2305.         break;
  2306.  
  2307.       break; /* end of jump-table */
  2308.     }
  2309.  
  2310.     return( error );
  2311. }
  2312.  
  2313.  
  2314. static
  2315. LONG Put8SVXBody( struct ClassBase *cb, struct IFFHandle *iff, BYTE *sample, ULONG samplelength )
  2316. {
  2317.     LONG error;
  2318.  
  2319.     /* Write out a BODY chunk header */
  2320.     if( error = PushChunk( iff, NULL, ID_BODY, IFFSIZE_UNKNOWN ) )
  2321.       return( error );
  2322.  
  2323.     if( WriteChunkBytes( iff, sample, samplelength ) != samplelength )
  2324.       return( IFFERR_WRITE );
  2325.  
  2326.     /* Finish the chunk */
  2327.     error = PopChunk( iff );
  2328.  
  2329.     return( error );
  2330. }
  2331.  
  2332.  
  2333. /* write ILBM CMAP  */
  2334. static
  2335. LONG PutILBMCMAP( struct ClassBase *cb, struct IFFHandle *iff, ULONG *cregs, ULONG numcolors )
  2336. {
  2337.     long                 error;
  2338.     ULONG                i;
  2339.     struct ColorRegister cm;
  2340.  
  2341.     if( error = PushChunk( iff, 0UL, ID_CMAP, IFFSIZE_UNKNOWN ) )
  2342.       return( error );
  2343.  
  2344.     for( i = 0UL ; i < numcolors ; i++ )
  2345.     {
  2346.       /* reduce colors from 32 bits to cmap's 8 bit-per-gun */
  2347.       cm . red   = (UBYTE)(cregs[ ((i * 3) + 0) ] >> 24UL);
  2348.       cm . green = (UBYTE)(cregs[ ((i * 3) + 1) ] >> 24UL);
  2349.       cm . blue  = (UBYTE)(cregs[ ((i * 3) + 2) ] >> 24UL);
  2350.  
  2351.       /* Write R, B, G bytes */
  2352.       if( WriteChunkBytes( iff, (APTR)(&cm), 3UL ) != 3UL )
  2353.       {
  2354.         return( IFFERR_WRITE );
  2355.       }
  2356.     }
  2357.  
  2358.     return( PopChunk( iff ) );
  2359. }
  2360.  
  2361. /*****************************************************************************/
  2362.  
  2363. /* from IFF example code ("iffp/ilbm.h") */
  2364. #define RowBytes( w )     ((((w) + 15) >> 4) << 1)
  2365. #define RowBits( w )      ((((w) + 15) >> 4) << 4)
  2366.  
  2367.  
  2368. static
  2369. LONG PutILBMBody( struct ClassBase *cb, struct IFFHandle *iff, struct BitMap *bitmap, struct BitMapHeader *bmh )
  2370. {
  2371.     LONG     error;
  2372.     LONG     rowBytes        = bitmap -> BytesPerRow;           /* for source modulo only  */
  2373.     LONG     FileRowBytes    = RowBytes( (bmh -> bmh_Width) );  /* width to write in bytes */
  2374.     ULONG    planeCnt        = bmh -> bmh_Depth;                /* number of bit planes including mask */
  2375.     ULONG    iPlane,
  2376.              iRow;
  2377.     BYTE    *planes[ 24 ]; /* array of ptrs to planes & mask */
  2378.  
  2379.     /* Copy the ptrs to bit & mask planes into local array "planes" */
  2380.     for( iPlane = 0 ; iPlane < planeCnt; iPlane++ )
  2381.        planes[ iPlane ] = (BYTE *)(bitmap -> Planes[ iPlane ]);
  2382.  
  2383.     /* Write out a BODY chunk header */
  2384.     if( error = PushChunk( iff, 0L, ID_BODY, IFFSIZE_UNKNOWN ) )
  2385.       return( error );
  2386.  
  2387.     /* Write out the BODY contents */
  2388.     for( iRow = bmh -> bmh_Height ; iRow > 0 ; iRow-- )
  2389.     {
  2390.       for( iPlane = 0 ; iPlane < planeCnt ; iPlane++ )
  2391.       {
  2392.         /* Write next row.*/
  2393.         if( WriteChunkBytes( iff, planes[ iPlane ], FileRowBytes ) != FileRowBytes )
  2394.           return( IFFERR_WRITE );
  2395.  
  2396.         planes[ iPlane ] += rowBytes; /* Possibly skipping unused bytes */
  2397.       }
  2398.     }
  2399.  
  2400.     /* Finish the chunk */
  2401.     error = PopChunk( iff );
  2402.  
  2403.     return( error );
  2404. }
  2405.  
  2406.  
  2407.