peterson@utah-cs.UUCP (John W Peterson) (10/07/85)
/* * view.c - View mandlebrot sets on an Apollo display * * Author: J. W. Peterson, * based on "ibmcg4" by Bennett Todd @ Duke University. * * Computer Science Dept. * University of Utah * Date: Fri Sep 20 1985 * Copyright (c) 1985 J. W. Peterson * */ /* View the mandlebrot set on a Color apollo (assumes 8 bit display) */ /* * view [name] * Display file name.pic created by "compute" on an Apollo color display * Works best with 8 bit color, but can produce interesting results on * bitmapped displays. * * This version is extended to you to use the mouse to find new regions * for "exploration". The program will print out the coordinates * and the "scale" of the box defined by the last two mouse selections * (bottom left and top right). * * The "c" mouse key (whatever that is on your particular mouse) * exits the program. */ #include <stdio.h> #include "/sys/ins/base.ins.c" #include "/sys/ins/gpr.ins.c" #include "/sys/ins/pad.ins.c" #include "/sys/ins/streams.ins.c" status_$t status; stream_$id_t out_stream; gpr_$pixel_value_t scanline[2000]; int hpix, vpix; #define MAXNAMELEN 64 /* max filename length for MS-DOS */ #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef EOF #define EOF (-1) #endif #define ISSUFFIX(s1, s2) !strcmp((s1), (s2)+strlen(s2)-strlen(s1)) main(argc, argv) int argc; char **argv; { char name[MAXNAMELEN]; char ch; FILE *fp, *fopen(); int i, j, n; double center_r, center_i, scale_r, scale_i, new_r, new_i, last_r, last_i; char colormax[4]; int npix, count[256], temp_l; if (argc == 2) if (ISSUFFIX(".pic", argv[1])) strncpy(name, argv[1], MAXNAMELEN); else { strncpy(name, argv[1], MAXNAMELEN-4); strcat(name, ".pic"); } else { printf("syntax: view [name]\n"); printf("Name: "); gets(name); } if (!ISSUFFIX(".pic", name)) strcat(name, ".pic"); while ((fp = fopen(name, "r")) == NULL) { fprintf(stderr, "view: cannot open %s\n", name); printf("Name: "); gets(name); if (!ISSUFFIX(".pic", name)) strcat(name, ".pic"); } if (fscanf(fp, "Centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n\032", ¢er_r, ¢er_i, &scale_r, &scale_i, &hpix, &vpix) != 6) { fprintf(stderr, "view: cannot parse header of %s\n", name); exit(1); } npix = hpix*vpix; printf("Reading %s centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n", name, center_r, center_i, scale_r, scale_i, hpix, vpix); setup_scr(hpix,vpix); for (i=0; i<vpix; i++) { for (j=0; j<hpix; j++) { if ((n=getc(fp)) == EOF) { fprintf(stderr, "view: too few pixels!\n"); exit(1); } putpoint(j, i, (n==255) ? 0 : n ); /* 255 = Black */ } flushline(i); } /* Allow the user to interactivly select points on the grid. Code * will print out the center & scale of the box defined by the * last two points (lower left, upper right) selected. */ last_r = 0.0; last_i = 0.0; do { get_cursor( &i, &j, &ch ); new_r = (center_r - scale_r) + i * (2*scale_r/hpix); new_i = (center_i + scale_i) - j * (2*scale_i/vpix); printf("center=%lf+%lfi scale=%lf+%lfi\n", (new_r + last_r)/2.0, (new_i + last_i)/2.0, (new_r-last_r)/2.0, (new_i-last_i)/2.0 ); last_r = new_r; last_i = new_i; } while (ch != 'c'); } /* Apollo dependant code (warning - status codes aren't checked) */ /* Initialize the display, by popping up a new window to draw the picture * in. */ setup_scr(hsize,vsize) int hsize,vsize; { gpr_$offset_t size; gpr_$color_vector_t colmap; gpr_$attribute_desc_t hidden_desc; unsigned int value; int i; name_$pname_t output_file; short len; gpr_$window_t dest_box; pad_$window_desc_t window_shape; static gpr_$bitmap_desc_t main_bitmap; short fontid; /* Open a separate window to display the results */ window_shape.top = 0; window_shape.left = 0; window_shape.width = (short)hsize + 5; window_shape.height = (short)vsize + 5; pad_$create_window( "", (short) 0, pad_$transcript, (short) 1, window_shape, out_stream, status ); pad_$set_auto_close( out_stream, (short) 1, true, status ); size.x_size = 1024; /* GPR will shrink to fit */ size.y_size = 1024; /* Initialize the graphics primitives package */ gpr_$init(gpr_$direct, out_stream, /* "unit" */ size, /* size of the initial bitmap */ 7, /* identifier of the heightest numbered bitmap plane */ main_bitmap, /* resulting bitmap descriptor */ status); gpr_$set_auto_refresh( true, status ); /* all yours, DM. */ gpr_$acquire_display( status ) ; /* set the new bitmap descriptor to be the 'current bitmap' */ gpr_$set_bitmap(main_bitmap,status); gpr_$clear( gpr_$black, status ); gpr_$release_display( status ); /* Set up the color map. I like the results this produces, however * there's an awful lot of room available for creative tweaking here. * (Note pixels between 255-16 and 254 may wrap around...) */ for(i = 0; i < 256; i++) { colmap[i] = ((i * 4) % 128) + 127; colmap[i] |= i << 9; colmap[i] |= ((i * 2) & 0xFF) << 16 ; } colmap[0] = gpr_$black; /* assure 0 is black */ gpr_$acquire_display( status ) ; /* 16 is offset from DM window colors */ gpr_$set_color_map( (int) 16, 255 - 16 , colmap, status ); gpr_$release_display( status ); init_cursor(); } /* * Pixels are buffered on a Scanline basis - this increases the drawing * speed by an order of magnitude or so... */ putpoint(x, y, c) int x, y, c; { scanline[x] = c + 16; /* "+16" avoids DM colors, but can wrap around.. */ } flushline(y) int y; { gpr_$window_t dest_box; dest_box.window_base.x_coord = 0; dest_box.window_base.y_coord = y; dest_box.window_size.x_size = hpix; dest_box.window_size.y_size = 1; gpr_$acquire_display(status); gpr_$write_pixels( scanline, dest_box, status); gpr_$release_display( status ); } /* Cursor handling code (translated from an old Pascal program...) */ /* Do all the grunge to initialize a cross-hair cursor */ init_cursor() { static gpr_$bitmap_desc_t CursorBitmap; static gpr_$attribute_desc_t AttribBlock; static gpr_$keyset_t keyset; gpr_$position_t Pos; /* Cursor offset */ gpr_$offset_t Size; /* Cursor bitmap size */ gpr_$bitmap_desc_t Bitmap; /* System bitmap */ Size.x_size = 15; Size.y_size = 15; gpr_$inq_bitmap(Bitmap, status); /* save the original bitmap */ gpr_$allocate_attribute_block(AttribBlock,status); /*Now that we have a set of attributes, make a bitmap to store the cursor*/ gpr_$allocate_bitmap(Size, (gpr_$plane_t) 0, /*Plane ID*/ AttribBlock, /*Attribute block*/ CursorBitmap, status); gpr_$set_bitmap(CursorBitmap,status); /*Set graphics to cursor bitmap*/ /*Draw cross-hair pattern*/ gpr_$move((gpr_$coordinate_t) 0, (gpr_$coordinate_t) 7, status); gpr_$line((gpr_$coordinate_t) 15, (gpr_$coordinate_t) 7, status); gpr_$move((gpr_$coordinate_t) 7, (gpr_$coordinate_t) 0, status); gpr_$line((gpr_$coordinate_t) 7, (gpr_$coordinate_t) 15, status); gpr_$set_cursor_pattern(CursorBitmap, status); /*Assign bitmap to cursor*/ Pos.x_coord = 7; Pos.y_coord = 7; gpr_$set_cursor_origin(Pos, status); /*Center the origin*/ gpr_$set_bitmap(Bitmap, status); /*Reset the graphics to main bitmap*/ { int i; /* Kludge for pascal sets */ for (i=0; i <= 7; i++) { keyset[i] = 0xFFFFFFFF; }} gpr_$enable_input( gpr_$buttons, keyset, status ); gpr_$enable_input( gpr_$locator, keyset, status ); } /* Read the cursor */ get_cursor( px, py, c ) int * px, * py; char * c; { gpr_$position_t pos; gpr_$event_t event; char eventdata; gpr_$acquire_display( status ); do { gpr_$event_wait( event, eventdata, pos, status ); gpr_$set_cursor_active( false, status ); /* avoid cursor smear */ gpr_$set_cursor_position( pos, status ); gpr_$set_cursor_active( true, status ); } while ((event != gpr_$buttons) || ((eventdata >= 'A') && (eventdata <= 'D'))); /* ignore 'up's */ gpr_$release_display( status ); *px = pos.x_coord; *py = pos.y_coord; *c = eventdata; }