home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / NDK / NDK_3.1 / Examples1 / intuition / doublebuffer.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-10-27  |  20.1 KB  |  910 lines

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