home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d502 / cells.lha / CELLS / CELLSSource.lzh / cMain.c < prev    next >
C/C++ Source or Header  |  1991-04-20  |  14KB  |  520 lines

  1. /*
  2.  *  CELLS       An Implementation of the WireWorld cellular automata
  3.  *              as described in Scientific American, Jan 1990.
  4.  *
  5.  *              Copyright 1990 by Davide P. Cervone.
  6.  *  You may use this code, provided this copyright notice is kept intact.
  7.  *  See the CELLS.HELP file for complete information on distribution conditions.
  8.  */
  9.  
  10. /*
  11.  *  File:  cMain.c          Main wait loop and Intuition stuff.
  12.  */
  13.  
  14.  
  15. #include "cGadget.h"
  16. #include "cRequest.h"
  17. #include "cReqLP.h"
  18.  
  19. #undef AllocMem
  20.  
  21. #define IBMW    (LP_PNAMEW-2)               /* size of View image bit map */
  22. #define IBMH    (LP_PNAMEH-2)
  23.  
  24. extern struct Window *OpenWindow();
  25. extern struct Screen *OpenScreen();
  26. extern struct IntuiMessage *GetMsg();
  27. extern APTR OpenLibrary();
  28. extern struct TextFont *OpenDiskFont();
  29. extern UBYTE *AllocMem();
  30. extern PLANEPTR AllocRaster();
  31.  
  32. UBYTE *ResetArray,*UndoArray,*CurGen,*NewGen;           /* the state arrays */
  33.  
  34. static struct TextAttr cTextAttr = {"Moonstone.font", 8, 0, 0};
  35. static struct TextFont *myFont;
  36. static short MouseX,MouseY;             /* for buffered mouse move stuff */
  37.  
  38.  
  39. /*
  40.  *  The CELLS screen
  41.  */
  42.  
  43. static struct NewScreen NewScreen =
  44. {
  45.    0,0, SCREENW,SCREENH, SCREEND, BACKGROUND,FOREGROUND, 0, CUSTOMSCREEN, NULL,
  46.    " Cellular Automata  v1.2", NULL, NULL
  47. };
  48. struct Screen *myScreen;
  49.  
  50.  
  51. /*
  52.  *  The CELLS window
  53.  */
  54.  
  55. static struct NewWindow NewWindow =
  56. {
  57.    WINDOWX,WINDOWY, WINDOWW,WINDOWH, BACKGROUND,FOREGROUND,
  58.    RAWKEY| MOUSEBUTTONS| GADGETUP| GADGETDOWN| ACTIVEWINDOW|
  59.       INACTIVEWINDOW| REQSET| DISKINSERTED| DISKREMOVED,
  60.    SMART_REFRESH| NOCAREREFRESH| BACKDROP| BORDERLESS| ACTIVATE|
  61.       RMBTRAP| REPORTMOUSE,
  62.    NULL, NULL, NULL, NULL, NULL, 20,10, -1,-1, WBENCHSCREEN
  63. };
  64. struct Window *myWindow;
  65. struct RastPort *wrp,*rp,*irp;    /* the window RP, DBuffer rp, and View RP */
  66. static struct RastPort RP,iRP;    /* fake RPs for DBuffer and View image */
  67. static struct BitMap BM,iBM;      /* BitMaps for same */
  68. int DBufMode = TRUE;              /* TRUE if DBuffer Mode is one */
  69. int BufferMouse;                  /* TRUE if collecting mouse moves for later */
  70.  
  71.  
  72. /*
  73.  *  FreeBM()
  74.  *
  75.  *  Free the allocated planes of the Double Buffer BitMap
  76.  *  If the Image Bitmap planes were allocated, free them (they are all in
  77.  *  a contiguous block, to match both the BitMap and Image structures)
  78.  */
  79.  
  80. static void FreeBM()
  81. {
  82.    short i;
  83.    
  84.    for (i=0; i<SCREEND; i++)
  85.       if (BM.Planes[i]) FreeRaster(BM.Planes[i],BOARDW,BOARDH);
  86.    if (iBM.Planes[0]) FreeRaster(iBM.Planes[0],IBMW,IBMH*SCREEND);
  87. }
  88.  
  89.  
  90. /*
  91.  *  DoExit()
  92.  *
  93.  *  Main exit routine - prints an error message, if necessary, and then
  94.  *  cleans up any allocated memory, closes windows and screens, 
  95.  *  closes libraries, etc., then exits with a proper return value.
  96.  */
  97.  
  98. void DoExit(s,x1,x2,x3)
  99. char *s, *x1,*x2,*x3;
  100. {
  101.    int status = OK_EXIT;
  102.  
  103.    if (s)
  104.    {
  105.       printf(s,x1,x2,x3);
  106.       printf("\n");
  107.       status = ERROR_EXIT;
  108.    }
  109.    ClearHelp();
  110.    ClearDirectoryList();
  111.    ClearLists(TRUE);
  112.    ClearLibs();
  113.    FreeBlock();
  114.    FreeBM();
  115.    ResetErrorWindow();
  116.    RestoreStartingDir();
  117.    if (myWindow)        CloseWindow(myWindow);
  118.    if (myScreen)        CloseScreen(myScreen);
  119.    if (ResetArray)      FreeMem(ResetArray,ARRAYSIZE);
  120.    if (UndoArray)       FreeMem(UndoArray,ARRAYSIZE);
  121.    if (CurGen)          FreeMem(CurGen,ARRAYSIZE);
  122.    if (NewGen)          FreeMem(NewGen,ARRAYSIZE);
  123.    if (myFont)          CloseFont(myFont);
  124.    if (IntuitionBase)   CloseLibrary(IntuitionBase);
  125.    if (GfxBase)         CloseLibrary(GfxBase);
  126.    if (DiskfontBase)    CloseLibrary(DiskfontBase);
  127.    exit(status);
  128. }
  129.  
  130.  
  131. /*
  132.  *  CheckLibOpen()
  133.  *
  134.  *  Attempt to open the specified version of the specified library.
  135.  *  If a failure, report ythe error and exit, otherwise return the library
  136.  *  pointer.
  137.  */
  138.  
  139. void CheckLibOpen(lib,name,rev)
  140. APTR *lib;
  141. char *name;
  142. int rev;
  143. {
  144.    extern APTR OpenLibrary();
  145.    
  146.    if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
  147.       DoExit("Can't open '%s'",name);
  148. }
  149.  
  150.  
  151. /*
  152.  *  OpenMyWindow
  153.  *
  154.  *  If the screen has been openned, open the window on that screen
  155.  *  Try to open the window
  156.  *  If not OK, exit with an error
  157.  *  Otherwise, set the window rast port,
  158.  *  add the gadgets to the window and refresh them (this avoids the
  159.  *  extra refresh Intuition makes when it opens a window with gadgets)
  160.  *  Set the initial board size and clear the screen
  161.  *  Set the slider positions.
  162.  */
  163.  
  164. static void OpenMyWindow()
  165. {
  166.    if (myScreen)
  167.    {
  168.       NewWindow.Screen = myScreen;
  169.       NewWindow.Type   = CUSTOMSCREEN;
  170.    }
  171.    myWindow = OpenWindow(&NewWindow);
  172.    if (myWindow == NULL) DoExit("Can't open my window");
  173.    wrp = myWindow->RPort;
  174.    AddGList(myWindow,&cGadget[0],-1,GADGET_COUNT,NULL);
  175.    RefreshGadgets(&cGadget[0],myWindow,NULL);
  176.    SetBoardSize(CELLSIZE);
  177.    ClearScreen(TRUE);
  178.    UpdateSliders();
  179. }
  180.  
  181.  
  182. /*
  183.  *  OpenMyScreen()
  184.  *
  185.  *  Try to get the CELLS font (Moonstone).
  186.  *  If successful, set the screen to use that font,
  187.  *  Otherwise, warn the user about the missing font
  188.  *  Try to open the screen
  189.  *  If not OK, exit with an error
  190.  *  Otherwise, load the colors and remove the screen title bar (we want the
  191.  *  CELLS window to be able to show over top of its border)
  192.  *  Reset the screen pen color in case NL-Daemon is running
  193.  */
  194.  
  195. static void OpenMyScreen()
  196. {
  197.    myFont = OpenDiskFont(&cTextAttr);
  198.    if (myFont)
  199.       NewScreen.Font = &cTextAttr;
  200.      else
  201.       printf("Can't Open %s -- Things may look ugly!\n",cTextAttr.ta_Name);
  202.    myScreen = OpenScreen(&NewScreen);
  203.    if (myScreen == NULL) DoExit("Can't open my screen");
  204.    LoadColors();
  205.    ShowTitle(myScreen,FALSE);
  206.    myScreen->DetailPen = BACKGROUND;
  207. }
  208.  
  209.  
  210. /*
  211.  *  SetupRP()
  212.  *
  213.  *  Initialize the DBuffer and View image rastports, and their pointers
  214.  *  Initialize the BitMaps for them
  215.  *  Attempt to allocate board-sized rasters for the DBuffer
  216.  *  Attempt to allocate contiguous rasters for the View image
  217.  *   (it will be used by an Image structure during View mode)
  218.  *  Set the rast ports to use the bitmaps
  219.  */
  220.  
  221. static void SetupRP()
  222. {
  223.    short i;
  224.  
  225.    InitRastPort(&RP); InitRastPort(&iRP);
  226.    rp = &RP; irp = &iRP;
  227.    InitBitMap(&BM,SCREEND,BOARDW,BOARDH);
  228.    InitBitMap(&iBM,SCREEND,IBMW,IBMH);
  229.    for (i=0; i<SCREEND; i++)
  230.    {
  231.       BM.Planes[i] = AllocRaster(BOARDW,BOARDH);
  232.       if (BM.Planes[i] == NULL)
  233.          DoExit("Can't Allocate Raster %d of size %d,%d",i,BOARDW,BOARDH);
  234.    }
  235.    iBM.Planes[0] = AllocRaster(IBMW,IBMH*SCREEND);
  236.    if (iBM.Planes[0] == NULL)
  237.       DoExit("Can't Allocate Raster for Image Data");
  238.    for (i=1; i<SCREEND; i++)
  239.       iBM.Planes[i] = iBM.Planes[i-1] + RASSIZE(IBMW,IBMH);
  240.    RP.BitMap = &BM; iRP.BitMap = &iBM;
  241. }
  242.  
  243.  
  244. /*
  245.  *  SetDBufMode()
  246.  *
  247.  *  Set to the specified mode
  248.  *  If turning DBuf mode ON
  249.  *    use the DBuffer Rast Port, and copy the screen to the buffer
  250.  *  Otherwise
  251.  *    use the window Rast Port directly
  252.  */
  253.  
  254. void SetDBufMode(theMode)
  255. int theMode;
  256. {
  257.    DBufMode = theMode;
  258.    if (theMode == TRUE)
  259.    {
  260.       rp = &RP;
  261.       UpdateBuffer();
  262.    } else {
  263.       rp = wrp;
  264.    }
  265. }
  266.  
  267.  
  268. /*
  269.  *  SetupArrays()
  270.  *
  271.  *  Allocate the arrays needed for the state information
  272.  *  (Reset is used by the RESET button, Undo by the UNDO button,
  273.  *   CurGen is the current states as shown on the screen, NewGen is
  274.  *   the next generation being calculated, and is used by SELECT and
  275.  *   MOVE/COPY/PART to determine the selected cells)
  276.  *  If any of the arrays could not be allocated, exit with an error
  277.  *  Otherwise, clear the important arrays.
  278.  */
  279.  
  280. static void SetupArrays()
  281. {
  282.    ResetArray = AllocMem(ARRAYSIZE,0);
  283.    UndoArray  = AllocMem(ARRAYSIZE,0);
  284.    CurGen     = AllocMem(ARRAYSIZE,0);
  285.    NewGen     = AllocMem(ARRAYSIZE,0);
  286.    if (ResetArray == NULL || UndoArray == NULL ||
  287.        CurGen == NULL || NewGen == NULL)
  288.           DoExit("Not enough memory for Generation Arrays");
  289.    ClearGrid(ResetArray);
  290.    ClearGrid(UndoArray);
  291.    ClearGrid(CurGen);
  292. }
  293.  
  294.  
  295. /*
  296.  *  MoveMouse()
  297.  *
  298.  *  If a requester is up, do the requester mouse routine
  299.  *  Otherwise do the regular mouse routine
  300.  *  Clear the remembered mouse position
  301.  */
  302.  
  303. static void MoveMouse(Mx,My,theMessage)
  304. short Mx,My;
  305. struct IntuiMessage *theMessage;
  306. {
  307.    if (ActiveRequest)
  308.      DoReqMouseMove(Mx,My,theMessage);
  309.     else
  310.      DoMouseMove(Mx,My,theMessage);
  311.    MouseX = MouseY = 0;
  312. }
  313.  
  314.  
  315. /*
  316.  *  DoMessage()
  317.  *
  318.  *  Clear any error messages (in the title bar)
  319.  *  Set the gadgets to the proper shifted or un-shifted mode
  320.  *  If there are stored mouse moves and the current message is NOT another
  321.  *    mouse move, then do the stored mouse move before going on
  322.  *
  323.  *  For each type of message, do the right thing:
  324.  *
  325.  *    RAWKEY:
  326.  *      Do the kayboard routine
  327.  *
  328.  *    MOUSEBUTTONS:
  329.  *      Do the mouse button routine
  330.  *
  331.  *    MOUSEMOVE:
  332.  *      If mouse moves are being collected and combined (to save time)
  333.  *        save the new mouse position
  334.  *      otherwise
  335.  *        do the mouse move right away
  336.  *
  337.  *    GADGETDOWN:
  338.  *      Get the gadget in question
  339.  *      If the gadget is from a requester, do the requester routine
  340.  *      otherwise do the gadget down routine
  341.  *
  342.  *    GADGETUP:
  343.  *      Get the gadget in question
  344.  *      If the gadget is from a requester, do the requester routine
  345.  *      otherwise do the gadget up routine
  346.  *
  347.  *   REQSET:
  348.  *     Do the request set routine for the active requester
  349.  *
  350.  *   INACTIVEWINDOW:
  351.  *     Do the window inactivate routine
  352.  *
  353.  *   DISKREMOVED or INSERTED:
  354.  *     Do the proper disk routine
  355.  */
  356.  
  357. short DoMessage(theMessage,NotDone)
  358. struct IntuiMessage *theMessage;
  359. short NotDone;
  360. {
  361.    struct Gadget *theGadget;
  362.  
  363.    ClearError(theMessage);
  364.    ShiftGadgets(theMessage->Qualifier & SHIFTKEYS);
  365.    if (theMessage->Class != MOUSEMOVE && (MouseX || MouseY))
  366.       MoveMouse(MouseX,MouseY,NULL);
  367.    switch (theMessage->Class)
  368.    {
  369.       case RAWKEY:
  370.          NotDone = DoKey(theMessage->Code,theMessage,NotDone);
  371.          break;
  372.  
  373.       case MOUSEBUTTONS:
  374.          DoMouseButton(theMessage->Code,theMessage->MouseX,
  375.            theMessage->MouseY,theMessage);
  376.          break;
  377.  
  378.       case MOUSEMOVE:
  379.          if (BufferMouse)
  380.          {
  381.             MouseX = theMessage->MouseX;
  382.             MouseY = theMessage->MouseY;
  383.          } else {
  384.             MoveMouse(theMessage->MouseX,theMessage->MouseY,theMessage);
  385.          }
  386.          break;
  387.  
  388.       case GADGETDOWN:
  389.          theGadget = (struct Gadget *)theMessage->IAddress;
  390.          if (theGadget->GadgetType & REQGADGET)
  391.             DoReqGadgetDown(theGadget,theMessage);
  392.            else
  393.             DoGadgetDown(theGadget,theMessage);
  394.          break;
  395.  
  396.       case GADGETUP:
  397.          theGadget = (struct Gadget *)theMessage->IAddress;
  398.          if (theGadget->GadgetType & REQGADGET)
  399.             NotDone = DoReqGadgetUp(theGadget,theMessage,NotDone);
  400.            else
  401.             NotDone = DoGadgetUp(theGadget,theMessage,NotDone);
  402.          break;
  403.  
  404.       case REQSET:
  405.          DoReqSet(ActiveRequest);
  406.          break;
  407.  
  408.       case INACTIVEWINDOW:
  409.          DoInactive(theMessage->IDCMPWindow,theMessage);
  410.          break;
  411.          
  412.       case DISKINSERTED:
  413.          DoDiskInserted(theMessage);
  414.          break;
  415.  
  416.       case DISKREMOVED:
  417.          DoDiskRemoved(theMessage);
  418.          break;
  419.    }
  420.    return(NotDone);
  421. }
  422.  
  423.  
  424. /*
  425.  *  WaitForAction()
  426.  *
  427.  *  While there are more actions to be done,
  428.  *    While there are messages in the message port
  429.  *      Do the messages, and reply to them
  430.  *    If we are still not done and there are no more messages
  431.  *      if there are buffered mouse moves, do them
  432.  *      update the shifted status of the keys (in case the changes was delayed)
  433.  *      wait for the next message
  434.  */
  435.  
  436. static void WaitForAction()
  437. {
  438.    struct IntuiMessage *theMessage;
  439.    short NotDone = TRUE;
  440.    struct MsgPort *thePort = myWindow->UserPort;
  441.    long SignalMask = (1 << thePort->mp_SigBit);
  442.  
  443.    while (NotDone)
  444.    {
  445.       while (theMessage = GetMsg(thePort))
  446.       {
  447.          if (NotDone) NotDone = DoMessage(theMessage,NotDone);
  448.          ReplyMsg(theMessage);
  449.       }
  450.       if (NotDone)
  451.       {
  452.          if (MouseX || MouseY) MoveMouse(MouseX,MouseY,NULL);
  453.          UpdateShiftKeys();
  454.          Wait(SignalMask);
  455.       }
  456.    }
  457. }
  458.  
  459.  
  460. /*
  461.  *  CheckForAction_)
  462.  *
  463.  *  Do any actions that may be in the message queue, but don't wait for
  464.  *  new messages (this is called when CELLS is executing a circuit)
  465.  */
  466.  
  467. short CheckForAction(NotDone)
  468. short NotDone;
  469. {
  470.    struct IntuiMessage *theMessage;
  471.    struct MsgPort *thePort = myWindow->UserPort;
  472.  
  473.    while (theMessage = GetMsg(thePort))
  474.    {
  475.       if (NotDone) NotDone = DoMessage(theMessage,NotDone);
  476.       ReplyMsg(theMessage);
  477.    }
  478.    return(NotDone);
  479. }
  480.  
  481.  
  482. /*
  483.  *  main()
  484.  *
  485.  *  Open the requeired libraries
  486.  *  Get the inital directory for replacement when we are done
  487.  *  Attempt to read a color file, if any
  488.  *  Allocate and set up the state arrays, rast ports and bit maps
  489.  *  Open the screen and window
  490.  *  Set the CELLS screen as the one where System Requests should appear
  491.  *  If a file name was provided on the command line, try to load it
  492.  *  Set the pointer to the drawing color
  493.  *  Do the main action loop
  494.  *  When that loop exits, we are all done, so exit with no error
  495.  */
  496.  
  497. void main(argc,argv)
  498. int argc;
  499. char *argv[];
  500. {
  501.    CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
  502.    CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
  503.    CheckLibOpen(&DiskfontBase,"diskfont.library",DISKFONT_REV);
  504.    SaveStartingDir();
  505.    ReadColorFile();
  506.    SetupArrays();
  507.    SetupRP();
  508.    OpenMyScreen();
  509.    OpenMyWindow();
  510.    SetErrorWindow(myWindow);
  511.    if (argc > 1)
  512.    {
  513.       InvertGadget(&cGadget[ID_LOAD]);
  514.       ReadFile(argv[1],FALSE);
  515.    }
  516.    SetPointerColor(PenInUse);
  517.    WaitForAction();
  518.    DoExit(NULL);
  519. }
  520.