/* * worm.c * * Adapted from the Scientific American article 12/87. Original for Sun UNIX. * Original Author - Brad Taylor (sun!brad) * Adapted to the Amiga by Chuck McManis (sun!cmcmanis) * Basically there are five switches they are : * -l n Set the length of the worms to 'n' units, this defaults to 32. * -s n Set the size of the worm units to n X n, defaults to 1 but try * some larger sizes too, their kinda neat. * -n n Set the number of worms on the screen, defaults to 16 worms which * is fairly slow, 4 is pretty quick. Numbers like 3000 are neat too. * -r n Set the screen resolution, 0 = low res (320 X 200), 1 = medium (640 X 200) * and 2 = high (640 X 400) * -d n Set number of bitplanes, 1-5 are acceptable numbers. * * Note this uses a random number generator that Leo used in demo.c * Copyright (C) 1987 by Charles McManis * Freely Redistributable if you leave the above comment and following declaration * intact ... */ static char copyright[] = "Copyright (C) 1987, Charles McManis, ok to copy."; #include #include #include #include #include #include #include #include #include #include #ifdef LATTICE #include #include #endif /* Declare the required Intuition pointers */ struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; struct DiskfontBase *DiskfontBase; /* Declare some global tool stuff */ struct Window *MyWindow; struct Menu *MyMenu, *CurrentMenu; struct Screen *MyScreen; struct TextFont *MyFont; /* Declare some defines that make the code a bit more readable */ #define SIGBIT(w) (1L << (w->UserPort->mp_SigBit)) #define GetIntuiMessage(w) (struct IntuiMessage *)GetMsg(w->UserPort) struct TextAttr ta = {"topaz.font",11,0,0}; #define CMSIZE 30 /* Max color map size */ #define CMFUDGE 2 /* colors needed for borders and background */ #define SEGMENTS 36 /* Size of sin and cos tables */ #define MAXCOLOR 15 /* Most intense color */ extern char *malloc(); int wormlength = 32; int circsize = 1; int nworms = 16; int black,white; int cmsize; int sintab[SEGMENTS]; int costab[SEGMENTS]; /* * Initialized data section. These structures are pre-initialized with * the values that the program knows ahead of time. */ struct NewScreen ns = { 0,0,640,400,3, /* (X,Y) (W,H) (bitplanes) */ 1,0, /* Foreground, Background */ 0, /* View Modes (defaults to none */ CUSTOMSCREEN, /* What else is new */ NULL, /* Font is set up below */ "Worms, implementation by Chuck McManis V1.0", NULL, /* No special Gadgets */ NULL /* No Custom Bitmap */ }; struct NewWindow nw = { 0,0,640,400, /* (X,Y) (W,H) */ 7,6, /* Foreground, Background */ CLOSEWINDOW+REFRESHWINDOW, WINDOWCLOSE+SIMPLE_REFRESH+ACTIVATE, NULL, /* No special Gadgets */ NULL, /* Use the default Checkmark */ "Squiggly Worms, Implementation by Chuck McManis", NULL, /* This will be our screen pointer */ NULL, /* We'll use the Bitmap we get */ 640,400,640,400, /* No resizing going on */ CUSTOMSCREEN /* We'll use our own screen thankyou */ }; /* * Some declarations for worm, */ USHORT colors[32]; /* A place to create the color table */ int ScreenRes = 1; /* Screen Resolution (0=low 2=hi) */ ULONG MaxX, MaxY; /* Window inside dimensions */ struct wormstuff { int *xcirc; int *ycirc; int dir; int tail; int x; int y; int id; }; void worm_doit(),drawseg(),goaway(),usage(), color_setup(); short rnd(); struct wormstuff *worm_init(); /* * Ok, declarations are out of the way, on with the main function */ void main(argc,argv) int argc; char *argv[]; { struct IntuiMessage *im; /* Intuimessage pointer */ struct Window *wp; /* Temporary window pointer */ ULONG class; /* Message Class holder */ USHORT code,qual;/* Message Code and qualifiers */ SHORT msx,msy; /* Mouse Co-ordinates for event */ int i, /* Your basic counter variable */ xsize,ysize, depth; /* How many bitplanes did you want? */ struct wormstuff **worm; /* Worm data */ char *cmd; cmd = argv[0]; depth = 3; /* default depth */ rnd(0); if (argc == 0) { /* Started from workbench */ printf("Worm length : "); scanf("%d",&wormlength); printf("Number of worms [n] :"); scanf("%d",&nworms); printf("Worm width [n] :"); scanf("%d",&circsize); printf("Screen Resolution [0=Low, 1=Medium, 2=High] :"); scanf("%d",&ScreenRes); printf("Number of bitplanes [1-5 for Low res, 1-4 for medium or high] :"); scanf("%d",&depth); } for (i = 1; i < argc; i++) { if (i == argc - 1 || argv[i][0] != '-' || argv[i][2] != 0) { usage(cmd); } switch (argv[i][1]) { case 'l': wormlength = atoi(argv[++i]); break; case 'n': nworms = atoi(argv[++i]); break; case 's': circsize = atoi(argv[++i]); break; case 'r': ScreenRes = atoi(argv[++i]); break; case 'd': depth = atoi(argv[++i]); if ((depth < 1) || (depth > 5)) usage(cmd); break; default: usage(cmd); } } if ((ScreenRes > 0) && (depth == 5)) depth = 4; cmsize = (1 << depth) - CMFUDGE; for (i = 0; i < SEGMENTS; i++) { sintab[i] = round(circsize * sin(i * 2 * PI / SEGMENTS)); costab[i] = round(circsize * cos(i * 2 * PI / SEGMENTS)); } /* Open the intuition library first ... */ IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0); if (! IntuitionBase) goaway(); /* Now opening the graphics library ... */ GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0); if (! GfxBase) goaway(); /* Now opening the diskfont library ... */ DiskfontBase = (struct DiskfontBase *)OpenLibrary("diskfont.library",0); if (! DiskfontBase) goaway(); /* This opens a custom screen to the maximum possible size ... */ ns.Depth = depth; ns.Width = GfxBase->NormalDisplayColumns; ns.Height = GfxBase->NormalDisplayRows; switch (ScreenRes) { case 0 : ns.Width /= 2; ta.ta_YSize = 8; ta.ta_Flags |= FPF_ROMFONT; ns.Font = &ta; break; case 1 : ns.ViewModes |= HIRES; /* In medium res use Topaz 8 */ ta.ta_YSize = 8; ta.ta_Flags |= FPF_ROMFONT; ns.Font = &ta; break; case 2 : ns.Height *= 2; ns.ViewModes |= HIRES+LACE; /* In Interlace mode us Topaz 11 */ ns.Font = &ta; } /* Now we open the font we want so that it will be resident when the * OpenScreen call below needs it. */ MyFont = (struct TextFont *) OpenDiskFont(&ta); MyScreen = (struct Screen *)OpenScreen(&ns); if (! MyScreen) goaway(); color_setup(); /* Initialize the color map */ /* OK so far, now lets open a full size window ... */ nw.Screen = MyScreen; nw.TopEdge = 1; /* Leave a row to grab the screen drag bar */ nw.Width = ns.Width; nw.Height = ns.Height-1; nw.DetailPen = white; /* initialized by color_setup() */ nw.BlockPen = black; MyWindow = (struct Window *)OpenWindow(&nw); if (! MyWindow) goaway(); SetFont(MyWindow->RPort,MyFont); /* This should not be required ! */ MaxX = xsize = MyWindow->Width-MyWindow->BorderLeft-MyWindow->BorderRight; MaxY = ysize = MyWindow->Height-MyWindow->BorderTop-MyWindow->BorderBottom; SetAPen(MyWindow->RPort,black); RectFill(MyWindow->RPort, MyWindow->BorderLeft,MyWindow->BorderTop, MyWindow->BorderLeft+xsize, MyWindow->BorderTop+ysize); worm = (struct wormstuff **)malloc((unsigned)(sizeof(struct wormstuff *) * nworms)); for (i = 0; i < nworms; i++) { worm[i] = worm_init(xsize, ysize, wormlength); } if (!cmsize) cmsize = 1; for (;;) { for (i = 0; i < nworms; i++) { worm_doit((void *)MyWindow->RPort, worm[i], xsize, ysize, (((i * cmsize) / nworms) % cmsize)); } /* Note: If we are running continuously we don't Wait(), this lets */ /* the program continue to update the screen until the user sends */ /* it some form of request. */ while ((im = GetIntuiMessage(MyWindow)) != NULL) { class = im->Class; /* Extract relavent info */ code = im->Code; qual = im->Qualifier; /* Stuff like shift down etc */ msx = im->MouseX; /* And the mouse position */ msy = im->MouseY; wp = im->IDCMPWindow; /* Figure out which window sent this message */ ReplyMsg(im); /* Reply quickly! */ switch (class) { case CLOSEWINDOW : /* Process a close window message. */ goaway(); /* Exit the program */ case REFRESHWINDOW : BeginRefresh(MyWindow); EndRefresh(MyWindow,TRUE); break; default : /* We choose to ignore unknown message classes */ break; } /* switch statement */ } /* until no messages are still waiting */ } } /* * Utility routines used by the Worm Program... */ /* * Function goaway() * * This function shuts down after we are done. Since this can happen at * anytime, it checks the various global variables and those that have * been initialized (non-null), it removes/clears etc depending on the * variable. */ void goaway() { if (MyWindow) CloseWindow(MyWindow); if (MyScreen) CloseScreen(MyScreen); if (GfxBase) CloseLibrary(GfxBase); if (MyFont) CloseFont(MyFont); if (DiskfontBase) CloseLibrary(DiskfontBase); if (IntuitionBase) CloseLibrary(IntuitionBase); exit(0); /* This cleans up FILE pointers and malloc'd memory */ } struct wormstuff * worm_init(xsize, ysize, wormlength) int xsize; int ysize; int wormlength; { static int thisworm = 0; int i; struct wormstuff *ws; ws = (struct wormstuff *)malloc((unsigned)sizeof(struct wormstuff)); ws->xcirc = (int *)malloc((unsigned)(wormlength * sizeof(int))); ws->ycirc = (int *)malloc((unsigned)(wormlength * sizeof(int))); for (i = 0; i < wormlength; i++) { ws->xcirc[i] = xsize / 2; ws->ycirc[i] = ysize / 2; } ws->dir = rnd(SEGMENTS); ws->tail = 0; ws->x = xsize / 2; ws->y = ysize / 2; ws->id = thisworm; thisworm = (thisworm + 1) % 14; return (ws); } void worm_doit(h, priv, xsize, ysize, color) void *h; void *priv; int xsize; int ysize; int color; { int x; int y; struct wormstuff *ws = (struct wormstuff *)priv; ws->tail = (ws->tail + 1) % wormlength; x = ws->xcirc[ws->tail]; y = ws->ycirc[ws->tail]; drawseg(h, x, y, black); if ((rnd(32765)&(1<id)) != 0) { ws->dir = (ws->dir + 1) % SEGMENTS; } else { ws->dir = (ws->dir + SEGMENTS - 1) % SEGMENTS; } x = (ws->x + costab[ws->dir] + xsize) % xsize; y = (ws->y + sintab[ws->dir] + ysize) % ysize; ws->xcirc[ws->tail] = x; ws->ycirc[ws->tail] = y; /* Note when using one bitplane worm_doit gets called with color == 0 */ drawseg(h, x, y, (color != black) ? color : 1); ws->x = x; ws->y = y; } round(x) float x; { if (x >= 0) return ((int)(x + .5)); return ((int)(x - .5)); } /* Note that drawseg does it's own clipping... */ void drawseg(priv, x, y, color) void *priv; int x; int y; int color; { struct RastPort *gfx = (struct RastPort *)priv; ULONG X,Y; X = ((unsigned) x % (MaxX-circsize)) + MyWindow->BorderLeft; Y = ((unsigned) y % (MaxY-circsize)) + MyWindow->BorderTop; SetAPen(gfx,color); if (circsize == 1) WritePixel(gfx,X,Y); else RectFill(gfx,X,Y,X+circsize,Y+circsize); } /* Sets up some reasonable colors ... note CMSIZE is max colors and * cmsize is the actual number of colors */ void color_setup() { int i; for (i = 0; i < cmsize; i++) { colors[i] = rnd(4096); } colors[cmsize] = 0; colors[cmsize+1] = 4095; LoadRGB4(&(MyScreen->ViewPort),colors,cmsize+CMFUDGE); /* Load in our colors */ black = cmsize; white = cmsize+1; } void usage(cmd) char *cmd; { (void)fprintf(stderr, "usage: %s [-l length] [-s size] [-n number] [-r resolution] [-d depth]\n", cmd); exit(1); }