/* * What fun! A new LIFE program by Tomas Rokicki. Commented rather * erratically; hell, this is all just one big hack. */ int modulo ; int wmodulo ; int vsize ; #define RASTSIZE (wmodulo * (long)(vsize+1)) #include "structures.h" #include "blit.h" short *a, *b, *c, *d, *e, *t1=NULL, *t2=NULL, *t3=NULL, *t4=NULL ; short noplanes ; short torus ; short orify ; short asm ; struct GfxBase *GfxBase = NULL ; /* the GfxBase */ struct IntuitionBase *IntuitionBase = NULL ; /* the IntuitionBase */ struct Screen *myscreen = NULL ; struct Window *mywindow = NULL ; struct TextAttr myfont = {(STRPTR)"topaz.font", TOPAZ_EIGHTY, 0, 0 }; struct NewScreen mynewscreen = {0, 0, 0, 0, 0, 1, 2, 0, CUSTOMSCREEN, &myfont, (UBYTE *)"AmigaLIFE -- Radical Eye Software"} ; /* * Let's use a borderless window too, so we can get vanilla * keys. This gives us a nicer way to exit and adjust the * speed of the program. But we still play with the screen * bitmaps. */ static struct NewWindow mynewwindow = { 0, 0, 0, 0, 0, 1, VANILLAKEY, SIMPLE_REFRESH | ACTIVATE | NOCAREREFRESH | BORDERLESS | BACKDROP, NULL, NULL, NULL, NULL, NULL, -1, -1, -1, -1, CUSTOMSCREEN } ; /* * This routine gets a raster for temporary storage. */ short *myalloc(type) long type ; { void *AllocMem() ; void *p ; if ((p=AllocMem(2L*RASTSIZE, type | MEMF_CLEAR))==NULL) { printf("Could not allocate raster data\n") ; cleanup() ; } return(p) ; } /* * Here we set things up. */ initialize() { long color ; if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library",0L))==NULL || (GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L)) ==NULL) { printf("Couldn't open libraries.\n") ; cleanup() ; } if ((myscreen = OpenScreen(&mynewscreen))==NULL) { printf("Couldn't open screen.\n") ; cleanup() ; } mynewwindow.Screen = myscreen ; if ((mywindow = OpenWindow(&mynewwindow))==NULL) { printf("Couldn't open window.\n") ; cleanup() ; } a = ((short *)(myscreen->BitMap.Planes[0])) ; b = ((short *)(myscreen->BitMap.Planes[1])) ; c = ((short *)(myscreen->BitMap.Planes[2])) ; d = ((short *)(myscreen->BitMap.Planes[3])) ; e = ((short *)(myscreen->BitMap.Planes[4])) ; if (asm) { t1 = myalloc(0L) ; t2 = myalloc(0L) ; } else { t1 = myalloc(MEMF_CHIP) ; t2 = myalloc(MEMF_CHIP) ; t4 = myalloc(MEMF_CHIP) ; } t3 = myalloc(MEMF_CHIP) ; if (orify) { color = GetRGB4(myscreen->ViewPort.ColorMap, 0L) ; if (color & 0xf00) color -= 256 ; if (color & 0xf0) color -= 16 ; if (color & 0xf) color -= 1 ; SetRGB4(&(myscreen->ViewPort), 1L << (noplanes - 1), (color >> 8) & 15, (color >> 4) & 15, color & 15) ; } WaitBlit() ; } /* * Exit routine. */ cleanup() { if (mywindow != NULL) CloseWindow(mywindow) ; if (myscreen != NULL) CloseScreen(myscreen) ; if (IntuitionBase) CloseLibrary(IntuitionBase) ; IntuitionBase = NULL ; if (GfxBase) CloseLibrary(GfxBase) ; GfxBase = NULL ; if (t1) FreeMem(t1, 2L*RASTSIZE) ; if (t2) FreeMem(t2, 2L*RASTSIZE) ; if (t3) FreeMem(t3, 2L*RASTSIZE) ; if (t4) FreeMem(t4, 2L*RASTSIZE) ; exit(0) ; } #define PARITY (0x96) #define CARRY (0xe8) #define SPEC1 (0x6a) #define SPEC2 (0xbe) #define SPEC3 (0x40) #define COPY (0xf0) #define ORIFY (0xfc) #define ORAC (0xfa) /* * This routine does the necessary four blits to wrap the LIFE image. * Please make sure that you own the blitter when you call it! */ struct blitparam blitparam ; fixit() { register struct blitparam *p = &blitparam ; if (asm) { pass3t(a, wmodulo * 2L, (long)vsize) ; return ; } p->bltsize = BLTSIZE(1, vsize) ; p->asource = a ; p->csource = a + wmodulo - 1 ; p->dsource = a + wmodulo - 1 ; p->amod = 2 * (wmodulo - 1) ; p->bmod = 0 ; p->cmod = 2 * (wmodulo - 1) ; p->dmod = 2 * (wmodulo - 1) ; p->fwm = 0x4000 ; p->lwm = 0xffff ; p->con0 = SHIFTSHIFT(14) + USEA + USEC + USED + ORAC ; p->con1 = 0 ; blit(p) ; p->asource = a + 2 * wmodulo - 1 ; p->csource = a ; p->dsource = a ; p->fwm = 0x0002 ; p->con0 = SHIFTSHIFT(2) + USEA + USEC + USED + ORAC ; blit(p) ; p->bltsize = BLTSIZE(wmodulo, 1) ; p->asource = a + wmodulo ; p->dsource = a + wmodulo * (long)(vsize - 1) ; p->amod = 0 ; p->cmod = 0 ; p->dmod = 0 ; p->fwm = 0xffff ; p->lwm = 0xffff ; p->con0 = USEA + USED + COPY ; blit(p) ; p->asource = a + wmodulo * (long)(vsize - 2) ; p->dsource = a ; blit(p) ; } /* * Does one LIFE generation. Fancy algorithm uses only 9 blits. If * anyone can improve this, please let me know. */ dogeneration() { register struct blitparam *p = &blitparam ; register long t ; register short *tt ; /* * Initialize the parameters we are not going to change. */ p->fwm = 0xffff ; p->lwm = 0xffff ; p->amod = 0 ; p->bmod = 0 ; p->cmod = 0 ; p->dmod = 0 ; p->asource = a - wmodulo ; p->bsource = a - wmodulo + 1 ; p->csource = a - wmodulo ; p->dsource = t1 ; p->bltsize = BLTSIZE(wmodulo, vsize+1) ; p->con0 = SHIFTSHIFT(1) + USEA + USEB + USEC + USED + PARITY ; p->con1 = SHIFTSHIFT(15) ; if (asm) { if (noplanes > 1) tt = t3 ; else tt = a ; t = (wmodulo * (long)vsize) >> 1 ; pass1(a, t1, t2, t) ; pass2(a + wmodulo, t1 + wmodulo, t2 + wmodulo, tt + wmodulo, wmodulo * 2L, t - wmodulo) ; p->con1 = 0 ; } else { OwnBlitter() ; blit(p) ; p->dsource = t2 ; p->con0 = SHIFTSHIFT(1) + USEA + USEB + USEC + USED + CARRY ; blit(p) ; p->csource = t1 + wmodulo ; p->dsource = t3 ; p->con0 = SHIFTSHIFT(1) + USEA + USEB + USEC + USED + CARRY ; blit(p) ; p->bltsize = BLTSIZE(wmodulo, vsize) ; p->asource = t2 ; p->bsource = t2 + 2 * wmodulo ; p->csource = t3 + wmodulo ; p->dsource = t4 ; p->con1 = 0 ; p->con0 = USEA + USEB + USEC + USED + CARRY ; blit(p) ; p->dsource = t3 ; p->con0 = USEA + USEB + USEC + USED + PARITY ; blit(p) ; p->bltsize = BLTSIZE(wmodulo, vsize+1) ; p->asource = a - wmodulo ; p->bsource = a - wmodulo + 1 ; p->csource = t1 + wmodulo ; p->dsource = t2 ; p->con0 = SHIFTSHIFT(1) + USEA + USEB + USEC + USED + PARITY ; p->con1 = SHIFTSHIFT(15) ; blit(p) ; p->bltsize = BLTSIZE(wmodulo, vsize) ; p->asource = t1 ; p->bsource = t2 + wmodulo ; p->csource = t3 ; p->dsource = t3 ; p->con0 = USEA + USEB + USEC + USED + SPEC1 ; p->con1 = 0 ; blit(p) ; p->csource = a ; p->dsource = t1 ; p->con0 = USEA + USEB + USEC + USED + SPEC2 ; blit(p) ; } /* * Before we do the final write, we copy bits down one generation. */ p->bltsize = BLTSIZE(wmodulo, vsize) ; if (noplanes > 1 && asm) OwnBlitter() ; if (orify) { a = ((short *)(myscreen->BitMap.Planes[0])) ; p->asource = ((short *)(myscreen->BitMap.Planes[noplanes-1])) ; p->bsource = ((short *)(myscreen->BitMap.Planes[noplanes-2])) ; p->dsource = p->asource ; p->con0 = USEA + USEB + USED + ORIFY ; blit(p) ; } p->con0 = USEA + USED + COPY ; switch (noplanes - orify) { case 5: p->asource = d ; p->dsource = e ; blit(p) ; case 4: p->asource = c ; p->dsource = d ; blit(p) ; case 3: p->asource = b ; p->dsource = c ; blit(p) ; case 2: p->asource = a ; p->dsource = b ; blit(p) ; default: ; } if (! asm) { p->bltsize = BLTSIZE(wmodulo, vsize-2) ; p->asource = t1 + wmodulo ; p->bsource = t3 + wmodulo ; p->csource = t4 + wmodulo ; p->dsource = a + wmodulo ; p->fwm = 0x7fff ; p->lwm = 0xfffe ; p->con0 = USEA + USEB + USEC + USED + SPEC3 ; blit(p) ; } else if (noplanes > 1) { p->asource = t3 ; p->dsource = a ; p->bltsize = BLTSIZE(wmodulo, vsize) ; blit(p) ; } /* * Wrap, if necessary */ if (torus) fixit() ; else if (asm) pass3(a, wmodulo * 2L, (long)vsize) ; if (! asm || noplanes > 1) DisownBlitter() ; } /* * Random number generator; probably not a very good one. */ int rnd(i) int i ; { static long seed = 323214521 ; long rval ; seed = seed * 123213 + 121 ; rval = (seed >> 5) & 65535 ; return ((i * rval) >> 16) ; } /* * Main routine. If called with no arguments, makes 1 bit plane screen. * Otherwise, first argument is used as the number of bit planes. */ char buffer[200] ; long time1[3], time2[3] ; long ratio(a,b,c) register long a, b, c ; { while (a > 32768L) { a /= 2 ; c /= 2 ; } while (b > 32768L) { b /= 2 ; c /= 2 ; } if (c == 0) return(0) ; else return(a * b / c) ; } main (argc, argv) int argc ; char *argv[] ; { register int x, y ; int hires = 320 ; int randoms = 0 ; int ir ; int dvsize = 0 ; struct IntuiMessage *message ; int code ; long delayval = 0 ; long generations ; long t ; noplanes = 1 ; while (argc > 1 && argv[1][0]=='-') { argc-- ; argv++ ; if (argv[0][1]=='h' || argv[0][1]=='H') { if (sscanf(argv[0]+2, "%d", &hires)!=1) hires = 640 ; } else if (argv[0][1]=='a' || argv[0][1]=='A') { asm = 1 ; } else if (argv[0][1]=='r' || argv[0][1]=='R') { if (sscanf(argv[0]+2, "%d", &randoms)!=1) randoms = 1 ; } else if (argv[0][1]=='p' || argv[0][1]=='P') { noplanes = argv[0][2] - '0' ; if (noplanes < 1 || noplanes > 6) noplanes = 1 ; } else if (argv[0][1]=='o' || argv[0][1]=='O') { orify = 1 ; } else if (argv[0][1]=='t' || argv[0][1]=='T') { torus = 1 ; } else if (argv[0][1]=='v' || argv[0][1]=='V') { if (sscanf(argv[0]+2, "%d", &dvsize)!=1) dvsize = 0 ; } else if (argv[0][1]=='s' || argv[0][1]=='S') { delayval = -1 ; } } if (noplanes == 1) orify = 0 ; if (argc > 1) { if (argv[1][0]=='?' && argv[1][1]==0) { printf( "Usage: life [-h[n]] [-r[n]] [-p[n]] [-o] [-t] [-v[n]] [-s] [infile]\n") ; cleanup() ; } if (freopen(argv[1], "r", stdin)==NULL) { printf("Couldn't open %s\n", argv[1]) ; cleanup() ; } } if (hires > 400) { vsize = 400 ; mynewscreen.ViewModes |= HIRES ; } else { vsize = 200 ; } modulo = hires & ~31 ; hires = modulo ; ir = randoms ; if (dvsize >= 10 && dvsize <= 600) vsize = dvsize ; wmodulo = modulo / 16 ; mynewscreen.Depth = noplanes ; mynewscreen.Width = modulo ; mynewscreen.Height = vsize ; mynewwindow.Width = modulo ; mynewwindow.Height = vsize ; if (vsize > 300) mynewscreen.ViewModes |= LACE ; initialize() ; SetAPen(&myscreen->RastPort, 0L) ; RectFill(&myscreen->RastPort, 0L, 0L, (long)hires-1, (long)vsize-1) ; WaitBlit() ; readin(a) ; if (torus) { OwnBlitter() ; fixit() ; DisownBlitter() ; } WaitBlit() ; generations = 0 ; DateStamp(time1) ; while (1) { if (message = (struct IntuiMessage *)GetMsg(mywindow->UserPort)) { code = message->Code ; ReplyMsg(message) ; switch(code) { case 27 : case 3 : case 'q' : case 'Q' : case 'x' : case 'X' : goto done ; case '0' : case 'g' : case 'G' : delayval = 0 ; break ; case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : delayval = 1L << (code - '0') ; break ; case ' ' : delayval = -1 ; goto doone ; case 'S' : case 's' : delayval = -1 ; default : break ; } } if (delayval) { if (delayval == -1) continue ; Delay(delayval) ; } doone: if (randoms) { if (ir-- == 0) { x = rnd(modulo-2) + 1 ; y = rnd(vsize-2) + 1 ; if (!asm || noplanes > 1) WaitBlit() ; a[y * (long)wmodulo + (x >> 4)] |= 1 << (15 - (15 & x)) ; ir = randoms ; } } dogeneration() ; generations++ ; } done: DateStamp(time2) ; delayval = time2[2]-time1[2] + (time2[1]-time1[1]) * 3000L + (time2[0]-time1[0]) * 4320000L ; t = (modulo - 2) * (long)(vsize - 2) * 50L ; t = ((t / delayval) * generations + ratio(t % delayval, generations, delayval)) ; printf("%ld generations by %ld pixels in %ld ticks is %ld cells/sec\n", generations, (modulo-2)*(long)(vsize-2), delayval, t) ; cleanup() ; }