home *** CD-ROM | disk | FTP | other *** search
/ The Best of Mecomp Multimedia 1 / Mecomp-CD.iso / amiga / datatypes / film_datatype / dispatch.c < prev    next >
C/C++ Source or Header  |  1997-04-18  |  84KB  |  2,509 lines

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