home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / C / OTL-MC7.DMS / in.adf / ansicdemo.lha / ANSI-C / Intuition / doublebuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-30  |  20.0 KB  |  905 lines

  1. /*
  2.  * doublebuffer.c - shows double-buffering, attached screens, menu lending
  3.  *
  4.  * (c) Copyright 1992 Commodore-Amiga, Inc.  All Rights Reserved.
  5.  *
  6.  * Example shows use of V39 double-buffering functions to achieve
  7.  * 60 frame-per-second animation.  Also shows use of menus in
  8.  * double-buffered screens, and the use of attached screens with
  9.  * menu-lending to achieve the appearance of slider gadgets in
  10.  * double-buffered screens.
  11.  * 
  12.  */
  13.  
  14. /*----------------------------------------------------------------------*/
  15.  
  16. #include <stdio.h>
  17. #include <exec/types.h>
  18. #include <graphics/displayinfo.h>
  19. #include <graphics/videocontrol.h>
  20. #include <intuition/intuition.h>
  21. #include <intuition/gadgetclass.h>
  22. #include <libraries/gadtools.h>
  23.  
  24. #include <pragma/exec_lib.h>
  25. #include <pragma/graphics_lib.h>
  26. #include <pragma/intuition_lib.h>
  27. #include <pragma/gadtools_lib.h>
  28.  
  29. /*----------------------------------------------------------------------*/
  30.  
  31. STRPTR init_all( void  );
  32. void error_exit( STRPTR errorstring );
  33. struct Gadget *createAllGadgets( struct Gadget **glistptr, void *vi );
  34. BOOL handleIntuiMessage( struct IntuiMessage *imsg );
  35. void handleDBufMessage( struct Message *dbmsg );
  36. ULONG handleBufferSwap( void );
  37. struct BitMap *makeImageBM( void );
  38. void CloseWindowSafely( struct Window *win );
  39.  
  40. #define abs( x )    ( ( x )>=0?( x ):-( x ) )
  41. int CXBRK( void ) {return( 0 );}
  42.  
  43. /*----------------------------------------------------------------------*/
  44.  
  45. /* Some constants to handle the rendering of the animated face */
  46. #define BM_WIDTH    120
  47. #define BM_HEIGHT    60
  48. #define BM_DEPTH    2
  49.  
  50. /* Odd numbers to give a non-repeating bounce */
  51. #define CONTROLSC_TOP        191
  52. #define SC_ID            HIRES_KEY
  53.  
  54. /*----------------------------------------------------------------------*/
  55.  
  56. /* User interface constants and variables */
  57.  
  58. #define GAD_HORIZ    1
  59. #define GAD_VERT    2
  60.  
  61. #define MENU_RUN    1
  62. #define MENU_STEP    2
  63. #define MENU_QUIT    3
  64. #define MENU_HSLOW    4
  65. #define MENU_HFAST    5
  66. #define MENU_VSLOW    6
  67. #define MENU_VFAST    7
  68.  
  69. struct TextAttr Topaz80 =
  70. {
  71.     "topaz.font",     /* Name */
  72.     8,             /* YSize */
  73.     0,             /* Style */
  74.     0,             /* Flags */
  75. };
  76.  
  77. struct TagItem vctags[] =
  78. {
  79.     VTAG_BORDERSPRITE_SET, TRUE, 
  80.     TAG_DONE, 0, 
  81. };
  82.  
  83. UWORD pens[] =
  84. {
  85.     0, /* DETAILPEN */
  86.     1, /* BLOCKPEN    */
  87.     1, /* TEXTPEN    */
  88.     2, /* SHINEPEN    */
  89.     1, /* SHADOWPEN    */
  90.     3, /* FILLPEN    */
  91.     1, /* FILLTEXTPEN    */
  92.     0, /* BACKGROUNDPEN    */
  93.     2, /* HIGHLIGHTTEXTPEN    */
  94.  
  95.     1, /* BARDETAILPEN    */
  96.     2, /* BARBLOCKPEN    */
  97.     1, /* BARTRIMPEN    */
  98.  
  99.     ~0, 
  100. };
  101.  
  102. struct NewMenu demomenu[] =
  103. {
  104.     { NM_TITLE, "Project",           0 , 0, 0, 0, }, 
  105.     {  NM_ITEM, "Run",          "R", 0, 0, ( APTR ) MENU_RUN, }, 
  106.     {  NM_ITEM, "Step",          "S", 0, 0, ( APTR ) MENU_STEP, }, 
  107.     {  NM_ITEM, NM_BARLABEL,       0 , 0, 0, 0, }, 
  108.     {  NM_ITEM, "Slower Horizontal", "1", 0, 0, ( APTR ) MENU_HSLOW, }, 
  109.     {  NM_ITEM, "Faster Horizontal", "2", 0, 0, ( APTR ) MENU_HFAST, }, 
  110.     {  NM_ITEM, "Slower Vertical",      "3", 0, 0, ( APTR ) MENU_VSLOW, }, 
  111.     {  NM_ITEM, "Faster Vertical",      "4", 0, 0, ( APTR ) MENU_VFAST, }, 
  112.  
  113.     {  NM_ITEM, NM_BARLABEL,       0 , 0, 0, 0, }, 
  114.     {  NM_ITEM, "Quit...",          "Q", 0, 0, ( APTR ) MENU_QUIT, }, 
  115.  
  116.     {   NM_END, 0,               0 , 0, 0, 0, }, 
  117. };
  118.  
  119. struct Screen *canvassc = NULL;
  120. struct Screen *controlsc = NULL;
  121. struct Window *controlwin = NULL;
  122. struct Window *canvaswin = NULL;
  123. struct Gadget *glist = NULL;
  124. struct Gadget *horizgad, *vertgad;
  125. struct Menu *menu = NULL;
  126. void *canvasvi = NULL;
  127. void *controlvi = NULL;
  128.  
  129. /*----------------------------------------------------------------------*/
  130.  
  131. #define    OK_REDRAW    1    /* Buffer fully detached, ready for redraw */
  132. #define OK_SWAPIN    2    /* Buffer redrawn, ready for swap-in */
  133.  
  134. struct GfxBase *GfxBase = NULL;
  135. struct IntuitionBase *IntuitionBase = NULL;
  136. struct Library *GadToolsBase = NULL;
  137.  
  138. struct MsgPort *dbufport = NULL;
  139. struct MsgPort *userport = NULL;
  140.  
  141. struct ScreenBuffer *scbuf[] =
  142. {
  143.     NULL, 
  144.     NULL, 
  145. };
  146. struct RastPort rport[ 2 ];
  147.  
  148. ULONG status[ 2 ];
  149.  
  150. LONG prevx[ 2 ] =
  151. {
  152.     50, 50, 
  153. };
  154.  
  155. LONG prevy[ 2 ] =
  156. {
  157.     50, 50, 
  158. };
  159.  
  160. ULONG buf_current, buf_nextdraw, buf_nextswap;
  161. ULONG count;
  162. struct BitMap *face = NULL;
  163. LONG x, y, xstep, xdir, ystep, ydir;
  164.  
  165. /*----------------------------------------------------------------------*/
  166.  
  167. main()
  168. {
  169.     STRPTR errorstring;
  170.     ULONG sigs;
  171.     BOOL terminated = FALSE;
  172.  
  173.     /* Let's get everything initialized */
  174.     if ( errorstring = init_all() )
  175.     {
  176.     error_exit( errorstring );
  177.     }
  178.  
  179.     count = 0;
  180.     buf_current = 0;
  181.     buf_nextdraw = 1;
  182.     buf_nextswap = 1;
  183.     sigs = 0;
  184.  
  185.     while ( !terminated )
  186.     {
  187.     /* Check for and handle any IntuiMessages */
  188.     if ( sigs & ( 1 << userport->mp_SigBit ) )
  189.     {
  190.         struct IntuiMessage *imsg;
  191.  
  192.         while ( imsg = GT_GetIMsg( userport ) )
  193.         {
  194.         terminated |= handleIntuiMessage( imsg );
  195.         GT_ReplyIMsg( imsg );
  196.         }
  197.     }
  198.  
  199.     /* Check for and handle any double-buffering messages.
  200.      * Note that double-buffering messages are "replied" to
  201.      * us, so we don't want to reply them to anyone.
  202.      */
  203.     if ( sigs & ( 1 << dbufport->mp_SigBit ) )
  204.     {
  205.         struct Message *dbmsg;
  206.         while ( dbmsg = GetMsg( dbufport ) )
  207.         {
  208.         handleDBufMessage( dbmsg );
  209.         }
  210.     }
  211.  
  212.  
  213.     if ( !terminated )
  214.     {
  215.         ULONG held_off = 0;
  216.         /* Only handle swapping buffers if count is non-zero */
  217.         if ( count )
  218.         {
  219.         held_off = handleBufferSwap();
  220.         }
  221.         if ( held_off )
  222.         {
  223.         /* If were held-off at ChangeScreenBuffer() time, then we
  224.          * need to try ChangeScreenBuffer() again, without awaiting
  225.          * a signal.  We WaitTOF() to avoid busy-looping.
  226.          */
  227.          WaitTOF();
  228.         }
  229.         else
  230.         {
  231.         /* If we were not held-off, then we're all done
  232.          * with what we have to do.  We'll have no work to do
  233.          * until some kind of signal arrives.  This will normally
  234.          * be the arrival of the dbi_SafeMessage from the ROM
  235.          * double-buffering routines, but it might also be an
  236.          * IntuiMessage.
  237.          */
  238.         sigs = Wait( ( 1 << dbufport->mp_SigBit ) | ( 1 << userport->mp_SigBit ) );
  239.         }
  240.     }
  241.     }
  242.  
  243.     error_exit( NULL );
  244. }
  245.  
  246.  
  247. /*----------------------------------------------------------------------*/
  248.  
  249. /* Handle the rendering and swapping of the buffers */
  250.  
  251. ULONG handleBufferSwap( void )
  252. {
  253.     ULONG held_off = 0;
  254.     /* 'buf_nextdraw' is the next buffer to draw into.
  255.      * The buffer is ready for drawing when we've received the
  256.      * dbi_SafeMessage for that buffer.  Our routine to handle
  257.      * messaging from the double-buffering functions sets the
  258.      * OK_REDRAW flag when this message has appeared.
  259.      *
  260.      * Here, we set the OK_SWAPIN flag after we've redrawn
  261.      * the imagery, since the buffer is ready to be swapped in.
  262.      * We clear the OK_REDRAW flag, since we're done with redrawing
  263.      */
  264.     if ( status[ buf_nextdraw ] == OK_REDRAW )
  265.     {
  266.     x += xstep*xdir;
  267.     if ( x < 0 )
  268.     {
  269.         x = 0;
  270.         xdir = 1;
  271.     }
  272.     else if ( x > canvassc->Width - BM_WIDTH )
  273.     {
  274.         x = canvassc->Width - BM_WIDTH - 1;
  275.         xdir = -1;
  276.     }
  277.  
  278.     y += ystep*ydir;
  279.     if ( y < canvassc->BarLayer->Height )
  280.     {
  281.         y = canvassc->BarLayer->Height;
  282.         ydir = 1;
  283.     }
  284.     else if ( y >= CONTROLSC_TOP - BM_HEIGHT )
  285.     {
  286.         y = CONTROLSC_TOP - BM_HEIGHT - 1;
  287.         ydir = -1;
  288.     }
  289.  
  290.     SetAPen( &rport[ buf_nextdraw ], 0 );
  291.     RectFill( &rport[ buf_nextdraw ], 
  292.         prevx[ buf_nextdraw ], prevy[ buf_nextdraw ], 
  293.         prevx[ buf_nextdraw ] + BM_WIDTH - 1, prevy[ buf_nextdraw ] + BM_HEIGHT - 1 );
  294.     prevx[ buf_nextdraw ] = x;
  295.     prevy[ buf_nextdraw ] = y;
  296.  
  297.     BltBitMapRastPort( face, 0, 0, &rport[ buf_nextdraw ], x, y, 
  298.         BM_WIDTH, BM_HEIGHT, 0xc0 );
  299.  
  300.     WaitBlit(); /* Gots to let the BBMRP finish */
  301.  
  302.     status[ buf_nextdraw ] = OK_SWAPIN;
  303.  
  304.     /* Toggle which the next buffer to draw is.
  305.      * If you're using multiple ( >2 ) buffering, you
  306.      * would use
  307.      *
  308.      *    buf_nextdraw = ( buf_nextdraw+1 ) % NUMBUFFERS;
  309.      *
  310.      */
  311.     buf_nextdraw ^= 1;
  312.     }
  313.  
  314.     /* Let's make sure that the next frame is rendered before we swap...
  315.      */
  316.     if ( status[ buf_nextswap ] == OK_SWAPIN )
  317.     {
  318.     scbuf[ buf_nextswap ]->sb_DBufInfo->dbi_SafeMessage.mn_ReplyPort = dbufport;
  319.  
  320.     if ( ChangeScreenBuffer( canvassc, scbuf[ buf_nextswap ] ) )
  321.     {
  322.         status[ buf_nextswap ] = 0;
  323.  
  324.         buf_current = buf_nextswap;
  325.         /* Toggle which the next buffer to swap in is.
  326.          * If you're using multiple ( >2 ) buffering, you
  327.          * would use
  328.          *
  329.          *    buf_nextswap = ( buf_nextswap+1 ) % NUMBUFFERS;
  330.          *
  331.          */
  332.         buf_nextswap ^= 1;
  333.  
  334.         count--;
  335.     }
  336.     else
  337.     {
  338.         held_off = 1;
  339.     }
  340.     }
  341.     return( held_off );
  342. }
  343.  
  344. /*----------------------------------------------------------------------*/
  345.  
  346. /* Handle Intuition messages */
  347.  
  348. BOOL handleIntuiMessage( struct IntuiMessage *imsg )
  349. {
  350.     UWORD code = imsg->Code;
  351.     BOOL terminated = FALSE;
  352.  
  353.     switch ( imsg->Class )
  354.     {
  355.     case IDCMP_GADGETDOWN:
  356.     case IDCMP_GADGETUP:
  357.     case IDCMP_MOUSEMOVE:
  358.         switch ( ( ( struct Gadget * )imsg->IAddress )->GadgetID )
  359.         {
  360.         case GAD_HORIZ:
  361.             xstep = code;
  362.             break;
  363.  
  364.         case GAD_VERT:
  365.             ystep = code;
  366.             break;
  367.         }
  368.         break;
  369.  
  370.     case IDCMP_VANILLAKEY:
  371.         switch ( code )
  372.         {
  373.         case 'S':
  374.         case 's':
  375.             count = 1;
  376.             break;
  377.  
  378.         case 'R':
  379.         case 'r':
  380.             count = ~0;
  381.             break;
  382.  
  383.         case 'Q':
  384.         case 'q':
  385.             count = 0;
  386.             terminated = TRUE;
  387.             break;
  388.         }
  389.         break;
  390.  
  391.     case IDCMP_MENUPICK:
  392.         while ( code != MENUNULL )
  393.         {
  394.         struct MenuItem *item;
  395.  
  396.         item = ItemAddress( menu, code );
  397.         switch ( ( ULONG ) GTMENUITEM_USERDATA( item ) )
  398.         {
  399.             case MENU_RUN:
  400.             count = ~0;
  401.             break;
  402.  
  403.             case MENU_STEP:
  404.             count = 1;
  405.             break;
  406.  
  407.             case MENU_QUIT:
  408.             count = 0;
  409.             terminated = TRUE;
  410.             break;
  411.  
  412.             case MENU_HSLOW:
  413.             if ( xstep > 0 )
  414.             {
  415.                 xstep--;
  416.             }
  417.             GT_SetGadgetAttrs( horizgad, controlwin, NULL, 
  418.                 GTSL_Level, xstep, 
  419.                 TAG_DONE );
  420.             break;
  421.  
  422.             case MENU_HFAST:
  423.             if ( xstep < 9 )
  424.             {
  425.                 xstep++;
  426.             }
  427.             GT_SetGadgetAttrs( horizgad, controlwin, NULL, 
  428.                 GTSL_Level, xstep, 
  429.                 TAG_DONE );
  430.             break;
  431.  
  432.             case MENU_VSLOW:
  433.             if ( ystep > 0 )
  434.             {
  435.                 ystep--;
  436.             }
  437.             GT_SetGadgetAttrs( vertgad, controlwin, NULL, 
  438.                 GTSL_Level, ystep, 
  439.                 TAG_DONE );
  440.             break;
  441.  
  442.             case MENU_VFAST:
  443.             if ( ystep < 9 )
  444.             {
  445.                 ystep++;
  446.             }
  447.             GT_SetGadgetAttrs( vertgad, controlwin, NULL, 
  448.                 GTSL_Level, ystep, 
  449.                 TAG_DONE );
  450.             break;
  451.         }
  452.         code = item->NextSelect;
  453.         }
  454.         break;
  455.     }
  456.     return( terminated );
  457. }
  458.  
  459. /*----------------------------------------------------------------------*/
  460.  
  461. void handleDBufMessage( struct Message *dbmsg )
  462. {
  463.     ULONG buffer;
  464.  
  465.     /* dbi_SafeMessage is followed by an APTR dbi_UserData1, which
  466.      * contains the buffer number.  This is an easy way to extract
  467.      * it.
  468.      * The dbi_SafeMessage tells us that it's OK to redraw the
  469.      * in the previous buffer.
  470.      */
  471.     buffer = ( ULONG ) *( ( APTR ** ) ( dbmsg+1 ) );
  472.     /* Mark the previous buffer as OK to redraw into.
  473.      * If you're using multiple ( >2 ) buffering, you
  474.      * would use
  475.      *
  476.      *    ( buffer + NUMBUFFERS - 1 ) % NUMBUFFERS
  477.      *
  478.      */
  479.     status[ buffer^1 ] = OK_REDRAW;
  480. }
  481.  
  482. /*----------------------------------------------------------------------*/
  483.  
  484. /* Get the resources and objects we need */
  485.  
  486. STRPTR init_all( void )
  487. {
  488.     if ( !( GfxBase = ( struct GfxBase * )
  489.     OpenLibrary( "graphics.library", 39L ) ) )
  490.     {
  491.     return( "Couldn't open Gfx V39\n" );
  492.     }
  493.  
  494.     if ( !( IntuitionBase = ( struct IntuitionBase * )
  495.     OpenLibrary( "intuition.library", 39L ) ) )
  496.     {
  497.     return( "Couldn't open Intuition V39\n" );
  498.     }
  499.  
  500.     if ( !( GadToolsBase = OpenLibrary( "gadtools.library", 39L ) ) )
  501.     {
  502.     return( "Couldn't open GadTools V39\n" );
  503.     }
  504.  
  505.     if ( !( dbufport = CreateMsgPort() ) )
  506.     {
  507.     return( "Failed to create port\n" );
  508.     }
  509.  
  510.     if ( !( userport = CreateMsgPort() ) )
  511.     {
  512.     return( "Failed to create port\n" );
  513.     }
  514.  
  515.     if ( !( canvassc = OpenScreenTags( NULL, 
  516.     SA_DisplayID, SC_ID, 
  517.     SA_Overscan, OSCAN_TEXT, 
  518.     SA_Depth, 2, 
  519.     SA_AutoScroll, 1, 
  520.     SA_Pens, pens, 
  521.     SA_Height, 200, 
  522.     SA_ShowTitle, TRUE, 
  523.     SA_Title, "Intuition double-buffering example", 
  524.     SA_VideoControl, vctags, 
  525.     SA_SysFont, 1, 
  526.     TAG_DONE ) ) )
  527.     {
  528.     return( "Couldn't open screen\n" );
  529.     }
  530.  
  531.     if ( !( canvasvi = GetVisualInfo( canvassc, 
  532.     TAG_DONE ) ) )
  533.     {
  534.     return( "Couldn't get VisualInfo\n" );
  535.     }
  536.  
  537.     if ( !( canvaswin = OpenWindowTags( NULL, 
  538.     WA_NoCareRefresh, TRUE, 
  539.     WA_Activate, TRUE, 
  540.     WA_Borderless, TRUE, 
  541.     WA_Backdrop, TRUE, 
  542.     WA_CustomScreen, canvassc, 
  543.     WA_NewLookMenus, TRUE, 
  544.     TAG_DONE ) ) )
  545.     {
  546.     return( "Couldn't open window\n" );
  547.     }
  548.     canvaswin->UserPort = userport;
  549.  
  550.     ModifyIDCMP( canvaswin, IDCMP_MENUPICK | IDCMP_VANILLAKEY );
  551.  
  552.     if ( !( controlsc = OpenScreenTags( NULL, 
  553.     SA_DisplayID, SC_ID, 
  554.     SA_Overscan, OSCAN_TEXT, 
  555.     SA_Depth, 2, 
  556.     SA_Pens, pens, 
  557.     SA_Top, CONTROLSC_TOP, 
  558.     SA_Height, 28, 
  559.     SA_Parent, canvassc, 
  560.     SA_ShowTitle, FALSE, 
  561.     SA_Draggable, FALSE, 
  562.     SA_VideoControl, vctags, 
  563.     SA_Quiet, TRUE, 
  564.     SA_SysFont, 1, 
  565.     TAG_DONE ) ) )
  566.     {
  567.     return( "Couldn't open screen\n" );
  568.     }
  569.  
  570.     if ( !( controlvi = GetVisualInfo( controlsc, 
  571.     TAG_DONE ) ) )
  572.     {
  573.     return( "Couldn't get VisualInfo\n" );
  574.     }
  575.  
  576.     if ( !( menu = CreateMenus( demomenu, 
  577.     TAG_DONE ) ) )
  578.     {
  579.     return( "Couldn't create menus\n" );
  580.     }
  581.  
  582.     if ( !LayoutMenus( menu, canvasvi, 
  583.     GTMN_NewLookMenus, TRUE, 
  584.     TAG_DONE ) )
  585.     {
  586.     return( "Couldn't layout menus\n" );
  587.     }
  588.  
  589.     if ( !createAllGadgets( &glist, controlvi ) )
  590.     {
  591.     return( "Couldn't create gadgets\n" );
  592.     }
  593.  
  594.     /* A borderless backdrop window so we can get input */
  595.     if ( !( controlwin = OpenWindowTags( NULL, 
  596.     WA_NoCareRefresh, TRUE, 
  597.     WA_Activate, TRUE, 
  598.     WA_Borderless, TRUE, 
  599.     WA_Backdrop, TRUE, 
  600.     WA_CustomScreen, controlsc, 
  601.     WA_NewLookMenus, TRUE, 
  602.     WA_Gadgets, glist, 
  603.     TAG_DONE ) ) )
  604.     {
  605.     return( "Couldn't open window\n" );
  606.     }
  607.  
  608.     controlwin->UserPort = userport;
  609.     ModifyIDCMP( controlwin, SLIDERIDCMP | IDCMP_MENUPICK | IDCMP_VANILLAKEY );
  610.  
  611.     GT_RefreshWindow( controlwin, NULL );
  612.     SetMenuStrip( canvaswin, menu );
  613.     LendMenus( controlwin, canvaswin );
  614.  
  615.     if ( !( scbuf[ 0 ] = AllocScreenBuffer( canvassc, NULL, SB_SCREEN_BITMAP ) ) )
  616.     {
  617.     return( "Couldn't allocate ScreenBuffer 1\n" );
  618.     }
  619.  
  620.     if ( !( scbuf[ 1 ] = AllocScreenBuffer( canvassc, NULL, SB_COPY_BITMAP ) ) )
  621.     {
  622.     return( "Couldn't allocate ScreenBuffer 2\n" );
  623.     }
  624.  
  625.     /* Let's use the UserData to store the buffer number, for
  626.      * easy identification when the message comes back.
  627.      */
  628.     scbuf[ 0 ]->sb_DBufInfo->dbi_UserData1 = ( APTR ) ( 0 );
  629.     scbuf[ 1 ]->sb_DBufInfo->dbi_UserData1 = ( APTR ) ( 1 );
  630.     status[ 0 ] = OK_REDRAW;
  631.     status[ 1 ] = OK_REDRAW;
  632.  
  633.     if ( !( face = makeImageBM() ) )
  634.     {
  635.     return( "Couldn't allocate image bitmap\n" );
  636.     }
  637.     InitRastPort( &rport[ 0 ] );
  638.     InitRastPort( &rport[ 1 ] );
  639.     rport[ 0 ].BitMap = scbuf[ 0 ]->sb_BitMap;
  640.     rport[ 1 ].BitMap = scbuf[ 1 ]->sb_BitMap;
  641.  
  642.     x = 50;
  643.     y = 70;
  644.     xstep = 1;
  645.     xdir = 1;
  646.     ystep = 1;
  647.     ydir = -1;
  648.  
  649.     /* All is OK */
  650.     return( 0 );
  651. }
  652.  
  653. /*----------------------------------------------------------------------*/
  654.  
  655. /* Draw a crude "face" for animation */
  656.  
  657. #define MAXVECTORS    10
  658.  
  659. struct BitMap *makeImageBM( void )
  660. {
  661.     struct BitMap *bm;
  662.     struct RastPort rport;
  663.     struct AreaInfo area;
  664.     struct TmpRas tmpRas;
  665.     PLANEPTR planePtr;
  666.  
  667.     BYTE areabuffer[ MAXVECTORS*5 ];
  668.  
  669.     if ( bm = ( struct BitMap * )AllocBitMap( BM_WIDTH, BM_HEIGHT, 
  670.     BM_DEPTH, BMF_CLEAR, NULL ) )
  671.     {
  672.     if ( planePtr = AllocRaster( BM_WIDTH, BM_HEIGHT ) )
  673.     {
  674.         InitRastPort( &rport );
  675.         rport.BitMap = bm;
  676.  
  677.         InitArea( &area, areabuffer, MAXVECTORS );
  678.         rport.AreaInfo = &area;
  679.  
  680.         InitTmpRas( &tmpRas, planePtr, RASSIZE( BM_WIDTH, BM_HEIGHT ) );
  681.         rport.TmpRas = &tmpRas;
  682.  
  683.         SetABPenDrMd( &rport, 3, 0, JAM1 );
  684.         AreaEllipse( &rport, BM_WIDTH/2, BM_HEIGHT/2, 
  685.         BM_WIDTH/2-4, BM_HEIGHT/2-4 );
  686.         AreaEnd( &rport );
  687.  
  688.         SetAPen( &rport, 2 );
  689.         AreaEllipse( &rport, 5*BM_WIDTH/16, BM_HEIGHT/4, 
  690.         BM_WIDTH/9, BM_HEIGHT/9 );
  691.         AreaEllipse( &rport, 11*BM_WIDTH/16, BM_HEIGHT/4, 
  692.         BM_WIDTH/9, BM_HEIGHT/9 );
  693.         AreaEnd( &rport );
  694.  
  695.         SetAPen( &rport, 1 );
  696.         AreaEllipse( &rport, BM_WIDTH/2, 3*BM_HEIGHT/4, 
  697.         BM_WIDTH/3, BM_HEIGHT/9 );
  698.         AreaEnd( &rport );
  699.  
  700.         FreeRaster( planePtr, BM_WIDTH, BM_HEIGHT );
  701.     }
  702.     else
  703.     {
  704.         FreeBitMap( bm );
  705.         bm = NULL;
  706.     }
  707.     return( bm );
  708.     }
  709. }
  710.  
  711. /*----------------------------------------------------------------------*/
  712.  
  713. /* Make a pair of slider gadgets to control horizontal and vertical
  714.  * speed of motion.
  715.  */
  716. struct Gadget *createAllGadgets( struct Gadget **glistptr, void *vi )
  717. {
  718.     struct NewGadget ng;
  719.     struct Gadget *gad;
  720.  
  721.     gad = CreateContext( glistptr );
  722.  
  723.     ng.ng_LeftEdge = 100;
  724.     ng.ng_TopEdge = 1;
  725.     ng.ng_Width = 100;
  726.     ng.ng_Height = 12;
  727.     ng.ng_GadgetText = "Horiz:  ";
  728.     ng.ng_TextAttr = &Topaz80;
  729.     ng.ng_VisualInfo = vi;
  730.     ng.ng_GadgetID = GAD_HORIZ;
  731.     ng.ng_Flags = 0;
  732.  
  733.     horizgad = gad = CreateGadget( SLIDER_KIND, gad, &ng, 
  734.     GTSL_Min, 0, 
  735.     GTSL_Max, 9, 
  736.     GTSL_Level, 1, 
  737.     GTSL_MaxLevelLen, 1, 
  738.     GTSL_LevelFormat, "%ld", 
  739.     TAG_DONE );
  740.  
  741.     ng.ng_LeftEdge += 200;
  742.     ng.ng_GadgetID = GAD_VERT;
  743.     ng.ng_GadgetText = "Vert:  ";
  744.     vertgad = gad = CreateGadget( SLIDER_KIND, gad, &ng, 
  745.     GTSL_Min, 0, 
  746.     GTSL_Max, 9, 
  747.     GTSL_Level, 1, 
  748.     GTSL_MaxLevelLen, 1, 
  749.     GTSL_LevelFormat, "%ld", 
  750.     TAG_DONE );
  751.  
  752.     return( gad );
  753. }
  754.  
  755. /*----------------------------------------------------------------------*/
  756.  
  757. /* Clean up everything and exit, printing the errorstring if any */
  758. void error_exit( STRPTR errorstring )
  759. {
  760.     if ( controlwin )
  761.     {
  762.     ClearMenuStrip( controlwin );
  763.     CloseWindowSafely( controlwin );
  764.     }
  765.  
  766.     if ( canvaswin )
  767.     {
  768.     ClearMenuStrip( canvaswin );
  769.     CloseWindowSafely( canvaswin );
  770.     }
  771.  
  772.     if ( controlsc )
  773.     {
  774.     CloseScreen( controlsc );
  775.     }
  776.  
  777.     if ( canvassc )
  778.     {
  779.     FreeScreenBuffer( canvassc, scbuf[ 1 ] );
  780.     FreeScreenBuffer( canvassc, scbuf[ 0 ] );
  781.     CloseScreen( canvassc );
  782.     }
  783.  
  784.     if ( dbufport )
  785.     {
  786.     DeleteMsgPort( dbufport );
  787.     }
  788.  
  789.     if ( userport )
  790.     {
  791.     DeleteMsgPort( userport );
  792.     }
  793.  
  794.     if ( GadToolsBase )
  795.     {
  796.     FreeGadgets( glist );
  797.     FreeMenus( menu );
  798.     FreeVisualInfo( canvasvi );
  799.     FreeVisualInfo( controlvi );
  800.     CloseLibrary( GadToolsBase );
  801.     }
  802.  
  803.     if ( IntuitionBase )
  804.     {
  805.     CloseLibrary( ( struct Library *)IntuitionBase );
  806.     }
  807.  
  808.     if ( face )
  809.     {
  810.     FreeBitMap( face );
  811.     }
  812.  
  813.     if ( GfxBase )
  814.     {
  815.     CloseLibrary( ( struct Library *)GfxBase );
  816.     }
  817.  
  818.     if ( errorstring )
  819.     {
  820.     printf( errorstring );
  821.     exit( 20 );
  822.     }
  823.  
  824.     exit( 0 );
  825. }
  826.  
  827.  
  828. /*----------------------------------------------------------------------*/
  829.  
  830. void StripIntuiMessages( struct MsgPort *mp, struct Window *win );
  831.  
  832. /* these functions close an Intuition window
  833.  * that shares a port with other Intuition
  834.  * windows or IPC customers.
  835.  *
  836.  * We are careful to set the UserPort to
  837.  * null before closing, and to free
  838.  * any messages that it might have been
  839.  * sent.
  840.  */
  841. #include "exec/types.h"
  842. #include "exec/nodes.h"
  843. #include "exec/lists.h"
  844. #include "exec/ports.h"
  845. #include "intuition/intuition.h"
  846.  
  847. void
  848. CloseWindowSafely( struct Window *win )
  849. {
  850.     /* we forbid here to keep out of race conditions with Intuition */
  851.     Forbid();
  852.  
  853.     /* send back any messages for this window 
  854.      * that have not yet been processed
  855.      */
  856.     StripIntuiMessages( win->UserPort, win );
  857.  
  858.     /* clear UserPort so Intuition will not free it */
  859.     win->UserPort = NULL;
  860.  
  861.     /* tell Intuition to stop sending more messages */
  862.     ModifyIDCMP( win, 0L );
  863.  
  864.     /* turn multitasking back on */
  865.     Permit();
  866.  
  867.     /* and really close the window */
  868.     CloseWindow( win );
  869. }
  870.  
  871. /* remove and reply all IntuiMessages on a port that
  872.  * have been sent to a particular window
  873.  * ( note that we don't rely on the ln_Succ pointer
  874.  *  of a message after we have replied it )
  875.  */
  876. void
  877. StripIntuiMessages( mp, win )
  878. struct MsgPort *mp;
  879. struct Window *win;
  880. {
  881.     struct IntuiMessage *msg;
  882.     struct Node *succ;
  883.  
  884.     msg = ( struct IntuiMessage * ) mp->mp_MsgList.lh_Head;
  885.  
  886.     while( succ =  msg->ExecMessage.mn_Node.ln_Succ )
  887.     {
  888.  
  889.     if( msg->IDCMPWindow ==  win )
  890.     {
  891.  
  892.         /* Intuition is about to free this message.
  893.          * Make sure that we have politely sent it back.
  894.          */
  895.         Remove( ( struct Node * )msg );
  896.  
  897.         ReplyMsg( ( struct Message * )msg );
  898.     }
  899.         
  900.     msg = ( struct IntuiMessage * ) succ;
  901.     }
  902. }
  903.  
  904. /*----------------------------------------------------------------------*/
  905.