//* vizfx.c - visual special effects module //* Sysytem library headers #include #include #include //* Application headers #include "main.h" #include "halloc.h" #include "icsal.h" #include "fxprocs.c" //* FX ICSAL procs and associated data arrays #define BUFF_SIZE (153600) //* (320*240)*2=153600 #define COPY_X (320) #define COPY_Y (0) //* VRAM coords of frame copy (top-left corner) #define WIDTH_256 (0) #define WIDTH_320 (1) #define USE_CRT_IMAGE (0) #define USE_NEW_IMAGE (1) //* Locals initialized by OpenBuffCopy() & OpenAliasBuff() static u_long *imageBuffp; //* Heap mem address of stored Tpages static u_long *aliasBuffp; //* Work area for anti-alias functions //* Static service function prototypes static void OpenBuffCopy(int imageWidth, int opType); static void CloseBuffCopy(void); //*------------------------------------------------------------------------------------------ //* OpenBuffCopy - Makes a copy of currently displayed frame at COPY_X,COPY_Y in VRAM //*------------------------------------------------------------------------------------- static void OpenBuffCopy(int imageWidth, int opType) { RECT tps; //* Tpage source register int i; if (opType==USE_CRT_IMAGE) { ResetGraph(1); //* Cancel drawing of new frame tps.y = !*psdidx * 240; //* Will copy currently displayed image } else { DrawSync(0); //* Finish drawing new frame tps.y = *psdidx * 240; //* Will copy newly drawn image } tps.x = 0; tps.w = 320; tps.h = 240; //* Allocate enough heap mem to hold Tpage contents that //* will be over-written by frame copy if ((imageBuffp = (u_long *) malloc(BUFF_SIZE))==NULL) { printf("\nFailed to allocate memory to store frame buffer\n"); return; } //* Set all STP bits in screen image used for FX StoreImage(&tps, imageBuffp); //* Copy image to main mem for modification DrawSync(0); for (i=0; i<38400; i++) imageBuffp[i] |= 0x80008000; //* Set STP bits in this pixel pair tps.y = *psdidx * 240; //* Replace into unseen buffer to stop flicker LoadImage(&tps, imageBuffp); //* Note: this will also be the image displayed DrawSync(0); //* by the 1st GsSwapDispBuff() in the FX routine //* unless GPU is set to draw a new image beforehand //* Store original Tpage contents into heap buffer tps.x = COPY_X; tps.y = COPY_Y; StoreImage(&tps, imageBuffp); DrawSync(0); //* Make copy of STP-modified frame at COPY_X,COPY_Y in Tpages if (imageWidth==WIDTH_256) { tps.x = 32; tps.w = 256; } else { tps.x = 0; tps.w = 320; } tps.h = 240; tps.y = *psdidx * 240; MoveImage(&tps, COPY_X, COPY_Y); DrawSync(0); if (opType==USE_NEW_IMAGE) //* For 'fade-in' routines... ClearImage(&tps, 0, 0, 0); //* Blank image so 1st GsSwapDispBuff wont show it!!! } //*------------------------------------------------------------------------------------------ //* CloseBuffCopy - Restores original Tpage contents from heap buffer //*------------------------------------------------------------------------------------- static void CloseBuffCopy(void) { RECT tpd; //* Tpage destination //* Restore original Tpage contents from mem tpd.x = COPY_X; tpd.y = COPY_Y; tpd.w = 320; tpd.h = 240; LoadImage(&tpd, imageBuffp); DrawSync(0); //* Free Tpage buffer memory free(imageBuffp); } //*------------------------------------------------------------------------------------------ //* FX_Peel_Screen //*------------------------------------------------------------------------------------- void FX_Peel_Screen(void) { register GsOT *currOT; register GsSPRITE *sp2; register struct SCTRL *scp2; register int activeBuff; register int n; PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; GsSPRITE *sp; struct SCTRL *scp; int r, c, i; int allDone; int numSprites; int vs=0; //* VSync delay count - 0 by default int now,slow; //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. numSprites = 160; OpenSpriteArray(&sp, numSprites, &scp); OpenOT(OTs, buffs, 1, 300); //* NB: expanded packet area to allow rotation //* Initialize screen sprites for (c=0; c>6)<<6), COPY_Y); sp[c].u = (c<<1) % 64; sp[c].v = 0; sp[c].cx = sp[c].cy = 0; //* not used sp[c].r = sp[c].g = sp[c].b = 128; sp[c].scalex = ONE; sp[c].scaley = ONE; sp[c].rotate = 0; //* Assign ICSAL proc and hand-initialize initial delay loop incrementally scp[c].ICSALop = peelProc; scp[c].ICSALloopCount = c+1; scp[c].ICSALloopStart = peelProc; } //* Switch to fast register pointers sp2 = sp; scp2 = scp; SsUtKeyOn(0, SFX_PEEL_SCREEN, 0, 65, 0, 127, 127); slow=now=0;VSync(0); //* Run effect until all ICSAL procs have ended do { allDone = 1; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); for (n=0; nICSALop) { RunICSAL(scp2+n); allDone = 0; GsSortSprite(sp2+n, currOT, 0); } DrawSync(0); // VSync(vs); if ((now=VSync(vs)) > slow) slow = now; GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } while (!allDone); //* Show final frame of effect DrawSync(0); VSync(vs); GsSwapDispBuff(); //VSync(60*5); //printf("\nSlowest vSync = %d",slow); //* End of effect house keeping CloseSpriteArray(sp2, scp2); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_Splice_Screen //*------------------------------------------------------------------------------------- void FX_Splice_Screen(int spliceType) { register GsOT *currOT; register GsSPRITE *sp2; register struct SCTRL *scp2; register int activeBuff; register int n; PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; GsSPRITE *sp; struct SCTRL *scp; int r, c, i; int allDone; int numSprites; int vs=2; //* VSync delay count GsBOXF box; register GsBOXF *boxp=&box; RECT copy; register RECT *copyp=© //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. numSprites = 160; OpenSpriteArray(&sp, numSprites, &scp); OpenOT(OTs, buffs, 1, 300); //* NB: expanded packet area to allow rotation //* Initialize transparent overlay GsBOXF boxp->attribute=(A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); boxp->x = boxp->y = 0; boxp->w = 320; boxp->h = 240; boxp->r = boxp->g = boxp->b = 16; //* Initialize MoveImage() source rect. (.y set below) copyp->x = 0; copyp->w = 320; copyp->h = 240; //* Initialize screen sprites for (c=0; c>6)<<6), COPY_Y); sp[c].u = (c<<1) % 64; sp[c].v = 0; sp[c].cx = sp[c].cy = 0; //* not used sp[c].r = sp[c].g = sp[c].b = 128; sp[c].scalex = ONE; sp[c].scaley = ONE; sp[c].rotate = 0; //* Assign ICSAL procs alternately if (c<<31) { scp[c].ICSALop = spliceDownProc; //* Odd numbered sprites scp[c].ICSALloopStart = spliceDownProc; } else { scp[c].ICSALop = spliceUpProc; //* Even numbered sprites scp[c].ICSALloopStart = spliceUpProc; } //* Hand-initialize initial delay loop for requested splice type switch (spliceType) { case FX_MELT_SPLICE: scp[c].ICSALloopCount = meltDelay[c]; break; case FX_RIP_SPLICE: scp[c].ICSALloopCount = c+1; break; case FX_RIP2_SPLICE: scp[c].ICSALloopCount = (c>80 ? 160-c : c+1); break; case FX_NORMAL_SPLICE: scp[c].ICSALloopCount = 1; break; case FX_DIAG_SPLICE: scp[c].ICSALloopCount = (c<<31 ? c+1 : 160-c); break; } } //* Switch to fast register pointers sp2 = sp; scp2 = scp; //SsUtKeyOn(0, SFX_LEV_SCREEN, 0, 58, 0, 127, 127); //* Run effect until all ICSAL procs have ended do { allDone = 1; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); for (n=0; nICSALop) { RunICSAL(scp2+n); allDone = 0; GsSortSprite(sp2+n, currOT, 0); } GsSortBoxFill(boxp, currOT, 1); DrawSync(0); VSync(vs); GsSwapDispBuff(); copyp->y = psdofsy[!*psdidx]; //* Point to CRT image as source MoveImage(copyp, 0, psdofsy[*psdidx]); //* Copy it to draw buffer DrawSync(0); GsDrawOt(currOT); } while (!allDone); //* Show final frame of effect DrawSync(0); VSync(vs); GsSwapDispBuff(); //* End of effect house keeping CloseSpriteArray(sp2, scp2); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_Tile_Spin_Fade //*------------------------------------------------------------------------------------- void FX_Tile_Spin_Fade(void) { register GsOT *currOT; register GsSPRITE *sp2; register struct SCTRL *scp2; register int activeBuff; register int n; PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; GsSPRITE *sp; struct SCTRL *scp; int r, c, i; int allDone; int numSprites; int vs=0; //* VSync delay count - 0 by default int now,slow; //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. numSprites = 300; OpenSpriteArray(&sp, numSprites, &scp); OpenOT(OTs, buffs, 1, 500+1); //* NB: expanded packet area to allow rotation //* Initialize screen sprites for (r=0; r<15; r++) for (c=0; c<20; c++) { n = (r*20)+c; sp[n].attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp[n].x = (c<<4) + (sp[n].mx = 8); sp[n].y = (r<<4) + (sp[n].my = 8); sp[n].w = sp[n].h = 16; sp[n].tpage = GetTPage(2, 0, COPY_X+(((c<<4)>>6)<<6), COPY_Y); sp[n].u = (c<<4) % 64; sp[n].v = r<<4; sp[n].cx = sp[n].cy = 0; //* not used sp[n].r = sp[n].g = sp[n].b = 128; sp[n].scalex = sp[n].scaley = ONE; sp[n].rotate = 0; //* Assign ICSAL proc and hand-initialize initial delay loop incrementally scp[n].ICSALop = spinProc; scp[n].ICSALloopCount = (r*20)+c+1; scp[n].ICSALloopStart = spinProc; } //* Switch to fast register pointers sp2 = sp; scp2 = scp; slow=now=0;VSync(0); //* Run effect until all ICSAL procs have ended do { allDone = 1; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); for (n=0; nICSALop) { RunICSAL(scp2+n); allDone = 0; GsSortSprite(sp2+n, currOT, 0); } DrawSync(0); // VSync(vs); if ((now=VSync(vs)) > slow) slow = now; GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } while (!allDone); //* Show final frame of effect DrawSync(0); VSync(vs); GsSwapDispBuff(); //VSync(60*5); //printf("\nSlowest vSync = %d",slow); //* End of effect house keeping CloseSpriteArray(sp2, scp2); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_Pixel_Out //*------------------------------------------------------------------------------------- void FX_Pixel_Out(int r, int g, int b) { int row, col, i, cnt=0; u_char temp; struct GRID_PAIR temp2; struct GRID_PAIR pgrid[60][80]; struct GRID_PAIR *gridp=(struct GRID_PAIR *)pgrid; RECT cRect, mRect; RECT *cRectp=&cRect; //* Finish drawing & display new frame DrawSync(0); VSync(0); GsSwapDispBuff(); //* Copy displayed frame to draw bufffer cRect.w = 320; cRect.h = 240; cRect.x = 0; cRect.y = psdofsy[!*psdidx]; MoveImage(&cRect, 0, psdofsy[*psdidx]); DrawSync(0); cRect.w = cRect.h = 4; mRect.w = 320; mRect.h = 240; mRect.x = 0; //* First, create all possible coordinate pairs for (row=0; row<60; row++) for (col=0; col<80; col++) { pgrid[row][col].r = row; pgrid[row][col].c = col; } //* Mix .c coords in each row for (row=0; row<60; row++) for (col=0; col<80; col++) { i = rand() % 80; temp = pgrid[row][i].c; pgrid[row][i].c = pgrid[row][col].c; pgrid[row][col].c = temp; } //* Mix coord pairs in each column for (col=0; col<80; col++) for (row=0; row<60; row++) { i = rand() % 60; temp2 = pgrid[i][col]; pgrid[i][col] = pgrid[row][col]; pgrid[row][col] = temp2; } while (cnt < 4800) { for (i=0; i<50; i++, gridp++, cnt++) { cRectp->x = (gridp->c<<2); cRectp->y = (gridp->r<<2) + psdofsy[*psdidx]; ClearImage(cRectp, r, g, b); } DrawSync(0); VSync(0); GsSwapDispBuff(); SsUtKeyOn(0, SFX_GUN_FDROP, 0, 84+(rand()%21), 0, 100, 100); mRect.y = psdofsy[!*psdidx]; MoveImage(&mRect, 0, psdofsy[*psdidx]); //* Copy it to draw buffer DrawSync(0); } } //*------------------------------------------------------------------------------------------ //* FX_Meltdown //*------------------------------------------------------------------------------------- void FX_Meltdown(void) { register GsOT *currOT; register GsSPRITE *sp2; register struct SCTRL *scp2; register int activeBuff; register int n; PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; GsSPRITE *sp; struct SCTRL *scp; int r, c, i; int allDone; RECT copy; register RECT *copyp=© GsBOXF box; register GsBOXF *boxp=&box; int numSprites; int vs; int now,slow; //RECT t; //t.x=0,t.y=!*psdidx*240,t.w=320,t.h=2; //ClearImage(&t,255,255,255); //DrawSync(0); //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. numSprites = 160; OpenSpriteArray(&sp, numSprites, &scp); OpenOT(OTs, buffs, 1, 300); //* NB: expanded packet area to allow rotation //* Initialize MoveImage() source rect. (.y set below) copyp->x = 0; copyp->w = 320; copyp->h = 240; //* Initialize transparent overlay GsBOXF boxp->attribute=(A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); boxp->x = boxp->y = 0; boxp->w = 320; boxp->h = 240; boxp->r = boxp->g = boxp->b = 16; //* Initialize screen strip sprites for (c=0; c>6)<<6), COPY_Y); sp[c].u = (c<<1) % 64; sp[c].v = 0; sp[c].cx = sp[c].cy = 0; //* not used sp[c].r = sp[c].g = sp[c].b = 128; sp[c].scalex = sp[c].scaley = ONE; sp[c].rotate = 0; //* Assign ICSAL proc and hand-initialize initial delay loop from meltDelay[] scp[c].ICSALop = meltProc; scp[c].ICSALloopCount = meltDelay[c]; scp[c].ICSALloopStart = meltProc; } vs=2; //* Switch to fast register pointers sp2 = sp; scp2 = scp; SsUtKeyOn(0, SFX_MELT_SCREEN, 0, 40, 0, 127, 127); //slow=now=0;VSync(0); //* Run effect until all ICSAL procs have ended do { allDone = 1; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); for (n=0; nICSALop) { RunICSAL(scp2+n); allDone = 0; GsSortSprite(sp2+n, currOT, 0); } GsSortBoxFill(boxp, currOT, 0); //* Brightness reduction overlay box DrawSync(0); VSync(vs); //if ((now=VSync(vs)) > slow) slow = now; GsSwapDispBuff(); copyp->y = psdofsy[!*psdidx]; //* Point to CRT image as source MoveImage(copyp, 0, psdofsy[*psdidx]); //* Copy it to draw buffer DrawSync(0); GsDrawOt(currOT); } while (!allDone); //* Show final frame of effect DrawSync(0); VSync(vs); GsSwapDispBuff(); //VSync(60*5); //printf("\nSlowest vSync = %d",slow); //* End of effect house keeping CloseSpriteArray(sp2, scp2); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_TV_Off //*------------------------------------------------------------------------------------- void FX_TV_Off(void) { register GsOT *currOT; register int activeBuff; PACKET *buffs[2]; GsOT *OTs[2]; GsSPRITE *sp; register GsSPRITE *sp2; register int i; GsLINE midLine; register GsLINE *mlp=&midLine; //* Provide a 256x240 copy of screen image OpenBuffCopy(WIDTH_256, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. OpenSpriteArray(&sp, 1, NULL); OpenOT(OTs, buffs, 1, 5); //* NB: 40-packets-per-primitive for scaleable sprite sp2 = sp; //* Change to fast pointer //* Initialize GsLINE central scan line mlp->attribute = (A_TRANS_OFF + A_DISPLAY_ON); mlp->x0 = -16; mlp->y0 = 120; mlp->x1 = 255+17; mlp->y1 = 120; mlp->r = mlp->g = mlp->b = 255; //* Bright white //* Initialize sprite perameters needed for start of effect sp2->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_3 + A_TRANS_OFF + A_DISPLAY_ON); sp2->x = 128; sp2->y = 120; //* Set x,y to mid-screen point of rotation sp2->w = 256; sp2->h = 240; sp2->u = sp2->v = 0; sp2->cx = sp2->cy = 0; //* not used sp2->r = sp2->g = sp2->b = 135; sp2->mx = 128; sp2->my = 120; //* Set mx,my to tally with point of rotation sp2->scalex = ONE; sp2->scaley = ONE; sp2->rotate = 0; sp2->tpage = GetTPage(2, 2, COPY_X, COPY_Y); //* Set for correct transparency rate!? //* Start drawing initial 256-wide frame GsDISPENV.disp.w = 256; currOT = OTs[!*psdidx]; GsSetWorkBase(buffs[!*psdidx]); GsClearOt(0, 0, currOT); GsSortSprite(sp2, currOT, 0); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); SsUtKeyOn(0, SFX_MELT_SCREEN, 0, 84, 0, 100, 100); //* Reduce screen image (40 pixels a time: 20 from top & bottom) to a single scan line for (i=5; i; i--) { sp2->scaley -= 683; //* 683=17.06r*40; (1pixel=17.06r) sp2->scalex += 640; //* 640=16*40pixels (1pixel=16) sp2->r = sp2->g = sp2->b += 24; //* 135+(5*24)=255 currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); GsSortSprite(sp2, currOT, 0); DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } //* Shrink single remaining scan line to a dot for (i=9; i; i--) { mlp->x0 += 16; mlp->x1 -= 16; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); GsSortLine(mlp, currOT, 0); DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } //* Fade-out remaining dot for (i=51; i; i--) { mlp->r = mlp->g = mlp->b -= 5; //* 5*51=255 currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); GsSortLine(mlp, currOT, 0); DrawSync(0); VSync(2); GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } //* Show final frame of effect DrawSync(0); VSync(2); GsSwapDispBuff(); //* Re-enable original 320-wide display from next GsSwapDispBuff() GsDISPENV.disp.w = 320; //* End of effect house keeping CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_Spin_Smudge //*------------------------------------------------------------------------------------- void FX_Spin_Smudge(void) { register GsOT *currOT; register int activeBuff; PACKET *buffs[2]; GsOT *OTs[2]; GsSPRITE *sp; register int i; register GsSPRITE *sp1p, *sp2p; //* Fast pointers to the 2 sprites RECT copy; register RECT *copyp=© GsBOXF box; register GsBOXF *boxp=&box; //RECT t; //t.x=0,t.y=!*psdidx*240+100,t.w=320,t.h=50; //ClearImage(&t,255,255,255); //DrawSync(0); //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. OpenSpriteArray(&sp, 2, NULL); OpenOT(OTs, buffs, 1, 5); //* NB: 40-packets-per-primitive for scaleable sprite sp2p = (sp1p = sp) + 1; //* Change to fast pointers //* Initialize transparent overlay GsBOXF boxp->attribute=(A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); boxp->x = boxp->y = 0; boxp->w = 320; boxp->h = 240; boxp->r = boxp->g = boxp->b = 8; //* Initialize MoveImage() source rect. (.y set below) copyp->x = 0; copyp->w = 320; copyp->h = 240; //* Sprite 1: 160x240 left section of screen image sp1p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp1p->x = 160; sp1p->y = 120; //* Set x,y to common, mid-screen point of rotation sp1p->w = 160; sp1p->h = 240; sp1p->tpage = GetTPage(2, 0, COPY_X, COPY_Y); sp1p->u = sp1p->v = 0; sp1p->cx = sp1p->cy = 0; //* not used sp1p->r = sp1p->g = sp1p->b = 128; sp1p->mx = 160; //* Set mx,my to tally with common point of rotation sp1p->my = 120+2; //* Slight offset to prevent unchanged central focus sp1p->rotate = 0; //* Sprite 2: 160x240 right section of screen image sp2p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_ON + A_DISPLAY_ON); sp2p->x = 160; sp2p->y = 120; //* Set x,y to common, mid-screen point of rotation sp2p->w = 160; sp2p->h = 240; sp2p->tpage = GetTPage(2, 0, COPY_X+128, COPY_Y); sp2p->u = 32; sp2p->v = 0; sp2p->cx = sp2p->cy = 0; //* not used sp2p->r = sp2p->g = sp2p->b = 128; sp2p->mx = 0; //* Set mx,my to tally with common point of rotation sp2p->my = 120+2; //* Slight offset to prevent unchanged central focus sp2p->rotate = 0; sp1p->scalex = sp2p->scalex = ONE+(25.6*(float)15); sp1p->scaley = sp2p->scaley = ONE+(17.06*(float)30); SsUtKeyOn(0, SFX_SPIN_SCREEN, 0, 65, 0, 127, 127); //* Run effect for (i=50; i; i--) { sp1p->rotate = sp2p->rotate -= ONE>>2; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); if (i<30) GsSortBoxFill(boxp, currOT, 1); //* Fade-out GsBOXF overlay GsSortSprite(sp1p, currOT, 0); GsSortSprite(sp2p, currOT, 0); DrawSync(0); VSync(2); GsSwapDispBuff(); copyp->y = psdofsy[!*psdidx]; //* Point to CRT image as source MoveImage(copyp, 0, psdofsy[*psdidx]); //* Copy it to draw buffer MoveImage(copyp, COPY_X, COPY_Y); //* Copy it to sprite area DrawSync(0); GsDrawOt(currOT); //* Start drawing over last image } //* Show final frame of effect DrawSync(0); VSync(2); GsSwapDispBuff(); //VSync(60*5); //* End of effect house keeping CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_test //*------------------------------------------------------------------------------------- void FX_test(void) { register GsOT *currOT; register int activeBuff; PACKET *buffs[2]; GsOT *OTs[2]; GsSPRITE *sp; register int i; register GsSPRITE *sp1p, *sp2p; //* Fast pointers to the 2 sprites RECT copy; register RECT *copyp=© GsBOXF box; register GsBOXF *boxp=&box; //RECT t; //t.x=0,t.y=!*psdidx*240+100,t.w=320,t.h=50; //ClearImage(&t,255,255,255); //DrawSync(0); //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. OpenSpriteArray(&sp, 2, NULL); OpenOT(OTs, buffs, 1, 5); //* NB: 40-packets-per-primitive for scaleable sprite sp2p = (sp1p = sp) + 1; //* Change to fast pointers //* Initialize transparent overlay GsBOXF boxp->attribute=(A_TRATE_3 + A_TRANS_ON + A_DISPLAY_ON); boxp->x = boxp->y = 0; boxp->w = 320; boxp->h = 240; boxp->r = boxp->g = boxp->b = 8; //* Initialize MoveImage() source rect. (.y set below) copyp->x = 0; copyp->w = 320; copyp->h = 240; //* Sprite 1: 160x240 left section of screen image sp1p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp1p->x = 160; sp1p->y = 120; //* Set x,y to common, mid-screen point of rotation sp1p->w = 160; sp1p->h = 240; sp1p->tpage = GetTPage(2, 0, COPY_X, COPY_Y); sp1p->u = sp1p->v = 0; sp1p->cx = sp1p->cy = 0; //* not used sp1p->r = sp1p->g = sp1p->b = 128; sp1p->mx = 160; //* Set mx,my to tally with common point of rotation sp1p->my = 120; //* Slight offset to prevent unchanged central focus sp1p->rotate = 0; //* Sprite 2: 160x240 right section of screen image sp2p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp2p->x = 160; sp2p->y = 120; //* Set x,y to common, mid-screen point of rotation sp2p->w = 160; sp2p->h = 240; sp2p->tpage = GetTPage(2, 0, COPY_X+128, COPY_Y); sp2p->u = 32; sp2p->v = 0; sp2p->cx = sp2p->cy = 0; //* not used sp2p->r = sp2p->g = sp2p->b = 128; sp2p->mx = 0; //* Set mx,my to tally with common point of rotation sp2p->my = 120; //* Slight offset to prevent unchanged central focus sp2p->rotate = 0; sp1p->scalex = sp2p->scalex = ONE+(25.6*(float)8); sp1p->scaley = sp2p->scaley = ONE+(17.06*(float)8); //* Run effect for (i=50; i; i--) { //sp1p->rotate = sp2p->rotate -= ONE>>2; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); //if (i<30) // GsSortBoxFill(boxp, currOT, 1); //* Fade-out GsBOXF overlay GsSortSprite(sp1p, currOT, 0); GsSortSprite(sp2p, currOT, 0); DrawSync(0); VSync(60); GsSwapDispBuff(); copyp->y = psdofsy[!*psdidx]; //* Point to CRT image as source MoveImage(copyp, 0, psdofsy[*psdidx]); //* Copy it to draw buffer MoveImage(copyp, COPY_X, COPY_Y); //* Copy it to sprite area DrawSync(0); GsDrawOt(currOT); //* Start drawing over last image } //* Show final frame of effect DrawSync(0); VSync(2); GsSwapDispBuff(); //VSync(60*5); //* End of effect house keeping CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* FX_Spin_Fade_Out //*------------------------------------------------------------------------------------- void FX_Spin_Fade_Out(void) { register GsOT *currOT; register int activeBuff; PACKET *buffs[2]; GsOT *OTs[2]; GsSPRITE *sp; register int i; register GsSPRITE *sp1p, *sp2p; //* Fast pointers to the 2 sprites //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_CRT_IMAGE); //* Set up sprite, OT mem etc. OpenSpriteArray(&sp, 2, NULL); OpenOT(OTs, buffs, 1, 5); //* NB: 40-packets-per-primitive for scaleable sprite sp2p = (sp1p = sp) + 1; //* Change to fast pointers //* Sprite 1: 160x240 left section of screen image sp1p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp1p->x = 160; sp1p->y = 120; //* Set x,y to common, mid-screen point of rotation sp1p->w = 160; sp1p->h = 240; sp1p->tpage = GetTPage(2, 0, COPY_X, COPY_Y); sp1p->u = sp1p->v = 0; sp1p->cx = sp1p->cy = 0; //* not used sp1p->r = sp1p->g = sp1p->b = 128; sp1p->mx = 160; sp1p->my = 120; //* Set mx,my to tally with common point of rotation sp1p->scalex = sp1p->scaley = ONE; sp1p->rotate = 0; //* Sprite 2: 160x240 right section of screen image sp2p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp2p->x = 160; sp2p->y = 120; //* Set x,y to common, mid-screen point of rotation sp2p->w = 160; sp2p->h = 240; sp2p->tpage = GetTPage(2, 0, COPY_X+128, COPY_Y); sp2p->u = 32; sp2p->v = 0; sp2p->cx = sp2p->cy = 0; //* not used sp2p->r = sp2p->g = sp2p->b = 128; sp2p->mx = 0; sp2p->my = 120; //* Set mx,my to tally with common point of rotation sp2p->scalex = sp2p->scaley = ONE; sp2p->rotate = 0; //* Rotate, shrink and fade-out screen image for (i=27; i; i--) { sp1p->scalex = sp2p->scalex -= 128; sp1p->scaley = sp2p->scaley -= 136; sp1p->r = sp1p->g = sp1p->b = sp2p->r = sp2p->g = sp2p->b -= 4; sp1p->rotate += 40960; //* 40960=ONE*10; sp2p->rotate += 40960; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); GsSortSprite(sp1p, currOT, 0); GsSortSprite(sp2p, currOT, 0); DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } //* Show final frame of effect DrawSync(0); VSync(0); GsSwapDispBuff(); //VSync(60*2); //* End of effect house keeping CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //* Screen position x,y addition pairs int quake[10][2] = { {-5,10}, {0,-8}, {15,0}, {-10,-5}, {5,0}, {0,5}, {-4,2}, {-2,-4}, {5,-1}, {-2,4} }; //*------------------------------------------------------------------------------------------ //* FX_Spin_Fade_In //*------------------------------------------------------------------------------------- void FX_Spin_Fade_In(void) { register GsOT *currOT; register int activeBuff; PACKET *buffs[2]; GsOT *OTs[2]; GsSPRITE *sp; register int i; register GsSPRITE *sp1p, *sp2p; //* Fast pointers to the 2 sprites RECT tps; int sx, sy; //* Provide a 320x240 copy of screen image OpenBuffCopy(WIDTH_320, USE_NEW_IMAGE); //* Set up sprite, OT mem etc. OpenSpriteArray(&sp, 2, NULL); OpenOT(OTs, buffs, 1, 5); //* NB: 40-packets-per-primitive for scaleable sprite sp2p = (sp1p = sp) + 1; //* Change to fast pointers //* Sprite 1: 160x240 left section of screen image sp1p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp1p->x = 160; sp1p->y = 120; //* Set x,y to common, mid-screen point of rotation sp1p->w = 160; sp1p->h = 240; sp1p->tpage = GetTPage(2, 0, COPY_X, COPY_Y); sp1p->u = sp1p->v = 0; sp1p->cx = sp1p->cy = 0; //* not used sp1p->r = sp1p->g = sp1p->b = 20; sp1p->mx = 160; sp1p->my = 120; //* Set mx,my to tally with common point of rotation sp1p->scalex = 640; sp1p->scaley = 424; sp1p->rotate = 1105920; //* Sprite 2: 160x240 right section of screen image sp2p->attribute = (A_BRIGHT_ON + A_15BIT_NOCLUT + A_ROTATE_ON + A_TRATE_1 + A_TRANS_OFF + A_DISPLAY_ON); sp2p->x = 160; sp2p->y = 120; //* Set x,y to common, mid-screen point of rotation sp2p->w = 160; sp2p->h = 240; sp2p->tpage = GetTPage(2, 0, COPY_X+128, COPY_Y); sp2p->u = 32; sp2p->v = 0; sp2p->cx = sp2p->cy = 0; //* not used sp2p->r = sp2p->g = sp2p->b = 20; sp2p->mx = 0; sp2p->my = 120; //* Set mx,my to tally with common point of rotation sp2p->scalex = 640; sp2p->scaley = 424; sp2p->rotate = 1105920; //* Rotate, expand and fade-in screen image for (i=54; i; i--) { sp1p->scalex = sp2p->scalex += 64; sp1p->scaley = sp2p->scaley += 68; sp1p->r = sp1p->g = sp1p->b = sp2p->r = sp2p->g = sp2p->b += 2; sp1p->rotate -= 20480; //* 40960=ONE*10; sp2p->rotate -= 20480; currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); GsSortSprite(sp1p, currOT, 0); GsSortSprite(sp2p, currOT, 0); DrawSync(0); VSync(0); GsSwapDispBuff(); GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } //* Show final frame of effect DrawSync(0); VSync(0); GsSwapDispBuff(); //VSync(60*2); //* Copy CRT image to draw buffer tps.x = 0; tps.w = 320; tps.h = 240; tps.y = !*psdidx * 240; MoveImage(&tps, 0, *psdidx * 240); DrawSync(0); SsUtKeyOn(0, SFX_ENEMY_EXPLODE1, 0, 58, 0, 127, 127); //* Make the screen shake sx = GsDISPENV.screen.x; sy = GsDISPENV.screen.y; for (i=0; i<10; i++) { GsDISPENV.screen.x += quake[i][0]; GsDISPENV.screen.y += quake[i][1]; VSync(2); GsSwapDispBuff(); } //* Restore screen to original position GsDISPENV.screen.x = sx; GsDISPENV.screen.y = sy; VSync(2); GsSwapDispBuff(); //* End of effect house keeping CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); CloseBuffCopy(); } //*------------------------------------------------------------------------------------------ //* WhiteNoise //*------------------------------------------------------------------------------------- void WhiteNoise(int frames) { register GsOT *currOT; register int activeBuff; register int n; PACKET *buffs[2]; //* Pointers to the 2 packet buffers - initialized by OpenOT() GsOT *OTs[2]; GsSPRITE *sp; int i, r, c, voice; int numSprites; int vramX, vramY; //* Calculate u,v tpage offsets vramX = ((timData[TIM_WNOISE].px<<2) % 256); //* .px<<2 because 4bit = 4 pixels per VRAM pixel vramY = (timData[TIM_WNOISE].py & 0xff); //* Set up sprite, OT mem etc. numSprites = 300; OpenSpriteArray(&sp, numSprites, NULL); OpenOT(OTs, buffs, 1, 300+5); //* Initialize screen sprites for (r=0; r<15; r++) for (c=0; c<20; c++) { n = (r*20)+c; sp[n].attribute = (A_BRIGHT_ON + A_4BIT_CLUT + A_ROTATE_OFF + A_TRANS_OFF + A_DISPLAY_ON); sp[n].x = (c<<4); sp[n].y = (r<<4); sp[n].w = sp[n].h = 16; sp[n].tpage = GetTPage(0, 0, timData[TIM_WNOISE].px, timData[TIM_WNOISE].py); //sp[n].u = rand()%16; //sp[n].v = 16+(rand()%16); sp[n].cx = timData[TIM_WNOISE].cx; sp[n].cy = timData[TIM_WNOISE].cy; sp[n].r = sp[n].g = sp[n].b = 128; sp[n].scalex = sp[n].scaley = ONE; sp[n].rotate = 0; } //* Run effect voice = SsUtKeyOn(0, SFX_WNOISE, 0, 50, 0, 127, 127); for (i=frames; i; i--) { currOT = OTs[activeBuff = GsGetActiveBuff()]; GsSetWorkBase(buffs[activeBuff]); GsClearOt(0, 0, currOT); for (n=0; nu = vramX + (rand() % 48); (sp+n)->v = vramY + (rand() % 48); GsSortFastSprite(sp+n, currOT, 0); } DrawSync(0); //* Wait for GPU to finish drawing VSync(0); //* Wait for CRT to finish scan GsSwapDispBuff(); //* Switch double buffers GsSortClear(0, 0, 0, currOT); GsDrawOt(currOT); } SsUtKeyOff(voice, 0, SFX_WNOISE, 0, 50); DrawSync(0); //* Ensure GPU has finished using mem before returning it to heap CloseSpriteArray(sp, NULL); CloseOT(OTs[0], buffs[0]); } //*------------------------------------------------------------------------------------------ //* OpenAliasBuff - Provides work buffer for anti-alias functions //*------------------------------------------------------------------------------------- void OpenAliasBuff(void) { if ((aliasBuffp = (u_long *) malloc(BUFF_SIZE))==NULL) { printf("\nFailed to allocate memory to store frame buffer\n"); return; } } //*------------------------------------------------------------------------------------------ //* CloseAliasBuff - Releases anti-alias functions working buffer back to heap //*------------------------------------------------------------------------------------- void CloseAliasBuff(void) { free(aliasBuffp); } //*------------------------------------------------------------------------------------------ //* FX_Soften_Rect - Softens (mild anti-alias) a rectangular section of the draw buffer image //* Note: arguments x and y must be at least 1 because pixels above and to the left of these //* coords are referenced although not actually changed. Also, the effect on some colours //* (particularly those with low RGB) can be quite lossy because of the speed-optimized code //*------------------------------------------------------------------------------------- void FX_Soften_Rect(int x, int y, int w, int h) { register u_int col, row, dp1, dp2, dp3; register u_int *top, *mid, *bot, *dest; RECT si; register u_int hw = w>>1; //* Half width si.x = x-1, si.y = *psdidx * 240+y-1, si.w = w+2, si.h = h+2; StoreImage(&si, aliasBuffp); DrawSync(0); EnterCriticalSection(); bot = (mid = (top = dest = (u_int *) aliasBuffp) + hw + 1) + hw + 1; for (row=h; row; row--) { dp1=*top++, dp2=*mid++, dp3=*bot++; for (col=hw; col; col--) *dest++ = ((dp1>>4) & 0x04210421) + \ ((dp1>>19) & 0x00000c63) + \ ((dp2>>3) & 0x0c630c63) + \ ((dp2>>17) & 0x00003def) + \ ((dp3>>4) & 0x04210421) + \ ((dp3>>19) & 0x00000c63) + \ (((dp1=*top++)>>4) & 0x04210421) + \ ((dp1<<13) & 0x0c630000) + \ (((dp2=*mid++)>>3) & 0x0c630c63) + \ ((dp2<<15) & 0x3def0000) + \ (((dp3=*bot++)>>4) & 0x04210421) + \ ((dp3<<13) & 0x0c630000); } si.x = x, si.y = *psdidx * 240+y, si.w = w, si.h = h; ExitCriticalSection(); LoadImage(&si, aliasBuffp); DrawSync(0); } //*------------------------------------------------------------------------------------------ //* FX_Blur_Rect - Blurs (harsh anti-alias) a rectangular section of the draw buffer image //* Note: arguments x and y must be at least 1 because pixels above and to the left of these //* coords are referenced although not actually changed. Also, the effect on some colours //* (particularly those with low RGB) can be quite lossy because of the speed-optimized code //*------------------------------------------------------------------------------------- void FX_Blur_Rect(int x, int y, int w, int h) { register u_int col, row, dp1, dp2, dp3; register u_int *top, *mid, *bot, *dest; RECT si; register u_int hw = w>>1; //* Half width si.x = x-1, si.y = *psdidx * 240+y-1, si.w = w+2, si.h = h+2; StoreImage(&si, aliasBuffp); DrawSync(0); EnterCriticalSection(); bot = (mid = (top = dest = (u_int *) aliasBuffp) + hw + 1) + hw + 1; for (row=h; row--;) { dp1=*top++, dp2=*mid++, dp3=*bot++; for (col=hw; col--;) { *dest++ = ((dp1>>3) & 0x0c630c63) + ((dp1>>19) & 0x00000c63) + \ ((dp2>>3) & 0x0c630c63) + ((dp2>>18) & 0x00001ce7) + \ ((dp3>>3) & 0x0c630c63) + ((dp3>>19) & 0x00000c63) + \ (((dp1=*top++)>>3) & 0x0c630c63) + ((dp1<<13) & 0x0c630000) + \ (((dp2=*mid++)>>3) & 0x0c630c63) + ((dp2<<14) & 0x1ce70000) + \ (((dp3=*bot++)>>3) & 0x0c630c63) + ((dp3<<13) & 0x0c630000); } } si.x = x, si.y = *psdidx * 240+y, si.w = w, si.h = h; ExitCriticalSection(); LoadImage(&si, aliasBuffp); DrawSync(0); }