echo; /* Self-compilation stuff ala John Toebes for Lattice users: lc -M bdemon.c bdintui.c bdblit.c bdwin.c blink with bdemon.with quit ***************************************************************************** * BlitDemons by Walter Strickler * This program and all its source code are in the public domain and are * freely distributable and usable for any purpose, private or commercial. * * This program is a port of a program by Loren Blaney which runs under * Apex, an unknown operating system on the Amiga. It is based on the * cellular automaton called 'Demons' described in the August, 1989, * issue of Scientific American. * * It is not my fault that it busy-waits. This is usually inexcusable in * an Amiga program, but it is the call to WaitBlit() that causes it. It is * really a shame, since this program should require only a small portion of * the 68000. As it is, it hogs all of it. ****************************************************************************/ #include #include "bdemon.h" int main() { int IntuiReturn, IPRet, RetVal; struct BDMainStruct BDStuff; IntuiReturn = InitIntui(); if (IntuiReturn == INTUI_OK) { IPRet = InitPlanes(&BDStuff, BDWindow); if (IPRet != PLANES_CHOKE) { BDStuff.BDBlitNodes = InitBlits(&BDStuff); if (BDStuff.BDBlitNodes != NULL) { RetVal = MainLoop(&BDStuff); } else { RetVal = INIT_BLIT_CHOKE; } } /* End BDStuff OK */ else { RetVal = PLANES_CHOKE; } /* End BDStuff not OK */ KillPlanes(&BDStuff); } else /* Single entry, single exit: so there, Guy! */ { RetVal = IntuiReturn; } CloseIntui(); ErrorMsgs(RetVal); return RetVal; } /* End main() */ void ErrorMsgs(ErrorNum) int ErrorNum; { switch (ErrorNum) { case 0: break; /* A-OK */ case NO_INTUI: printf("Couldn't open Intuition!\n"); break; case NO_GFX: printf("Couldn't open Graphics!\n"); break; case NO_SCREEN: printf("Couldn't open the Screen.\n"); break; case NO_WIN: printf("Couldn't open the Window.\n"); break; case PLANES_CHOKE: printf("Couldn't allocate the temp. bit planes.\n"); break; case ABOUT_CHOKE: printf("Couldn't open the about window.\n"); break; case INIT_BLIT_CHOKE: printf("Couldn't allocate the blitter nodes.\n"); break; case WBI_CHOKE: printf("Couldn't start the blitter interrupt.\n"); break; default: printf("Unknown error: %d\n", ErrorNum); break; } } /************************************************************************/ int MainLoop(BDSchtoff) struct BDMainStruct *BDSchtoff; { int RetVal, LeavingNow, MsgVal, MsgControl, RandReturn, First; RetVal = ML_OK; LeavingNow = FALSE; MsgControl = NO_WAIT; First = TRUE; while (LeavingNow == FALSE) { if (First) { First = FALSE; /* Do this once only */ MsgVal = NEW; /* Hotwire MsgVal on first time through */ } /* End First */ else { if (MsgControl == NO_WAIT) /* If we do WAIT, hurry up and wait! */ { OneGen(BDSchtoff); } MsgVal = CheckMsg(MsgControl); } /* End not First */ switch (MsgVal) { case CLOSE_WIN: case QUIT: LeavingNow = TRUE; break; case NEW: RandReturn = Randomize(BDSchtoff, BDWindow); switch (RandReturn) { case RAND_OK: OffStart(); /* Set menu items */ OnStop(); MsgControl = NO_WAIT; break; case RAND_QUIT: LeavingNow = TRUE; break; case RAND_ABOUT_CHOKE: LeavingNow = TRUE; RetVal = ABOUT_CHOKE; break; } break; case STOP: MsgControl = WAIT; OffStop(); OnStart(); break; case START: MsgControl = NO_WAIT; OffStart(); OnStop(); break; case ABOUT: if (DisplayAbout() == DA_CHOKE) { LeavingNow = TRUE; RetVal = ABOUT_CHOKE; } break; case NO_MSG: /* One more generation. */ break; default: assert (FALSE); /* Shouldn't be here */ break; } /* End case CheckMsg() */ } /* End while not leaving */ return RetVal; } /* End MainLoop() */ /******************************************************************************* InitPlanes() fills in a structure of type BDMainStruct, pointed at by Strcut, given the pointer to a window, *Win. Returns PLANES_CHOKE if any allocations weren't successful. *******************************************************************************/ int InitPlanes(Struct, Win) struct BDMainStruct *Struct; struct Window *Win; { int i, DispStartOffset, RetVal; RetVal = PLANES_OK; /* Find the relative start of the blitfield in words */ /* Note that BorderTop and BorderBottom are 1 too large */ DispStartOffset = (((Win -> BorderTop) - 1 ) + Win -> TopEdge) * ((Win -> WScreen -> Width) / 16) + (Win -> LeftEdge) / 16; for (i=0; i < NUM_PLANES; i++) { (Struct -> Display)[i] = DispStartOffset + (WORD *) Win -> RPort -> BitMap -> Planes[i]; /* Whew! */ } Struct -> XSize = Win -> Width; Struct -> YSize = (Win -> Height) - ((Win -> BorderTop) - 1) - ((Win -> BorderBottom) - 1); /* Sub. borders */ Struct -> Mod = (Win -> WScreen -> Width) - (Win -> Width);/* Blit Modulo */ /* Note that BorderLeft and BorderRight are 2 too large */ Struct -> LRBorder = max (Win -> BorderLeft - 2, Win -> BorderLeft - 2); /* Now allocate some bitplanes for temporaries... */ Struct -> Temp = (WORD *) AllocRaster(Struct -> XSize, Struct -> YSize); if (Struct -> Temp == 0) { RetVal = PLANES_CHOKE; } /* End Temp Choke */ else { Struct -> Equal = (WORD *)AllocRaster(Struct -> XSize, Struct -> YSize); if (Struct -> Equal == 0) { RetVal = PLANES_CHOKE; } /* End Equal choke */ else { i = 0; while ((RetVal != PLANES_CHOKE) && (i < NUM_PLANES)) { Struct -> Incr[i] = (WORD *) AllocRaster(Struct -> XSize, Struct -> YSize); if (Struct -> Incr[i] == 0) { RetVal = PLANES_CHOKE; } i++; } /* End While allocating Incr */ } /* End Equal OK */ } /* End Temp OK */ return RetVal; } /* End InitPlanes */ /******************************************************************************* KillPlanes() deallocates all of the temporary bitplanes allocated in InitPlanes. *******************************************************************************/ void KillPlanes(Struct) struct BDMainStruct *Struct; { int i; if (Struct -> Temp != 0) { FreeRaster((PLANEPTR)Struct -> Temp, Struct -> XSize, Struct -> YSize); Struct -> Temp = 0; } if (Struct -> Equal != 0) { FreeRaster((PLANEPTR)Struct -> Equal, Struct -> XSize, Struct -> YSize); Struct -> Equal = 0; } for (i = 0; i < NUM_PLANES; i++) { if (Struct -> Incr[i] != 0) { FreeRaster((PLANEPTR) Struct -> Incr[i], Struct -> XSize, Struct -> YSize); Struct -> Incr[i] = NULL; } } } /* End KillPlanes() */ /******************************************************************************* Randomize() sets every pixel within the borders of the window pointed at by Win. *******************************************************************************/ int Randomize(BDStuff, Win) struct BDMainStruct *BDStuff; struct Window *Win; { int Left, Right, Top, Bottom, XWords, YLines, i, x, y, Redo, MsgControl, MsgVal, LeavingNow, PlaneNum, RetVal; WORD LRBorder, LMask, RMask, *(Disp[NUM_PLANES]), MyWord, RandWord; long Seed; struct DateStamp *Now; MsgControl = NO_WAIT; RetVal = RAND_OK; /* Innocent until proven guilty */ LeavingNow = FALSE; do /* Loop if Redo gets set to TRUE by the NEW menuitem. */ { Redo = FALSE; /* Only one more time unless Redo gets set */ /* Seed the random number generator with number of TICK's today: */ Now = (struct DateStamp *) malloc (sizeof (struct DateStamp)); DateStamp(Now); /* This Lattice compiler warning is not my fault */ Seed = (Now -> ds_Tick) + ((Now -> ds_Minute) * TICKS_PER_SECOND * 60); free(Now); srand(Seed); /* Set the border masks */ LRBorder = BDStuff -> LRBorder; LMask = 0xffff >> LRBorder; RMask = 0xffff << LRBorder; /* Set the plane pointers */ for (i=0; i < NUM_PLANES; i++) { Disp[i] = BDStuff -> Display[i]; } /* Clear the screen first */ Left = LRBorder; Right = ((BDStuff -> XSize) -1) - LRBorder; Top = (BDWindow -> BorderTop) -1; /* Border off by one */ Bottom = (BDWindow -> Height) - (BDWindow -> BorderBottom); SetAPen (BDWindow -> RPort, 0); RectFill (BDWindow -> RPort, Left, Top, Right, Bottom); /* Now set pixels Randomly */ /* Sweep from top to bottom; bail out if Redo or LeavingNow gets set */ XWords = (BDStuff -> XSize) / 16; YLines = (BDStuff -> YSize); y = 0; while ((y < YLines) && (!Redo) && (!LeavingNow)) { for (x = 0; x < XWords; x++) { for (PlaneNum = 0; PlaneNum < NUM_PLANES; PlaneNum++) { RandWord = (rand() >> 8) & 0xffff; /* Use middle 16 bits */ /* Set MyWord given LMask and RMask */ if (x == 0) /* First word */ { MyWord = *(Disp[PlaneNum]) & ~LMask; MyWord = MyWord | (RandWord & LMask); } else if (x == (XWords -1)) /* Last word */ { MyWord = *(Disp[PlaneNum]) & ~RMask; MyWord = MyWord | (RandWord & RMask); } else { MyWord = RandWord; } *(Disp[PlaneNum]) = MyWord; (Disp[PlaneNum])++; } /* End for PlaneNum */ } /* End for x */ MsgVal = CheckMsg(MsgControl); switch(MsgVal) { case CLOSE_WIN: case QUIT: RetVal = RAND_QUIT; LeavingNow = TRUE; break; case STOP: MsgControl = WAIT; OffStop(); OnStart(); break; case START: MsgControl = NO_WAIT; OffStart(); OnStop(); break; case NEW: Redo = TRUE; MsgControl = NO_WAIT; OffStart(); OnStop(); break; case ABOUT: if (DisplayAbout() == DA_CHOKE) { LeavingNow = TRUE; /* Let's bomb out now */ RetVal = RAND_ABOUT_CHOKE; } break; case NO_MSG: break; default: assert (FALSE); /* Shouldn't be here */ break; } y++; /* Next line */ } /* End for y */ } while (Redo); return RetVal; } /* End Randomize() */