/********************************************************************/ /* Sprite display with animation */ /* Author: ScoTT Campbell (~escotia) */ /* Date: 25/7/98 */ /* Updated: 26/7/98 Motion added in all directions */ /* 27/7/98 Code cleaned up. Transparency fixed */ /* */ /* BIG thanks to my mate Dave for the images! */ /* */ /* Please mail me any problems you find to - escotia@hotmail.com */ /********************************************************************/ #include #include "screen.h" #include "pad.h" // Ordering table related definitions #define OT_Length (1) GsOT worldOT[2]; // OT headers GsOT_TAG OTElements[2][1 << OT_Length]; // OT's //Primitive related definitions #define Sprite_Neutral_Address (0x800A8000) // Where the 'neutral' sprite will be placed in memory #define Sprite_Address_Offset (0x00006000) // Offset for position of other sprites. ie sprite 2 will be at 0xA00A800 + (2*0x6000) #define Max_Sprites (1) // Max number of sprites to be displayed at a time #define Max_Tilt_Frames (4) // Amount of animation in each direction #define Total_Frames (9) // Number of different images used #define Num_Packets (Max_Sprites + 1) // 1 extra allows a clear screen command to be added to the OT GsSPRITE sprite[Total_Frames]; // Sprite handler array #define Sprite_Array_Offset (Max_Tilt_Frames) // Just to make the program read better PACKET packetArray[2][Num_Packets * sizeof(GsSPRITE)]; // Only diplaying sprites so can specify size exactly // Controller related definitions volatile unsigned char *padbuff1, *padbuff2; // Function definitions void InitialiseGraphics(); // Sets up graphics according to MACROS defined in screen.h void InitialiseOTs(); // Sets up ordering table headers void InitialiseControllers(); // Sets up the controller buffers unsigned long int PadRead(); // Returns value from controller 1 void InitialiseText(); // Loads system font into memory void InitialiseSprite(GsSPRITE*, long); // Sets up a sprite in frame buffer int ChooseSprite(unsigned long int, unsigned long int); // Returns number of sprite to display on the screen // depending on the players inputs int GetSpriteYValue(unsigned long int pad1Value, int* currentY, int spriteHeight); // Returns amount of movement required in Y direction int main() { int activeBuffer; unsigned long int pad1; int currentSprite; unsigned long currentSpriteAddress; int spriteX, spriteY; // Current sprites X/Y position InitialiseGraphics(); InitialiseOTs(); InitialiseControllers(); InitialiseText(); for(currentSprite=0; currentSprite (Actual_Screen_Width - sprite[currentSprite + Sprite_Array_Offset].w)) sprite[currentSprite + Sprite_Array_Offset].x = spriteX = (Actual_Screen_Width - sprite[currentSprite + Sprite_Array_Offset].w); else sprite[currentSprite+Sprite_Array_Offset].x = spriteX; // Move ship up and down on screen depending on pad direction sprite[currentSprite+Sprite_Array_Offset].y =GetSpriteYValue(pad1, &spriteY, sprite[currentSprite+Sprite_Array_Offset].h); FntPrint("Animation frame: %d", currentSprite); activeBuffer = GsGetActiveBuff(); // Find out which buffer we want to draw in GsSetWorkBase((PACKET*)packetArray[activeBuffer]); // Set drawing command storage address GsClearOt(0,0,&worldOT[activeBuffer]); // Clear the current ordering table GsSortFastSprite(&sprite[currentSprite + Sprite_Array_Offset], // Put sprite into current OT &worldOT[activeBuffer],0); // No scaling or rotation so can use GsSortFastSprite FntFlush(-1); // Put text into OT DrawSync(0); // Wait for current drawing to finish VSync(0); // Wait for screen to finish drawing GsSwapDispBuff(); // Swap drawing buffer with display buffer GsSortClear(25,25,25,&worldOT[activeBuffer]); // Clear the screen to grey GsDrawOt(&worldOT[activeBuffer]); // Draw the OT we just processed } return(0); } void InitialiseGraphics() // Needs global definitions from screen.h { SetVideoMode(Video_Mode); // PAL or NTSC - defined in screen.h GsInitGraph(Screen_Width, Screen_Height,4,0,0); // Defines screen resolution to Screen_Width & Screen_Height, // sets non-interlace with gpu offset, dither off and 16-bit video mode GsDefDispBuff(0,0,0,Screen_Height); // Define double buffers } void InitialiseOTs() // Initialises WorldOT's (headers) { int i; for(i=0;i<2;i++) { worldOT[i].length = OT_Length; worldOT[i].org = OTElements[i]; } } void InitialiseControllers() // Get addresses of controllers' buffers { GetPadBuf(&padbuff1, &padbuff2); } unsigned long int PadRead() // Read from controllers (No I don't know WHAT that does) { return (~(*(padbuff1+3) | *(padbuff1+2) << 8 | *(padbuff2+3) << 16 | *(padbuff2+2) << 24)); } void InitialiseSprite(GsSPRITE* sprite, long Sprite_Address) { RECT rect; GsIMAGE timData; // Get info at Sprite_Address and put into timData GsGetTimInfo((unsigned long*)(Sprite_Address+4), &timData); // Load sprite into frame buffer rect.x = timData.px; rect.y = timData.py; rect.w = timData.pw; rect.h = timData.ph; LoadImage(&rect, timData.pixel); // Load sprites CLUT into frame buffer rect.x = timData.cx; rect.y = timData.cy; rect.w = timData.cw; rect.h = timData.ch; LoadImage(&rect, timData.clut); sprite->attribute = 0x59000000; // 8-bit with overlay transparency and scaling off sprite->w = (timData.pw * 2); sprite->h = (timData.ph); sprite->mx = sprite->w/2; sprite->my = sprite->h/2; sprite->x = (Screen_Width/2)-sprite->mx; // Using GsSortFastSprite so x and y are the top left corner sprite->y = (Screen_Height/2)-sprite->my; // of the sprite and they need adjusted accordingly sprite->tpage = GetTPage(1, 0, timData.px, timData.py); sprite->u = 0; sprite->v = 0; sprite->cx = timData.cx; sprite->cy = timData.cy; sprite->r = 128; sprite->g = 128; sprite->b = 128; sprite->scalex = ONE; sprite->scaley = ONE; sprite->rotate = 0; DrawSync(0); } int ChooseSprite(unsigned long int pad1Value, unsigned long int maxTiltFrames) { static int tiltCount = 0; static int smoother = 0; // Slows down the animation by only changing the frame every second time round if(smoother) { smoother--; if(pad1Value & PADLleft) { if(tiltCount != -maxTiltFrames) tiltCount--; } else if(pad1Value & PADLright) { if(tiltCount != maxTiltFrames) tiltCount++; } else { if(tiltCount < 0) tiltCount++; else if(tiltCount > 0) tiltCount--; } } else smoother++; return tiltCount; } int GetSpriteYValue(unsigned long int pad1Value, int* currentY, int spriteHeight) { if(pad1Value & PADLup) { // Pad is in up direction so decrease Y // Stop sprite going off screen if((*currentY -= 4) < 0) *currentY = 0; } else if(pad1Value & PADLdown) { // Pad is in down direction so increase Y // Stop sprite going off screen if((*currentY +=4) > (Actual_Screen_Height - spriteHeight)) *currentY = (Actual_Screen_Height - spriteHeight); } return *currentY; } void InitialiseText() { FntLoad(960, 256); FntOpen(16, 16, 256, 200, 0, 512); }