[comp.sys.amiga.tech] Son of Hopalong: ROSES

ranjit@eniac.seas.upenn.edu (Ranjit Bhatnagar) (09/05/88)

[Where are the fiends that would eat lines now?]

You may have seen the posting of ROSES.C for the PC in comp.graphics.
That code itself is very simple; making a nice Intuition interface to
it is hard.  After 8 straight hours of whacking, here is an implementation
of ROSES with a resizable window, openable on the workbench or just about
any kind of custom screen.  Most parameters are specified on the command line.

Roses is another Hopalong type iteration program, which makes beautiful
colored patterns as it runs.  Again there is a magnification factor,
called "diameter" this time; there's a "vector length" parameter to
tweak, and you can try one of 3 built in color sets on a custom screen,
or add your own color sets to the source code.  The program explains
itself when you type "roses ?" or look at the source code.

Compile it with Aztec in compatibility mode (+p) and link with 
ml32 and cl32 in that order.  I have not tried it in any other mode,
nor with Lattice - it should not be hard to convert, except that I
was very careless with casting pointers.

As with Hopalong, if you want a uuencoded copy of the binary, send
me mail.  Depending on how discussions come out, I might just post
the darn thing eventually.

Without further ado, here it is.  Search for == cut here ==.

== cut here ==


/* THIS version of EGAROSES has been modified for an Amiga, and also
        made to look a bit nicer in source code.   (Ranjit Bhatnagar)
	Also removed time-delay feature; added specification of rose diameter,
	and NUM_PTS, and various window/color goodies.  Removed
	boundary checking, since windows do that.
                -- RB 4 Sep 88                                 */

/* This version of EGAROSES has been modified for a standard EGA display and
        for use with Microsoft C 5.0, and its graphics routines.  Comments have
        been added to explain how some of the constants and variables work */

/* For more information, see "Introduction to Recursive Discrete Dynamic
        Systems" - published in 1980 by Springer-Verlag. */

#include <exec/types.h>
#include <intuition/intuition.h>
#include <graphics/gfxmacros.h>
#include <math.h>

#define NUM_PTS   num_pts   /* number of dots along a vector to draw */
/* #define MAXCOL   3   */  /* number of colors (not counting 0) to use  --RB */
#define XMAX     200   /* initial X dimension in pixels for window   */
#define YMAX     200   /* initial Y dimension in pixels for window   */
int maxcol, xmax, ymax;
#define COLORSETS 2    /* # of built in color sets not including default */
int colorSet;

int SMAXX = 640;   /* x size for custom screen */
int SMAXY = 200;   /* y size for custom screen */
int customScreen;	/* flag: should we open a new screen? */
int pause;		/* flag: program paused? */

#define     frnd()         ((float)rand() / 32767.)
#define     scale(x)       (diam*x - 0.51) 
		  
#define     init_rnd()     srand((unsigned int)time(NULL))

char copywrite[] = "ROSES Copywrite (C) 1986 by TLG Software & Derek B Clegg";
/*                        ^^^^^^^^^ Legally misspelled: That's a copywrong. */
char usage[] = "Parameters for ROSES are (showing defaults):\n\
  d1.0	 - diameter of pattern\n\
  n8     - number of points per vector\n\
  h or H - use hires or hires interlace custom screen\n\
  l or L - use lores or lores interlace custom screen\n\
  c1	 - which color set to use (0 - %d) (custom screens only\n\
Example: Roses L c2 n7 d1.8\n\
Hints:\n\
  The larger 'n' is, the larger the image is - use a smaller 'd'.\n\
  Use the 'P' gadget under the depth-arrangers to pause for a screen dump.\n\
  There's a random factor, so don't expect to see the same thing twice!\n";


main(argc,argv)
int   argc;
char  *argv[];
{
        float   c, w, x[32], y[32], z[32], 
                diam, xn, yn, xscale, yscale, tmp;
        
        int      num_pts, x1, y1, k;
        register i,j;
                      /*  Amiga specific variable */
        struct RastPort *rp;                /* for drawing */
        

 	customScreen = -1;
	diam = 1.0;
	num_pts = 8;
	colorSet = 0;
	for (i=1; i<argc; i++) {
		switch (argv[i][0]) {
			case 'd' :
			case 'D' :
				sscanf(argv[i]+1, "%e",&diam); break;
			case 'h' :
				customScreen = HIRES;
				SMAXX = 640; SMAXY = 200; break;
			case 'H' :
				customScreen = HIRES|LACE;
				SMAXX = 640; SMAXY = 400; break;
			case 'l' :
				customScreen = 0; 
				SMAXX = 320; SMAXY = 200; break;
			case 'L' :
				customScreen = LACE; 
				SMAXX = 320; SMAXY = 400; break;
			case 'n' :
			case 'N' : 
				sscanf(argv[i]+1, "%d",&k);
				if (k>0) num_pts=k;
				break;
			case 'c' :
			case 'C' :
				sscanf(argv[i]+1, "%d", &k);
				if (k>=0 && k<=COLORSETS) colorSet = k;
				break;
			default:
				printf(usage,COLORSETS);
				exit(0);
				break;
			};
	}
        init_rnd();
        xscale = 10.0;  /* Width of CRT in inches */
        yscale = 7.5;   /* Height of CRT in inches - for aspect ratio */
 
        opendisplay(&rp); /* open screen and/or window, get rastport */
 

restart:
        SetRast(rp, 0L);   /* clear window */

        for (i = 0; i < NUM_PTS; i++) {
                x[i] = y[i] = scale(i);
        }
 
        c = -1. + 2.*frnd();
 
        w = 1. -c;
        for (i = 0; i < NUM_PTS; i++)
                z[i] = 2.*x[i]*x[i]*w / (1. + x[i]*x[i]);
 
        for (j=0;;j++) { /* introduced j for color variety - RB */
                for (i = 0; i < NUM_PTS; i++) {
                        xn = y[i] + c*x[i] + z[i];
                        tmp = xn*xn;
                        z[i] = 2.*tmp*w / (1. + tmp);
                        yn = -x[i] + c*xn + z[i];
                        x1 = xmax/2 + xscale*xn;
                        y1 = ymax/2 + yscale*yn;
                        SetAPen(rp, (LONG)((j>>4)+i)%maxcol+1);
                        WritePixel(rp, (LONG)x1, (LONG)y1);
                        x[i] = xn;
                        y[i] = yn;
                }
                 
                /* check for message from Intuition */
                checkmessages(&k);
                if (k<=0) break;

        }

	/* might add something here to allow restart with a change
		of parameters... */
	/* ok, here you go: start over on a resize */
	if (k<0) goto restart;

        closedisplay(); 
}
 


/*         amiga specific stuff (not counting graphics calls in main()) */

struct Window *window=0;
struct Screen *screen=0;
LONG GfxBase=0, IntuitionBase = 0;

	/* color sets */
UWORD colorTables[COLORSETS][32] = {
       {0x0000, 0x0fff, 0x0e04, 0x0b40, 0x0fb0, 0x0bf0, 0x05d0, 0x0ed0, 
	0x07df, 0x069f, 0x0c0e, 0x0f2e, 0x0feb, 0x0c98, 0x0bbb, 0x07df,
	0x0e30, 0x0222, 0x0444, 0x0666, 0x0888, 0x0aaa, 0x0ccc, 0x0fff,
	0x00f0, 0x00ff, 0x0ff0, 0x0f0f, 0x0f45, 0x04f5, 0x054f, 0x0172},
       {0x0000, 0x0fff, 0x0f03, 0x0e04, 0x0d05, 0x0c07, 0x0c09, 0x0c0a,
        0x0b0b, 0x0a1c, 0x083c, 0x074e, 0x044f, 0x025f, 0x026e, 0x025e,
	0x026b, 0x037a, 0x0389, 0x02a8, 0x02e7, 0x02f5, 0x04f5, 0x06e4,
	0x07c3, 0x08b3, 0x0993, 0x0a74, 0x0c53, 0x0d33, 0x0e23, 0x0f12}
};
struct IntuiText pauseText = {
	2, 1, JAM2, 0, 0, NULL, "P\0", NULL
};
struct Gadget pauseGadget = {
	NULL,				/* next gadget */
	-12, 10, 14, 14,
	GADGHCOMP | GRELRIGHT,
	TOGGLESELECT | GADGIMMEDIATE,
	BOOLGADGET | GZZGADGET,
	NULL,		/* image, selected image */
	NULL,
	&pauseText,
	NULL,		/* mutual exclude, special info, id, data */
	NULL,
	1,
	NULL
};	

struct NewWindow windowDefinition = {
        0, 10, XMAX, YMAX-10,                /* pos & size */
        0, 1,                                /* detail and block pens */
        CLOSEWINDOW | GADGETDOWN | NEWSIZE,  /* messages requested */
	GIMMEZEROZERO | WINDOWSIZING |
        WINDOWDRAG | WINDOWCLOSE |
        SMART_REFRESH | WINDOWDEPTH,         /* features requested */
        &pauseGadget, NULL,                   /* gadgets and checkmark */
        "Roses",                             /* title */
        NULL, NULL,                          /* custom screen and bitmap */
        150, 150, -1, -1,                    /* min and max size */
        WBENCHSCREEN                         /* where to put it */
};

struct TextAttr theFont = {"topaz.font",8,0,0};
struct NewScreen screenDefinition = {
	0, 0, 320, 200,		/* size  */
	4,			/* depth */
	1, 0,			/* pens */
	HIRES,			/* attributes */
	CUSTOMSCREEN,
	&theFont,		/* font */
	"Rose Screen",
	NULL, NULL		/* gadgets, custom bitmap */
};

opendisplay(rp)
struct RastPort **rp;
{
        struct ViewPort *vp;
 	int i;

	pause = GfxBase = IntuitionBase = window = screen = 0;


        if (!(GfxBase = OpenLibrary("graphics.library",0))) {
                printf("Can't open graphics.library\n");
                goto fail;
        }
        
        if (!(IntuitionBase = OpenLibrary("intuition.library",0))) {
                printf("Can't open intuition.library\n");
                goto fail;
        }

	if (customScreen>=0) {
		screenDefinition.Width = SMAXX;
		screenDefinition.Height = SMAXY;
		screenDefinition.ViewModes = customScreen;
		if (!(customScreen & HIRES)) screenDefinition.Depth = 5;
		if (!(screen = OpenScreen(&screenDefinition))) {
			printf("Can't open a custom screen\n");
			goto fail;
		}
		windowDefinition.Screen = screen;
		windowDefinition.Type = CUSTOMSCREEN;
		windowDefinition.Width = SMAXX;
		windowDefinition.Height = SMAXY-1;
		windowDefinition.TopEdge = 1;
		vp = &(screen->ViewPort);
		if (colorSet) {
			LoadRGB4(vp, colorTables[colorSet-1], 
				1<<screenDefinition.Depth);
		}
	}

        if (!(window = OpenWindow(&windowDefinition))) {
                printf("Can't open a window\n");
                goto fail;
        }

	/* is this a nice way to find depth of a window's screen? */
	maxcol = (1 << (SHORT)window->WScreen->BitMap.Depth)-1; 
	xmax = window->Width - 20;
	ymax = window->Height - 10;
        *rp = window->RPort;

	OnGadget(&pauseGadget, window, NULL);

        return;

fail:
        closedisplay();
        exit(0);
}


closedisplay()
{
        if (window) CloseWindow(window);
	if (screen) CloseScreen(screen);
        if (GfxBase) CloseLibrary(GfxBase);
        if (IntuitionBase) CloseLibrary(IntuitionBase);
}

/* 0 status means stop; negative means start over; positive means keep going */
checkmessages(status)
int *status;
{
        struct IntuiMessage *msg;

waiting:
	*status=1;
        while (msg = (struct IntuiMessage *)GetMsg(window->UserPort)) {
                switch (msg->Class) {

		    case CLOSEWINDOW: *status=0; break;
					
		    case NEWSIZE:       xmax = window->Width-20;
					ymax = window->Height-10;
					*status=-1; break;

                    case GADGETDOWN: 	pause = !pause; break;

		    default: 		*status=1; break;

		}
                ReplyMsg(msg);
        }
	if (pause && (*status==1)) {
		WaitPort(window->UserPort);
		goto waiting;
	}
}

== cut here ==




=== === ===         Pa!  Molly's dead!  She ate some leaves!       === === ===
"Trespassers w"   ranjit@eniac.seas.upenn.edu	ucbvax!rutgers!super!eniac!...
Ranjit Bhatnagar, Graduate Student     I'm not an actor, but I play one on TV.