#include /* Two standard includes when using the SGI 'gl' library ... */ #include #include #include "plot.h" /*********************************************************************** Global variables: Igen: How many generations have been plotted. Plotting proceeds from the top of the window down. Y: Current y-coordinate for plotting. Winid: GL window ID. Not used in current code, but included for completeness. ***********************************************************************/ int Igen = 0; int Y; int Winid; /*********************************************************************** Fortran-callable interface to C-routine 'sgicaplot'. Fortran usage: integer nsite(maxnsite), rule, nsite, ngen coloff, colon call sgicaplot(site,rule,nsite,ngen,coloff,colon) This code is illustrative of a general technique for coding routines which are callable from Fortran *and* C (and almost always written in C). This precise technique will work on most scientific workstation Unix environments, on many CRAYs the Fortran entry-point should be an all-upper-case C routine. GENERAL HINTS: (1) Always prototype the routine in Fortran first. Fortran has the more restrictive set of data structures and anything you can pass in Fortran you can generally pass in C. (2) Avoid character arguments and particularly arrays of characters. SPECIFICS: (1) Append an underscore to the name of the C-routine in order to create an entry point which will be referenced by a Fortran call to a subprogram with the same name. In other words, Fortran external symbols have an underscore appended to them (in versions of Unix which implement this convention) so when you say call foo the loader actually looks for a symbol 'foo_' which might have been created either via subroutine foo *OR* void foo_() ... (2) All argument passing in Fortran is pass-by address, so the C header should use pointers-to-scalars wherever the Fortran declaration would use scalars. E.g. subroutine foo(argh) integer argh becomes void foo_(int *pargh) ... (3) All Fortran array arguments (irrespective of dimension) are equivalent to pointer-to- C arguments. Thus subroutine bar(varg1,varg2,n) integer n, varg1(n), varg2(n,n) becomes void bar_(int *varg1,int *varg2,int *pn) ... ***********************************************************************/ void sgicaplot_(int *site,int *prule,int *pnsite,int *pngen,int *pcoloff, int *pcolon) { sgicaplot(site,*prule,*pnsite,*pngen,*pcoloff,*pcolon); } /*********************************************************************** sgicaplot: Uses 'gl' library to plot time history of 1-dimensional cellular automata. Works in single-buffered, color-map mode. site: Integer vector of current state of CA sites. This version assumes site to be binary valued (0,1). rule: The cellular automata rule being used (presumably in some standard encoding). Used to provide title for graphics window. nsite: Length of site array (and x width in pixels of window) ngen: Number of generations simulation will run for (and y depth of window in pixels) coloff: Dead pixel color. colon: Live pixel color. Code uses global variable 'Igen' to record how many times it has been invoked. On first invocation it opens a GL window of the appropriate size and paints it dead. Then, and on subsequent calls, the site vector is plotted at constant y pixel coordinate (maintained in global vbl. 'Y'). When 'ngen' rows have been output OR when ''ngen' is less than 0, the routine waits for the -key to be pressed while the graphics window has input focus. ***********************************************************************/ void sgicaplot(int *site,int rule,int nsite,int ngen,int coloff,int colon) { int i; long v[2]; char buffer[1024]; /* Passing negative value for 'nsite' forces routine into 'wait-for-ESC mode */ if( nsite < 0 ) goto Done; /* If this is the first invocation ... */ if( !Igen ) { /* Set the window size: nsite x ngen pixels. */ prefsize(nsite,ngen); /* Keep the graphics task in the foreground. */ foreground(); /* Label the window with the value of 'rule'. */ sprintf(buffer,"casgi: Rule %d",rule); /* Open the window and store the GL graphics ID for the window. */ Winid = winopen(buffer); /* Define a 2d coordinate system which maps to the physical window. In this case use "natural coordinates": x = 0 .. nsite - 1, y = 0 .. ngen - 1 */ ortho2(0,nsite-1,0,ngen-1); /* Clear the window to the "dead" color. */ color(coloff); clear(); /* Queue ESCKEY so that subsequent use of the escape-key will generate detectable events. */ qdevice(ESCKEY); /* Initialize y-coordinate for output. */ Y = ngen-1; } /* Output current state of automata. */ Igen++; color(colon); bgnpoint(); v[1] = Y; for( i = 0; i < nsite; i++ ) { int f77_seven = 7; if( site[i] ) { v[0] = i; v2i(v); } } Y--; if( Y < 0 ) { Done: fprintf(stderr,"Type in window to exit\n"); wait_for_ESCKEY(); } } /*********************************************************************** Self-explanatory. ***********************************************************************/ void wait_for_ESCKEY(void) { long dev; short val; while( 1 ) { if( qtest() ) { dev = qread(&val); switch(dev) { case ESCKEY: if( val ) return; break; default: break; } } } }