home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 3 / AACD03.BIN / AACD / Graphics / ViewILBM / Source / view.c < prev    next >
C/C++ Source or Header  |  1999-10-08  |  53KB  |  2,605 lines

  1. /*
  2.  * $Id: view.c 1.10 1999/10/08 10:55:20 olsen Exp olsen $
  3.  *
  4.  * :ts=4
  5.  *
  6.  * ViewILBM, by Olaf `Olsen' Barthel, public domain
  7.  *
  8.  * Postal address: Olaf Barthel
  9.  *                 Brabeckstr. 35
  10.  *                 30559 Hannover
  11.  *
  12.  *                 Federal Republic of Germany
  13.  *
  14.  * e-mail address: olsen@sourcery.han.de
  15.  */
  16.  
  17. #include "global.h"
  18.  
  19. #include "ViewILBM_rev.h"
  20.  
  21. /******************************************************************************/
  22.  
  23. enum
  24. {
  25.     ERR_BASE = 30000,
  26.  
  27.     ERR_NO_INTUITION,
  28.     ERR_NO_GRAPHICS,
  29.     ERR_NO_ICON,
  30.     ERR_NO_UTILITY,
  31.     ERR_NO_ASL,
  32.     ERR_NO_IFFPARSE,
  33.     ERR_NO_CYBERGFX,
  34.     ERR_NO_PORT,
  35.     ERR_NO_REQUEST,
  36.     ERR_NO_TIMER,
  37.     ERR_NO_MEMORY,
  38.     ERR_NO_WINDOW,
  39.     ERR_NO_SCREEN,
  40.     ERR_NO_ASL_REQUEST,
  41.  
  42.     ERR_IFF_BASE,
  43.     ERR_IFF_EOF,
  44.     ERR_IFF_EOC,
  45.     ERR_IFF_NOSCOPE,
  46.     ERR_IFF_NOMEM,
  47.     ERR_IFF_READ,
  48.     ERR_IFF_WRITE,
  49.     ERR_IFF_SEEK,
  50.     ERR_IFF_MANGLED,
  51.     ERR_IFF_SYNTAX,
  52.     ERR_IFF_NOTIFF,
  53.     ERR_IFF_NOHOOK,
  54.  
  55.     ERR_UNKNOWN_COMPRESSION,
  56.     ERR_NOT_IFF_ILBM,
  57.  
  58.     ERR_MODE_NOT_AVAILABLE,
  59.     ERR_DIM_TOO_BIG,
  60.     ERR_DIM_TOO_DEPTH,
  61.     ERR_DOUBLE_BUF_TOO_BIG,
  62.     ERR_CANT_OPEN_SCREEN,
  63.  
  64.     ERR_ABORTED,
  65. };
  66.  
  67. /******************************************************************************/
  68.  
  69. #define MILLION 1000000
  70.  
  71. /******************************************************************************/
  72.  
  73. #define MAX_FILENAME_LEN 256
  74. #define MAX_PATHNAME_LEN 512
  75.  
  76. /******************************************************************************/
  77.  
  78. typedef long            SWITCH;
  79. typedef unsigned char *    KEYWORD;
  80. typedef long *            NUMBER;
  81.  
  82. /******************************************************************************/
  83.  
  84. #define SAME (0)
  85. #define OK (0)
  86. #define DONT !
  87. #define NO !
  88. #define BUSY ((struct IORequest *)NULL)
  89.  
  90. /******************************************************************************/
  91.  
  92. #define NUM_ENTRIES(t) (sizeof(t) / sizeof(t[0]))
  93.  
  94. /******************************************************************************/
  95.  
  96. #define BRIGHTNESS(r,g,b) (((WORD)r) * 30 + ((WORD)g) * 59 + ((WORD)b) * 11) / 100
  97.  
  98. /******************************************************************************/
  99.  
  100. #define FLAG_IS_SET(x,f)    ((x & f) == f)
  101. #define FLAG_IS_CLEAR(x,f)    ((x & f) == 0)
  102.  
  103. #define CLEAR_FLAG(x,f)        (x &= ~(f))
  104. #define SET_FLAG(x,f)        (x |=  f)
  105.  
  106. /******************************************************************************/
  107.  
  108. /* Masking techniques */
  109. #define    mskNone        0
  110. #define    mskHasMask    1
  111.  
  112. /* Compression techniques */
  113. #define    cmpNone        0
  114. #define    cmpByteRun1    1
  115.  
  116. /* Bitmap header (BMHD) structure */
  117. struct BitMapHeader
  118. {
  119.     UWORD    bmh_Width;
  120.     UWORD    bmh_Height;
  121.     WORD    bmh_Left;
  122.     WORD    bmh_Top;
  123.     UBYTE    bmh_Depth;
  124.     UBYTE    bmh_Masking;
  125.     UBYTE    bmh_Compression;
  126.     UBYTE    bmh_Pad;
  127.     UWORD    bmh_Transparent;
  128.     UBYTE    bmh_XAspect;
  129.     UBYTE    bmh_YAspect;
  130.     WORD    bmh_PageWidth;
  131.     WORD    bmh_PageHeight;
  132. };
  133.  
  134. /******************************************************************************/
  135.  
  136. /* A "CRNG" chunk contains "color register range" information. It's used
  137.  * by Electronic Arts' Deluxe Paint program to identify a contiguous
  138.  * range of color registers for a "shade range" and color cycling. There
  139.  * can be zero or more CRNG chunks in an ILBM, but all should appear
  140.  * before the BODY chunk. Deluxe Paint normally writes 4 CRNG chunks
  141.  * in an ILBM when the user asks it to "Save Picture".
  142.  */
  143.  
  144. struct CRange
  145. {
  146.     WORD    counter;    /* Reserved for future use; store 0 here */
  147.     WORD    rate;        /* The field "rate" determines the speed at which the colors will step
  148.                          * when color cycling is on. The units are such that a rate of 60 steps
  149.                          * per second is represented as 214 = 16384. Slower rates can be obtained
  150.                          * by linear scaling: for 30 steps/second, rate = 8192; for 1 step/second,
  151.                          * rate = 16384/60, i.e. 273.
  152.                          */
  153.     WORD    active;        /* Nonzero means cycle the colors */
  154.     UBYTE    low,high;    /* The fields "low" and "high" indicate the range of color registers (color
  155.                          * numbers) selected by this CRange.
  156.                          */
  157. };
  158.  
  159. /* Commodore's Graphicraft program uses a similar chunk "CCRT" (for Color
  160.  * Cyling Range and Timing). This chunk contains a CycleInfo structure.
  161.  * This is pretty similar to a CRNG chunk. A program would probably only
  162.  * use one of these two methods of expressing color cycle data. You could
  163.  * write out both if you want to communicate this information to both
  164.  * Deluxe Paint and Graphicraft.
  165.  *
  166.  * A CCRT chunk expresses the color cycling rate as a number of seconds
  167.  * plus a number of microseconds.
  168.  */
  169.  
  170. struct CycleInfo
  171. {
  172.     WORD    direction;        /* 0 = don't cycle. -1 = cycle forwards (1, 2, 3).
  173.                              * 1 = cycle backwards (3, 2, 1)
  174.                              */
  175.     UBYTE    start,end;        /* Lower and upper color registers selected */
  176.     LONG    seconds;        /* # seconds between changing colors */
  177.     LONG    microseconds;    /* # microseconds between changing colors */
  178.     WORD    pad;            /* Reserved for future use; store 0 here */
  179. };
  180.  
  181. /******************************************************************************/
  182.  
  183. /* IFF types that may be in pictures */
  184. #define    ID_ILBM MAKE_ID('I','L','B','M')
  185. #define    ID_BMHD MAKE_ID('B','M','H','D')
  186. #define    ID_CMAP MAKE_ID('C','M','A','P')
  187. #define    ID_CAMG MAKE_ID('C','A','M','G')
  188. #define    ID_BODY MAKE_ID('B','O','D','Y')
  189. #define ID_CCRT MAKE_ID('C','C','R','T')
  190. #define ID_CRNG MAKE_ID('C','R','N','G')
  191.  
  192. /******************************************************************************/
  193.  
  194. #define MODIFY_RED6        0x20
  195. #define MODIFY_GREEN6    0x30
  196. #define MODIFY_BLUE6    0x10
  197. #define MODIFY_MASK6    0x30
  198. #define MODIFY_LUT6        0x00
  199.  
  200. #define MODIFY_RED8        0x80
  201. #define MODIFY_GREEN8    0xC0
  202. #define MODIFY_BLUE8    0x40
  203. #define MODIFY_MASK8    0xC0
  204. #define MODIFY_LUT8        0x00
  205.  
  206. /******************************************************************************/
  207.  
  208. #define PORTMASK(p)    (1L << ((struct MsgPort *)(p))->mp_SigBit)
  209. #define SPREAD(a)    (0x01010101 * (a))
  210.  
  211. /******************************************************************************/
  212.  
  213. struct ColorRegister
  214. {
  215.     UBYTE red, green, blue;
  216. };
  217.  
  218. /******************************************************************************/
  219.  
  220. struct CycleData
  221. {
  222.     struct Task *            cd_Task;
  223.     LONG                    cd_A4;
  224.     struct Task *            cd_Parent;
  225.     struct Screen *            cd_Screen;
  226.  
  227.     struct CRange            cd_Ranges[8];
  228.  
  229.     LONG                    cd_PaletteSize;
  230.     struct ColorRegister *    cd_OriginalPalette;
  231.     struct ColorRegister *    cd_CurrentPalette;
  232.  
  233.     BOOL                    cd_Cycling;
  234.     BOOL                    cd_IsEHB;
  235. };
  236.  
  237. /******************************************************************************/
  238.  
  239. STRPTR VersTag = VERSTAG;
  240.  
  241. /******************************************************************************/
  242.  
  243. struct Library * IntuitionBase;
  244. struct Library * GfxBase;
  245. struct Library * AslBase;
  246. struct Library * UtilityBase;
  247. struct Library * CyberGfxBase;
  248. struct Library * IFFParseBase;
  249. struct Library * IconBase;
  250.  
  251. /******************************************************************************/
  252.  
  253. struct MsgPort *        TimePort;
  254. struct timerequest *    TimeRequest;
  255. BOOL                    TimeTicking;
  256.  
  257. /******************************************************************************/
  258.  
  259. struct Screen *        Screen;
  260. struct Window *        Window;
  261. LONG                DisplayDepth;
  262. Object *            TransparentPointer;
  263.  
  264. /******************************************************************************/
  265.  
  266. BOOL    PrefCenter,
  267.         PrefQuiet,
  268.         PrefCycle,
  269.         PrefHAM,
  270.         PrefEHB;
  271. LONG    PrefWait,
  272.         PrefWaitAfterOpen;
  273.  
  274. /******************************************************************************/
  275.  
  276. VOID __asm ReadPlanarLine8(register __a0 struct BitMap * source,
  277.                            register __a1 UBYTE * line,
  278.                            register __d0 LONG interleave);
  279.  
  280. /******************************************************************************/
  281.  
  282. VOID
  283. CloseDisplay(VOID)
  284. {
  285.     if(Window != NULL)
  286.     {
  287.         CloseWindow(Window);
  288.         Window = NULL;
  289.     }
  290.  
  291.     if(Screen != NULL)
  292.     {
  293.         CloseScreen(Screen);
  294.         Screen = NULL;
  295.     }
  296.  
  297.     if(TransparentPointer != NULL)
  298.     {
  299.         DisposeObject(TransparentPointer);
  300.         TransparentPointer = NULL;
  301.     }
  302. }
  303.  
  304. ULONG *
  305. SetupPalette(UBYTE * palette,LONG numColours)
  306. {
  307.     STATIC ULONG LoadTable[1 + 256*3 + 1];
  308.  
  309.     ULONG * t = LoadTable;
  310.     LONG i,j;
  311.  
  312.     (*t++) = numColours << 16;
  313.  
  314.     for(i = 0 ; i < numColours ; i++)
  315.     {
  316.         for(j = 0 ; j < 3 ; j++)
  317.             (*t++) = SPREAD(*palette++);
  318.     }
  319.  
  320.     (*t) = 0;
  321.  
  322.     return(LoadTable);
  323. }
  324.  
  325. ERRORCODE
  326. OpenDisplay(
  327.     UWORD    width,
  328.     UWORD    height,
  329.     UWORD    depth,
  330.     UBYTE    backgroundColour,
  331.     UBYTE *    palette,
  332.     LONG    numColours)
  333. {
  334.     ERRORCODE error = OK;
  335.     ULONG displayID;
  336.  
  337.     displayID = BestCModeIDTags(
  338.         CYBRBIDTG_NominalWidth,        width,
  339.         CYBRBIDTG_NominalHeight,    height,
  340.         CYBRBIDTG_Depth,            depth,
  341.     TAG_DONE);
  342.  
  343.     if(displayID != INVALID_ID)
  344.     {
  345.         STATIC struct BitMap pointerBitMap;
  346.         STATIC UWORD blank[2];
  347.  
  348.         memset(blank,0,sizeof(blank));
  349.  
  350.         memset(&pointerBitMap,0,sizeof(pointerBitMap));
  351.         InitBitMap(&pointerBitMap,2,16,1);
  352.         pointerBitMap.Planes[0] = (PLANEPTR)&blank[0];
  353.         pointerBitMap.Planes[1] = (PLANEPTR)&blank[1];
  354.  
  355.         TransparentPointer = NewObject(NULL,POINTERCLASS,
  356.             POINTERA_BitMap,    &pointerBitMap,
  357.             POINTERA_WordWidth,    1,
  358.         TAG_DONE);
  359.         if(TransparentPointer != NULL)
  360.         {
  361.             ULONG colors32tag = TAG_IGNORE;
  362.             ULONG * colors32 = NULL;
  363.  
  364.             if(palette != NULL && numColours > 0 && depth <= 8)
  365.             {
  366.                 colors32tag = SA_Colors32;
  367.                 colors32 = SetupPalette(palette,numColours);
  368.             }
  369.  
  370.             Screen = OpenScreenTags(NULL,
  371.                 SA_DisplayID,    displayID,
  372.                 SA_Depth,        depth,
  373.                 SA_Quiet,        TRUE,
  374.                 SA_ShowTitle,    FALSE,
  375.                 SA_BackFill,    LAYERS_NOBACKFILL,
  376.                 SA_Interleaved,    TRUE,
  377.                 colors32tag,    colors32,
  378.             TAG_DONE);
  379.             if(Screen != NULL)
  380.             {
  381.                 DisplayDepth = depth;
  382.  
  383.                 Window = OpenWindowTags(NULL,
  384.                     WA_Width,            Screen->Width,
  385.                     WA_Height,            Screen->Height,
  386.                     WA_Left,            0,
  387.                     WA_Height,            0,
  388.                     WA_Backdrop,        TRUE,
  389.                     WA_Borderless,        TRUE,
  390.                     WA_RMBTrap,            TRUE,
  391.                     WA_SimpleRefresh,    TRUE,
  392.                     WA_NoCareRefresh,    TRUE,
  393.                     WA_IDCMP,            IDCMP_VANILLAKEY | IDCMP_MOUSEBUTTONS,
  394.                     WA_Activate,        TRUE,
  395.                     WA_CustomScreen,    Screen,
  396.                     WA_BackFill,        LAYERS_NOBACKFILL,
  397.                     WA_BusyPointer,        TRUE,
  398.                 TAG_DONE);
  399.                 if(Window != NULL)
  400.                 {
  401.                     if(depth == 24)
  402.                         SetRGB4(&Screen->ViewPort,0,0,0,0);
  403.  
  404.                     SetRast(Window->RPort,backgroundColour);
  405.     
  406.                     if(PrefWaitAfterOpen > 0)
  407.                         Delay(TICKS_PER_SECOND * PrefWaitAfterOpen);
  408.                 }
  409.                 else
  410.                 {
  411.                     error = ERR_NO_WINDOW;
  412.                 }
  413.             }
  414.             else
  415.             {
  416.                 error = ERR_NO_SCREEN;
  417.             }
  418.         }
  419.         else
  420.         {
  421.             error = ERROR_NO_FREE_STORE;
  422.         }
  423.     }
  424.     else
  425.     {
  426.         error = ERR_NO_SCREEN;
  427.     }
  428.  
  429.     if(error != OK)
  430.     {
  431.         CloseDisplay();
  432.     }
  433.  
  434.     return(error);
  435. }
  436.  
  437. /******************************************************************************/
  438.  
  439. VOID
  440. DivideRange(UBYTE * range,LONG rangesize,LONG numvalues,LONG maxvalue)
  441. {
  442.     LONG i,j,from,to,value;
  443.  
  444.     for(i = 0; i < numvalues; i++)
  445.     {
  446.         from = (i * rangesize) / numvalues;
  447.         to = ((i + 1) * rangesize) / numvalues;
  448.         value = (i * maxvalue) / (numvalues - 1);
  449.  
  450.         for(j = from ; j < to ; j++)
  451.             range[j] = value;
  452.     }
  453. }
  454.  
  455. /******************************************************************************/
  456.  
  457. enum
  458. {
  459.     PICTURETYPE_Planar,
  460.     PICTURETYPE_HAM6,
  461.     PICTURETYPE_HAM8,
  462.     PICTURETYPE_TrueColour
  463. };
  464.  
  465. struct BitPlaneData
  466. {
  467.     struct BitMap    bpd_Planes;
  468.     PLANEPTR        bpd_MorePlanes[16];
  469.  
  470.     struct BitMap    bpd_PlanesWithoutMask;
  471.  
  472.     struct BitMap    bpd_Red;
  473.     struct BitMap    bpd_Green;
  474.     struct BitMap    bpd_Blue;
  475.  
  476.     UBYTE *            bpd_PlaneZero;
  477.     UBYTE *            bpd_PlaneData[24];
  478.     UBYTE *            bpd_Pixels;
  479.  
  480.     UBYTE            bpd_Translation[256];
  481.  
  482.     LONG            bpd_Width;
  483.     LONG            bpd_PictureType;
  484. };
  485.  
  486. VOID
  487. DeleteBitPlaneData(struct BitPlaneData * bpd)
  488. {
  489.     if(bpd != NULL)
  490.     {
  491.         LONG i;
  492.  
  493.         FreeVec(bpd->bpd_PlaneZero);
  494.  
  495.         for(i = 0 ; i < 24 ; i++)
  496.             FreeVec(bpd->bpd_PlaneData[i]);
  497.  
  498.         FreeVec(bpd->bpd_Pixels);
  499.  
  500.         FreeVec(bpd);
  501.     }
  502. }
  503.  
  504. struct BitPlaneData *
  505. CreateBitPlaneData(struct BitMapHeader * bmh,ULONG viewModes)
  506. {
  507.     struct BitPlaneData * bpd;
  508.     LONG depth = bmh->bmh_Depth;
  509.     LONG bytesPerPixel;
  510.     LONG bytesPerRow;
  511.     LONG i;
  512.  
  513.     bpd = AllocVec(sizeof(*bpd),MEMF_ANY|MEMF_CLEAR);
  514.     if(bpd == NULL)
  515.     {
  516.         goto cleanup;
  517.     }
  518.  
  519.     if((depth > 8) && ((depth < 12) || (depth > 24) || (depth % 3) != 0))
  520.     {
  521.         goto cleanup;
  522.     }
  523.  
  524.     if((depth > 8) && (bmh->bmh_Masking != mskNone))
  525.     {
  526.         goto cleanup;
  527.     }
  528.  
  529.     if(depth > 8)
  530.     {
  531.         bpd->bpd_PictureType = PICTURETYPE_TrueColour;
  532.     }
  533.     else
  534.     {
  535.         if(FLAG_IS_SET(viewModes,HAM))
  536.         {
  537.             if(bmh->bmh_Depth == 6)
  538.                 bpd->bpd_PictureType = PICTURETYPE_HAM6;
  539.             else
  540.                 bpd->bpd_PictureType = PICTURETYPE_HAM8;
  541.         }
  542.         else
  543.         {
  544.             bpd->bpd_PictureType = PICTURETYPE_Planar;
  545.         }
  546.     }
  547.  
  548.     if(depth <= 8 && FLAG_IS_CLEAR(viewModes,HAM))
  549.         bytesPerPixel = 1;
  550.     else
  551.         bytesPerPixel = 3;
  552.  
  553.     bpd->bpd_Width = bmh->bmh_Width;
  554.  
  555.     InitBitMap(&bpd->bpd_PlanesWithoutMask,max(24,depth),bmh->bmh_Width,bmh->bmh_Height);    
  556.     InitBitMap(&bpd->bpd_Planes,8,bmh->bmh_Width,bmh->bmh_Height);
  557.  
  558.     InitBitMap(&bpd->bpd_Red,8,bmh->bmh_Width,bmh->bmh_Height);
  559.     InitBitMap(&bpd->bpd_Green,8,bmh->bmh_Width,bmh->bmh_Height);
  560.     InitBitMap(&bpd->bpd_Blue,8,bmh->bmh_Width,bmh->bmh_Height);
  561.  
  562.     bytesPerRow = bpd->bpd_Planes.BytesPerRow;
  563.  
  564.     bpd->bpd_PlaneZero = AllocVec(bytesPerRow,MEMF_ANY|MEMF_CLEAR);
  565.     if(bpd->bpd_PlaneZero == NULL)
  566.     {
  567.         goto cleanup;
  568.     }
  569.  
  570.     bpd->bpd_Pixels = AllocVec(((bmh->bmh_Width + 15) & ~15) * bytesPerPixel * 2,MEMF_ANY);
  571.     if(bpd->bpd_Pixels == NULL)
  572.     {
  573.         goto cleanup;
  574.     }
  575.  
  576.     for(i = 0 ; i < 24 ; i++)
  577.     {
  578.         bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneZero;
  579.     }
  580.  
  581.     for(i = 0 ; i < 8 ; i++)
  582.     {
  583.         bpd->bpd_PlanesWithoutMask.Planes[i] = bpd->bpd_PlaneZero;
  584.  
  585.         bpd->bpd_Red.Planes[i]        = bpd->bpd_PlaneZero;
  586.         bpd->bpd_Green.Planes[i]    = bpd->bpd_PlaneZero;
  587.         bpd->bpd_Blue.Planes[i]        = bpd->bpd_PlaneZero;
  588.     }
  589.  
  590.     if(depth <= 8)
  591.     {
  592.         for(i = 0 ; i < 9 ; i++)
  593.         {
  594.             bpd->bpd_PlaneData[i] = AllocVec(bytesPerRow,MEMF_ANY);
  595.             if(bpd->bpd_PlaneData[i] == NULL)
  596.             {
  597.                 goto cleanup;
  598.             }
  599.         }
  600.  
  601.         for(i = 0 ; i < depth ; i++)
  602.         {
  603.             bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneData[i];
  604.             bpd->bpd_PlanesWithoutMask.Planes[i] = bpd->bpd_PlaneData[i];
  605.         }
  606.  
  607.         if(bmh->bmh_Masking == mskHasMask)
  608.         {
  609.             bpd->bpd_Planes.Planes[depth] = bpd->bpd_PlaneData[depth];
  610.         }
  611.     }
  612.     else
  613.     {
  614.         LONG oneThird = depth / 3;
  615.  
  616.         for(i = 0 ; i < 24 ; i++)
  617.         {
  618.             bpd->bpd_PlaneData[i] = AllocVec(bytesPerRow,MEMF_ANY);
  619.             if(bpd->bpd_PlaneData[i] == NULL)
  620.             {
  621.                 goto cleanup;
  622.             }
  623.         }
  624.  
  625.         for(i = 0 ; i < depth ; i++)
  626.         {
  627.             bpd->bpd_Planes.Planes[i] = bpd->bpd_PlaneData[i];
  628.         }
  629.  
  630.         for(i = 0 ; i < oneThird ; i++)
  631.         {
  632.             bpd->bpd_Red.Planes[i]        = bpd->bpd_PlaneData[i];
  633.             bpd->bpd_Green.Planes[i]    = bpd->bpd_PlaneData[i + oneThird];
  634.             bpd->bpd_Blue.Planes[i]        = bpd->bpd_PlaneData[i + oneThird + oneThird];
  635.         }
  636.  
  637.         if(oneThird == 8)
  638.         {
  639.             for(i = 0 ; i < 256 ; i++)
  640.                 bpd->bpd_Translation[i] = i;
  641.         }
  642.         else
  643.         {
  644.             DivideRange(bpd->bpd_Translation,256,(1L << oneThird),255);
  645.         }
  646.     }
  647.  
  648.     return(bpd);
  649.  
  650.  cleanup:
  651.  
  652.     DeleteBitPlaneData(bpd);
  653.     return(NULL);
  654. }
  655.  
  656. /******************************************************************************/
  657.  
  658. VOID
  659. StopTimer(VOID)
  660. {
  661.     if(TimeTicking)
  662.     {
  663.         if(CheckIO((struct IORequest *)TimeRequest) == BUSY)
  664.             AbortIO((struct IORequest *)TimeRequest);
  665.  
  666.         WaitIO((struct IORequest *)TimeRequest);
  667.         TimeTicking = FALSE;
  668.  
  669.         SetSignal(0,PORTMASK(TimePort));
  670.     }
  671. }
  672.  
  673. VOID
  674. StartTimer(ULONG seconds,ULONG micros)
  675. {
  676.     StopTimer();
  677.  
  678.     TimeRequest->tr_node.io_Command    = TR_ADDREQUEST;
  679.     TimeRequest->tr_time.tv_secs    = seconds;
  680.     TimeRequest->tr_time.tv_micro    = micros;
  681.  
  682.     SetSignal(0,PORTMASK(TimePort));
  683.     SendIO((struct IORequest *)TimeRequest);
  684.  
  685.     TimeTicking = TRUE;
  686. }
  687.  
  688. /******************************************************************************/
  689.  
  690. VOID
  691. PutLine(LONG left,LONG top,BOOL doubleHorizontal,struct BitPlaneData * bpd,UBYTE * palette,ULONG viewModes)
  692. {
  693.     if(top < Screen->Height)
  694.     {
  695.         LONG lineLength;
  696.  
  697.         if(doubleHorizontal)
  698.             lineLength = 2 * bpd->bpd_Width;
  699.         else
  700.             lineLength = bpd->bpd_Width;
  701.  
  702.         if(lineLength > Screen->Width - left)
  703.             lineLength = Screen->Width - left;
  704.  
  705.         if(lineLength > 0)
  706.         {
  707.             LONG bytesPerPixel;
  708.             LONG format;
  709.  
  710.             if(bpd->bpd_PictureType == PICTURETYPE_Planar)
  711.             {
  712.                 format            = RECTFMT_LUT8;
  713.                 bytesPerPixel    = 1;
  714.             }
  715.             else
  716.             {
  717.                 format            = RECTFMT_RGB;
  718.                 bytesPerPixel    = 3;
  719.             }
  720.  
  721.             if(bpd->bpd_PictureType == PICTURETYPE_HAM6)
  722.             {
  723.                 UBYTE * t;
  724.                 UBYTE r,g,b;
  725.                 LONG colour,i;
  726.  
  727.                 ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,3);
  728.  
  729.                 r = g = b = 0;
  730.  
  731.                 t = bpd->bpd_Pixels;
  732.  
  733.                 for(i = 0 ; i < bpd->bpd_Width ; i++)
  734.                 {
  735.                     switch((*t) & MODIFY_MASK6)
  736.                     {
  737.                         case MODIFY_LUT6:
  738.  
  739.                             colour = (*t) & 15;
  740.  
  741.                             r = palette[colour * 3];
  742.                             g = palette[colour * 3 + 1];
  743.                             b = palette[colour * 3 + 2];
  744.  
  745.                             break;
  746.  
  747.                         case MODIFY_BLUE6:
  748.  
  749.                             colour = (*t) & 15;
  750.                             b = 0x11 * colour;
  751.                             break;
  752.  
  753.                         case MODIFY_RED6:
  754.  
  755.                             colour = (*t) & 15;
  756.                             r = 0x11 * colour;
  757.                             break;
  758.  
  759.                         case MODIFY_GREEN6:
  760.  
  761.                             colour = (*t) & 15;
  762.                             g = 0x11 * colour;
  763.                             break;
  764.                     }
  765.  
  766.                     (*t++) = r;
  767.                     (*t++) = g;
  768.                     (*t++) = b;
  769.                 }
  770.             }
  771.  
  772.             if(bpd->bpd_PictureType == PICTURETYPE_HAM8)
  773.             {
  774.                 UBYTE * t;
  775.                 UBYTE r,g,b;
  776.                 LONG colour,i;
  777.  
  778.                 ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,3);
  779.  
  780.                 r = g = b = 0;
  781.  
  782.                 t = bpd->bpd_Pixels;
  783.  
  784.                 for(i = 0 ; i < bpd->bpd_Width ; i++)
  785.                 {
  786.                     switch((*t) & MODIFY_MASK8)
  787.                     {
  788.                         case MODIFY_LUT8:
  789.  
  790.                             colour = (*t) & 63;
  791.  
  792.                             r = palette[colour * 3];
  793.                             g = palette[colour * 3 + 1];
  794.                             b = palette[colour * 3 + 2];
  795.  
  796.                             break;
  797.  
  798.                         case MODIFY_BLUE8:
  799.  
  800.                             colour = (*t) & 63;
  801.                             b = (colour << 2) | (colour >> 4);
  802.                             break;
  803.  
  804.                         case MODIFY_RED8:
  805.  
  806.                             colour = (*t) & 63;
  807.                             r = (colour << 2) | (colour >> 4);
  808.                             break;
  809.  
  810.                         case MODIFY_GREEN8:
  811.  
  812.                             colour = (*t) & 63;
  813.                             g = (colour << 2) | (colour >> 4);
  814.                             break;
  815.                     }
  816.  
  817.                     (*t++) = r;
  818.                     (*t++) = g;
  819.                     (*t++) = b;
  820.                 }
  821.             }
  822.  
  823.             if(bpd->bpd_PictureType == PICTURETYPE_Planar)
  824.             {
  825.                 ReadPlanarLine8(&bpd->bpd_Planes,bpd->bpd_Pixels,1);
  826.             }
  827.  
  828.             if(bpd->bpd_PictureType == PICTURETYPE_TrueColour)
  829.             {
  830.                 UBYTE * t;
  831.                 LONG i;
  832.  
  833.                 ReadPlanarLine8(&bpd->bpd_Red,bpd->bpd_Pixels,3);
  834.                 ReadPlanarLine8(&bpd->bpd_Green,bpd->bpd_Pixels+1,3);
  835.                 ReadPlanarLine8(&bpd->bpd_Blue,bpd->bpd_Pixels+2,3);
  836.  
  837.                 for(t = bpd->bpd_Pixels, i = 0 ; i < 3*lineLength ; i++, t++)
  838.                 {
  839.                     (*t) = bpd->bpd_Translation[(*t)];
  840.                 }
  841.             }
  842.  
  843.             if(doubleHorizontal)
  844.             {
  845.                 LONG total = 2 * bpd->bpd_Width;
  846.  
  847.                 if(bytesPerPixel == 1)
  848.                 {
  849.                     UBYTE * src;
  850.                     UBYTE * dst;
  851.                     LONG i;
  852.  
  853.                     src = bpd->bpd_Pixels + bpd->bpd_Width - 1;
  854.                     dst = bpd->bpd_Pixels + total - 1;
  855.  
  856.                     for(i = 0 ; i < bpd->bpd_Width ; i++)
  857.                         (*dst--) = (*dst--) = (*src--);
  858.                 }
  859.                 else
  860.                 {
  861.                     UBYTE * src;
  862.                     UBYTE * dst;
  863.                     LONG i;
  864.  
  865.                     src = bpd->bpd_Pixels + 3 * bpd->bpd_Width - 1;
  866.                     dst = bpd->bpd_Pixels + 3 * total - 1;
  867.  
  868.                     for(i = 0 ; i < bpd->bpd_Width ; i++)
  869.                     {
  870.                         (*dst--) = src[ 0];
  871.                         (*dst--) = src[-1];
  872.                         (*dst--) = src[-2];
  873.                         (*dst--) = (*src--);
  874.                         (*dst--) = (*src--);
  875.                         (*dst--) = (*src--);
  876.                     }
  877.                 }
  878.             }
  879.  
  880.             WritePixelArray(bpd->bpd_Pixels,0,0,lineLength * bytesPerPixel,Window->RPort,left,top,lineLength,1,format);
  881.         }
  882.     }
  883. }
  884.  
  885. /******************************************************************************/
  886.  
  887. STRPTR
  888. GetErrorString(ERRORCODE error)
  889. {
  890.     STATIC struct { LONG Code; STRPTR Name; } LocalErrors[] =
  891.     {
  892.         ERR_NO_INTUITION,        "Error opening intuition.library v39",
  893.         ERR_NO_GRAPHICS,        "Error opening graphics.library v39",
  894.         ERR_NO_UTILITY,            "Error opening utility.library v37",
  895.         ERR_NO_ICON,            "Error opening icon.library v37",
  896.         ERR_NO_ASL,                "Error opening asl.library v37",
  897.         ERR_NO_IFFPARSE,        "Error opening iffparse.library v40",
  898.         ERR_NO_CYBERGFX,        "Error opening cybergraphics.library v40",
  899.         ERR_NO_WINDOW,            "Error opening window",
  900.         ERR_NO_SCREEN,            "Error opening screen",
  901.         ERR_NO_MEMORY,            "Out of memory",
  902.  
  903.         ERR_NO_PORT,            "Error opening message port",
  904.         ERR_NO_REQUEST,            "Error allocating timer request",
  905.         ERR_NO_TIMER,            "Error opening timer.device",
  906.         ERR_NO_ASL_REQUEST,        "Error allocating file requester",
  907.         ERR_MODE_NOT_AVAILABLE,    "Requested screen mode is not available",
  908.         ERR_DIM_TOO_BIG,        "Requested screen size is too large",
  909.         ERR_DIM_TOO_DEPTH,        "Requested number of colours not available",
  910.         ERR_DOUBLE_BUF_TOO_BIG,    "Not enough memory for double-buffering",
  911.         ERR_CANT_OPEN_SCREEN,    "Background screen did not open",
  912.         ERR_UNKNOWN_COMPRESSION,"Unknown compression format",
  913.         ERR_NOT_IFF_ILBM,        "Not an IFF-ILBM file",
  914.  
  915.         ERR_IFF_EOF,            "Reached logical end of file",
  916.         ERR_IFF_EOC,            "About to leave context",
  917.         ERR_IFF_NOSCOPE,        "No valid scope for property",
  918.         ERR_IFF_NOMEM,            "Internal memory allocation failed",
  919.         ERR_IFF_READ,            "Stream read error",
  920.         ERR_IFF_WRITE,            "Stream write error",
  921.         ERR_IFF_SEEK,            "Stream seek error",
  922.         ERR_IFF_MANGLED,        "Data in file is corrupt",
  923.         ERR_IFF_SYNTAX,            "IFF syntax error",
  924.         ERR_IFF_NOTIFF,            "Not an IFF file",
  925.         ERR_IFF_NOHOOK,            "No call-back hook provided",
  926.  
  927.         0,                        NULL
  928.     };
  929.  
  930.     STRPTR result = NULL;
  931.     LONG i;
  932.  
  933.     for(i = 0 ; LocalErrors[i].Name != NULL ; i++)
  934.     {
  935.         if(LocalErrors[i].Code == error)
  936.         {
  937.             result = LocalErrors[i].Name;
  938.             break;
  939.         }
  940.     }
  941.  
  942.     if(result == NULL)
  943.     {
  944.         STATIC UBYTE buffer[256];
  945.  
  946.         Fault(error,NULL,buffer,sizeof(buffer));
  947.         result = buffer;
  948.     }
  949.  
  950.     return(result);
  951. }
  952.  
  953. VOID
  954. PrintErrorString(ERRORCODE error,STRPTR header)
  955. {
  956.     if(header != NULL)
  957.         Printf("%s: %s\n",header,GetErrorString(error));
  958.     else
  959.         Printf("%s\n",GetErrorString(error));
  960. }
  961.  
  962. /******************************************************************************/
  963.  
  964. ERRORCODE
  965. ProcessWindowInput(struct Window * window,struct CycleData * cd)
  966. {
  967.     struct IntuiMessage * message;
  968.     ERRORCODE error = OK;
  969.  
  970.     while((message = (struct IntuiMessage *)GetMsg(window->UserPort)) != NULL)
  971.     {
  972.         switch(message->Class)
  973.         {
  974.             case IDCMP_VANILLAKEY:
  975.  
  976.                 if(message->Code == '\33' || message->Code == '\3')
  977.                 {
  978.                     error = ERR_ABORTED;
  979.                 }
  980.                 else
  981.                 {
  982.                     if(message->Code == '\t')
  983.                     {
  984.                         if(cd != NULL)
  985.                         {
  986.                             if(cd->cd_Cycling)
  987.                             {
  988.                                 DisableCycling(cd);
  989.                                 ResetCycling(cd);
  990.                             }
  991.                             else
  992.                             {
  993.                                 EnableCycling(cd);
  994.                             }
  995.                         }
  996.                     }
  997.                     else
  998.                     {
  999.                         error = ERROR_BREAK;
  1000.                     }
  1001.                 }
  1002.  
  1003.                 break;
  1004.  
  1005.             case IDCMP_MOUSEBUTTONS:
  1006.  
  1007.                 if(message->Code == MENUDOWN)
  1008.                 {
  1009.                     error = ERR_ABORTED;
  1010.                 }
  1011.                 else
  1012.                 {
  1013.                     if(FLAG_IS_CLEAR(message->Code,IECODE_UP_PREFIX))
  1014.                         error = ERROR_BREAK;
  1015.                 }
  1016.  
  1017.                 break;
  1018.         }
  1019.  
  1020.         ReplyMsg((struct Message *)message);
  1021.     }
  1022.  
  1023.     return(error);
  1024. }
  1025.  
  1026. ERRORCODE
  1027. WaitForEvent(struct CycleData * cd)
  1028. {
  1029.     ERRORCODE error;
  1030.     ULONG signals;
  1031.  
  1032.     do
  1033.     {
  1034.         error = OK;
  1035.  
  1036.         signals = Wait(PORTMASK(Window->UserPort) | PORTMASK(TimePort) | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_F);
  1037.  
  1038.         if(FLAG_IS_SET(signals,PORTMASK(Window->UserPort)))
  1039.         {
  1040.             error = ProcessWindowInput(Window,cd);
  1041.         }
  1042.  
  1043.         if(FLAG_IS_SET(signals,PORTMASK(TimePort)))
  1044.         {
  1045.             break;
  1046.         }
  1047.  
  1048.         if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_C))
  1049.         {
  1050.             error = ERR_ABORTED;
  1051.         }
  1052.  
  1053.         if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_F))
  1054.         {
  1055.             ScreenToFront(Screen);
  1056.         }
  1057.     }
  1058.     while(error == OK);
  1059.  
  1060.     return(error);
  1061. }
  1062.  
  1063. /******************************************************************************/
  1064.  
  1065. STATIC LONG __asm
  1066. AsyncStreamHandler(
  1067.     register __a0 struct Hook *            hook,
  1068.     register __a2 struct IFFHandle *    iff,
  1069.     register __a1 struct IFFStreamCmd *    actionpkt)
  1070. {
  1071.     AsyncFile * stream;
  1072.     LONG nbytes,error;
  1073.     UBYTE * buf;
  1074.     LONG a4 = getreg(REG_A4);
  1075.  
  1076.     putreg(REG_A4,(LONG)hook->h_Data);
  1077.  
  1078.     stream    = (AsyncFile *)iff->iff_Stream;
  1079.     nbytes    = actionpkt->sc_NBytes;
  1080.     buf        = (UBYTE *)actionpkt->sc_Buf;
  1081.  
  1082.     switch(actionpkt->sc_Command)
  1083.     {
  1084.         case IFFCMD_READ:
  1085.  
  1086.             error = (ReadAsync(stream,buf,nbytes) != nbytes);
  1087.             break;
  1088.  
  1089.         case IFFCMD_SEEK:
  1090.  
  1091.             error = (SeekAsync(stream,nbytes,MODE_CURRENT) == -1);
  1092.             break;
  1093.  
  1094.         default:
  1095.  
  1096.             error = OK;
  1097.             break;
  1098.     }
  1099.  
  1100.     putreg(REG_A4,a4);
  1101.  
  1102.     return(error);
  1103. }
  1104.  
  1105. STATIC struct Hook AsyncStreamHook =
  1106. {
  1107.     {NULL},
  1108.     (HOOKFUNC)AsyncStreamHandler
  1109. };
  1110.  
  1111. /****************************************************************************/
  1112.  
  1113. VOID
  1114. CloseIFFFile(struct IFFHandle * iff)
  1115. {
  1116.     if(iff != NULL)
  1117.     {
  1118.         CloseIFF(iff);
  1119.         CloseAsync((AsyncFile *)iff->iff_Stream);
  1120.         FreeIFF(iff);
  1121.     }
  1122. }
  1123.  
  1124. struct IFFHandle *
  1125. OpenIFFFile(const STRPTR fileName)
  1126. {
  1127.     struct IFFHandle * iff;
  1128.  
  1129.     iff = AllocIFF();
  1130.     if(iff != NULL)
  1131.     {
  1132.         iff->iff_Stream = (ULONG)OpenAsync((STRPTR)fileName,MODE_READ,8192);
  1133.         if(iff->iff_Stream != NULL)
  1134.         {
  1135.             AsyncStreamHook.h_Data = (APTR)getreg(REG_A4);
  1136.  
  1137.             InitIFF(iff,IFFF_FSEEK | IFFF_RSEEK,&AsyncStreamHook);
  1138.  
  1139.             if(OpenIFF(iff,IFFF_READ) == OK)
  1140.                 return(iff);
  1141.  
  1142.             CloseAsync((AsyncFile *)iff->iff_Stream);
  1143.         }
  1144.  
  1145.         FreeIFF(iff);
  1146.     }
  1147.  
  1148.     return(NULL);
  1149. }
  1150.  
  1151. /******************************************************************************/
  1152.  
  1153. LONG
  1154. ReadPlanes(struct IFFHandle * iff,struct BitMap * bitmap,LONG numPlanes)
  1155. {
  1156.     LONG bytesPerRow = bitmap->BytesPerRow;
  1157.     LONG status;
  1158.     LONG i;
  1159.  
  1160.     for(i = 0 ; i < numPlanes ; i++)
  1161.     {
  1162.         status = ReadChunkBytes(iff,bitmap->Planes[i],bytesPerRow);
  1163.         if(status != bytesPerRow)
  1164.         {
  1165.             return(status);
  1166.         }
  1167.     }
  1168.  
  1169.     return(OK);
  1170. }
  1171.  
  1172. /******************************************************************************/
  1173.  
  1174. struct IFFCache
  1175. {
  1176.     struct IFFHandle *    ic_Handle;
  1177.     UBYTE                ic_Data[4096];
  1178.     UBYTE *                ic_Index;
  1179.     LONG                ic_BytesLeft;
  1180.     LONG                ic_BytesInCache;
  1181. };
  1182.  
  1183. VOID
  1184. DeleteIFFCache(struct IFFCache * ic)
  1185. {
  1186.     FreeVec(ic);
  1187. }
  1188.  
  1189. struct IFFCache *
  1190. CreateIFFCache(struct IFFHandle * iff,LONG bytesLeft)
  1191. {
  1192.     struct IFFCache * ic;
  1193.  
  1194.     ic = AllocVec(sizeof(*ic),MEMF_ANY);
  1195.     if(ic != NULL)
  1196.     {
  1197.         ic->ic_Handle        = iff;
  1198.         ic->ic_Index        = ic->ic_Data;
  1199.         ic->ic_BytesLeft    = bytesLeft;
  1200.         ic->ic_BytesInCache    = 0;
  1201.     }
  1202.  
  1203.     return(ic);
  1204. }
  1205.  
  1206. LONG
  1207. FillIFFCache(struct IFFCache * ic)
  1208. {
  1209.     LONG bytesToRead;
  1210.     LONG status = IFFERR_EOF;
  1211.  
  1212.     bytesToRead = min(ic->ic_BytesLeft,sizeof(ic->ic_Data));
  1213.     if(bytesToRead > 0)
  1214.     {
  1215.         status = ReadChunkBytes(ic->ic_Handle,ic->ic_Data,bytesToRead);
  1216.         if(status == bytesToRead)
  1217.         {
  1218.             status = OK;
  1219.  
  1220.             ic->ic_Index         = ic->ic_Data;
  1221.             ic->ic_BytesInCache     = bytesToRead;
  1222.             ic->ic_BytesLeft    -= bytesToRead;
  1223.         }
  1224.     }
  1225.  
  1226.     return(status);
  1227. }
  1228.  
  1229. LONG
  1230. GetIFFCache(struct IFFCache * ic,UBYTE * c)
  1231. {
  1232.     if(ic->ic_BytesInCache == 0)
  1233.     {
  1234.         LONG result;
  1235.  
  1236.         result = FillIFFCache(ic);
  1237.         if(result != OK)
  1238.         {
  1239.             return(result);
  1240.         }
  1241.     }
  1242.  
  1243.     (*c) = (*ic->ic_Index++);
  1244.     ic->ic_BytesInCache--;
  1245.  
  1246.     return(OK);
  1247. }
  1248.  
  1249. LONG
  1250. ReadIFFCache(struct IFFCache * ic,APTR mem,LONG bytesToRead)
  1251. {
  1252.     UBYTE * data = mem;
  1253.     LONG bytesRead = 0;
  1254.     LONG numBytes;
  1255.  
  1256.     while(bytesToRead > 0)
  1257.     {
  1258.         if(ic->ic_BytesInCache == 0)
  1259.         {
  1260.             LONG result;
  1261.  
  1262.             result = FillIFFCache(ic);
  1263.             if(result != OK)
  1264.             {
  1265.                 return(result);
  1266.             }
  1267.         }
  1268.  
  1269.         numBytes = min(bytesToRead,ic->ic_BytesInCache);
  1270.         memcpy(data,ic->ic_Index,numBytes);
  1271.  
  1272.         ic->ic_Index += numBytes;
  1273.         ic->ic_BytesInCache -= numBytes;
  1274.  
  1275.         bytesToRead -= numBytes;
  1276.         bytesRead += numBytes;
  1277.         data += numBytes;
  1278.     }
  1279.  
  1280.     return(bytesRead);
  1281. }
  1282.  
  1283. /******************************************************************************/
  1284.  
  1285. LONG
  1286. ReadByteRun1Planes(struct IFFCache * ic,struct BitMap * bitmap,LONG numPlanes)
  1287. {
  1288.     LONG status;
  1289.     PLANEPTR plane;
  1290.     LONG count,bytesNeeded,i;
  1291.     BYTE value;
  1292.  
  1293.     for(i = 0 ; i < numPlanes ; i++)
  1294.     {
  1295.         bytesNeeded = bitmap->BytesPerRow;
  1296.         plane = bitmap->Planes[i];
  1297.  
  1298.         while(bytesNeeded > 0)
  1299.         {
  1300.             status = GetIFFCache(ic,(UBYTE *)&value);
  1301.             if(status != OK)
  1302.             {
  1303.                 return(status);
  1304.             }
  1305.  
  1306.             if(value == -128)
  1307.             {
  1308.             }
  1309.             else if (value >= 0)
  1310.             {
  1311.                 count = ((LONG)value) + 1;
  1312.                 bytesNeeded -= count;
  1313.  
  1314.                 if(bytesNeeded < 0)
  1315.                 {
  1316.                     return(IFFERR_EOF);
  1317.                 }
  1318.  
  1319.                 status = ReadIFFCache(ic,plane,count);
  1320.                 if(status != count)
  1321.                 {
  1322.                     return(status);
  1323.                 }
  1324.  
  1325.                 plane += count;
  1326.             }
  1327.             else
  1328.             {
  1329.                 UBYTE c;
  1330.  
  1331.                 count = ((LONG)-value) + 1;
  1332.                 bytesNeeded -= count;
  1333.  
  1334.                 if(bytesNeeded < 0)
  1335.                 {
  1336.                     return(IFFERR_EOF);
  1337.                 }
  1338.  
  1339.                 status = GetIFFCache(ic,(UBYTE *)&c);
  1340.                 if(status != OK)
  1341.                 {
  1342.                     return(status);
  1343.                 }
  1344.  
  1345.                 while(--count >= 0)
  1346.                     (*plane++) = c;
  1347.             }
  1348.         }
  1349.     }
  1350.  
  1351.     return(OK);
  1352. }
  1353.  
  1354. /******************************************************************************/
  1355.  
  1356. ERRORCODE
  1357. ShowILBM(STRPTR fileName)
  1358. {
  1359.     STATIC LONG Stops[] =
  1360.     {
  1361.         ID_ILBM,ID_BMHD,
  1362.         ID_ILBM,ID_CMAP,
  1363.         ID_ILBM,ID_CAMG,
  1364.         ID_ILBM,ID_BODY,
  1365.         ID_ILBM,ID_CCRT,
  1366.         ID_ILBM,ID_CRNG
  1367.     };
  1368.  
  1369.     enum
  1370.     {
  1371.         HAVE_Nothing = 0,
  1372.         HAVE_BitMapHeader = 1,
  1373.         HAVE_ColorMap = 2,
  1374.         HAVE_CAMG = 4,
  1375.         HAVE_Body = 8
  1376.     };
  1377.  
  1378.     struct ContextNode * cn;
  1379.     ERRORCODE error = OK;
  1380.     struct IFFHandle * iff;
  1381.     LONG status;
  1382.     LONG have;
  1383.     struct BitMapHeader bmh;
  1384.     ULONG viewModes;
  1385.     UBYTE * palette;
  1386.     LONG paletteSize;
  1387.     struct BitPlaneData * bpd;
  1388.     struct IFFCache * ic;
  1389.     BOOL doubleVertical;
  1390.     BOOL doubleHorizontal;
  1391.     LONG verticalScale;
  1392.     LONG horizontalScale;
  1393.     LONG numCycleRanges;
  1394.     struct CRange cycleRanges[8];
  1395.     struct CycleInfo cycleInfo;
  1396.     struct CycleData * cd;
  1397.     LONG depth;
  1398.     BOOL done;
  1399.     LONG darkest;
  1400.  
  1401.     memset(&bmh,0,sizeof(bmh));
  1402.     viewModes = 0;
  1403.     palette = NULL;
  1404.     paletteSize = 0;
  1405.     have = HAVE_Nothing;
  1406.     bpd = NULL;
  1407.     ic = NULL;
  1408.     numCycleRanges = 0;
  1409.     cd = NULL;
  1410.     depth = 0;
  1411.  
  1412.     memset(cycleRanges,0,sizeof(cycleRanges));
  1413.  
  1414.     iff = OpenIFFFile(fileName);
  1415.     if(iff == NULL)
  1416.     {
  1417.         error = IoErr();
  1418.         goto cleanup;
  1419.     }
  1420.  
  1421.     status = StopChunks(iff,Stops,NUM_ENTRIES(Stops)/2);
  1422.     if(status != OK)
  1423.     {
  1424.         error = ERR_IFF_BASE - status;
  1425.         goto cleanup;
  1426.     }
  1427.  
  1428.     done = FALSE;
  1429.  
  1430.     while(NOT done && (status = ParseIFF(iff,IFFPARSE_SCAN)) == OK)
  1431.     {
  1432.         cn = CurrentChunk(iff);
  1433.  
  1434.         switch(cn->cn_ID)
  1435.         {
  1436.             case ID_BMHD:
  1437.  
  1438.                 status = ReadChunkBytes(iff,&bmh,sizeof(bmh));
  1439.                 if(status != sizeof(bmh))
  1440.                 {
  1441.                     error = ERR_IFF_BASE - status;
  1442.                     goto cleanup;
  1443.                 }
  1444.  
  1445.                 SET_FLAG(have,HAVE_BitMapHeader);
  1446.                 break;
  1447.  
  1448.             case ID_CMAP:
  1449.  
  1450.                 paletteSize = cn->cn_Size / 3;
  1451.  
  1452.                 FreeVec(palette);
  1453.  
  1454.                 palette = AllocVec(256 * 3,MEMF_ANY|MEMF_CLEAR|MEMF_PUBLIC);
  1455.                 if(palette == NULL)
  1456.                 {
  1457.                     error = ERROR_NO_FREE_STORE;
  1458.                     goto cleanup;
  1459.                 }
  1460.  
  1461.                 status = ReadChunkBytes(iff,palette,paletteSize * 3);
  1462.                 if(status != paletteSize * 3)
  1463.                 {
  1464.                     error = ERR_IFF_BASE - status;
  1465.                     goto cleanup;
  1466.                 }
  1467.  
  1468.                 SET_FLAG(have,HAVE_ColorMap);
  1469.                 break;
  1470.  
  1471.             case ID_CAMG:
  1472.  
  1473.                 status = ReadChunkBytes(iff,&viewModes,sizeof(viewModes));
  1474.                 if(status != sizeof(viewModes))
  1475.                 {
  1476.                     error = ERR_IFF_BASE - status;
  1477.                     goto cleanup;
  1478.                 }
  1479.  
  1480.                 SET_FLAG(have,HAVE_CAMG);
  1481.  
  1482.                 if(FLAG_IS_CLEAR(viewModes,MONITOR_ID_MASK) || (FLAG_IS_SET(viewModes,EXTENDED_MODE) && FLAG_IS_CLEAR(viewModes,0xFFFF0000)))
  1483.                 {
  1484.                     CLEAR_FLAG(viewModes,EXTENDED_MODE|SPRITES|GENLOCK_AUDIO|GENLOCK_VIDEO|VP_HIDE);
  1485.                 }
  1486.  
  1487.                 if(FLAG_IS_SET(viewModes,0xFFFF0000) && FLAG_IS_CLEAR(viewModes,0x00001000))
  1488.                 {
  1489.                     CLEAR_FLAG(have,HAVE_CAMG);
  1490.                 }
  1491.  
  1492.                 break;
  1493.  
  1494.             case ID_CRNG:
  1495.  
  1496.                 if(numCycleRanges < NUM_ENTRIES(cycleRanges))
  1497.                 {
  1498.                     status = ReadChunkBytes(iff,&cycleRanges[numCycleRanges],sizeof(struct CRange));
  1499.                     if(status != sizeof(struct CRange))
  1500.                     {
  1501.                         error = ERR_IFF_BASE - status;
  1502.                         goto cleanup;
  1503.                     }
  1504.  
  1505.                     numCycleRanges++;
  1506.                 }
  1507.  
  1508.                 break;
  1509.  
  1510.             case ID_CCRT:
  1511.  
  1512.                 if(numCycleRanges < NUM_ENTRIES(cycleRanges))
  1513.                 {
  1514.                     status = ReadChunkBytes(iff,&cycleInfo,sizeof(cycleInfo));
  1515.                     if(status != sizeof(cycleInfo))
  1516.                     {
  1517.                         error = ERR_IFF_BASE - status;
  1518.                         goto cleanup;
  1519.                     }
  1520.  
  1521.                     cycleRanges[numCycleRanges].rate    = 16384 / (cycleInfo.seconds * 60 + (cycleInfo.microseconds + 8334) / 16667);
  1522.                     cycleRanges[numCycleRanges].active    = -cycleInfo.direction;
  1523.                     cycleRanges[numCycleRanges].low        = cycleInfo.start;
  1524.                     cycleRanges[numCycleRanges].high    = cycleInfo.end;
  1525.  
  1526.                     numCycleRanges++;
  1527.                 }
  1528.  
  1529.                 break;
  1530.  
  1531.             case ID_BODY:
  1532.  
  1533.                 if(FLAG_IS_SET(have,HAVE_BitMapHeader))
  1534.                 {
  1535.                     SET_FLAG(have,HAVE_Body);
  1536.  
  1537.                     if(FLAG_IS_CLEAR(have,HAVE_CAMG))
  1538.                     {
  1539.                         if(bmh.bmh_Width >= 640)
  1540.                             SET_FLAG(viewModes,HIRES);
  1541.  
  1542.                         if(bmh.bmh_Height >= 400)
  1543.                             SET_FLAG(viewModes,LACE);
  1544.  
  1545.                         if(bmh.bmh_Depth == 6)
  1546.                         {
  1547.                             if(PrefEHB && NOT PrefHAM)
  1548.                                 SET_FLAG(viewModes,EXTRA_HALFBRITE);
  1549.                             else
  1550.                                 SET_FLAG(viewModes,HAM);
  1551.                         }
  1552.                     }
  1553.  
  1554.                     if(FLAG_IS_SET(viewModes,HIRES) && FLAG_IS_CLEAR(viewModes,LACE))
  1555.                     {
  1556.                         doubleVertical = TRUE;
  1557.                         verticalScale = 2;
  1558.                     }
  1559.                     else
  1560.                     {
  1561.                         doubleVertical = FALSE;
  1562.                         verticalScale = 1;
  1563.                     }
  1564.  
  1565.                     if(FLAG_IS_CLEAR(viewModes,HIRES) && FLAG_IS_SET(viewModes,LACE))
  1566.                     {
  1567.                         doubleHorizontal = TRUE;
  1568.                         horizontalScale = 2;
  1569.                     }
  1570.                     else
  1571.                     {
  1572.                         doubleHorizontal = FALSE;
  1573.                         horizontalScale = 1;
  1574.                     }
  1575.  
  1576.                     darkest = 0;
  1577.  
  1578.                     if(bmh.bmh_Depth <= 8 && FLAG_IS_CLEAR(viewModes,HAM))
  1579.                     {
  1580.                         LONG darkestValue;
  1581.                         LONG value;
  1582.                         LONG i;
  1583.  
  1584.                         darkestValue = BRIGHTNESS(palette[0],palette[1],palette[2]);
  1585.  
  1586.                         for(i = 1 ; i < paletteSize ; i++)
  1587.                         {
  1588.                             value = BRIGHTNESS(palette[3 * i + 0],palette[3 * i + 1],palette[3 * i + 2]);
  1589.                             if(value < darkestValue)
  1590.                             {
  1591.                                 darkest = i;
  1592.                                 darkestValue = value;
  1593.                             }
  1594.                         }
  1595.                     }
  1596.  
  1597.                     if(FLAG_IS_SET(viewModes,EXTRA_HALFBRITE) && bmh.bmh_Depth == 6)
  1598.                     {
  1599.                         UBYTE * from;
  1600.                         UBYTE * to;
  1601.                         LONG i;
  1602.  
  1603.                         from    = &palette[ 0 * 3];
  1604.                         to        = &palette[32 * 3];
  1605.  
  1606.                         for(i = 0 ; i < 32 ; i++)
  1607.                         {
  1608.                             (*to++) = (*from++) / 2;
  1609.                             (*to++) = (*from++) / 2;
  1610.                             (*to++) = (*from++) / 2;
  1611.                         }
  1612.  
  1613.                         paletteSize *= 2;
  1614.                     }
  1615.  
  1616.                     if(bmh.bmh_Depth <= 8)
  1617.                     {
  1618.                         depth = 8;
  1619.  
  1620.                         if(FLAG_IS_SET(viewModes,HAM))
  1621.                             depth = 24;
  1622.                     }
  1623.                     else
  1624.                     {
  1625.                         depth = 24;
  1626.                     }
  1627.  
  1628.                     bpd = CreateBitPlaneData(&bmh,viewModes);
  1629.                     if(bpd == NULL)
  1630.                     {
  1631.                         error = ERROR_NO_FREE_STORE;
  1632.                         goto cleanup;
  1633.                     }
  1634.  
  1635.                     if(PrefCenter && Screen != NULL)
  1636.                     {
  1637.                         if((bmh.bmh_PageWidth * horizontalScale) > Screen->Width || (bmh.bmh_PageHeight * verticalScale) > Screen->Height || depth != DisplayDepth)
  1638.                             CloseDisplay();
  1639.                     }
  1640.  
  1641.                     if(Screen != NULL)
  1642.                     {
  1643.                         SetRast(Window->RPort,darkest);
  1644.  
  1645.                         SetWindowPointer(Window,
  1646.                             WA_BusyPointer,TRUE,
  1647.                         TAG_DONE);
  1648.  
  1649.                         if(depth <= 8)
  1650.                             LoadRGB32(&Screen->ViewPort,SetupPalette(palette,paletteSize));
  1651.                     }
  1652.                     else
  1653.                     {
  1654.                         error = OpenDisplay(bmh.bmh_PageWidth * horizontalScale,bmh.bmh_PageHeight * verticalScale,depth,darkest,palette,paletteSize);
  1655.                     }
  1656.  
  1657.                     if(error == OK)
  1658.                     {
  1659.                         LONG LeftEdge,TopEdge,i;
  1660.                         LONG numPlanes;
  1661.  
  1662.                         if(bmh.bmh_Masking == mskHasMask)
  1663.                         {
  1664.                             numPlanes = bmh.bmh_Depth + 1;
  1665.                         }
  1666.                         else
  1667.                         {
  1668.                             numPlanes = bmh.bmh_Depth;
  1669.                         }
  1670.  
  1671.                         if(PrefCenter)
  1672.                         {
  1673.                             LeftEdge = (Screen->Width - (bmh.bmh_Width * horizontalScale)) / 2;
  1674.                             if(LeftEdge < 0)
  1675.                                 LeftEdge = 0;
  1676.     
  1677.                             TopEdge = (Screen->Height - (bmh.bmh_Height * verticalScale)) / 2;
  1678.                             if(TopEdge < 0)
  1679.                                 TopEdge = 0;
  1680.                         }
  1681.                         else
  1682.                         {
  1683.                             LeftEdge    = bmh.bmh_Left;
  1684.                             TopEdge        = bmh.bmh_Top;
  1685.                         }
  1686.     
  1687.                         if(bmh.bmh_Compression == cmpByteRun1)
  1688.                         {
  1689.                             ic = CreateIFFCache(iff,cn->cn_Size);
  1690.                             if(ic == NULL)
  1691.                             {
  1692.                                 error = ERROR_NO_FREE_STORE;
  1693.                                 goto cleanup;
  1694.                             }
  1695.  
  1696.                             for(i = 0 ; i < bmh.bmh_Height ; i++)
  1697.                             {
  1698.                                 if(CheckSignal(SIGBREAKF_CTRL_C))
  1699.                                 {
  1700.                                     error = ERR_ABORTED;
  1701.                                     break;
  1702.                                 }
  1703.  
  1704.                                 if(Window != NULL)
  1705.                                 {
  1706.                                     error = ProcessWindowInput(Window,NULL);
  1707.                                     if(error != OK)
  1708.                                     {
  1709.                                         break;
  1710.                                     }
  1711.                                 }
  1712.  
  1713.                                 status = ReadByteRun1Planes(ic,&bpd->bpd_Planes,numPlanes);
  1714.                                 if(status != OK)
  1715.                                 {
  1716.                                     break;
  1717.                                 }
  1718.  
  1719.                                 if(doubleVertical)
  1720.                                 {
  1721.                                     PutLine(LeftEdge,TopEdge+2*i,doubleHorizontal,bpd,palette,viewModes);
  1722.                                     PutLine(LeftEdge,TopEdge+2*i+1,doubleHorizontal,bpd,palette,viewModes);
  1723.                                 }
  1724.                                 else
  1725.                                 {
  1726.                                     PutLine(LeftEdge,TopEdge+i,doubleHorizontal,bpd,palette,viewModes);
  1727.                                 }
  1728.                             }
  1729.                         }
  1730.                         else if (bmh.bmh_Compression == cmpNone)
  1731.                         {
  1732.                             for(i = 0 ; i < bmh.bmh_Height ; i++)
  1733.                             {
  1734.                                 if(CheckSignal(SIGBREAKF_CTRL_C))
  1735.                                 {
  1736.                                     error = ERR_ABORTED;
  1737.                                     break;
  1738.                                 }
  1739.  
  1740.                                 if(Window != NULL)
  1741.                                 {
  1742.                                     error = ProcessWindowInput(Window,NULL);
  1743.                                     if(error != OK)
  1744.                                     {
  1745.                                         break;
  1746.                                     }
  1747.                                 }
  1748.  
  1749.                                 status = ReadPlanes(iff,&bpd->bpd_Planes,numPlanes);
  1750.                                 if(status != OK)
  1751.                                 {
  1752.                                     break;
  1753.                                 }
  1754.  
  1755.                                 if(doubleVertical)
  1756.                                 {
  1757.                                     PutLine(LeftEdge,TopEdge+2*i,doubleHorizontal,bpd,palette,viewModes);
  1758.                                     PutLine(LeftEdge,TopEdge+2*i+1,doubleHorizontal,bpd,palette,viewModes);
  1759.                                 }
  1760.                                 else
  1761.                                 {
  1762.                                     PutLine(LeftEdge,TopEdge+i,doubleHorizontal,bpd,palette,viewModes);
  1763.                                 }
  1764.                             }
  1765.                         }
  1766.                         else
  1767.                         {
  1768.                             error = ERR_UNKNOWN_COMPRESSION;
  1769.                             goto cleanup;
  1770.                         }
  1771.  
  1772.                         done = TRUE;
  1773.                     }
  1774.                 }
  1775.  
  1776.                 break;
  1777.         }
  1778.  
  1779.         if(cn->cn_Type != ID_ILBM)
  1780.         {
  1781.             error = ERR_NOT_IFF_ILBM;
  1782.             break;
  1783.         }
  1784.     }
  1785.  
  1786.     if(error == OK && status != OK)
  1787.     {
  1788.         if(status == IFFERR_EOF)
  1789.             error = OK;
  1790.         else
  1791.             error = ERR_IFF_BASE - status;
  1792.     }
  1793.  
  1794.     if(error == OK && FLAG_IS_CLEAR(have,HAVE_Body))
  1795.     {
  1796.         error = ERR_NOT_IFF_ILBM;
  1797.     }
  1798.  
  1799.     if(error == OK && Window != NULL)
  1800.     {
  1801.         SetWindowPointer(Window,
  1802.             WA_Pointer,TransparentPointer,
  1803.         TAG_DONE);
  1804.  
  1805.         if(PrefWait > 0)
  1806.             StartTimer(PrefWait,0);
  1807.  
  1808.         if(depth <= 8 && numCycleRanges > 0)
  1809.         {
  1810.             cd = CreateCycleData(Screen,(BOOL)(FLAG_IS_SET(viewModes,EXTRA_HALFBRITE) && bmh.bmh_Depth == 6),cycleRanges,palette,paletteSize);
  1811.  
  1812.             if(PrefCycle)
  1813.                 EnableCycling(cd);
  1814.         }
  1815.  
  1816.         error = WaitForEvent(cd);
  1817.         if(error == ERROR_BREAK)
  1818.             error = OK;
  1819.  
  1820.         StopTimer();
  1821.  
  1822.         if(NOT PrefCenter)
  1823.         {
  1824.             DeleteCycleData(cd);
  1825.             cd = NULL;
  1826.  
  1827.             CloseDisplay();
  1828.         }
  1829.     }
  1830.  
  1831.  cleanup:
  1832.  
  1833.     DeleteCycleData(cd);
  1834.  
  1835.     DeleteIFFCache(ic);
  1836.  
  1837.     CloseIFFFile(iff);
  1838.  
  1839.     DeleteBitPlaneData(bpd);
  1840.  
  1841.     FreeVec(palette);
  1842.  
  1843.     return(error);
  1844. }
  1845.  
  1846. /******************************************************************************/
  1847.  
  1848. STATIC VOID
  1849. CycleTask(VOID)
  1850. {
  1851.     struct Library * SysBase = *(struct Library **)4;
  1852.     struct Task * task = FindTask(NULL);
  1853.     struct CycleData * cd = task->tc_UserData;
  1854.     struct MsgPort * port;
  1855.     struct timerequest * tr;
  1856.  
  1857.     putreg(REG_A4,cd->cd_A4);
  1858.  
  1859.     port = CreateMsgPort();
  1860.     if(port != NULL)
  1861.     {
  1862.         tr = (struct timerequest *)CreateIORequest(port,sizeof(*tr));
  1863.         if(tr != NULL)
  1864.         {
  1865.             if(OpenDevice(TIMERNAME,UNIT_VBLANK,(struct IORequest *)tr,0) == OK)
  1866.             {
  1867.                 ULONG timerMask = (1UL << port->mp_SigBit);
  1868.                 BOOL ticking = FALSE;
  1869.                 BOOL start = FALSE;
  1870.                 ULONG signals;
  1871.                 BOOL reload;
  1872.                 LONG i;
  1873.  
  1874.                 cd->cd_Task = task;
  1875.  
  1876.                 Signal(cd->cd_Parent,SIGF_SINGLE);
  1877.  
  1878.                 FOREVER
  1879.                 {
  1880.                     signals = Wait(timerMask | SIGBREAKF_CTRL_C | SIGBREAKF_CTRL_D | SIGBREAKF_CTRL_E | SIGBREAKF_CTRL_F);
  1881.  
  1882.                     if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_C))
  1883.                         break;
  1884.  
  1885.                     if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_D))
  1886.                     {
  1887.                         cd->cd_Cycling = FALSE;
  1888.  
  1889.                         Signal(cd->cd_Parent,SIGF_SINGLE);
  1890.                     }
  1891.  
  1892.                     if(FLAG_IS_SET(signals,SIGBREAKF_CTRL_E))
  1893.                     {
  1894.                         cd->cd_Cycling = start = TRUE;
  1895.  
  1896.                         Signal(cd->cd_Parent,SIGF_SINGLE);
  1897.                     }
  1898.  
  1899.                     reload = FALSE;
  1900.  
  1901.                     if(FLAG_IS_SET(signals,timerMask) || start)
  1902.                     {
  1903.                         start = FALSE;
  1904.  
  1905.                         if(ticking)
  1906.                         {
  1907.                             WaitIO((struct IORequest *)tr);
  1908.                             ticking = FALSE;
  1909.                         }
  1910.  
  1911.                         if(cd->cd_Cycling)
  1912.                         {
  1913.                             for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
  1914.                             {
  1915.                                 if(cd->cd_Ranges[i].active != 0)
  1916.                                 {
  1917.                                     cd->cd_Ranges[i].counter += cd->cd_Ranges[i].rate;
  1918.                                     if(cd->cd_Ranges[i].counter >= 16384)
  1919.                                     {
  1920.                                         struct ColorRegister t;
  1921.                                         LONG j;
  1922.  
  1923.                                         cd->cd_Ranges[i].counter = 0;
  1924.  
  1925.                                         if(cd->cd_Ranges[i].active > 0)
  1926.                                         {
  1927.                                             t = cd->cd_CurrentPalette[cd->cd_Ranges[i].high];
  1928.  
  1929.                                             for(j = cd->cd_Ranges[i].high ; j > cd->cd_Ranges[i].low ; j--)
  1930.                                                 cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j-1];
  1931.  
  1932.                                             cd->cd_CurrentPalette[cd->cd_Ranges[i].low] = t;
  1933.  
  1934.                                             if(cd->cd_IsEHB)
  1935.                                             {
  1936.                                                 t = cd->cd_CurrentPalette[cd->cd_Ranges[i].high + 31];
  1937.  
  1938.                                                 for(j = cd->cd_Ranges[i].high + 31 ; j > cd->cd_Ranges[i].low + 31 ; j--)
  1939.                                                     cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j-1];
  1940.  
  1941.                                                 cd->cd_CurrentPalette[cd->cd_Ranges[i].low + 31] = t;
  1942.                                             }
  1943.                                         }
  1944.                                         else
  1945.                                         {
  1946.                                             t = cd->cd_CurrentPalette[cd->cd_Ranges[i].low];
  1947.  
  1948.                                             for(j = cd->cd_Ranges[i].low ; j < cd->cd_Ranges[i].high ; j++)
  1949.                                                 cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j+1];
  1950.  
  1951.                                             cd->cd_CurrentPalette[cd->cd_Ranges[i].high] = t;
  1952.  
  1953.                                             if(cd->cd_IsEHB)
  1954.                                             {
  1955.                                                 t = cd->cd_CurrentPalette[cd->cd_Ranges[i].low + 31];
  1956.  
  1957.                                                 for(j = cd->cd_Ranges[i].low + 31 ; j < cd->cd_Ranges[i].high + 31 ; j++)
  1958.                                                     cd->cd_CurrentPalette[j] = cd->cd_CurrentPalette[j+1];
  1959.  
  1960.                                                 cd->cd_CurrentPalette[cd->cd_Ranges[i].high + 31] = t;
  1961.                                             }
  1962.                                         }
  1963.  
  1964.                                         reload = TRUE;
  1965.                                     }
  1966.                                 }
  1967.                             }
  1968.  
  1969.                             tr->tr_node.io_Command    = TR_ADDREQUEST;
  1970.                             tr->tr_time.tv_secs        = 0;
  1971.                             tr->tr_time.tv_micro    = MILLION / 60;
  1972.  
  1973.                             SetSignal(0,timerMask);
  1974.                             SendIO((struct IORequest *)tr);
  1975.                             ticking = TRUE;
  1976.                         }
  1977.                     }
  1978.  
  1979.                     if(signals & SIGBREAKF_CTRL_F)
  1980.                     {
  1981.                         LONG i;
  1982.  
  1983.                         memcpy(cd->cd_CurrentPalette,cd->cd_OriginalPalette,sizeof(struct ColorRegister) * cd->cd_PaletteSize);
  1984.  
  1985.                         for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
  1986.                             cd->cd_Ranges[i].counter = 0;
  1987.  
  1988.                         reload = TRUE;
  1989.  
  1990.                         Signal(cd->cd_Parent,SIGF_SINGLE);
  1991.                     }
  1992.  
  1993.                     if(reload)
  1994.                         LoadRGB32(&cd->cd_Screen->ViewPort,SetupPalette((UBYTE *)cd->cd_CurrentPalette,cd->cd_PaletteSize));
  1995.                 }
  1996.  
  1997.                 if(ticking)
  1998.                 {
  1999.                     if(CheckIO((struct IORequest *)tr) == BUSY)
  2000.                         AbortIO((struct IORequest *)tr);
  2001.  
  2002.                     WaitIO((struct IORequest *)tr);
  2003.                 }
  2004.  
  2005.                 CloseDevice((struct IORequest *)tr);
  2006.             }
  2007.  
  2008.             DeleteIORequest((struct IORequest *)tr);
  2009.         }
  2010.  
  2011.         DeleteMsgPort(port);
  2012.     }
  2013.  
  2014.     Forbid();
  2015.  
  2016.     cd->cd_Task = NULL;
  2017.  
  2018.     if(cd->cd_Parent != NULL)
  2019.         Signal(cd->cd_Parent,SIGF_SINGLE);
  2020. }
  2021.  
  2022. /******************************************************************************/
  2023.  
  2024. VOID
  2025. DisableCycling(struct CycleData * cd)
  2026. {
  2027.     if(cd != NULL)
  2028.     {
  2029.         SetSignal(0,SIGF_SINGLE);
  2030.  
  2031.         Signal(cd->cd_Task,SIGBREAKF_CTRL_D);
  2032.  
  2033.         Wait(SIGF_SINGLE);
  2034.     }
  2035. }
  2036.  
  2037. VOID
  2038. EnableCycling(struct CycleData * cd)
  2039. {
  2040.     if(cd != NULL)
  2041.     {
  2042.         SetSignal(0,SIGF_SINGLE);
  2043.  
  2044.         Signal(cd->cd_Task,SIGBREAKF_CTRL_E);
  2045.  
  2046.         Wait(SIGF_SINGLE);
  2047.     }
  2048. }
  2049.  
  2050. VOID
  2051. ResetCycling(struct CycleData * cd)
  2052. {
  2053.     if(cd != NULL)
  2054.     {
  2055.         SetSignal(0,SIGF_SINGLE);
  2056.  
  2057.         Signal(cd->cd_Task,SIGBREAKF_CTRL_F);
  2058.  
  2059.         Wait(SIGF_SINGLE);
  2060.     }
  2061. }
  2062.  
  2063. VOID
  2064. DeleteCycleData(struct CycleData * cd)
  2065. {
  2066.     if(cd != NULL)
  2067.     {
  2068.         if(cd->cd_Task != NULL)
  2069.         {
  2070.             Forbid();
  2071.  
  2072.             Signal(cd->cd_Task,SIGBREAKF_CTRL_C);
  2073.  
  2074.             SetSignal(0,SIGF_SINGLE);
  2075.             Wait(SIGF_SINGLE);
  2076.  
  2077.             Permit();
  2078.         }
  2079.  
  2080.         FreeVec(cd);
  2081.     }
  2082. }
  2083.  
  2084. struct CycleData *
  2085. CreateCycleData(struct Screen * screen,BOOL isEHB,struct CRange * ranges,UBYTE * palette,LONG paletteSize)
  2086. {
  2087.     struct CycleData * result = NULL;
  2088.     struct CycleData * cd;
  2089.  
  2090.     cd = AllocVec(sizeof(*cd) + 2 * paletteSize * sizeof(struct ColorRegister),MEMF_ANY|MEMF_PUBLIC|MEMF_CLEAR);
  2091.     if(cd != NULL)
  2092.     {
  2093.         struct Task * task;
  2094.         LONG numActive;
  2095.         LONG i;
  2096.  
  2097.         cd->cd_A4            = getreg(REG_A4);
  2098.         cd->cd_Parent        = (struct Task *)FindTask(NULL);
  2099.         cd->cd_Screen        = screen;
  2100.         cd->cd_PaletteSize    = paletteSize;
  2101.         cd->cd_IsEHB        = isEHB;
  2102.  
  2103.         memcpy(cd->cd_Ranges,ranges,sizeof(cd->cd_Ranges));
  2104.  
  2105.         numActive = 0;
  2106.  
  2107.         for(i = 0 ; i < NUM_ENTRIES(cd->cd_Ranges) ; i++)
  2108.         {
  2109.             cd->cd_Ranges[i].counter = 0;
  2110.  
  2111.             if(cd->cd_Ranges[i].rate <= 36 || cd->cd_Ranges[i].low >= cd->cd_Ranges[i].high)
  2112.                 cd->cd_Ranges[i].active = 0;
  2113.  
  2114.             if(cd->cd_Ranges[i].active != 0)
  2115.                 numActive++;
  2116.         }
  2117.  
  2118.         if(numActive > 0)
  2119.         {
  2120.             cd->cd_OriginalPalette    = (struct ColorRegister *)(cd + 1);
  2121.             cd->cd_CurrentPalette    = cd->cd_OriginalPalette + paletteSize;
  2122.     
  2123.             memcpy(cd->cd_OriginalPalette,palette,sizeof(struct ColorRegister) * paletteSize);
  2124.             memcpy(cd->cd_CurrentPalette,palette,sizeof(struct ColorRegister) * paletteSize);
  2125.     
  2126.             Forbid();
  2127.     
  2128.             task = CreateTask("Cycle Task",0,(APTR)CycleTask,8192);
  2129.             task->tc_UserData = cd;
  2130.     
  2131.             SetSignal(0,SIGF_SINGLE);
  2132.             Wait(SIGF_SINGLE);
  2133.     
  2134.             Permit();
  2135.  
  2136.             if(cd->cd_Task != NULL)
  2137.                 result = cd;
  2138.         }
  2139.     }
  2140.  
  2141.     if(result == NULL)
  2142.         DeleteCycleData(cd);
  2143.  
  2144.     return(result);
  2145. }
  2146.  
  2147. /******************************************************************************/
  2148.  
  2149. VOID
  2150. IconCheck(struct DiskObject *Icon)
  2151. {
  2152.     STRPTR String;
  2153.  
  2154.     if(String = FindToolType(Icon->do_ToolTypes,"CENTER"))
  2155.     {
  2156.         if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
  2157.             PrefCenter = TRUE;
  2158.  
  2159.         if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
  2160.             PrefCenter = FALSE;
  2161.     }
  2162.  
  2163.     if(String = FindToolType(Icon->do_ToolTypes,"CYCLE"))
  2164.     {
  2165.         if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
  2166.             PrefCycle = TRUE;
  2167.  
  2168.         if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
  2169.             PrefCycle = FALSE;
  2170.     }
  2171.  
  2172.     if(String = FindToolType(Icon->do_ToolTypes,"HAM"))
  2173.     {
  2174.         if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
  2175.             PrefHAM = TRUE;
  2176.  
  2177.         if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
  2178.             PrefHAM = FALSE;
  2179.     }
  2180.  
  2181.     if(String = FindToolType(Icon->do_ToolTypes,"EHB"))
  2182.     {
  2183.         if(MatchToolValue(String,"ON") || MatchToolValue(String,"YES"))
  2184.             PrefEHB = TRUE;
  2185.  
  2186.         if(MatchToolValue(String,"OFF") || MatchToolValue(String,"NO"))
  2187.             PrefEHB = FALSE;
  2188.     }
  2189.  
  2190.     if(String = FindToolType(Icon->do_ToolTypes,"WAIT"))
  2191.     {
  2192.         LONG Value;
  2193.  
  2194.         if(StrToLong(String,&Value) > 0)
  2195.         {
  2196.             if(Value > 0)
  2197.                 PrefWait = Value;
  2198.             else
  2199.                 PrefWait = 0;
  2200.         }
  2201.         else
  2202.         {
  2203.             PrefWait = 0;
  2204.         }
  2205.     }
  2206.  
  2207.     if(String = FindToolType(Icon->do_ToolTypes,"WAITAFTEROPEN"))
  2208.     {
  2209.         LONG Value;
  2210.  
  2211.         if(StrToLong(String,&Value) > 0)
  2212.         {
  2213.             if(Value > 0)
  2214.                 PrefWaitAfterOpen = Value;
  2215.             else
  2216.                 PrefWaitAfterOpen = 0;
  2217.         }
  2218.         else
  2219.         {
  2220.             PrefWaitAfterOpen = 0;
  2221.         }
  2222.     }
  2223. }
  2224.  
  2225. /******************************************************************************/
  2226.  
  2227. VOID
  2228. CloseAll(VOID)
  2229. {
  2230.     CloseDisplay();
  2231.  
  2232.     StopTimer();
  2233.  
  2234.     if(TimeRequest != NULL)
  2235.     {
  2236.         if(TimeRequest->tr_node.io_Device != NULL)
  2237.             CloseDevice(TimeRequest);
  2238.  
  2239.         DeleteIORequest(TimeRequest);
  2240.         TimeRequest = NULL;
  2241.     }
  2242.  
  2243.     if(TimePort != NULL)
  2244.     {
  2245.         DeleteMsgPort(TimePort);
  2246.         TimePort = NULL;
  2247.     }
  2248.  
  2249.     if(CyberGfxBase != NULL)
  2250.     {
  2251.         CloseLibrary(CyberGfxBase);
  2252.         CyberGfxBase = NULL;
  2253.     }
  2254.  
  2255.     if(IFFParseBase != NULL)
  2256.     {
  2257.         CloseLibrary(IFFParseBase);
  2258.         IFFParseBase = NULL;
  2259.     }
  2260.  
  2261.     if(AslBase != NULL)
  2262.     {
  2263.         CloseLibrary(AslBase);
  2264.         AslBase = NULL;
  2265.     }
  2266.  
  2267.     if(IconBase != NULL)
  2268.     {
  2269.         CloseLibrary(IconBase);
  2270.         IconBase = NULL;
  2271.     }
  2272.  
  2273.     if(UtilityBase != NULL)
  2274.     {
  2275.         CloseLibrary(UtilityBase);
  2276.         UtilityBase = NULL;
  2277.     }
  2278.  
  2279.     if(GfxBase != NULL)
  2280.     {
  2281.         CloseLibrary(GfxBase);
  2282.         GfxBase = NULL;
  2283.     }
  2284.  
  2285.     if(IntuitionBase != NULL)
  2286.     {
  2287.         CloseLibrary(IntuitionBase);
  2288.         IntuitionBase = NULL;
  2289.     }
  2290. }
  2291.  
  2292. ERRORCODE
  2293. OpenAll(VOID)
  2294. {
  2295.     IntuitionBase = OpenLibrary("intuition.library",39);
  2296.     if(IntuitionBase == NULL)
  2297.         return(ERR_NO_INTUITION);
  2298.  
  2299.     GfxBase = OpenLibrary("graphics.library",39);
  2300.     if(GfxBase == NULL)
  2301.         return(ERR_NO_GRAPHICS);
  2302.  
  2303.     UtilityBase = OpenLibrary("utility.library",37);
  2304.     if(UtilityBase == NULL)
  2305.         return(ERR_NO_UTILITY);
  2306.  
  2307.     IFFParseBase = OpenLibrary("iffparse.library",40);
  2308.     if(IFFParseBase == NULL)
  2309.         return(ERR_NO_IFFPARSE);
  2310.  
  2311.     CyberGfxBase = OpenLibrary("cybergraphics.library",40);
  2312.     if(CyberGfxBase == NULL)
  2313.         return(ERR_NO_CYBERGFX);
  2314.  
  2315.     IconBase = OpenLibrary("icon.library",37);
  2316.     if(IconBase == NULL)
  2317.         return(ERR_NO_ICON);
  2318.  
  2319.     AslBase = OpenLibrary("asl.library",37);
  2320.     if(AslBase == NULL)
  2321.         return(ERR_NO_ASL);
  2322.  
  2323.     TimePort = CreateMsgPort();
  2324.     if(TimePort == NULL)
  2325.         return(ERR_NO_PORT);
  2326.  
  2327.     TimeRequest = (struct timerequest *)CreateIORequest(TimePort,sizeof(struct timerequest));
  2328.     if(TimeRequest == NULL)
  2329.         return(ERR_NO_REQUEST);
  2330.  
  2331.     if(OpenDevice(TIMERNAME,UNIT_VBLANK,TimeRequest,NULL) != OK)
  2332.         return(ERR_NO_TIMER);
  2333.  
  2334.     return(OK);
  2335. }
  2336.  
  2337. /******************************************************************************/
  2338.  
  2339. int
  2340. main(int argc,char **argv)
  2341. {
  2342.     int result = RETURN_FAIL;
  2343.  
  2344.     if(DOSBase->lib_Version >= 37)
  2345.     {
  2346.         ERRORCODE error;
  2347.  
  2348.         error = OpenAll();
  2349.         if(error == OK)
  2350.         {
  2351.             if(argc > 0)
  2352.             {
  2353.                 struct
  2354.                 {
  2355.                     KEYWORD *    Files;
  2356.                     SWITCH        Center;
  2357.                     NUMBER        Wait;
  2358.                     SWITCH        Quiet;
  2359.                     SWITCH        All;
  2360.                     NUMBER        WaitAfterOpen;
  2361.                     SWITCH        Cycle;
  2362.                     SWITCH        UseHAM;
  2363.                     SWITCH        UseEHB;
  2364.                 } args;
  2365.  
  2366.                 struct RDArgs * rda;
  2367.  
  2368.                 memset(&args,0,sizeof(args));
  2369.  
  2370.                 rda = ReadArgs("FILES/M/A,"
  2371.                                "C=CENTER/S,"
  2372.                                "W=WAIT/K/N,"
  2373.                                "Q=QUIET/S,"
  2374.                                "A=ALL/S,"
  2375.                                "WAO=WAITAFTEROPEN/K/N,"
  2376.                                "CYCLE/S,"
  2377.                                "HAM/S,"
  2378.                                "EHB/S",
  2379.                                (LONG *)&args,NULL);
  2380.                 if(rda)
  2381.                 {
  2382.                     STRPTR * files = (STRPTR *)args.Files;
  2383.                     struct AnchorPath * ap;
  2384.  
  2385.                     if(args.Wait != NULL)
  2386.                     {
  2387.                         if((*args.Wait) > 0)
  2388.                             PrefWait = (*args.Wait);
  2389.                     }
  2390.  
  2391.                     if(args.WaitAfterOpen != NULL)
  2392.                     {
  2393.                         if((*args.WaitAfterOpen) > 0)
  2394.                             PrefWaitAfterOpen = (*args.WaitAfterOpen);
  2395.                     }
  2396.  
  2397.                     if(args.Center)
  2398.                         PrefCenter = TRUE;
  2399.  
  2400.                     if(args.Quiet)
  2401.                         PrefQuiet = TRUE;
  2402.  
  2403.                     if(args.Cycle)
  2404.                         PrefCycle = TRUE;
  2405.  
  2406.                     if(args.UseHAM)
  2407.                         PrefHAM = TRUE;
  2408.  
  2409.                     if(args.UseEHB)
  2410.                         PrefEHB = TRUE;
  2411.  
  2412.                     result = RETURN_OK;
  2413.  
  2414.                     ap = (struct AnchorPath *)AllocVec(sizeof(*ap) + MAX_PATHNAME_LEN,MEMF_ANY);
  2415.                     if(ap != NULL)
  2416.                     {
  2417.                         BOOL errorPrinted = FALSE;
  2418.  
  2419.                         while((*files) != NULL && error == OK)
  2420.                         {
  2421.                             memset(ap,0,sizeof(*ap) + MAX_PATHNAME_LEN);
  2422.  
  2423.                             ap->ap_Strlen        = MAX_PATHNAME_LEN;
  2424.                             ap->ap_BreakBits    = SIGBREAKF_CTRL_C;
  2425.  
  2426.                             error = MatchFirst((*files++),ap);
  2427.  
  2428.                             if(error == OK && ap->ap_Info.fib_DirEntryType > 0)
  2429.                             {
  2430.                                 SET_FLAG(ap->ap_Flags,APF_DODIR);
  2431.                             }
  2432.  
  2433.                             while(error == OK)
  2434.                             {
  2435.                                 if(ap->ap_Info.fib_DirEntryType < 0 && ap->ap_Info.fib_Size > 0)
  2436.                                 {
  2437.                                     if(NOT PrefQuiet)
  2438.                                     {
  2439.                                         Printf("Showing \"%s\"... ",ap->ap_Buf);
  2440.                                         Flush(Output());
  2441.                                     }
  2442.  
  2443.                                     error = ShowILBM(ap->ap_Buf);
  2444.  
  2445.                                     if(NOT PrefQuiet)
  2446.                                     {
  2447.                                         switch(error)
  2448.                                         {
  2449.                                             case OK:
  2450.  
  2451.                                                 Printf("Done.\n");
  2452.                                                 break;
  2453.  
  2454.                                             case ERROR_BREAK:
  2455.  
  2456.                                                 PrintErrorString(ERROR_BREAK,NULL);
  2457.                                                 error = OK;
  2458.                                                 break;
  2459.  
  2460.                                             case ERR_ABORTED:
  2461.  
  2462.                                                 PrintErrorString(ERROR_BREAK,NULL);
  2463.                                                 error = ERROR_BREAK;
  2464.                                                 break;
  2465.  
  2466.                                             default:
  2467.  
  2468.                                                 PrintErrorString(error,NULL);
  2469.                                                 error = OK;
  2470.                                                 break;
  2471.                                         }
  2472.  
  2473.                                         if(error != OK)
  2474.                                             errorPrinted = TRUE;
  2475.                                     }
  2476.                                 }
  2477.  
  2478.                                 if(args.All && ap->ap_Info.fib_DirEntryType > 0)
  2479.                                 {
  2480.                                     if(FLAG_IS_SET(ap->ap_Flags,APF_DIDDIR))
  2481.                                         CLEAR_FLAG(ap->ap_Flags,APF_DIDDIR);
  2482.                                     else
  2483.                                         SET_FLAG(ap->ap_Flags,APF_DODIR);
  2484.                                 }
  2485.  
  2486.                                 if(error == OK)
  2487.                                     error = MatchNext(ap);
  2488.                             }
  2489.  
  2490.                             MatchEnd(ap);
  2491.                         }
  2492.  
  2493.                         if((error == ERROR_NO_MORE_ENTRIES) || (error != OK && errorPrinted))
  2494.                             error = OK;
  2495.  
  2496.                         FreeVec(ap);
  2497.                     }
  2498.                     else
  2499.                     {
  2500.                         error = ERROR_NO_FREE_STORE;
  2501.                     }
  2502.  
  2503.                     if(error != OK)
  2504.                         PrintErrorString(error,"ViewILBM");
  2505.  
  2506.                     FreeArgs(rda);
  2507.                 }
  2508.                 else
  2509.                 {
  2510.                     PrintErrorString(IoErr(),"ViewILBM");
  2511.  
  2512.                     result = RETURN_ERROR;
  2513.                 }
  2514.             }
  2515.             else
  2516.             {
  2517.                 struct WBStartup * WBenchMsg = (struct WBStartup *)argv;
  2518.  
  2519.                 if(WBenchMsg->sm_NumArgs > 0)
  2520.                 {
  2521.                     struct DiskObject * Icon;
  2522.                     BPTR OldDir;
  2523.                     LONG i;
  2524.  
  2525.                     result = RETURN_OK;
  2526.  
  2527.                     Icon = GetDiskObject(WBenchMsg->sm_ArgList[0].wa_Name);
  2528.                     if(Icon != NULL)
  2529.                     {
  2530.                         IconCheck(Icon);
  2531.  
  2532.                         FreeDiskObject(Icon);
  2533.                     }
  2534.  
  2535.                     if(WBenchMsg->sm_NumArgs > 1)
  2536.                     {
  2537.                         for(i = 1 ; error == OK && i < WBenchMsg->sm_NumArgs ; i++)
  2538.                         {
  2539.                             OldDir = CurrentDir(WBenchMsg->sm_ArgList[i].wa_Lock);
  2540.  
  2541.                             Icon = GetDiskObject(WBenchMsg->sm_ArgList[i].wa_Name);
  2542.                             if(Icon != NULL)
  2543.                             {
  2544.                                 IconCheck(Icon);
  2545.  
  2546.                                 FreeDiskObject(Icon);
  2547.                             }
  2548.  
  2549.                             error = ShowILBM(WBenchMsg->sm_ArgList[i].wa_Name);
  2550.                             if(error != ERR_ABORTED)
  2551.                                 error = OK;
  2552.  
  2553.                             CurrentDir(OldDir);
  2554.                         }
  2555.                     }
  2556.                     else
  2557.                     {
  2558.                         struct FileRequester *FileRequest;
  2559.  
  2560.                         FileRequest = (struct FileRequester *)AllocAslRequestTags(ASL_FileRequest,
  2561.                             ASL_Hail,        "Load which file?",
  2562.                             ASL_OKText,        "Load",
  2563.                             ASL_FuncFlags,    FILF_PATGAD | FILF_MULTISELECT,
  2564.                         TAG_DONE);
  2565.                         if(FileRequest != NULL)
  2566.                         {
  2567.                             while(AslRequestTags(FileRequest, ASLFR_RejectIcons,TRUE, TAG_DONE) && FileRequest->fr_NumArgs > 0)
  2568.                             {
  2569.                                 for(i = 0 ; error == OK && i < FileRequest->fr_NumArgs ; i++)
  2570.                                 {
  2571.                                     OldDir = CurrentDir(FileRequest->fr_ArgList[i].wa_Lock);
  2572.  
  2573.                                     Icon = GetDiskObject(FileRequest->fr_ArgList[i].wa_Name);
  2574.                                     if(Icon != NULL)
  2575.                                     {
  2576.                                         IconCheck(Icon);
  2577.  
  2578.                                         FreeDiskObject(Icon);
  2579.                                     }
  2580.  
  2581.                                     error = ShowILBM(FileRequest->fr_ArgList[i].wa_Name);
  2582.                                     if(error != ERR_ABORTED)
  2583.                                         error = OK;
  2584.  
  2585.                                     CurrentDir(OldDir);
  2586.                                 }
  2587.                             }
  2588.  
  2589.                             FreeAslRequest(FileRequest);
  2590.                         }
  2591.                     }
  2592.                 }
  2593.             }
  2594.         }
  2595.         else
  2596.         {
  2597.             PrintErrorString(error,"ViewILBM");
  2598.         }
  2599.  
  2600.         CloseAll();
  2601.     }
  2602.  
  2603.     return(result);
  2604. }
  2605.