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