[comp.sys.amiga] Sun Tools on Amiga

ugmiker@sunybcs.UUCP (03/28/87)

does anyone know of a program that will let me interface an Amiga
with a Sun workstation and be able to effectively run Suntools
with the Amiga as a remote terminal, I have heard the atari's 
are capable of it, so I know the Amiga must be, I even heard that
it was Sun microsystems that wrote the program(Chuck Mcmannis ?? any
help from the home of Sun????).

						mike(r)


________________________________________________________________________
        		Mike Reilly

SUNY/Buffalo Computer Science 
csnet:	ugmiker@buffalo.CSNET
uucp:	..!{nike|watmath,alegra,decvax}!sunybcs!ugmiker
BITNET:	ugmiker@sunybcs.BITNET, acsscott@ubvmsa.bitnet
        		Mike Reilly

SUNY/Buffalo Computer Science 
csnet:	ugmiker@buffalo.CSNET
uucp:	..!{nike|watmath,alegra,decvax}!sunybcs!ugmiker
BITNET:	ugmiker@sunybcs.BITNET, acsscott@ubvmsa.bitnet

cmcmanis@sun.UUCP (03/30/87)

In article <2734@sunybcs.UUCP>, ugmiker@sunybcs (Michael Reilly) writes:
> does anyone know of a program that will let me interface an Amiga
> with a Sun workstation and be able to effectively run Suntools
> with the Amiga as a remote terminal, I have heard the atari's 
> are capable of it, so I know the Amiga must be, I even heard that
> it was Sun microsystems that wrote the program(Chuck Mcmannis ?? any
> help from the home of Sun????).
> 						mike(r)

The answer is no, there isn't. What runs on a mono 1040ST is NeWS Sun's
Network extensible Window System. The port was written by Mitch Bradley.
THIS IS NOT A PRODUCT OF SUN MICROSYSTEMS! It was done as an exercise
to demonstrate how useful NeWS is and why you would want to support it
as your defacto window system. NeWS licenses are very reasonable for 
educational institutions, I suggest you contact Michelle Arden
...!sun!marden and ask her to mail you the details. Licenses get 
source and tips on porting it to different architectures.


-- 
--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.

rap@dana.UUCP (03/31/87)

A few weeks ago, a plea for help crossed the net regarding VSprites.
I am posting the source to the VSprite demo that I had written for
my book, the Programmers' Guide To The Amiga (SYBEX, January, 1987).

It produces 28 VSprites onscreen simultaneously, starting with one
distinct sprite image (an "S!"), and using only three distinct
sets of colors.  The limited number of colorsets was chosen to give
the gel engine the best possible chance to be able to assign
vsprites before running out of real sprites to use (especially
since I restrict it to sprites 2-7 by using the line:

   g->sprRsrvd = 0xFC;	/* do not use sprites 0 or 1. */

This prevents the gel engine from trying to change the color of the 
cursor.  

In the background area of the window, there are the digit sets
17 18 ... 31, each drawn in that particular color.  As the vsprites
move you will notice that certain of the colors (21-23, 25-27, 29-31)
get changed.  This illustrates that if you produce vsprites against
a 32-color screen, the upper set of color registers, which is shared
in the Amiga with the vsprites, get dynamically reassigned by the
gel engine.  Therefore one should avoid drawing any background stuff
using the colors that the vsprites use, unless you want the effect
you see there (yuck).

Also, as the sprites move, if you follow any one of them, you
will see it disappear occasionally.  This happens when there
are more than (N) sprites on a single horizontal line.  N is 
variable depending on the way that the colors have been assigned.

The list of vsprites to be produced is sorted (SortGList) from top
to bottom as well as from left to right.  The lowest numbered
available real sprite is chosen first, and the system creates
copper (coprocessor) instructions that point to the first vsprite
image, as well as instruction to load that first vsprite's colors
into the real sprite color registers.  The hardware sprite thus used
is declared unusable until a couple of lines past the bottommost
line of this vsprite's display.

For each subsequent vsprite in the list, the system attempts the
same kind of assignment for both image and color registers.  A
preference is given to assigning to a hardware sprite that is
both available, and for which its color registers have already
been loaded with the colors that it wants to use.  Thus, hardware
sprites 2 and 3 can occupy the same horizontal positions in any
overlap position if both carry the same colors, and can have
any arbitrary images.  The gel engine does not, however, compare
the colors in the colorset to make the decision about possible
sprite pair assignment.  Rather it compares the POINTERs to the 
colorsets.  That is why you would not want to have multiple
colorsets, each of which contained identical colors for your
vsprites... because the POINTER values to those colorsets would
be different and the system would run out of vsprites sooner.

The book goes into a similar example for simple sprites and uses
a nearly identical data structure for its Bob example.  The
programs are available on disk in both source and executable
form.  All, including this one, are in Lattice C, though I'm
working on converting all to run under either Lattice or Manx.

NOTE: THIS PROGRAM CAN BE COMPILED AND LINKED UNDER 1.1 (Lattice 3.03)
BUT ONLY RUNS UNDER 1.2.  (There was a problem in release 1.1 that
prevents VSprites from running).

Hope this helps.

Rob Peck

---------------- CUT HERE --------------- CUT HERE ---------------------
/* vsprite.final.c, merged with its support files */

/* execute makesimple vsprite.final ; Amiga C 1.1 (Lattice 3.03) */

#include "exec/types.h"
#include "intuition/intuition.h"
#include "graphics/sprite.h"
#include "exec/memory.h"
#include "graphics/gels.h"

/* ask system to create and manage MAXSP vsprites */
#define MAXSP 28 

/* define possible speeds for vsprites in counts per vblank */

SHORT speed[] = { 1, 2, -1, -2 };

SHORT xmove[MAXSP], ymove[MAXSP];  	
				/* sprite directions of movement */
struct VSprite *vsprite[MAXSP];	/* MAXSP simple sprites */
struct VSprite *vspr;		/* pointer to a sprite */
short maxgot;			/* max # of sprites we created */

struct GelsInfo mygelsinfo;	/* the window's RastPort needs one
				 * of these in order to do VSprites */

struct Window *w;	/* pointer to a Window   */
struct RastPort *rp;	/* pointer to a RastPort */
struct Screen *s;	/* a pointer to a Screen */	
struct ViewPort *vp;	/* pointer to a ViewPort */

struct Window *OpenWindow();
struct Screen *OpenScreen();
LONG GfxBase;
LONG IntuitionBase;

/* 18 words of sprite data = 9 lines of sprite data */

UWORD sprite_data[ ] = {
			0x0fc3, 0x0000, /* image data line 1*/
			0x3ff3, 0x0000, /* image data line 2*/
			0x30c3, 0x0000, /* image data line 3*/
			0x0000, 0x3c03, /* image data line 4*/
			0x0000, 0x3fc3, /* image data line 5*/
			0x0000, 0x03c3, /* image data line 6*/
			0xc033, 0xc033, /* image data line 7*/
			0xffc0, 0xffc0, /* image data line 8*/
			0x3f03, 0x3f03, /* image data line 9*/
			};
UWORD *sprdata;

movesprites()
{
	short i;

	for (i=0; i<maxgot; i++)
	{
		vspr = vsprite[i];

		vspr->X = xmove[i]+vspr->X;
		vspr->Y = ymove[i]+vspr->Y;

		/* move the sprites ... here. */

		if(vspr->X >= 300 || vspr->X <= 0) xmove[i]=-xmove[i];
		if(vspr->Y >= 190 || vspr->Y <= 0) ymove[i]=-ymove[i];
		
	}
	SortGList(rp);	/* get the list in order */
	DrawGList(rp, vp);	/* create the sprite instructions */

	MakeScreen(s);  /* ask Intuition to pull it all together */
	RethinkDisplay(); /* and to show us what we have now. */
}


#define AZCOLOR 1
#define WHITECOLOR 2

#define WC WINDOWCLOSE
#define WS WINDOWSIZING
#define WDP WINDOWDEPTH
#define WDR WINDOWDRAG

#define NORMALFLAGS (WC|WS|WDP)
/* Did not use windowdrag because dont want screen to be moved. */

/* Allow window sizing so user can decrease size of window, then
 * increase it again, thus erasing the background text and more
 * easily see that some vsprites wink out and into existence when
 * too many sprites are on a single horizontal plane and the
 * vsprite machine runs out of sprites to assign.
 */

/* myfont1 specifies characteristics of the default font;
 * this case selects the 80 column font that displays as 
 * 40 columns in low resolution mode.
 */	
struct TextAttr myfont1 = { "topaz.font", 8, 0, 0 };
	
struct NewScreen myscreen1 = {
	0, 0, 	  	/* LeftEdge, TopEdge ... where to put screen */
	320, 200, 	/* Width, Height ... size of the screen */
	5,	  	/* 5 planes Depth, means 2 to the 5th or 
		   	* 32 different colors to choose from once 
		  	* the screen is opened.
		   	*/
	1, 0,	  	/* DetailPen, BlockPen */
	SPRITES,	/* ViewModes ... value of 0 = low resolution */
	CUSTOMSCREEN,  	/* Type of screen */
	&myfont1, 	/* Font to be used as default for this screen */
	"32 Color Test", /* DefaultTitle for its title bar */
	NULL,     	/* screens user-gadgets, always NULL, ignored */
	NULL };
			/* address of custom bitmap for screen, 
		   	 * not used in this example 
		   	 */


struct NewWindow myWindow = {
	0, 		/* LeftEdge for window measured in pixels, 
			   at the current horizontal resolution,
			   from the leftmost edge of the Screen */
	0,		/* TopEdge for window is measured in lines 
			   from the top of the current Screen.   */
	320, 185,	/* Width, Height of this window */ 
	0,   		/* DetailPen - what pen number is to be 
			   used to draw the borders of the window */ 
	1,		/* BlockPen - what pen number is to be 
			   used to draw system generated window
			   gadgets */
			/* (for DetailPen and BlockPen, the value
			    of -1 says "use the default value")  */
	CLOSEWINDOW, 	/* simplesprite program used INTUITICKS also */
			/* IDCMP Flags */
	NORMALFLAGS | GIMMEZEROZERO | ACTIVATE,
			/* Window Flags:  (see below for more info) */
	NULL,		/* FirstGadget */
	NULL,		/* CheckMark   */
	"Click Close Gadget To Stop",	/* Window title */
	NULL,		/* Pointer to Screen if not workbench */
	NULL,		/* Pointer to BitMap if a SUPERBITMAP window */
	320, 10,	/* minimum width, minimum height */
	320, 200,	/* maximum width, maximum height */
	CUSTOMSCREEN
	};

#include "graphics/gfxmacros.h"

/* #include "event1.c"	*/
/* gets the event handler */
/* event1.c */

HandleEvent(code)
	LONG code;	/* provided by main */
{
	switch(code) 
	{
	case CLOSEWINDOW:
		return(0);
		break;
	case INTUITICKS:	/* could have done much faster
				 * but what the heck, this is
				 * shorter for test purposes
				 */
		movesprites();	/* 10 moves per second; test */
		default:
			break;
	}
return(1);
}

UWORD mycolortable[] = {

	0x0000, 0x0e30, 0x0fff, 0x0b40, 0x0fb0, 0x0bf0,
	0x05d0, 0x0ed0, 0x07df, 0x069f, 0x0c0e,
	0x0f2e, 0x0feb, 0x0c98, 0x0bbb, 0x07df, 

	0x0000, 0x0e30, 0x0fff, 0x0b40, 
	0x0fb0, 0x0bf0, 0x05d0, 0x0ed0, 
	0x07df, 0x069f, 0x0c0e, 0x0f2e, 
	0x0feb, 0x0c98, 0x0bbb, 0x07df 
	};

	/* black, red, white, fire-engine red, orange, yellow,
	lime green, green, aqua, dark blue, purple,
	violet, tan, brown, gray, skyblue, (everything again) */

UWORD colorset0[ ] = { 0x0e30, 0xffff, 0x0b40 }; /* same as colors 17-19 */
UWORD colorset1[ ] = { 0x0bf0, 0x05d0, 0x0ed0 }; /* 21-23 */
UWORD colorset2[ ] = { 0x069f, 0x0c0e, 0x0f2e }; /* 25-27 */
UWORD colorset3[ ] = { 0x0c98, 0x0bbb, 0x07df }; /* 29-31 */
UWORD *colorset[ ] = {
			colorset0, colorset1,
			colorset2, colorset3 };
int choice;
char *numbers[] = { "17","18","19",
		    "20","21","22","23",
		    "24","25","26","27",
		    "28","29","30","31" };

/* #include "ram:purgegels.c" */
/* purgegels.c */

/*
 * Use this to get rid of the gels stuff when it is not needed any more.
 * You must have allocated the gels info stuff (use the ReadyGels routine).
 */

PurgeGels(g)
struct GelsInfo *g;
{
   if (g->collHandler != NULL)
      FreeMem(g->collHandler, sizeof(struct collTable));
   if (g->lastColor != NULL)
      FreeMem(g->lastColor, sizeof(LONG) * 8);
   if (g->nextLine != NULL)
      FreeMem(g->nextLine, sizeof(WORD) * 8);
   if (g->gelHead != NULL)
      FreeMem(g->gelHead, sizeof(struct VSprite));
   if (g->gelTail != NULL)
      FreeMem(g->gelTail, sizeof(struct VSprite));
}


/* Deallocate memory which has been allocated by the routines Makexxx. */
/* Assumes images and imageshadow deallocated elsewhere. */

DeleteGel(v)
struct VSprite *v;
{
   if (v != NULL) {
      if (v->VSBob != NULL) {
         if (v->VSBob->SaveBuffer != NULL) {
            FreeMem(v->VSBob->SaveBuffer, sizeof(SHORT) * v->Width
                  * v->Height * v->Depth);
         }
         if (v->VSBob->DBuffer != NULL) {
            if (v->VSBob->DBuffer->BufBuffer != 0) {
               FreeMem(v->VSBob->DBuffer->BufBuffer,
                     sizeof(SHORT) * v->Width * v->Height * v->Depth);
            }
            FreeMem(v->VSBob->DBuffer, sizeof(struct DBufPacket));
         }
         FreeMem( v->VSBob, sizeof(struct Bob));
      }
      if (v->CollMask != NULL) {
         FreeMem(v->CollMask, sizeof(WORD) * v->Height * v->Width);
      }
      if (v->BorderLine != NULL) {
         FreeMem(v->BorderLine, sizeof(WORD) * v->Width);
      }
      FreeMem(v, sizeof(struct VSprite));
   }
}

/* end of purgegels.c */

/* #include "ram:readygels.c" */
/* readygels.c */

struct VSprite *SpriteHead = NULL;
struct VSprite *SpriteTail = NULL;

void border_dummy()	/* a dummy collision routine */
{ 
   return; 
}

ReadyGels(g, r)
struct RastPort *r;
struct GelsInfo *g;
{
   /* Allocate head and tail of list. */
   if ((SpriteHead = (struct VSprite *)AllocMem(sizeof
         (struct VSprite), MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      return(-1);
   }

   if ((SpriteTail = (struct VSprite *)AllocMem(sizeof
         (struct VSprite), MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      FreeMem(SpriteHead, sizeof(struct VSprite));
      return(-2);
   }
   g->sprRsrvd = 0xFC;	/* do not use sprites 0 or 1. */

   if ((g->nextLine = (WORD *)AllocMem(sizeof(WORD) * 8,
         MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-3);
   }
 
  if ((g->lastColor = (WORD **)AllocMem(sizeof(LONG) * 8,
         MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(g->nextLine,8 * sizeof(WORD));
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-4);
   }

  /* Next we prepare a table of pointers to the routines which should
   * be performed when DoCollision senses a collision.  This
   * declaration may not be necessary for a basic vsprite with
   * no collision detection implemented, but then it makes for
   * a complete example.
   */
   if ((g->collHandler = (struct collTable *)AllocMem(sizeof(struct
         collTable), MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(g->lastColor, 8 * sizeof(LONG));
      FreeMem(g->nextLine,8 * sizeof(WORD));
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-5);
   }

  /* When any part of the object touches or passes across
   * this boundary, it will cause the boundary collision
   * routine to be called.  This is at smash[0] in the
   * collision handler table and is called only if
   * DoCollision is called.
   */
   g->leftmost = 0;
   g->rightmost = r->BitMap->BytesPerRow * 8 - 1;
   g->topmost = 0;
   g->bottommost = r->BitMap->Rows - 1;

   r->GelsInfo = g;  /* Link together the two structures */

   InitGels(SpriteHead, SpriteTail, g );

  /* Pointers initialized to the dummy sprites which will be
   * used by the system to keep track of the animation system.
   */
   SetCollision(0, border_dummy, g);
   WaitTOF();
   return(0);	/* a return value of 0 says all ok, any 
		 * negative value tells you when it failed.
		 * (see the listing as to what the routine
		 * was trying to do... all failures are
		 * due to out of memory conditions).
		 */
}


/* end of readygels.c */

/* #include "ram:MakeVSprite.c" */
/* MakeVSprite.c */

struct VSprite *MakeVSprite(lineheight, image, colorset, x, y,
				wordwidth, imagedepth, flags)
SHORT lineheight;	/* How tall is this vsprite? */
WORD *image;		/* Where is the vsprite image data, should be
			   twice as many words as the value of lineheight */
WORD *colorset;		/* Where is the set of three words which describes
			   the colors that this vsprite can take on? */
SHORT x, y;		/* What is its initial onscreen position? */
SHORT wordwidth, imagedepth, flags;
{
   struct VSprite *v;	/* Make a pointer to the vsprite structure which
			   this routine dynamically allocates */

   if ((v = (struct VSprite *)AllocMem(sizeof(struct VSprite),
         MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      return(0);
   }

   v->Flags = flags;	/* Is this a vsprite, not a bob? */

   v->Y = y;		/* Establish initial position relative to */
   v->X = x;		/* the Display coordinates. */

   v->Height = lineheight;	/* The Caller says how high it is. */
   v->Width = wordwidth;   /* A vsprite is always 1 word (16 bits) wide. */

  /* There are two kinds of depth... the depth of the image itself, and the
   * depth of the playfield into which it will be drawn. The image depth
   * says how much data space will be needed to store an image if it's
   * dynamically allocated. The playfield depth establishes how much space
   * will be needed to save and restore the background when a bob is drawn.
   * A vsprite is always 2 planes deep, but if it's being used to make a
   * bob, it may be deeper...
   */

   v->Depth = imagedepth;

  /* Assume that the caller at least has a default boundary collision
   * routine.... bit 1 of this mask is reserved for boundary collision
   * detect during DoCollision(). The only collisions reported will be
   * with the borders. The caller can change all this later.
   */

   v->MeMask = 1;
   v->HitMask = 1;

   v->ImageData = image;	/* Caller says where to find the image. */

  /* Show system where to find a mask which is a squished down version
   * of the vsprite (allows for fast horizontal border collision detect).
   */

   if ((v->BorderLine = (WORD *)AllocMem((sizeof(WORD)*wordwidth),
         MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
   	FreeMem(v, sizeof(struct VSprite)); 
   	return(0);
   }

  /* Show system where to find the mask which contains a 1 bit for any
   * position in the object in any plane where there is a 1 bit (all planes
   * OR'ed together).
   */

   if ((v->CollMask = (WORD *)AllocMem(sizeof(WORD)*lineheight*wordwidth,
         MEMF_CHIP | MEMF_CLEAR)) == 0) 
   {
   	FreeMem(v, sizeof(struct VSprite)); 
   	FreeMem(v->BorderLine, wordwidth * sizeof(WORD));
        return(0);
   }

  /* This isn't used for a Bob, just a VSprite. It's where the
   * Caller says where to find the VSprites colors.
   */
   v->SprColors = colorset;

   /* These aren't used for a VSprite, and MakeBob'll do set up for Bob. */
   v->PlanePick  = 0x00;
   v->PlaneOnOff = 0x00;

   InitMasks(v);	/* Create the collMask and borderLine */	
   return(v);
}
/* end of MakeVSprite.c */

main()
{
	struct IntuiMessage *msg;
	LONG result;
	SHORT k, j, x, y, error;
	UWORD *src, *dest;	/* for copying sprite data to RAM */

	GfxBase = OpenLibrary("graphics.library",0);

	IntuitionBase = OpenLibrary("intuition.library",0);
	/* (error checking left out for brevity here) */

	s = OpenScreen(&myscreen1);  /* try to open it */
	if(s == 0)
	{
    		printf("Can't open myscreen1\n");
    		exit(10);
	}
	myWindow.Screen = s;	/* say where screen is located */

	ShowTitle(s, FALSE);	/* Dont let screen be dragged down...*/

	w = OpenWindow(&myWindow);
	if(w == 0)
	{
		printf("Window didn't open!\n");
		CloseScreen(s);
		exit(20);
	}
	vp = &(s->ViewPort);
	/* set the colors for this viewport */

	LoadRGB4(vp, &mycolortable[0], 32);
	rp = w->RPort;
		/* Now wait for a message to arrive from Intuition 
		 * (task goes to sleep while waiting for the message) 
		 */

	/* Write Text using sprite colors so that demo can show
	 * how the vsprite machine stuffs the colors as it goes
	 * down the screen.  Thus if using vsprites, user should
	 * avoid using the color registers that the vsprites use.
	 */

	/* Notice also that color numbers 17-19 are untouched.  
	 * That is because of the sprResrvd=0xFC in ReadyGels.
	 * (Doesn't allow the virtual sprite machine to access
	 * either sprite 0 or 1... 0 is used by mouse cursor and
	 * shares its colors with 1, so I reserved both of them.
	 */

	for(j=8; j<180; j+=50)
	{
		for(k=0; k<15; k++)
		{
			Move(rp,k*20,j);
			SetAPen(rp,k+17);	/* show 17-31 */
			/* 16, 20, 24, 28 are unaffected by vsprites 
			 * because they are not used by hardware sprites */

			Text(rp,numbers[k],2);
		}
	}
	/* *************************************** */
	/* VSPRITE DEMO SECTION 		   */
	/* *************************************** */

	/* Allocate CHIP memory to hold the actual sprite data */
	/* (necessary if ever to run on an expanded RAM Amiga) */

	sprdata = (UWORD *)AllocMem(36, MEMF_CHIP);

	if(sprdata == NULL)
	{
		/* not enough memory for sprite */
	}
	/* now copy the sprite data into the CHIP RAM. */

	src = sprite_data;  
	dest = sprdata; 	/* source, destination */

	for( j=0; j<18; j++)
	{
		*dest++ = *src++;
	}			

	choice = 0;
	maxgot = 0;

	/* Prepare the GELS system to work with VSPRITE or BOBS */

	error = ReadyGels(&mygelsinfo, rp);

	for(k=0; k<MAXSP; k++)	/* whatever maximum number of vsprites */
	{
		xmove[k]=speed[RangeRand(4)];
		ymove[k]=speed[RangeRand(4)];

		/* establish a position for the sprite */
		x = 10 + RangeRand(280);
		y = 10 + RangeRand(170);

		/* create a vsprite */
		vsprite[k] = MakeVSprite( 9, sprdata, colorset[choice], 
					x, y, 1, 2, VSPRITE);
		/* 9 lines high, using MEMF_CHIP image of a sprite,
		 * with a particular set of colors, at an X,Y location
		 * 1 word wide, 2 planes deep (all vsprites are 2 deep)
		 * and it is a VSPRITE */

		if(vsprite[k] == 0)
		{
			break;	/* ran out of memory! */
		}
		AddVSprite(vsprite[k], rp);

		maxgot++;

		choice++; /* choose a different color set */
		if(choice >= 4) 
		{
			choice = 0;	/* wrap around on colorsets */
		}
	}
	while(1)	/* forever */
	{
		WaitTOF();
		movesprites();

		result = -1;	/* now see if CLOSEWINDOW is waiting */
		msg = (struct IntuiMessage *)GetMsg(w->UserPort);		
		if(msg != 0)
		{
			result = HandleEvent(msg->Class);

			/* Let Intuition reuse the msg */
			ReplyMsg(msg);	
		}
		if(result == 0) 
		{
			break;  /* got a CLOSEWINDOW */
		}
	}

	/* DONE, now cleanup */

	/* Free however many vsprites we actually managed to create */

	for(k=0; k<maxgot; k++)
	{
		DeleteGel(vsprite[k]);				
	}
	/* delete what ReadyGels created */
	PurgeGels(&mygelsinfo);	

	FreeMem(sprdata, 36);	/* free what we allocated. */

	CloseWindow(w);
	CloseScreen(s);
}	

Hope this helps.

Rob Peck	hplabs!dana!rap
		USnail: DATAPATH, POBox 1828, Los Gatos, Ca. 95031-1828

bret@hi.UUCP (03/31/87)

In article <2734@sunybcs.UUCP> ugmiker@sunybcs.UUCP (Michael Reilly) writes:

>does anyone know of a program that will let me interface an Amiga
>with a Sun workstation and be able to effectively run Suntools
>with the Amiga as a remote terminal, I have heard the atari's 
>are capable of it, so I know the Amiga must be, I even heard that
>it was Sun microsystems that wrote the program(Chuck Mcmannis ?? any
>help from the home of Sun????).

A friend and I have been thinking about writing just such a program.
The only real problem is that you need to install a pseudo graphics
device on the Sun that talks to the amiga. We were thinking about
creating a pseudo device that you open and then tell it to communicate
to the amiga using such and such a serial port. With any luck at all
we should be able to optimize the pseudo graphics device to send
high level commands to the amiga and therefor get a failry high
through put.

If anyone out there is working on (thinking about) a simmilar idea
I would love to here about it. I think the idea of adding extra low
cost color monitor to a Sun may have real potential.


				-Bret Thaeler
-- 
--------------------------------------------------------------------------------
Bret K. Thaeler		     ARPA: thaeler@hc.dspo.gov  |          /// Amiga
College of Enginering, UNM   UUCP: hc!thaeler           |         /// user
Professional Student                                    |   \\\  ///
(505) 277-4497                                          |    \\\///  And dam
I instinctively used the Vulcan death grip.             |     \///  proud of it

fnf@mcdsun.UUCP (04/02/87)

NOTE:  Rob is having problems posting from his system and has
asked me to post this for him, please respond to hplabs!dana!rap.
------------------------------------------------------------

A few weeks ago, a plea for help crossed the net regarding VSprites.
I am posting the source to the VSprite demo that I had written for
my book, the Programmers' Guide To The Amiga (SYBEX, January, 1987).

It produces 28 VSprites onscreen simultaneously, starting with one
distinct sprite image (an "S!"), and using only three distinct
sets of colors.  The limited number of colorsets was chosen to give
the gel engine the best possible chance to be able to assign
vsprites before running out of real sprites to use (especially
since I restrict it to sprites 2-7 by using the line:

   g->sprRsrvd = 0xFC;	/* do not use sprites 0 or 1. */

This prevents the gel engine from trying to change the color of the 
cursor.  

In the background area of the window, there are the digit sets
17 18 ... 31, each drawn in that particular color.  As the vsprites
move you will notice that certain of the colors (21-23, 25-27, 29-31)
get changed.  This illustrates that if you produce vsprites against
a 32-color screen, the upper set of color registers, which is shared
in the Amiga with the vsprites, get dynamically reassigned by the
gel engine.  Therefore one should avoid drawing any background stuff
using the colors that the vsprites use, unless you want the effect
you see there (yuck).

Also, as the sprites move, if you follow any one of them, you
will see it disappear occasionally.  This happens when there
are more than (N) sprites on a single horizontal line.  N is 
variable depending on the way that the colors have been assigned.

The list of vsprites to be produced is sorted (SortGList) from top
to bottom as well as from left to right.  The lowest numbered
available real sprite is chosen first, and the system creates
copper (coprocessor) instructions that point to the first vsprite
image, as well as instruction to load that first vsprite's colors
into the real sprite color registers.  The hardware sprite thus used
is declared unusable until a couple of lines past the bottommost
line of this vsprite's display.

For each subsequent vsprite in the list, the system attempts the
same kind of assignment for both image and color registers.  A
preference is given to assigning to a hardware sprite that is
both available, and for which its color registers have already
been loaded with the colors that it wants to use.  Thus, hardware
sprites 2 and 3 can occupy the same horizontal positions in any
overlap position if both carry the same colors, and can have
any arbitrary images.  The gel engine does not, however, compare
the colors in the colorset to make the decision about possible
sprite pair assignment.  Rather it compares the POINTERs to the 
colorsets.  That is why you would not want to have multiple
colorsets, each of which contained identical colors for your
vsprites... because the POINTER values to those colorsets would
be different and the system would run out of vsprites sooner.

The book goes into a similar example for simple sprites and uses
a nearly identical data structure for its Bob example.  The
programs are available on disk in both source and executable
form.  All, including this one, are in Lattice C, though I'm
working on converting all to run under either Lattice or Manx.

NOTE: THIS PROGRAM CAN BE COMPILED AND LINKED UNDER 1.1 (Lattice 3.03)
BUT ONLY RUNS UNDER 1.2.  (There was a problem in release 1.1 that
prevents VSprites from running).

Hope this helps.

Rob Peck

---------------- CUT HERE --------------- CUT HERE ---------------------
/* vsprite.final.c, merged with its support files */

/* execute makesimple vsprite.final ; Amiga C 1.1 (Lattice 3.03) */

#include "exec/types.h"
#include "intuition/intuition.h"
#include "graphics/sprite.h"
#include "exec/memory.h"
#include "graphics/gels.h"

/* ask system to create and manage MAXSP vsprites */
#define MAXSP 28 

/* define possible speeds for vsprites in counts per vblank */

SHORT speed[] = { 1, 2, -1, -2 };

SHORT xmove[MAXSP], ymove[MAXSP];  	
				/* sprite directions of movement */
struct VSprite *vsprite[MAXSP];	/* MAXSP simple sprites */
struct VSprite *vspr;		/* pointer to a sprite */
short maxgot;			/* max # of sprites we created */

struct GelsInfo mygelsinfo;	/* the window's RastPort needs one
				 * of these in order to do VSprites */

struct Window *w;	/* pointer to a Window   */
struct RastPort *rp;	/* pointer to a RastPort */
struct Screen *s;	/* a pointer to a Screen */	
struct ViewPort *vp;	/* pointer to a ViewPort */

struct Window *OpenWindow();
struct Screen *OpenScreen();
LONG GfxBase;
LONG IntuitionBase;

/* 18 words of sprite data = 9 lines of sprite data */

UWORD sprite_data[ ] = {
			0x0fc3, 0x0000, /* image data line 1*/
			0x3ff3, 0x0000, /* image data line 2*/
			0x30c3, 0x0000, /* image data line 3*/
			0x0000, 0x3c03, /* image data line 4*/
			0x0000, 0x3fc3, /* image data line 5*/
			0x0000, 0x03c3, /* image data line 6*/
			0xc033, 0xc033, /* image data line 7*/
			0xffc0, 0xffc0, /* image data line 8*/
			0x3f03, 0x3f03, /* image data line 9*/
			};
UWORD *sprdata;

movesprites()
{
	short i;

	for (i=0; i<maxgot; i++)
	{
		vspr = vsprite[i];

		vspr->X = xmove[i]+vspr->X;
		vspr->Y = ymove[i]+vspr->Y;

		/* move the sprites ... here. */

		if(vspr->X >= 300 || vspr->X <= 0) xmove[i]=-xmove[i];
		if(vspr->Y >= 190 || vspr->Y <= 0) ymove[i]=-ymove[i];
		
	}
	SortGList(rp);	/* get the list in order */
	DrawGList(rp, vp);	/* create the sprite instructions */

	MakeScreen(s);  /* ask Intuition to pull it all together */
	RethinkDisplay(); /* and to show us what we have now. */
}


#define AZCOLOR 1
#define WHITECOLOR 2

#define WC WINDOWCLOSE
#define WS WINDOWSIZING
#define WDP WINDOWDEPTH
#define WDR WINDOWDRAG

#define NORMALFLAGS (WC|WS|WDP)
/* Did not use windowdrag because dont want screen to be moved. */

/* Allow window sizing so user can decrease size of window, then
 * increase it again, thus erasing the background text and more
 * easily see that some vsprites wink out and into existence when
 * too many sprites are on a single horizontal plane and the
 * vsprite machine runs out of sprites to assign.
 */

/* myfont1 specifies characteristics of the default font;
 * this case selects the 80 column font that displays as 
 * 40 columns in low resolution mode.
 */	
struct TextAttr myfont1 = { "topaz.font", 8, 0, 0 };
	
struct NewScreen myscreen1 = {
	0, 0, 	  	/* LeftEdge, TopEdge ... where to put screen */
	320, 200, 	/* Width, Height ... size of the screen */
	5,	  	/* 5 planes Depth, means 2 to the 5th or 
		   	* 32 different colors to choose from once 
		  	* the screen is opened.
		   	*/
	1, 0,	  	/* DetailPen, BlockPen */
	SPRITES,	/* ViewModes ... value of 0 = low resolution */
	CUSTOMSCREEN,  	/* Type of screen */
	&myfont1, 	/* Font to be used as default for this screen */
	"32 Color Test", /* DefaultTitle for its title bar */
	NULL,     	/* screens user-gadgets, always NULL, ignored */
	NULL };
			/* address of custom bitmap for screen, 
		   	 * not used in this example 
		   	 */


struct NewWindow myWindow = {
	0, 		/* LeftEdge for window measured in pixels, 
			   at the current horizontal resolution,
			   from the leftmost edge of the Screen */
	0,		/* TopEdge for window is measured in lines 
			   from the top of the current Screen.   */
	320, 185,	/* Width, Height of this window */ 
	0,   		/* DetailPen - what pen number is to be 
			   used to draw the borders of the window */ 
	1,		/* BlockPen - what pen number is to be 
			   used to draw system generated window
			   gadgets */
			/* (for DetailPen and BlockPen, the value
			    of -1 says "use the default value")  */
	CLOSEWINDOW, 	/* simplesprite program used INTUITICKS also */
			/* IDCMP Flags */
	NORMALFLAGS | GIMMEZEROZERO | ACTIVATE,
			/* Window Flags:  (see below for more info) */
	NULL,		/* FirstGadget */
	NULL,		/* CheckMark   */
	"Click Close Gadget To Stop",	/* Window title */
	NULL,		/* Pointer to Screen if not workbench */
	NULL,		/* Pointer to BitMap if a SUPERBITMAP window */
	320, 10,	/* minimum width, minimum height */
	320, 200,	/* maximum width, maximum height */
	CUSTOMSCREEN
	};

#include "graphics/gfxmacros.h"

/* #include "event1.c"	*/
/* gets the event handler */
/* event1.c */

HandleEvent(code)
	LONG code;	/* provided by main */
{
	switch(code) 
	{
	case CLOSEWINDOW:
		return(0);
		break;
	case INTUITICKS:	/* could have done much faster
				 * but what the heck, this is
				 * shorter for test purposes
				 */
		movesprites();	/* 10 moves per second; test */
		default:
			break;
	}
return(1);
}

UWORD mycolortable[] = {

	0x0000, 0x0e30, 0x0fff, 0x0b40, 0x0fb0, 0x0bf0,
	0x05d0, 0x0ed0, 0x07df, 0x069f, 0x0c0e,
	0x0f2e, 0x0feb, 0x0c98, 0x0bbb, 0x07df, 

	0x0000, 0x0e30, 0x0fff, 0x0b40, 
	0x0fb0, 0x0bf0, 0x05d0, 0x0ed0, 
	0x07df, 0x069f, 0x0c0e, 0x0f2e, 
	0x0feb, 0x0c98, 0x0bbb, 0x07df 
	};

	/* black, red, white, fire-engine red, orange, yellow,
	lime green, green, aqua, dark blue, purple,
	violet, tan, brown, gray, skyblue, (everything again) */

UWORD colorset0[ ] = { 0x0e30, 0xffff, 0x0b40 }; /* same as colors 17-19 */
UWORD colorset1[ ] = { 0x0bf0, 0x05d0, 0x0ed0 }; /* 21-23 */
UWORD colorset2[ ] = { 0x069f, 0x0c0e, 0x0f2e }; /* 25-27 */
UWORD colorset3[ ] = { 0x0c98, 0x0bbb, 0x07df }; /* 29-31 */
UWORD *colorset[ ] = {
			colorset0, colorset1,
			colorset2, colorset3 };
int choice;
char *numbers[] = { "17","18","19",
		    "20","21","22","23",
		    "24","25","26","27",
		    "28","29","30","31" };

/* #include "ram:purgegels.c" */
/* purgegels.c */

/*
 * Use this to get rid of the gels stuff when it is not needed any more.
 * You must have allocated the gels info stuff (use the ReadyGels routine).
 */

PurgeGels(g)
struct GelsInfo *g;
{
   if (g->collHandler != NULL)
      FreeMem(g->collHandler, sizeof(struct collTable));
   if (g->lastColor != NULL)
      FreeMem(g->lastColor, sizeof(LONG) * 8);
   if (g->nextLine != NULL)
      FreeMem(g->nextLine, sizeof(WORD) * 8);
   if (g->gelHead != NULL)
      FreeMem(g->gelHead, sizeof(struct VSprite));
   if (g->gelTail != NULL)
      FreeMem(g->gelTail, sizeof(struct VSprite));
}


/* Deallocate memory which has been allocated by the routines Makexxx. */
/* Assumes images and imageshadow deallocated elsewhere. */

DeleteGel(v)
struct VSprite *v;
{
   if (v != NULL) {
      if (v->VSBob != NULL) {
         if (v->VSBob->SaveBuffer != NULL) {
            FreeMem(v->VSBob->SaveBuffer, sizeof(SHORT) * v->Width
                  * v->Height * v->Depth);
         }
         if (v->VSBob->DBuffer != NULL) {
            if (v->VSBob->DBuffer->BufBuffer != 0) {
               FreeMem(v->VSBob->DBuffer->BufBuffer,
                     sizeof(SHORT) * v->Width * v->Height * v->Depth);
            }
            FreeMem(v->VSBob->DBuffer, sizeof(struct DBufPacket));
         }
         FreeMem( v->VSBob, sizeof(struct Bob));
      }
      if (v->CollMask != NULL) {
         FreeMem(v->CollMask, sizeof(WORD) * v->Height * v->Width);
      }
      if (v->BorderLine != NULL) {
         FreeMem(v->BorderLine, sizeof(WORD) * v->Width);
      }
      FreeMem(v, sizeof(struct VSprite));
   }
}

/* end of purgegels.c */

/* #include "ram:readygels.c" */
/* readygels.c */

struct VSprite *SpriteHead = NULL;
struct VSprite *SpriteTail = NULL;

void border_dummy()	/* a dummy collision routine */
{ 
   return; 
}

ReadyGels(g, r)
struct RastPort *r;
struct GelsInfo *g;
{
   /* Allocate head and tail of list. */
   if ((SpriteHead = (struct VSprite *)AllocMem(sizeof
         (struct VSprite), MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      return(-1);
   }

   if ((SpriteTail = (struct VSprite *)AllocMem(sizeof
         (struct VSprite), MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      FreeMem(SpriteHead, sizeof(struct VSprite));
      return(-2);
   }
   g->sprRsrvd = 0xFC;	/* do not use sprites 0 or 1. */

   if ((g->nextLine = (WORD *)AllocMem(sizeof(WORD) * 8,
         MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-3);
   }
 
  if ((g->lastColor = (WORD **)AllocMem(sizeof(LONG) * 8,
         MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(g->nextLine,8 * sizeof(WORD));
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-4);
   }

  /* Next we prepare a table of pointers to the routines which should
   * be performed when DoCollision senses a collision.  This
   * declaration may not be necessary for a basic vsprite with
   * no collision detection implemented, but then it makes for
   * a complete example.
   */
   if ((g->collHandler = (struct collTable *)AllocMem(sizeof(struct
         collTable), MEMF_PUBLIC | MEMF_CLEAR)) == NULL) 
   {
      FreeMem(g->lastColor, 8 * sizeof(LONG));
      FreeMem(g->nextLine,8 * sizeof(WORD));
      FreeMem(SpriteHead, sizeof(struct VSprite));
      FreeMem(SpriteTail, sizeof(struct VSprite));
      return(-5);
   }

  /* When any part of the object touches or passes across
   * this boundary, it will cause the boundary collision
   * routine to be called.  This is at smash[0] in the
   * collision handler table and is called only if
   * DoCollision is called.
   */
   g->leftmost = 0;
   g->rightmost = r->BitMap->BytesPerRow * 8 - 1;
   g->topmost = 0;
   g->bottommost = r->BitMap->Rows - 1;

   r->GelsInfo = g;  /* Link together the two structures */

   InitGels(SpriteHead, SpriteTail, g );

  /* Pointers initialized to the dummy sprites which will be
   * used by the system to keep track of the animation system.
   */
   SetCollision(0, border_dummy, g);
   WaitTOF();
   return(0);	/* a return value of 0 says all ok, any 
		 * negative value tells you when it failed.
		 * (see the listing as to what the routine
		 * was trying to do... all failures are
		 * due to out of memory conditions).
		 */
}


/* end of readygels.c */

/* #include "ram:MakeVSprite.c" */
/* MakeVSprite.c */

struct VSprite *MakeVSprite(lineheight, image, colorset, x, y,
				wordwidth, imagedepth, flags)
SHORT lineheight;	/* How tall is this vsprite? */
WORD *image;		/* Where is the vsprite image data, should be
			   twice as many words as the value of lineheight */
WORD *colorset;		/* Where is the set of three words which describes
			   the colors that this vsprite can take on? */
SHORT x, y;		/* What is its initial onscreen position? */
SHORT wordwidth, imagedepth, flags;
{
   struct VSprite *v;	/* Make a pointer to the vsprite structure which
			   this routine dynamically allocates */

   if ((v = (struct VSprite *)AllocMem(sizeof(struct VSprite),
         MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
      return(0);
   }

   v->Flags = flags;	/* Is this a vsprite, not a bob? */

   v->Y = y;		/* Establish initial position relative to */
   v->X = x;		/* the Display coordinates. */

   v->Height = lineheight;	/* The Caller says how high it is. */
   v->Width = wordwidth;   /* A vsprite is always 1 word (16 bits) wide. */

  /* There are two kinds of depth... the depth of the image itself, and the
   * depth of the playfield into which it will be drawn. The image depth
   * says how much data space will be needed to store an image if it's
   * dynamically allocated. The playfield depth establishes how much space
   * will be needed to save and restore the background when a bob is drawn.
   * A vsprite is always 2 planes deep, but if it's being used to make a
   * bob, it may be deeper...
   */

   v->Depth = imagedepth;

  /* Assume that the caller at least has a default boundary collision
   * routine.... bit 1 of this mask is reserved for boundary collision
   * detect during DoCollision(). The only collisions reported will be
   * with the borders. The caller can change all this later.
   */

   v->MeMask = 1;
   v->HitMask = 1;

   v->ImageData = image;	/* Caller says where to find the image. */

  /* Show system where to find a mask which is a squished down version
   * of the vsprite (allows for fast horizontal border collision detect).
   */

   if ((v->BorderLine = (WORD *)AllocMem((sizeof(WORD)*wordwidth),
         MEMF_PUBLIC | MEMF_CLEAR)) == 0) 
   {
   	FreeMem(v, sizeof(struct VSprite)); 
   	return(0);
   }

  /* Show system where to find the mask which contains a 1 bit for any
   * position in the object in any plane where there is a 1 bit (all planes
   * OR'ed together).
   */

   if ((v->CollMask = (WORD *)AllocMem(sizeof(WORD)*lineheight*wordwidth,
         MEMF_CHIP | MEMF_CLEAR)) == 0) 
   {
   	FreeMem(v, sizeof(struct VSprite)); 
   	FreeMem(v->BorderLine, wordwidth * sizeof(WORD));
        return(0);
   }

  /* This isn't used for a Bob, just a VSprite. It's where the
   * Caller says where to find the VSprites colors.
   */
   v->SprColors = colorset;

   /* These aren't used for a VSprite, and MakeBob'll do set up for Bob. */
   v->PlanePick  = 0x00;
   v->PlaneOnOff = 0x00;

   InitMasks(v);	/* Create the collMask and borderLine */	
   return(v);
}
/* end of MakeVSprite.c */

main()
{
	struct IntuiMessage *msg;
	LONG result;
	SHORT k, j, x, y, error;
	UWORD *src, *dest;	/* for copying sprite data to RAM */

	GfxBase = OpenLibrary("graphics.library",0);

	IntuitionBase = OpenLibrary("intuition.library",0);
	/* (error checking left out for brevity here) */

	s = OpenScreen(&myscreen1);  /* try to open it */
	if(s == 0)
	{
    		printf("Can't open myscreen1\n");
    		exit(10);
	}
	myWindow.Screen = s;	/* say where screen is located */

	ShowTitle(s, FALSE);	/* Dont let screen be dragged down...*/

	w = OpenWindow(&myWindow);
	if(w == 0)
	{
		printf("Window didn't open!\n");
		CloseScreen(s);
		exit(20);
	}
	vp = &(s->ViewPort);
	/* set the colors for this viewport */

	LoadRGB4(vp, &mycolortable[0], 32);
	rp = w->RPort;
		/* Now wait for a message to arrive from Intuition 
		 * (task goes to sleep while waiting for the message) 
		 */

	/* Write Text using sprite colors so that demo can show
	 * how the vsprite machine stuffs the colors as it goes
	 * down the screen.  Thus if using vsprites, user should
	 * avoid using the color registers that the vsprites use.
	 */

	/* Notice also that color numbers 17-19 are untouched.  
	 * That is because of the sprResrvd=0xFC in ReadyGels.
	 * (Doesn't allow the virtual sprite machine to access
	 * either sprite 0 or 1... 0 is used by mouse cursor and
	 * shares its colors with 1, so I reserved both of them.
	 */

	for(j=8; j<180; j+=50)
	{
		for(k=0; k<15; k++)
		{
			Move(rp,k*20,j);
			SetAPen(rp,k+17);	/* show 17-31 */
			/* 16, 20, 24, 28 are unaffected by vsprites 
			 * because they are not used by hardware sprites */

			Text(rp,numbers[k],2);
		}
	}
	/* *************************************** */
	/* VSPRITE DEMO SECTION 		   */
	/* *************************************** */

	/* Allocate CHIP memory to hold the actual sprite data */
	/* (necessary if ever to run on an expanded RAM Amiga) */

	sprdata = (UWORD *)AllocMem(36, MEMF_CHIP);

	if(sprdata == NULL)
	{
		/* not enough memory for sprite */
	}
	/* now copy the sprite data into the CHIP RAM. */

	src = sprite_data;  
	dest = sprdata; 	/* source, destination */

	for( j=0; j<18; j++)
	{
		*dest++ = *src++;
	}			

	choice = 0;
	maxgot = 0;

	/* Prepare the GELS system to work with VSPRITE or BOBS */

	error = ReadyGels(&mygelsinfo, rp);

	for(k=0; k<MAXSP; k++)	/* whatever maximum number of vsprites */
	{
		xmove[k]=speed[RangeRand(4)];
		ymove[k]=speed[RangeRand(4)];

		/* establish a position for the sprite */
		x = 10 + RangeRand(280);
		y = 10 + RangeRand(170);

		/* create a vsprite */
		vsprite[k] = MakeVSprite( 9, sprdata, colorset[choice], 
					x, y, 1, 2, VSPRITE);
		/* 9 lines high, using MEMF_CHIP image of a sprite,
		 * with a particular set of colors, at an X,Y location
		 * 1 word wide, 2 planes deep (all vsprites are 2 deep)
		 * and it is a VSPRITE */

		if(vsprite[k] == 0)
		{
			break;	/* ran out of memory! */
		}
		AddVSprite(vsprite[k], rp);

		maxgot++;

		choice++; /* choose a different color set */
		if(choice >= 4) 
		{
			choice = 0;	/* wrap around on colorsets */
		}
	}
	while(1)	/* forever */
	{
		WaitTOF();
		movesprites();

		result = -1;	/* now see if CLOSEWINDOW is waiting */
		msg = (struct IntuiMessage *)GetMsg(w->UserPort);		
		if(msg != 0)
		{
			result = HandleEvent(msg->Class);

			/* Let Intuition reuse the msg */
			ReplyMsg(msg);	
		}
		if(result == 0) 
		{
			break;  /* got a CLOSEWINDOW */
		}
	}

	/* DONE, now cleanup */

	/* Free however many vsprites we actually managed to create */

	for(k=0; k<maxgot; k++)
	{
		DeleteGel(vsprite[k]);				
	}
	/* delete what ReadyGels created */
	PurgeGels(&mygelsinfo);	

	FreeMem(sprdata, 36);	/* free what we allocated. */

	CloseWindow(w);
	CloseScreen(s);
}	

Hope this helps.

Rob Peck	hplabs!dana!rap
		USnail: DATAPATH, POBox 1828, Los Gatos, Ca. 95031-1828


-- 
= Drug tests; just say *NO*!  (Moto just announced new drug testing program)  =
= Fred Fish  Motorola Computer Division, 3013 S 52nd St, Tempe, Az 85282  USA =
= seismo!noao!mcdsun!fnf    (602) 438-5976                                    =