home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
500-599
/
ff502.lzh
/
CELLS
/
CELLSSource.lzh
/
cMain.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-20
|
14KB
|
520 lines
/*
* CELLS An Implementation of the WireWorld cellular automata
* as described in Scientific American, Jan 1990.
*
* Copyright 1990 by Davide P. Cervone.
* You may use this code, provided this copyright notice is kept intact.
* See the CELLS.HELP file for complete information on distribution conditions.
*/
/*
* File: cMain.c Main wait loop and Intuition stuff.
*/
#include "cGadget.h"
#include "cRequest.h"
#include "cReqLP.h"
#undef AllocMem
#define IBMW (LP_PNAMEW-2) /* size of View image bit map */
#define IBMH (LP_PNAMEH-2)
extern struct Window *OpenWindow();
extern struct Screen *OpenScreen();
extern struct IntuiMessage *GetMsg();
extern APTR OpenLibrary();
extern struct TextFont *OpenDiskFont();
extern UBYTE *AllocMem();
extern PLANEPTR AllocRaster();
UBYTE *ResetArray,*UndoArray,*CurGen,*NewGen; /* the state arrays */
static struct TextAttr cTextAttr = {"Moonstone.font", 8, 0, 0};
static struct TextFont *myFont;
static short MouseX,MouseY; /* for buffered mouse move stuff */
/*
* The CELLS screen
*/
static struct NewScreen NewScreen =
{
0,0, SCREENW,SCREENH, SCREEND, BACKGROUND,FOREGROUND, 0, CUSTOMSCREEN, NULL,
" Cellular Automata v1.2", NULL, NULL
};
struct Screen *myScreen;
/*
* The CELLS window
*/
static struct NewWindow NewWindow =
{
WINDOWX,WINDOWY, WINDOWW,WINDOWH, BACKGROUND,FOREGROUND,
RAWKEY| MOUSEBUTTONS| GADGETUP| GADGETDOWN| ACTIVEWINDOW|
INACTIVEWINDOW| REQSET| DISKINSERTED| DISKREMOVED,
SMART_REFRESH| NOCAREREFRESH| BACKDROP| BORDERLESS| ACTIVATE|
RMBTRAP| REPORTMOUSE,
NULL, NULL, NULL, NULL, NULL, 20,10, -1,-1, WBENCHSCREEN
};
struct Window *myWindow;
struct RastPort *wrp,*rp,*irp; /* the window RP, DBuffer rp, and View RP */
static struct RastPort RP,iRP; /* fake RPs for DBuffer and View image */
static struct BitMap BM,iBM; /* BitMaps for same */
int DBufMode = TRUE; /* TRUE if DBuffer Mode is one */
int BufferMouse; /* TRUE if collecting mouse moves for later */
/*
* FreeBM()
*
* Free the allocated planes of the Double Buffer BitMap
* If the Image Bitmap planes were allocated, free them (they are all in
* a contiguous block, to match both the BitMap and Image structures)
*/
static void FreeBM()
{
short i;
for (i=0; i<SCREEND; i++)
if (BM.Planes[i]) FreeRaster(BM.Planes[i],BOARDW,BOARDH);
if (iBM.Planes[0]) FreeRaster(iBM.Planes[0],IBMW,IBMH*SCREEND);
}
/*
* DoExit()
*
* Main exit routine - prints an error message, if necessary, and then
* cleans up any allocated memory, closes windows and screens,
* closes libraries, etc., then exits with a proper return value.
*/
void DoExit(s,x1,x2,x3)
char *s, *x1,*x2,*x3;
{
int status = OK_EXIT;
if (s)
{
printf(s,x1,x2,x3);
printf("\n");
status = ERROR_EXIT;
}
ClearHelp();
ClearDirectoryList();
ClearLists(TRUE);
ClearLibs();
FreeBlock();
FreeBM();
ResetErrorWindow();
RestoreStartingDir();
if (myWindow) CloseWindow(myWindow);
if (myScreen) CloseScreen(myScreen);
if (ResetArray) FreeMem(ResetArray,ARRAYSIZE);
if (UndoArray) FreeMem(UndoArray,ARRAYSIZE);
if (CurGen) FreeMem(CurGen,ARRAYSIZE);
if (NewGen) FreeMem(NewGen,ARRAYSIZE);
if (myFont) CloseFont(myFont);
if (IntuitionBase) CloseLibrary(IntuitionBase);
if (GfxBase) CloseLibrary(GfxBase);
if (DiskfontBase) CloseLibrary(DiskfontBase);
exit(status);
}
/*
* CheckLibOpen()
*
* Attempt to open the specified version of the specified library.
* If a failure, report ythe error and exit, otherwise return the library
* pointer.
*/
void CheckLibOpen(lib,name,rev)
APTR *lib;
char *name;
int rev;
{
extern APTR OpenLibrary();
if ((*lib = OpenLibrary(name,(ULONG)rev)) == NULL)
DoExit("Can't open '%s'",name);
}
/*
* OpenMyWindow
*
* If the screen has been openned, open the window on that screen
* Try to open the window
* If not OK, exit with an error
* Otherwise, set the window rast port,
* add the gadgets to the window and refresh them (this avoids the
* extra refresh Intuition makes when it opens a window with gadgets)
* Set the initial board size and clear the screen
* Set the slider positions.
*/
static void OpenMyWindow()
{
if (myScreen)
{
NewWindow.Screen = myScreen;
NewWindow.Type = CUSTOMSCREEN;
}
myWindow = OpenWindow(&NewWindow);
if (myWindow == NULL) DoExit("Can't open my window");
wrp = myWindow->RPort;
AddGList(myWindow,&cGadget[0],-1,GADGET_COUNT,NULL);
RefreshGadgets(&cGadget[0],myWindow,NULL);
SetBoardSize(CELLSIZE);
ClearScreen(TRUE);
UpdateSliders();
}
/*
* OpenMyScreen()
*
* Try to get the CELLS font (Moonstone).
* If successful, set the screen to use that font,
* Otherwise, warn the user about the missing font
* Try to open the screen
* If not OK, exit with an error
* Otherwise, load the colors and remove the screen title bar (we want the
* CELLS window to be able to show over top of its border)
* Reset the screen pen color in case NL-Daemon is running
*/
static void OpenMyScreen()
{
myFont = OpenDiskFont(&cTextAttr);
if (myFont)
NewScreen.Font = &cTextAttr;
else
printf("Can't Open %s -- Things may look ugly!\n",cTextAttr.ta_Name);
myScreen = OpenScreen(&NewScreen);
if (myScreen == NULL) DoExit("Can't open my screen");
LoadColors();
ShowTitle(myScreen,FALSE);
myScreen->DetailPen = BACKGROUND;
}
/*
* SetupRP()
*
* Initialize the DBuffer and View image rastports, and their pointers
* Initialize the BitMaps for them
* Attempt to allocate board-sized rasters for the DBuffer
* Attempt to allocate contiguous rasters for the View image
* (it will be used by an Image structure during View mode)
* Set the rast ports to use the bitmaps
*/
static void SetupRP()
{
short i;
InitRastPort(&RP); InitRastPort(&iRP);
rp = &RP; irp = &iRP;
InitBitMap(&BM,SCREEND,BOARDW,BOARDH);
InitBitMap(&iBM,SCREEND,IBMW,IBMH);
for (i=0; i<SCREEND; i++)
{
BM.Planes[i] = AllocRaster(BOARDW,BOARDH);
if (BM.Planes[i] == NULL)
DoExit("Can't Allocate Raster %d of size %d,%d",i,BOARDW,BOARDH);
}
iBM.Planes[0] = AllocRaster(IBMW,IBMH*SCREEND);
if (iBM.Planes[0] == NULL)
DoExit("Can't Allocate Raster for Image Data");
for (i=1; i<SCREEND; i++)
iBM.Planes[i] = iBM.Planes[i-1] + RASSIZE(IBMW,IBMH);
RP.BitMap = &BM; iRP.BitMap = &iBM;
}
/*
* SetDBufMode()
*
* Set to the specified mode
* If turning DBuf mode ON
* use the DBuffer Rast Port, and copy the screen to the buffer
* Otherwise
* use the window Rast Port directly
*/
void SetDBufMode(theMode)
int theMode;
{
DBufMode = theMode;
if (theMode == TRUE)
{
rp = &RP;
UpdateBuffer();
} else {
rp = wrp;
}
}
/*
* SetupArrays()
*
* Allocate the arrays needed for the state information
* (Reset is used by the RESET button, Undo by the UNDO button,
* CurGen is the current states as shown on the screen, NewGen is
* the next generation being calculated, and is used by SELECT and
* MOVE/COPY/PART to determine the selected cells)
* If any of the arrays could not be allocated, exit with an error
* Otherwise, clear the important arrays.
*/
static void SetupArrays()
{
ResetArray = AllocMem(ARRAYSIZE,0);
UndoArray = AllocMem(ARRAYSIZE,0);
CurGen = AllocMem(ARRAYSIZE,0);
NewGen = AllocMem(ARRAYSIZE,0);
if (ResetArray == NULL || UndoArray == NULL ||
CurGen == NULL || NewGen == NULL)
DoExit("Not enough memory for Generation Arrays");
ClearGrid(ResetArray);
ClearGrid(UndoArray);
ClearGrid(CurGen);
}
/*
* MoveMouse()
*
* If a requester is up, do the requester mouse routine
* Otherwise do the regular mouse routine
* Clear the remembered mouse position
*/
static void MoveMouse(Mx,My,theMessage)
short Mx,My;
struct IntuiMessage *theMessage;
{
if (ActiveRequest)
DoReqMouseMove(Mx,My,theMessage);
else
DoMouseMove(Mx,My,theMessage);
MouseX = MouseY = 0;
}
/*
* DoMessage()
*
* Clear any error messages (in the title bar)
* Set the gadgets to the proper shifted or un-shifted mode
* If there are stored mouse moves and the current message is NOT another
* mouse move, then do the stored mouse move before going on
*
* For each type of message, do the right thing:
*
* RAWKEY:
* Do the kayboard routine
*
* MOUSEBUTTONS:
* Do the mouse button routine
*
* MOUSEMOVE:
* If mouse moves are being collected and combined (to save time)
* save the new mouse position
* otherwise
* do the mouse move right away
*
* GADGETDOWN:
* Get the gadget in question
* If the gadget is from a requester, do the requester routine
* otherwise do the gadget down routine
*
* GADGETUP:
* Get the gadget in question
* If the gadget is from a requester, do the requester routine
* otherwise do the gadget up routine
*
* REQSET:
* Do the request set routine for the active requester
*
* INACTIVEWINDOW:
* Do the window inactivate routine
*
* DISKREMOVED or INSERTED:
* Do the proper disk routine
*/
short DoMessage(theMessage,NotDone)
struct IntuiMessage *theMessage;
short NotDone;
{
struct Gadget *theGadget;
ClearError(theMessage);
ShiftGadgets(theMessage->Qualifier & SHIFTKEYS);
if (theMessage->Class != MOUSEMOVE && (MouseX || MouseY))
MoveMouse(MouseX,MouseY,NULL);
switch (theMessage->Class)
{
case RAWKEY:
NotDone = DoKey(theMessage->Code,theMessage,NotDone);
break;
case MOUSEBUTTONS:
DoMouseButton(theMessage->Code,theMessage->MouseX,
theMessage->MouseY,theMessage);
break;
case MOUSEMOVE:
if (BufferMouse)
{
MouseX = theMessage->MouseX;
MouseY = theMessage->MouseY;
} else {
MoveMouse(theMessage->MouseX,theMessage->MouseY,theMessage);
}
break;
case GADGETDOWN:
theGadget = (struct Gadget *)theMessage->IAddress;
if (theGadget->GadgetType & REQGADGET)
DoReqGadgetDown(theGadget,theMessage);
else
DoGadgetDown(theGadget,theMessage);
break;
case GADGETUP:
theGadget = (struct Gadget *)theMessage->IAddress;
if (theGadget->GadgetType & REQGADGET)
NotDone = DoReqGadgetUp(theGadget,theMessage,NotDone);
else
NotDone = DoGadgetUp(theGadget,theMessage,NotDone);
break;
case REQSET:
DoReqSet(ActiveRequest);
break;
case INACTIVEWINDOW:
DoInactive(theMessage->IDCMPWindow,theMessage);
break;
case DISKINSERTED:
DoDiskInserted(theMessage);
break;
case DISKREMOVED:
DoDiskRemoved(theMessage);
break;
}
return(NotDone);
}
/*
* WaitForAction()
*
* While there are more actions to be done,
* While there are messages in the message port
* Do the messages, and reply to them
* If we are still not done and there are no more messages
* if there are buffered mouse moves, do them
* update the shifted status of the keys (in case the changes was delayed)
* wait for the next message
*/
static void WaitForAction()
{
struct IntuiMessage *theMessage;
short NotDone = TRUE;
struct MsgPort *thePort = myWindow->UserPort;
long SignalMask = (1 << thePort->mp_SigBit);
while (NotDone)
{
while (theMessage = GetMsg(thePort))
{
if (NotDone) NotDone = DoMessage(theMessage,NotDone);
ReplyMsg(theMessage);
}
if (NotDone)
{
if (MouseX || MouseY) MoveMouse(MouseX,MouseY,NULL);
UpdateShiftKeys();
Wait(SignalMask);
}
}
}
/*
* CheckForAction_)
*
* Do any actions that may be in the message queue, but don't wait for
* new messages (this is called when CELLS is executing a circuit)
*/
short CheckForAction(NotDone)
short NotDone;
{
struct IntuiMessage *theMessage;
struct MsgPort *thePort = myWindow->UserPort;
while (theMessage = GetMsg(thePort))
{
if (NotDone) NotDone = DoMessage(theMessage,NotDone);
ReplyMsg(theMessage);
}
return(NotDone);
}
/*
* main()
*
* Open the requeired libraries
* Get the inital directory for replacement when we are done
* Attempt to read a color file, if any
* Allocate and set up the state arrays, rast ports and bit maps
* Open the screen and window
* Set the CELLS screen as the one where System Requests should appear
* If a file name was provided on the command line, try to load it
* Set the pointer to the drawing color
* Do the main action loop
* When that loop exits, we are all done, so exit with no error
*/
void main(argc,argv)
int argc;
char *argv[];
{
CheckLibOpen(&IntuitionBase,"intuition.library",INTUITION_REV);
CheckLibOpen(&GfxBase,"graphics.library",GRAPHICS_REV);
CheckLibOpen(&DiskfontBase,"diskfont.library",DISKFONT_REV);
SaveStartingDir();
ReadColorFile();
SetupArrays();
SetupRP();
OpenMyScreen();
OpenMyWindow();
SetErrorWindow(myWindow);
if (argc > 1)
{
InvertGadget(&cGadget[ID_LOAD]);
ReadFile(argv[1],FALSE);
}
SetPointerColor(PenInUse);
WaitForAction();
DoExit(NULL);
}