Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!utgpu!water!watnot!watmath!clyde!rutgers!ames!amdahl!dlb!dana!rap From: rap@dana.UUCP Newsgroups: comp.sys.amiga Subject: Re: Sun Tools on Amiga Message-ID: <134@dana.UUCP> Date: Mon, 30-Mar-87 16:14:21 EST Article-I.D.: dana.134 Posted: Mon Mar 30 16:14:21 1987 Date-Received: Sun, 5-Apr-87 00:37:46 EST Distribution: world Organization: Dana Computer, Inc., Sunnyvale, CA Lines: 678 Keywords: vsprite demo Summary: VSprite Reposting (nobody seems to have seen it the first time) 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; iX = 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= 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