/* FastGro 1.0 - a simulation of Diffusion-Limited Aggregation Copyright (c) 1989 Doug Houck (03-Feb-89) This program has been placed in the PUBLIC DOMAIN, so anyone, anywhere can do anything they want with it. This was compiled with the Aztec C compiler, version 3.6a, using the large data, large code, small integer model. "cc +d +d ..." and linked with "ln FastGro.o Wander.o -lml -lcl" */ #include #include #include /* learn about system */ #define RANDOMS 50437 /* how many random #s to generate */ #define STARTING_POINTS 200 /* points around circle for starting */ #define ffp long /* Motorola Fast Floating Point */ extern ffp ran(), /* use manx random # generator */ SPFlt(), SPFix(), SPMul(), SPDiv(), SPSin(), SPCos(), SPAdd(), SPSub(); struct Screen *hires_screen = NULL; struct Window *hires_window = NULL; struct RastPort *hires_rp = NULL; struct MsgPort *window_port = NULL; long MathBase = NULL, /* library bases */ MathTransBase = NULL, IntuitionBase = NULL, GfxBase = NULL; int rows, columns, /* size of screen in pixels */ maxrow, maxcolumn, columnsdiv8; /* in bytes */ long radius, color_iterations, points, points_to_go; /* parameters for drawing */ char *row[550]; /* pointers to rows */ char *row_memory = NULL; /* in row memory */ char *border[550]; /* pointers to rows */ char *border_memory = NULL; /* in border memory */ long optimizer_memory; /* how much space used */ char *randoms = NULL; /* pointer to random array */ char *next_random; /* index into randoms */ struct start_t /* cache starting points */ { int x, y; }; struct start_t start[STARTING_POINTS]; struct NewScreen new_hires_screen = { 0,0, 640, STDSCREENHEIGHT, /* size from Workbench screen */ 4, /* 16 colors */ 2,1, /* pens */ HIRES | LACE, CUSTOMSCREEN | SHOWTITLE | SCREENQUIET | SCREENBEHIND, NULL, NULL, NULL, NULL }; struct NewWindow new_hires_window = { 0,0, /* coords */ 640,400, 0,1, /* pens */ MOUSEBUTTONS, BACKDROP | BORDERLESS, NULL, NULL, NULL, /* title */ NULL, /* screen */ NULL, /* bitmap */ 0,0,0,0, /* min, max */ CUSTOMSCREEN }; initialize(argc, argv) /* open libraries, allocate memory... */ int argc; char **argv; { IntuitionBase = (long)OpenLibrary( "intuition.library",33L); if (!IntuitionBase) { ReportProblem("I Really Needed Kickstart/Workbench 1.2"); return(0); } GfxBase = (long)OpenLibrary( "graphics.library",33L); if (!GfxBase) { ReportProblem("can't open graphics.library"); return(FALSE); } MathBase = (long)OpenLibrary( "mathffp.library",33L); if (!MathBase) { ReportProblem("can't open mathffp.library"); return(FALSE); } MathTransBase = (long)OpenLibrary( "mathtrans.library",33L); if (!MathTransBase) { ReportProblem("Would kinda liketa have 'mathtrans.library' 1.2, mebbee?"); return(FALSE); } rows = DisplayRows()<<1; /* get # of rows in WB screen */ maxrow = rows-1; columns = DisplayColumns()<<1; /* get # of columns in WB screen */ columnsdiv8 = (columns+7)>>3; maxcolumn = columns-1; optimizer_memory = rows * columnsdiv8; /* space arrays will use */ /* ------------------------------- display screen ---------------------- */ new_hires_screen.Height = rows; new_hires_screen.Width = columns; hires_screen = OpenScreen( &new_hires_screen ); if (!hires_screen) { ReportProblem("No Memory for HiRes Screen. Sorry!"); return(0); } new_hires_window.Screen = hires_screen; new_hires_window.Width = hires_screen->Width; new_hires_window.Height = hires_screen->Height; hires_window = OpenWindow( &new_hires_window ); if (!hires_window ) { ReportProblem("Can't open hires window"); return(0); } hires_rp = hires_window->RPort; window_port = hires_window->UserPort; { long red, green, blue; /* set up colors */ green = 12; for( red = 0, blue = 15; red <= 15; red++, blue-- ) SetRGB4( &hires_screen->ViewPort, red, red, green, blue ); SetRGB4( &hires_screen->ViewPort, 0L, 0L, 0L, 0L ); } /* ---------------------- allocate optimizing arrays --------------------- */ row_memory = (char*)AllocMem( optimizer_memory, 0L ); border_memory = (char*)AllocMem( optimizer_memory, 0L ); if (!row_memory || !border_memory) { ReportProblem("No Memory For Auxiliary Arrays"); return(FALSE); } { int i = 0; /* init row pointers into arrays */ char *row_ptr = row_memory; char *border_ptr = border_memory; for( i=0; i < rows; i++ ) { row[i] = row_ptr; border[i] = border_ptr; row_ptr += columnsdiv8; border_ptr += columnsdiv8; } } randoms = (char*)AllocMem( (long)RANDOMS, 0L ); if (!randoms) { ReportProblem( "no random array"); return(0); } { long counter = RANDOMS-1; /* init random array */ register char *ptr = randoms; long scaler; scaler = SPFlt( 254L ); while(--counter) *ptr++ = SPFix( SPMul(ran(), scaler ) )+ 1; *ptr = 0; /* 0 marks the end */ next_random = randoms; } radius = 70; color_iterations = 100; points = 5000; return( TRUE ); } wrapup() /* clean up, close libraries, deallocate, wipe nose, etc */ { if (randoms) FreeMem ( randoms, (long)RANDOMS ); if (row_memory) FreeMem ( row_memory, optimizer_memory ); if (border_memory) FreeMem ( border_memory, optimizer_memory ); if (hires_window) CloseWindow ( hires_window ); if (hires_screen) CloseScreen ( hires_screen ); if (IntuitionBase) CloseLibrary ( IntuitionBase ); if (GfxBase) CloseLibrary ( GfxBase ); if (MathTransBase) CloseLibrary ( MathTransBase ); if (MathBase) CloseLibrary ( MathBase ); exit( 0 ); } ReportProblem( text ) char *text; { char answer[64]; printf("Had a slight problem...\n\n"); printf(" %s\n\n", text); printf("Press to abort. "); gets( answer ); } mark_perimeter( x, y ) /* mark perimeter around a pixel */ int x, y; { setbit( row, x, y ); if (y>0) setbit( row, x , y-1 ); /* careful of edges... */ if (y0) { if (y>0) setbit( row, x-1, y-1 ); setbit( row, x-1, y ); if (y0) setbit( row, x+1, y-1 ); setbit( row, x+1, y ); if (y max_radius) radius = max_radius; } printf("Particles (1..1000000) [%ld] ",points); gets( answer ); if (answer[0]) sscanf(answer, "%ld", &points ); points_to_go = points; printf("Change Color After (1..1000000) [%ld] ",color_iterations); gets( answer ); if (answer[0]) sscanf( answer, "%ld", &color_iterations ); color = 1; color_counter = color_iterations; printf("To abort drawing, click anywhere on drawing.\n"); printf("Setting up...\n"); set_up_optimizing( radius); x = columns / 2; /* seed the center */ y = rows / 2; mark_perimeter(x,y); WritePixel( hires_rp, (long)x, (long)y ); SetAPen( hires_rp, 1L ); /* erase window */ SetDrMd( hires_rp, JAM2 ); SetRast( hires_rp, 0L ); ScreenToFront( hires_screen ); /* clean out port */ while( im = (struct IntuiMessage*)GetMsg( window_port) ) ReplyMsg( im ); while(!IsMessageWaiting(window_port) && (points_to_go> 0 )) { start_location = SPFix(SPMul( ran(), start_scale )); x = start[start_location].x; y = start[start_location].y; wander_asm( &x, &y ); /* do the time-consuming stuff */ if (!checkbit( border, x, y ) ) /* not a border hit? OK! */ { mark_perimeter(x,y); WritePixel( hires_rp, (long)x, (long)y ); points_to_go--; if( !(--color_counter) ) { color_counter = color_iterations; color++; if (color > 15) color = 1; SetAPen( hires_rp, color ); } } } ScreenToBack( hires_screen); } main( argc, argv ) int argc; char **argv; { char answer[32]; printf("Welcome to FastGro, a fractal program by Doug Houck,\n"); printf("simulating Diffusion-Limited Aggregation. The purpose\n"); printf("of this program is to demonstrate how selected\n"); printf("optimizations can improve the speed of a program by\n"); printf("an order of magnitude. Meanwhile, I'm setting up...\n"); if (!initialize( argc, argv )) wrapup(); do { draw_fractal(); printf("More? (Y/N) [Yes] "); gets( answer ); } while ( ! ((answer[0]=='N') || (answer[0]=='n')) ); wrapup(); }