/* 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; void 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). */ void 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. */ void 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 */ int 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