/* animtools.c ** ** This file is a collection of tools which are used with the VSprite, Bob and Animation ** system software. It is intended as a useful EXAMPLE, and while it shows what must be ** done, it is not the only way to do it. If Not Enough Memory, or error return, each ** cleans up after itself before returning. NOTE that these routines assume a very specific ** structure to the GEL lists. Make sure that you use the correct pairs together ** (i.e. makeOb()/freeOb(), etc.) ** ** Compile with SAS/C 5.10b: lc -b1 -cfist -v -y -oanimtools.o animtools.c */ #include <exec/types.h> #include <exec/memory.h> #include <graphics/gfx.h> #include <graphics/gels.h> #include <graphics/clip.h> #include <graphics/rastport.h> #include <graphics/view.h> #include <graphics/gfxbase.h> #include "animtools.h" /* Setup the GELs system. After this call is made you can use VSprites, Bobs, AnimComps ** and AnimObs. Note that this links the GelsInfo structure into the RastPort, and calls ** InitGels(). It uses information in your RastPort structure to establish boundary collision ** defaults at the outer edges of the raster. This routine sets up for everything - collision ** detection and all. You must already have run LoadView before ReadyGelSys is called. */ struct GelsInfo *setupGelSys(struct RastPort *rPort, BYTE reserved) { struct GelsInfo *gInfo; struct VSprite *vsHead; struct VSprite *vsTail; if (NULL != (gInfo = (struct GelsInfo *)AllocMem(sizeof(struct GelsInfo), MEMF_CLEAR))) { if (NULL != (gInfo->nextLine = (WORD *)AllocMem(sizeof(WORD) * 8, MEMF_CLEAR))) { if (NULL != (gInfo->lastColor = (WORD **)AllocMem(sizeof(LONG) * 8, MEMF_CLEAR))) { if (NULL != (gInfo->collHandler = (struct collTable *) AllocMem(sizeof(struct collTable),MEMF_CLEAR))) { if (NULL != (vsHead = (struct VSprite *) AllocMem((LONG)sizeof(struct VSprite), MEMF_CLEAR))) { if (NULL != (vsTail = (struct VSprite *) AllocMem(sizeof(struct VSprite), MEMF_CLEAR))) { gInfo->sprRsrvd = reserved; /* Set left- and top-most to 1 to better keep items */ /* inside the display boundaries. */ gInfo->leftmost = gInfo->topmost = 1; gInfo->rightmost = (rPort->BitMap->BytesPerRow << 3) - 1; gInfo->bottommost = rPort->BitMap->Rows - 1; rPort->GelsInfo = gInfo; InitGels(vsHead, vsTail, gInfo); return(gInfo); } FreeMem(vsHead, (LONG)sizeof(*vsHead)); } FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable)); } FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8); } FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8); } FreeMem(gInfo, (LONG)sizeof(*gInfo)); } return(NULL); } /* Free all of the stuff allocated by setupGelSys(). Only call this routine if ** setupGelSys() returned successfully. The GelsInfo structure is the one returned ** by setupGelSys(). It also unlinks the GelsInfo from the RastPort. */ VOID cleanupGelSys(struct GelsInfo *gInfo, struct RastPort *rPort) { rPort->GelsInfo = NULL; FreeMem(gInfo->collHandler, (LONG)sizeof(struct collTable)); FreeMem(gInfo->lastColor, (LONG)sizeof(LONG) * 8); FreeMem(gInfo->nextLine, (LONG)sizeof(WORD) * 8); FreeMem(gInfo->gelHead, (LONG)sizeof(struct VSprite)); FreeMem(gInfo->gelTail, (LONG)sizeof(struct VSprite)); FreeMem(gInfo, (LONG)sizeof(*gInfo)); } /* Create a VSprite from the information given in nVSprite. Use freeVSprite() ** to free this GEL. */ struct VSprite *makeVSprite(NEWVSPRITE *nVSprite) { struct VSprite *vsprite; LONG line_size; LONG plane_size; line_size = sizeof(WORD) * nVSprite->nvs_WordWidth; plane_size = line_size * nVSprite->nvs_LineHeight; if (NULL != (vsprite = (struct VSprite *)AllocMem((LONG)sizeof(struct VSprite), MEMF_CLEAR))) { if (NULL != (vsprite->BorderLine = (WORD *)AllocMem(line_size, MEMF_CHIP))) { if (NULL != (vsprite->CollMask = (WORD *)AllocMem(plane_size, MEMF_CHIP))) { vsprite->Y = nVSprite->nvs_Y; vsprite->X = nVSprite->nvs_X; vsprite->Flags = nVSprite->nvs_Flags; vsprite->Width = nVSprite->nvs_WordWidth; vsprite->Depth = nVSprite->nvs_ImageDepth; vsprite->Height = nVSprite->nvs_LineHeight; vsprite->MeMask = nVSprite->nvs_MeMask; vsprite->HitMask = nVSprite->nvs_HitMask; vsprite->ImageData = nVSprite->nvs_Image; vsprite->SprColors = nVSprite->nvs_ColorSet; vsprite->PlanePick = vsprite->PlaneOnOff = 0x00; InitMasks(vsprite); return(vsprite); } FreeMem(vsprite->BorderLine, line_size); } FreeMem(vsprite, (LONG)sizeof(*vsprite)); } return(NULL); } /* Create a Bob from the information given in nBob. Use freeBob() to free this GEL. ** A VSprite is created for this bob. This routine properly allocates all double ** buffered information if it is required. */ struct Bob *makeBob(NEWBOB *nBob) { struct Bob *bob; struct VSprite *vsprite; NEWVSPRITE nVSprite ; LONG rassize; rassize = (LONG)sizeof(UWORD) * nBob->nb_WordWidth * nBob->nb_LineHeight * nBob->nb_RasDepth; if (NULL != (bob = (struct Bob *)AllocMem((LONG)sizeof(struct Bob), MEMF_CLEAR))) { if (NULL != (bob->SaveBuffer = (WORD *)AllocMem(rassize, MEMF_CHIP))) { nVSprite.nvs_WordWidth = nBob->nb_WordWidth; nVSprite.nvs_LineHeight = nBob->nb_LineHeight; nVSprite.nvs_ImageDepth = nBob->nb_ImageDepth; nVSprite.nvs_Image = nBob->nb_Image; nVSprite.nvs_X = nBob->nb_X; nVSprite.nvs_Y = nBob->nb_Y; nVSprite.nvs_ColorSet = NULL; nVSprite.nvs_Flags = nBob->nb_BFlags; /* Push the values into the NEWVSPRITE structure for use in makeVSprite(). */ nVSprite.nvs_MeMask = nBob->nb_MeMask; nVSprite.nvs_HitMask = nBob->nb_HitMask; if ((vsprite = makeVSprite(&nVSprite)) != NULL) { vsprite->PlanePick = nBob->nb_PlanePick; vsprite->PlaneOnOff = nBob->nb_PlaneOnOff; vsprite->VSBob = bob; bob->BobVSprite = vsprite; bob->ImageShadow = vsprite->CollMask; bob->Flags = 0; bob->Before = NULL; bob->After = NULL; bob->BobComp = NULL; if (nBob->nb_DBuf) { if (NULL != (bob->DBuffer = (struct DBufPacket *) AllocMem((LONG)sizeof(struct DBufPacket), MEMF_CLEAR))) { if (NULL != (bob->DBuffer->BufBuffer = (WORD *)AllocMem(rassize, MEMF_CHIP))) return(bob); FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket)); } } else { bob->DBuffer = NULL; return(bob); } freeVSprite(vsprite); } FreeMem(bob->SaveBuffer, rassize); } FreeMem(bob, (LONG)sizeof(*bob)); } return(NULL); } /* ** Create a Animation Component from the information given in nAnimComp and nBob. Use ** freeComp() to free this GEL. makeComp() calls makeBob(), and links the Bob into an AnimComp. */ struct AnimComp *makeComp(NEWBOB *nBob, NEWANIMCOMP *nAnimComp) { struct Bob *compBob; struct AnimComp *aComp; if ((aComp = AllocMem((LONG)sizeof(struct AnimComp),MEMF_CLEAR)) != NULL) { if ((compBob = makeBob(nBob)) != NULL) { compBob->After = compBob->Before = NULL; compBob->BobComp = aComp; /* Link 'em up. */ aComp->AnimBob = compBob; aComp->TimeSet = nAnimComp->nac_Time; /* Num ticks active. */ aComp->YTrans = nAnimComp->nac_Yt; /* Offset rel to HeadOb */ aComp->XTrans = nAnimComp->nac_Xt; aComp->AnimCRoutine = nAnimComp->nac_Routine; aComp->Flags = nAnimComp->nac_CFlags; aComp->Timer = 0; aComp->NextSeq = aComp->PrevSeq = NULL; aComp->NextComp = aComp->PrevComp = NULL; aComp->HeadOb = NULL; return(aComp); } FreeMem(aComp, (LONG)sizeof(struct AnimComp)); } return(NULL); } /* Create an Animation Sequence from the information given in nAnimSeq and nBob. Use ** freeSeq() to free this GEL. This routine creates a linked list of animation components ** which make up the animation sequence. It links them all up, making a circular list of ** the PrevSeq and NextSeq pointers. That is to say, the first component of the sequences' ** PrevSeq points to the last component; the last component of * the sequences' NextSeq ** points back to the first component. If dbuf is on, the underlying Bobs will be set up ** for double buffering. If singleImage is non-zero, the pImages pointer is assumed to ** point to an array of only one image, instead of an array of 'count' images, and all ** Bobs will use the same image. */ struct AnimComp *makeSeq(NEWBOB *nBob, NEWANIMSEQ *nAnimSeq) { int seq; struct AnimComp *firstCompInSeq = NULL; struct AnimComp *seqComp = NULL; struct AnimComp *lastCompMade = NULL; LONG image_size; NEWANIMCOMP nAnimComp; /* get the initial image. this is the only image that is used ** if nAnimSeq->nas_SingleImage is non-zero. */ nBob->nb_Image = nAnimSeq->nas_Images; image_size = nBob->nb_LineHeight * nBob->nb_ImageDepth * nBob->nb_WordWidth; /* for each comp in the sequence */ for (seq = 0; seq < nAnimSeq->nas_Count; seq++) { nAnimComp.nac_Xt = *(nAnimSeq->nas_Xt + seq); nAnimComp.nac_Yt = *(nAnimSeq->nas_Yt + seq); nAnimComp.nac_Time = *(nAnimSeq->nas_Times + seq); nAnimComp.nac_Routine = nAnimSeq->nas_Routines[seq]; nAnimComp.nac_CFlags = nAnimSeq->nas_CFlags; if ((seqComp = makeComp(nBob, &nAnimComp)) == NULL) { if (firstCompInSeq != NULL) freeSeq(firstCompInSeq, (LONG)nBob->nb_RasDepth); return(NULL); } seqComp->HeadOb = nAnimSeq->nas_HeadOb; /* Make a note of where the first component is. */ if (firstCompInSeq == NULL) firstCompInSeq = seqComp; /* link the component into the list */ if (lastCompMade != NULL) lastCompMade->NextSeq = seqComp; seqComp->NextSeq = NULL; seqComp->PrevSeq = lastCompMade; lastCompMade = seqComp; /* If nAnimSeq->nas_SingleImage is zero, the image array has nAnimSeq->nas_Count images. */ if (!nAnimSeq->nas_SingleImage) nBob->nb_Image += image_size; } /* On The last component in the sequence, set Next/Prev to make */ /* the linked list a loop of components. */ lastCompMade->NextSeq = firstCompInSeq; firstCompInSeq->PrevSeq = lastCompMade; return(firstCompInSeq); } /* Free the data created by makeVSprite(). Assumes images deallocated elsewhere. */ VOID freeVSprite(struct VSprite *vsprite) { LONG line_size; LONG plane_size; line_size = (LONG)sizeof(WORD) * vsprite->Width; plane_size = line_size * vsprite->Height; FreeMem(vsprite->BorderLine, line_size); FreeMem(vsprite->CollMask, plane_size); FreeMem(vsprite, (LONG)sizeof(*vsprite)); } /* Free the data created by makeBob(). It's important that rasdepth match the depth you */ /* passed to makeBob() when this gel was made. Assumes images deallocated elsewhere. */ VOID freeBob(struct Bob *bob, LONG rasdepth) { LONG rassize = sizeof(UWORD) * bob->BobVSprite->Width * bob->BobVSprite->Height * rasdepth; if (bob->DBuffer != NULL) { FreeMem(bob->DBuffer->BufBuffer, rassize); FreeMem(bob->DBuffer, (LONG)sizeof(struct DBufPacket)); } FreeMem(bob->SaveBuffer, rassize); freeVSprite(bob->BobVSprite); FreeMem(bob, (LONG)sizeof(*bob)); } /* Free the data created by makeComp(). It's important that rasdepth match the depth you */ /* passed to makeComp() when this GEL was made. Assumes images deallocated elsewhere. */ VOID freeComp(struct AnimComp *myComp, LONG rasdepth) { freeBob(myComp->AnimBob, rasdepth); FreeMem(myComp, (LONG)sizeof(struct AnimComp)); } /* Free the data created by makeSeq(). Complimentary to makeSeq(), this routine goes through ** the NextSeq pointers and frees the Components. This routine only goes forward through the ** list, and so it must be passed the first component in the sequence, or the sequence must ** be circular (which is guaranteed if you use makeSeq()). It's important that rasdepth match ** the depth you passed to makeSeq() when this gel was made. Assumes images deallocated elsewhere! */ VOID freeSeq(struct AnimComp *headComp, LONG rasdepth) { struct AnimComp *curComp; struct AnimComp *nextComp; /* Break the NextSeq loop, so we get a NULL at the end of the list. */ headComp->PrevSeq->NextSeq = NULL; curComp = headComp; /* get the start of the list */ while (curComp != NULL) { nextComp = curComp->NextSeq; freeComp(curComp, rasdepth); curComp = nextComp; } } /* Free an animation object (list of sequences). freeOb() goes through the NextComp ** pointers, starting at the AnimObs' HeadComp, and frees every sequence. It only ** goes forward. It then frees the Object itself. Assumes images deallocated elsewhere! */ VOID freeOb(struct AnimOb *headOb, LONG rasdepth) { struct AnimComp *curSeq; struct AnimComp *nextSeq; curSeq = headOb->HeadComp; /* get the start of the list */ while (curSeq != NULL) { nextSeq = curSeq->NextComp; freeSeq(curSeq, rasdepth); curSeq = nextSeq; } FreeMem(headOb, sizeof(struct AnimOb)); }