Path: chuka.playstation.co.uk!news From: 2bad@lineone.net (Khan) Newsgroups: scea.yaroze.programming.2d_graphics Subject: BG Problem Date: Sun, 06 Sep 1998 17:32:25 GMT Organization: PlayStation Net Yaroze (SCEE) Lines: 1642 Message-ID: <35f2c71f.16917324@news.playstation.co.uk> NNTP-Posting-Host: host5-99-43-244.btinternet.com X-Newsreader: Forte Free Agent 1.11/32.235 Hi, Thanks everyone for your adivice and stuff. But I am still stuck with adding a 2D background to my 3D racing game. I've got George Bain's stuff but thats just for displaying sprites, isnt it? And anyway as I am a total beginner at coding I need some kind of Tutorial or something. By the way I made some added a backrond code to my game, which compiles and links ok but when the auto file tells it to go it freezes. I really dont know whats going wrong. I am trusting everyone and putting my full code below. Please can you guy take a look at it to see whats wrong. I will very much appreciate it. And if possible tell me a bit about collision detection. Thanks guys. Sorry about the messy code! Tanvir Khan EMAG DESIGN 2bad@lineone.net P.S Dont worry if you guys dont have time as the code is quite long, Cheers. // **** include libraries and files #include // load standard libraries #include // load playstation library #include "pad.h" // load joypad reading #include "libsound.h" // **** set up defines #define true (1) #define false (0) #define OTABLE_LENGTH (12) // define length of OTable #define MAX_PACKETS (248000) // define size of GPU scratchpad #define IS_PAL_USED (true) // true = PAL mode, false = NTSC mode #define PAL_WIDTH (320) // size of PAL screen #define PAL_HEIGHT (240) #define NTSC_WIDTH (320) // size of NTSC screen #define NTSC_HEIGHT (256) #define GROUND_MAXX (15) // define ground x size #define GROUND_MAXZ (15) // define ground z size #define GROUND_MAX_OBJECTS (225) // total max number of ground objects #define GROUND_SIZE (1200) // X and Z dimensions of one road object #define CAR_MEM_ADDR (0x80090000) // location of car .TMD data #define ROAD2_MEM_ADDR (0x800A2000) #define ROAD_MEM_ADDR (0x80098000) // location of track .TMD data #define ROAD_TEX_MEM_ADDR (0x800B0000) // location of texture .TIM data #define ROAD2_TEX_MEM_ADDR (0x800C0000) #define NUM_TEX_ADDR (0x800E0000) #define BL_TEX_ADDR (0x800E2000) #define HL_TEX_ADDR (0x800E4000) #define WHEEL_TEX_ADDR (0x800E6000) #define TYRE_TEX_ADDR (0x800E8000) #define BODY_TEX_ADDR (0x800B2000) #define WS_TEX_ADDR (0x800B4000) #define SKY_TEX_ADDR (0x800A4000) #define SKY_MEM_ADDR (0x800A8000) #define HELI_MEM_ADDR (0x800A0000) #define MAP_ADDR (0x800A0000) #define TILES_ADDR (0x800A4000) #define NCELLW (256) #define NCELLH (256) #define NUMCELLS (256) #define NUM_SPRITES (1+1) // BG work base primitive area u_long bgworkbase[(((PAL_WIDTH/16+1)*(PAL_HEIGHT/16+2)*6+4)*2+2)]; int hsyncs; extern DISPENV GsDISPENV; GsCELL gscell[NUMCELLS]; GsMAP gsmap; GsBG gsbg; u_short map[NCELLW*NCELLH]; // Function Prototypes void InitBg(); void ScrollBg(); void LoadMapData(); GsSPRITE sprite; // **** create global variables, structures, headers and arrays (mostly system stuff) int Running = true; // define program to be running u_long VerticalSync = 0; // set up speed counter for processor GsOT OTable_Header[2]; // Header files holding OTable info GsOT_TAG OTable_Array[2][1<0) // if automatic camera choosing is on... { FntPrint("Automatic camera\n"); // ...then print just that cameraCounter--; // decrement the counter if (cameraCounter == 0) // when it reaches zero... { cameraUsed = (cameraUsed+1) % 7; // ...choose next camera SelectCamera(cameraUsed); // select the camera and fogging info cameraCounter = 150; // reset counter }; }; switch (cameraUsed) // update a camera's viewing info { case 0 : { // static camera long tScale = 9 * GROUND_SIZE; long tScale2 = (tScale-1) / 2; FntPrint("Static camera\n"); Camera[0].vpx = ((CarModel.Object_Coord.coord.t[0]) / tScale * tScale) + tScale2; Camera[0].vpz = ((CarModel.Object_Coord.coord.t[2]) / tScale * tScale) + tScale2; Camera[0].vrx = CarModel.Object_Coord.coord.t[0]; Camera[0].vry = CarModel.Object_Coord.coord.t[1]; Camera[0].vrz = CarModel.Object_Coord.coord.t[2]; break;}; case 1 : { // tracking camera FntPrint("Tracking camera\n"); break;}; case 2 : { // scrolling side camera FntPrint("Side camera\n"); Camera[2].vpx = CarModel.Object_Coord.coord.t[0]; Camera[2].vpy = -1000 - (abs(CarModel.Object_Coord.coord.t[2]) / 2); Camera[2].vpz = -1000 + CarModel.Object_Coord.coord.t[2] / 4; Camera[2].vrx = Camera[2].vpx; Camera[2].vrz = CarModel.Object_Coord.coord.t[2]; break;}; case 3 : { // overhead camera FntPrint("Overhead camera\n"); break;}; case 4 : { // in car camera FntPrint("In car camera\n"); break;}; case 5 : { // blimp camera FntPrint("Blimp camera\n"); Camera[5].vrx = CarModel.Object_Coord.coord.t[0]; Camera[5].vry = CarModel.Object_Coord.coord.t[1]; Camera[5].vrz = CarModel.Object_Coord.coord.t[2]; break;}; case 6 : { // sidecar camera FntPrint("Sidecar camera\n"); break;}; }; //FntPrint("\nUse all eight buttons to change camera\n"); //FntPrint("Vertical sync value (%d)\n", VerticalSync); // display speed of screen drawing ProcessUserInput(); // call function to process joypad MoveModelForward(&CarModel, CarModel.speed); // move man every frame RenderWorld(); // render the playstation screen } //SoundStop(); ResetGraph(3); // clear up before quitting }; // Initialise Background map void InitBg() { RECT r; GsIMAGE im; int i; GsGetTimInfo((u_long *)TILES_ADDR+1, &im); r.x = im.px; r.y = im.py; r.w = im.pw; r.h = im.ph; LoadImage(&r, im.pixel); r.x = im.cx; r.y = im.cy; r.w = im.cw; r.h = im.ch; LoadImage(&r, im.clut); DrawSync(0); for (i=0; i < NUMCELLS; i++) { gscell[i].u = ((i%16)<<4); gscell[i].v = ((i/16)<<4); gscell[i].cba = GetClut(im.cx, im.cy); gscell[i].tpage = GetTPage(im.pmode, 0, im.px, im.py); } gsmap.cellw = 16; gsmap.cellh = 16; gsmap.ncellw = NCELLW; gsmap.ncellh = NCELLH; gsmap.base = gscell; gsmap.index = map; gsbg.attribute = (im.pmode<<24); gsbg.x = 0; gsbg.y = 0; gsbg.w = PAL_WIDTH; gsbg.h = PAL_HEIGHT; gsbg.scrollx = (127<<4) - 160; gsbg.scrolly = (127<<4) - 128; gsbg.r = gsbg.g = gsbg.b = 128; gsbg.map = &gsmap; GsInitFixBg16(&gsbg, bgworkbase); // Loads map data from MAP_ADDR into map[] array by default LoadMapData(); } // Loads map data (city.dat) from MAP_ADDR into map[] array void LoadMapData() { int i; u_char *pmap = (u_char *)MAP_ADDR; // NULL cell (transparent) map[i] = 0xffff // This is set as index ZERO in map.dat // Set map array to that of map.dat file for (i = 0; i < (NCELLW*NCELLH); i++) { if (pmap[i]) map[i] = pmap[i]; else map[i] = 0xffff; } } // *********************************************************************************** // User defined drawing functions // *********************************************************************************** // **** Actual main screen drawing routine (calls all functions) void RenderWorld() { int currentBuffer = GsGetActiveBuff(); // determine which buffer is to be used GsSetRefView2(&Camera[cameraUsed]); // activates the view GsSetWorkBase((PACKET*)Packet_Memory[currentBuffer]); // define where screen drawing commands // are going to be queued GsClearOt(0, 0, &OTable_Header[currentBuffer]); // clear out OTable sorting info DrawTrack(&TrackData, &OTable_Header[currentBuffer]); DrawObject(&CarModel, &OTable_Header[currentBuffer]); DrawObject2(&BackModel, &OTable_Header[currentBuffer]); DrawObject3(&HeliModel, &OTable_Header[currentBuffer]); // send draw commands to queue FntFlush(-1); // force text to be printed immediately DrawSync(0); // wait for completion of all output VerticalSync = VSync(0); // wait for blank and time it GsSwapDispBuff(); // swap buffer information GsSortClear(0, 0, 0,&OTable_Header[currentBuffer]); // send clear screen command to queue GsDrawOt(&OTable_Header[currentBuffer]); // draw commands in queue GsDISPENV.screen.y = 20; GsDISPENV.screen.h = PAL_HEIGHT; // Sort BG in OT GsSortFixBg16(&gsbg, bgworkbase, &OTable_Header[currentBuffer], 0); }; // **** draw an object on screen void DrawObject(Object_Header0 *tObject, GsOT *tOTable) { MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures GsGetLws(tObject->Object_Handler.coord2, &tLocalWorld, &tLocalScreen); // get the local world and screen // matrices. Needed for lightsourcing GsSetLightMatrix(&tLocalWorld); // Set local world matrix for lighting GsSetLsMatrix(&tLocalScreen); // Set local screen matrix for perspective GsSortObject4( &tObject->Object_Handler, tOTable, 4, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing }; // **** draw an object on screen void DrawObject2(Back_Header1 *tBack, GsOT *tOTable) { MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures GsGetLws(tBack->Object_Handler.coord2, &tLocalWorld, &tLocalScreen); // get the local world and screen // matrices. Needed for lightsourcing GsSetLightMatrix(&tLocalWorld); // Set local world matrix for lighting GsSetLsMatrix(&tLocalScreen); // Set local screen matrix for perspective GsSortObject4( &tBack->Object_Handler, tOTable, 4, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing }; // **** draw an object on screen void DrawObject3(Heli_Header2 *tHeli, GsOT *tOTable) { MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures GsGetLws(tHeli->Object_Handler.coord2, &tLocalWorld, &tLocalScreen); // get the local world and screen // matrices. Needed for lightsourcing GsSetLightMatrix(&tLocalWorld); // Set local world matrix for lighting GsSetLsMatrix(&tLocalScreen); // Set local screen matrix for perspective GsSortObject4( &tHeli->Object_Handler, tOTable, 4, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing }; // **** draw the entire track on screen void DrawTrack(Track_Header0 *tTrack, GsOT *tOTable) { MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures int tCounter; for (tCounter = 0; tCounter < tTrack->numberObjects; tCounter++) { // go through every cell in data array GsGetLws(tTrack->Object_Handler[tCounter].coord2, &tLocalWorld, &tLocalScreen); // get local world and screen // matrices. Needed for lightsourcing GsSetLightMatrix(&tLocalWorld); // Set local world matrix for lighting GsSetLsMatrix(&tLocalScreen); // Set local screen matrix for perspective GsSortObject4( &tTrack->Object_Handler[tCounter], tOTable, 2, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing // their value of 2 is lower than the // car's value of 4, therefore car is // drawn after ground which is correct }; }; // **** draw the entire track on screen void DrawTrack2(Track_Header1 *tTrack1, GsOT *tOTable) { MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures int tCounter; for (tCounter = 0; tCounter < tTrack1->numberObjects; tCounter++) { // go through every cell in data array GsGetLws(tTrack1->Object_Handler[tCounter].coord2, &tLocalWorld, &tLocalScreen); // get local world and screen // matrices. Needed for lightsourcing GsSetLightMatrix(&tLocalWorld); // Set local world matrix for lighting GsSetLsMatrix(&tLocalScreen); // Set local screen matrix for perspective GsSortObject4( &tTrack1->Object_Handler[tCounter], tOTable, 2, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing // their value of 2 is lower than the // car's value of 4, therefore car is // drawn after ground which is correct }; }; // *********************************************************************************** // User defined initialisation functions // *********************************************************************************** // **** Load in and setup a .TIM picture file (in this case to be used for a texture) void LoadTexture(long tMemAddress) { RECT tRect; // rectangular area to be used for TIM GsIMAGE tTim; // TIM image information tMemAddress += 4; // advance memory pointer to data GsGetTimInfo((u_long *) tMemAddress, &tTim); // fill tTim with info from TIM tRect.x = tTim.px; // tell GPU where graphics data is tRect.y = tTim.py; tRect.w = tTim.pw; tRect.h = tTim.ph; LoadImage(&tRect, tTim.pixel); // load video memory with TIM data if((tTim.pmode>>3) & 0x01) // do this if TIM uses a CLUT { tRect.x = tTim.cx; // tell GPU where colour table is tRect.y = tTim.cy; tRect.w = tTim.cw; tRect.h = tTim.ch; LoadImage(&tRect, tTim.clut); // load video memory with CLUT data } DrawSync(0); // force LoadImages to complete } // **** Setup up screen void InitialiseGraphics() { if (IS_PAL_USED) // set up PAL screen { SetVideoMode(MODE_PAL); // define screen as PAL GsInitGraph(PAL_WIDTH, PAL_HEIGHT, GsINTER|GsOFSGPU, 1, 0); // define screen resolution, whether // interlaced, dithered & colour depth GsDefDispBuff(0, 0, 0, PAL_HEIGHT); // define top left corners of // both screen buffers in memory } else // OR set up NTSC screen { SetVideoMode(MODE_NTSC); // define screen as NTSC GsInitGraph(NTSC_WIDTH, NTSC_HEIGHT, GsINTER|GsOFSGPU, 1, 0); GsDefDispBuff(0, 0, 0, NTSC_HEIGHT); // define top left corners of // both screen buffers in memory }; GsInit3D(); // initialise 3d graphics routine so // 3d and font functions can work OTable_Header[0].length = OTABLE_LENGTH; // notify OTable headers of OTable OTable_Header[1].length = OTABLE_LENGTH; // array lengths OTable_Header[0].org = OTable_Array[0]; // notify OTable headers of OTable OTable_Header[1].org = OTable_Array[1]; // array memory locations GsClearOt(0, 0, &OTable_Header[0]); // clear out OTable sorting info GsClearOt(0, 0, &OTable_Header[1]); // ready for use (not strictly necessary // as they are cleared before use in // RenderWorld() }; // **** Initialise a new object - ie, set up its rotation, position and model void InitModel(Object_Header0 *tObject, int tX, int tY, int tZ, u_long *tMemAddress) { tObject->rotation.vx = 0; // define orientation as zero tObject->rotation.vy = 0; tObject->rotation.vz = 0; tObject->speed = 0; // define velocity of car as zero AddModelToHeader(tObject, tX, tY, tZ, tMemAddress); // set up rest of object }; // **** Initialise a new object - ie, set up its rotation, position and model void InitModel2(Back_Header1 *tBack, int tX, int tY, int tZ, u_long *tMemAddress) { tBack->rotation.vx = 0; // define orientation as zero tBack->rotation.vy = 0; tBack->rotation.vz = 0; tBack->speed = 0; // define velocity of car as zero AddModelToHeader(tBack, tX, tY, tZ, tMemAddress); // set up rest of object }; // **** Add infomation to object header to specify a 3d model to be associated with it void AddModelToHeader(Object_Header0 *tObject, int tX, int tY, int tZ, u_long *tMemAddress) { tMemAddress++; // move pointer past model Id GsMapModelingData(tMemAddress); // specify that .TMD data exists // once past the model Id GsInitCoordinate2(WORLD, &tObject->Object_Coord); // set objects coord system to that // of the world (ie, 0, 0, 0) tMemAddress += 2; // move pointer to actual 3D data GsLinkObject4((u_long)tMemAddress, &tObject->Object_Handler, 0); // associate the model with it's handler tObject->Object_Handler.coord2 = &tObject->Object_Coord; // associate coords of model to // it's handler tObject->Object_Coord.coord.t[0] = tX; // set model's initial X translation tObject->Object_Coord.coord.t[1] = tY; // Y tObject->Object_Coord.coord.t[2] = tZ; // Z tObject->Object_Coord.flg = 0; // Set to zero so object is to be updated }; // **** Add infomation to object header to specify a 3d model to be associated with it void AddModelToHeader2(Back_Header1 *tBack, int tX, int tY, int tZ, u_long *tMemAddress) { tMemAddress++; // move pointer past model Id GsMapModelingData(tMemAddress); // specify that .TMD data exists // once past the model Id GsInitCoordinate2(WORLD, &tBack->Object_Coord); // set objects coord system to that // of the world (ie, 0, 0, 0) tMemAddress += 2; // move pointer to actual 3D data GsLinkObject4((u_long)tMemAddress, &tBack->Object_Handler, 0); // associate the model with it's handler tBack->Object_Handler.coord2 = &tBack->Object_Coord; // associate coords of model to // it's handler tBack->Object_Coord.coord.t[0] = tX; // set model's initial X translation tBack->Object_Coord.coord.t[1] = tY; // Y tBack->Object_Coord.coord.t[2] = tZ; // Z tBack->Object_Coord.flg = 0; // Set to zero so object is to be updated }; // Initialise the Track void InitTrack() { long tXpos, tZpos; // temp variables char tTrackStatus; // temp variable TrackData.numberObjects = 0; // define no objects in world to start //LoadTexture(ROAD_TEX_MEM_ADDR); // LoadTexture(ROAD2_TEX_MEM_ADDR); for (tXpos = 0; tXposnumberObjects; // determine which object is being handled tTrack->Object_Pointer[tNumber] = (u_long *) tMemAddress; // tell model where road TIM is tTrack->Object_Pointer[tNumber]++; // advance pointer past initial info GsMapModelingData(tTrack->Object_Pointer[tNumber]); // specify that TIM data exists GsInitCoordinate2(WORLD, &tTrack->Object_Coord[tNumber]); // signify object origin = WORLD origin tTrack->Object_Pointer[tNumber] += 2; // advance pointer again! (standard) GsLinkObject4((u_long)tTrack->Object_Pointer[tNumber], &tTrack->Object_Handler[tNumber], 0); // associate the model with it's handler tTrack->Object_Handler[tNumber].attribute = GsDIV1; // signify polygon subdivision occurs tTrack->Object_Handler[tNumber].coord2 = &tTrack->Object_Coord[tNumber]; // associate coords of model to handler tTrack->Object_Coord[tNumber].coord.t[0] = tX; // setup initial position of model tTrack->Object_Coord[tNumber].coord.t[1] = tY; tTrack->Object_Coord[tNumber].coord.t[2] = tZ; tTrack->Object_Coord[tNumber].flg = 0; // signify it has to be recalculated tTrack->numberObjects++; // increase counter for next object }; // **** Define all lights that will be used in object rendering void InitAllLights() { InitLight(&LightSource, 0, 1, 1, 0, 127, 127, 127); // define light GsSetAmbient(2047,2047,2047); // set ambient light in the scene }; // **** Explicitly define a light source (up to three maximum in scene) void InitLight(GsF_LIGHT *tLight, int tNum, int tXv, int tYv, int tZv, int tR, int tG, int tB) { tLight->vx = tXv; tLight->vy = tYv; tLight->vz = tZv; // define vector for light from source tLight->r = tR; tLight->g = tG; tLight->b = tB; // define RGB values for the light GsSetFlatLight(tNum, tLight); // assign light to an ID number (0-2) // and turning light on }; // **** Define all information for the viewpoint void InitView(GsRVIEW2 *tView, int tProjDist, int tRZ, int tFromX, int tFromY, int tFromZ, int tToX, int tToY, int tToZ, GsCOORDINATE2 *tReference) { GsSetProjection(tProjDist); // distance from view projection screen tView->vpx = tFromX; tView->vpy = tFromY; tView->vpz = tFromZ; // set up position to look from tView->vrx = tToX; tView->vry = tToY; tView->vrz = tToZ; // set up position to look to tView->rz=-tRZ; // define rotation about view line if (tReference != false) tView->super = tReference; // set origin of model else tView->super = WORLD; }; // *********************************************************************************** // User defined miscellaneous functions // *********************************************************************************** int Demo = true; // **** Net Yaroze respond to joypad input void ProcessUserInput() { u_long PAD = PadRead(); // read status of joypad 1 if (PAD& PADselect) Running = false; // select will quit if (PAD & PADstart) { // return car to center, and stop motion Demo = 0; CarModel.speed = 0; // set car speed to zero CarModel.rotation.vx = 0; // straighten car and reset position CarModel.rotation.vy = 0; BackModel.rotation.vz = -900; RotateModel(&CarModel, 0, 0, 0); RotateModel(&BackModel, 0, 0, 0); MoveModelTo(&BackModel, -4000, 4000, 0); MoveModelTo(&CarModel, 0, 0, 0);}; if (PAD& PADcross) { // move car away from viewer if (CarModel.speed<140) CarModel.speed++; }; if (Demo == 1){ CarModel.speed = 140; if (CarModel.speed>110) RotateModel(&CarModel, 0, 15, 0); FntOpen(-100, -120, 320, 100, 0, 512); FntPrint("\n\n\nemag design presents...\nroad racer\npress start to play"); //SoundInit(); // SoundVoiceQPlay(SOUND_ACCEL); }; FntPrint ("\n\nCar speed = %d mph\n", CarModel.speed); if (PAD == 0){ if (CarModel.speed>0) CarModel.speed--; if (CarModel.speed<0) CarModel.speed++; }; if (PAD == 0){ if (CarModel.rotation.vz>0) CarModel.rotation.vz-=40; RotateModel(&CarModel, 0, 0, CarModel.rotation.vz==0); if (CarModel.rotation.vz<0) CarModel.rotation.vz+=40; RotateModel(&CarModel, 0, 0, CarModel.rotation.vz==0); }; if (PAD == PADcross){ if (CarModel.rotation.vz>0) CarModel.rotation.vz-=40; RotateModel(&CarModel, 0, 0, CarModel.rotation.vz==0); if (CarModel.rotation.vz<0) CarModel.rotation.vz+=40; RotateModel(&CarModel, 0, 0, CarModel.rotation.vz==0); }; if (PAD == PADsquare){ if (CarModel.rotation.vz>0) CarModel.rotation.vz-=40; RotateModel(&CarModel, 0, 0, CarModel.rotation.vz==0); if (CarModel.rotation.vz<0) CarModel.rotation.vz+=40; }; if (PAD == PADright){ if (CarModel.speed>0) CarModel.speed--;}; if (PAD == PADleft){ if (CarModel.speed>0) CarModel.speed--;}; if (PAD & PADcross){ if (PAD& PADsquare){ if (CarModel.speed>0) CarModel.speed--; }; } if (PAD & PADcircle){ BackModel.rotation.vz++;}; if (PAD & PADsquare){ if (PAD& PADcross){ if (CarModel.speed<0) CarModel.speed++; }; } if (PAD & PADsquare){ if (CarModel.speed>0) CarModel.speed--; }; if (PAD& PADsquare) { // move car towards viewer if (CarModel.speed>-100) CarModel.speed--;}; if (PAD& PADleft) { // rotate car anti-clockwise RotateModel(&CarModel, 0, -30, CarModel.rotation.vz == 0); if (CarModel.rotation.vz<100) CarModel.rotation.vz+=10;}; if (PAD& PADright) { // rotate car clockwise RotateModel(&CarModel, 0, 30, CarModel.rotation.vz == 0); if (CarModel.rotation.vz>-100) CarModel.rotation.vz-=10;}; //if (PAD& PADsquare) {SelectCamera(0); // select static camera // cameraCounter = 0;}; //InitView(&Camera[1], 250, 0, 0,-500,-1500, 0,-250,-500 ,&CarModel.Object_Coord ); if (PAD& PADtriangle) {SelectCamera(1); // select tracker camera cameraCounter = 0;}; if (PAD& PADcircle) {SelectCamera(2); // select side tracker camera cameraCounter = 0;}; //if (PAD& PADcross) {SelectCamera(3); // select overhead camera // cameraCounter = 0;}; if (PAD& PADL1) {SelectCamera(4); // select in car camera cameraCounter = 0;}; if (PAD& PADL2) {SelectCamera(5); // select blimp camera cameraCounter = 0;}; if (PAD& PADR1) {SelectCamera(6); // select sidecar camera cameraCounter = 0;}; if ((PAD& PADR2) && (cameraCounter == 0)) {cameraCounter = 150; // select automatic camera cameraUsed = (cameraUsed+1) % 7; SelectCamera(cameraUsed);}; }; // **** Move an object to a coordinate void MoveModelTo(Object_Header0 *tObject, int tXc, int tYc, int tZc) { tObject->Object_Coord.coord.t[0] = tXc; // set the object's x coord tObject->Object_Coord.coord.t[1] = tYc; // set the object's y coord tObject->Object_Coord.coord.t[2] = tZc; // set the object's z coord tObject->Object_Coord.flg = 0; // signify object has changed }; // **** Move an object to a coordinate void MoveModelTo2(Back_Header1 *tBack, int tXc, int tYc, int tZc) { tBack->Object_Coord.coord.t[0] = tXc; // set the object's x coord tBack->Object_Coord.coord.t[1] = tYc; // set the object's y coord tBack->Object_Coord.coord.t[2] = tZc; // set the object's z coord tBack->Object_Coord.flg = 0; // signify object has changed }; // **** Move an object relative to where it is at the moment void MoveModelBy(Object_Header0 *tObject, int tXv, int tYv, int tZv) { tObject->Object_Coord.coord.t[0] += tXv; // add to the object's x coord tObject->Object_Coord.coord.t[1] += tYv; // add to the object's y coord tObject->Object_Coord.coord.t[2] += tZv; // add to the object's z coord tObject->Object_Coord.flg = 0; // signify object has changed }; // **** Translate an object according to the direction it is facing void MoveModelForward(Object_Header0 *tObject, int tSpeed) { MATRIX tMatrix; // temporary rotation matrix SVECTOR tOneUnitForward, tDirectionResult; // two vectors for rotation if(tSpeed != 0) // as long as speed is not zero, { // (would cause divide by zero error) tOneUnitForward.vx = 0; // to move forward = no x translation tOneUnitForward.vy = 0; // to move forward = no y translation tOneUnitForward.vz = ONE; // to move forward = 4096 z translation RotMatrix(&tObject->rotation, &tMatrix); // turn vector into rotation matrix ApplyMatrixSV(&tMatrix, &tOneUnitForward, &tDirectionResult); // multiply our direction vector with // the rotation matrix and give the // result as another direction vector tObject->Object_Coord.coord.t[0] += tDirectionResult.vx * tSpeed / 4096; tObject->Object_Coord.coord.t[1] += tDirectionResult.vy * tSpeed / 4096; tObject->Object_Coord.coord.t[2] += tDirectionResult.vz * tSpeed / 4096; tObject->Object_Coord.flg = 0; // signify object has changed }; }; // **** Rotate an object about it's own center void RotateModel(Object_Header0 *tObject, int tXr, int tYr, int tZr) { MATRIX tMatrix; // temporary rotation matrix ResetRotation(tObject->Object_Coord.coord.m); // reset rotation part of objects // rotation and translation matrix tObject->rotation.vx = (tObject->rotation.vx + tXr) % ONE; // set up rotation about the axes tObject->rotation.vy = (tObject->rotation.vy + tYr) % ONE; tObject->rotation.vz = (tObject->rotation.vz + tZr) % ONE; RotMatrix(&tObject->rotation, &tMatrix); // turn vector into rotation matrix MulMatrix0(&tObject->Object_Coord.coord, &tMatrix, &tObject->Object_Coord.coord); // multiply object and rotation matrices tObject->Object_Coord.flg = 0; // signify object has changed }; // **** Reset a three by three rotation/scaling matrix void ResetRotation(short tArray[3][3]) { tArray[0][0]=tArray[1][1]=tArray[2][2]=ONE; // turn scalars to one tArray[0][1]=tArray[0][2]=tArray[1][0]=tArray[1][2]=tArray[2][0]=tArray[2][1]=0; // turn other cells into zero }; // **** set up the camera and the correct lighting void SelectCamera(long tNumber) { switch(tNumber) // do routine based on which camera... { case 0 : {Fogging.dqa = -5000; // set up reasonable fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 0; break;}; // set the current camera case 1 : {Fogging.dqa = -5000; // set up reasonable fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 1; break;}; // set the current camera case 2 : {Fogging.dqa = -10000; // set up small fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 2; break;}; // set the current camera case 3 : {Fogging.dqa = -15000; // set up very little fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 3; break;}; // set the current camera case 4 : {Fogging.dqa = -5000; // set up reasonable fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 4; break;}; // set the current camera case 5 : {Fogging.dqa = -15000; // set up very little fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 5; break;}; // set the current camera case 6 : {Fogging.dqa = -5000; // set up reasonable fogging GsSetFogParam(&Fogging); // activate new fogging level cameraUsed = 6; break;}; // set the current camera }; }; /* * LIBSOUND.C * * Copyright (C) 1993-1997 by Sony Computer Entertainment of America, Inc. * All rights Reserved * ---------------------------------------------------------------------------- * * This file contains data definitions and function library to handle * sound effects and music in this sample. Care has been taken to make * this function library independent of the rest of the code in this sample * * This library can be easily updated to play any music and sound effect * with minimal changes. * * The structure SOUNDFILE provides acess to various VABs and SEQs. Plaese * make an entry for each VAB/SEQ combination in this table. In case there * is no SEQ to go with a VAB make the corresponding entry for that SEQ as * NULL. * * The structure VOICE provides access to various sound effects contained * in any of the VABs loaded through the SOUNDFILE table. The entries in * this table are self explanatory. For details please checkout the details * below. * ---------------------------------------------------------------------------- */ #include "libmain.h" #include "libsound.h" #include "libdata.h" /* * Sound related variables and functions * --------------------------------------------------------------------------- */ #define SOUND_MAIN_VOLUME 127 // Main volume level #define SOUND_MUSIC_VOLUME 127 // Game music SEQ volume level #define SOUND_SFX_VOLUME 127 // Sound effects volume /* Data structure to handle various sound files - VAB/SEQ files */ typedef struct __soundfile { // Structure to handle various sound files unsigned long *VHptr; // Pointer to VAB header in main memory unsigned long *VBptr; // Pointer to VAB data in main memory unsigned long *SEQptr; // Pointer to SEQ data in main memory short VabId; // VabId assigned by PlayStation OS short SeqId; // Sequence Id assigned by PlayStation OS } SOUNDFILE; #define SOUND_MAXFILES 1 // Maximum number of sound files static SOUNDFILE Sounds[ SOUND_MAXFILES ] = { { ADR_MUSIC_VH, ADR_MUSIC_VB, ADR_MUSIC_SEQ, -1, -1 }, }; /* * Data structures to handle various sound effects * - "SoundIndex" provides an index into the sound file table above. * This means that this particular voice sample is contained in * the which VAB. * * - "VabId" is the id secured by the initialization routines for * the VAB - indexed by SoundIndex. * * - "Program" is the index to the program in VAB where this voice belongs * This value is predefined at the time of the VAB creation. * * - "Tone" is the index to the voice in a particular "Program". * This value is predefined at the time of the VAB creation. * * - "Note" is the note being played in this voice. * This value is predefined at the time of the VAB creation. * * - "Fine" is the finer pitch value, usually set to 0. * This value is predefined at the time of the VAB creation. * * - "LVolume" and "RVolume" is the maximum volume of this voice * This value is predefined at the time of the VAB creation and * is used along with the panning (to be implemented later) * of the sound depending upon the origin of the voice in th world. */ typedef struct __voice { // Index into the SOUNDFILE table above short SoundIndex; // Index into the sound file list short VabId; // Vab Id used here short Program; // Program from the above vab short Tone; // Tone for this voice short Note; // Pitch specification for this voice short Fine; // Fine pitch specification short LVolume; // Maximum left volume for the voice short RVolume; // Maximum right volume for the voice } VOICE; static VOICE Voices[ SOUND_VC_MAXNO ] = { { 0, -1, 0x0000, 0, 0x0018, 0x0000, 96, 96 }, { 0, -1, 0x0000, 1, 0x0019, 0x0000, 96, 96 }, { 0, -1, 0x0000, 2, 0x001A, 0x0000, 96, 96 }, { 0, -1, 0x0000, 3, 0x001B, 0x0000, 96, 96 }, }; /* * Data structure to handle a voice table - * manages a FIFO queue for voices to be played */ typedef struct __voiceq { // Queue structure to handle voices short VoiceId; // Voice Id used for this entry VOICE *Voice; // Voice used in this queue } VOICEQ; #define SOUND_VQ_MAXNO 10 // Maximum length of FIFO queue for Voice IDs static VOICEQ VoiceQ[ SOUND_VQ_MAXNO ]; // FIFO queue for Voice IDs assigned static short VoiceQTop = -1; // Top of the FIFO queue for Voice IDs /* Sound data on memory playback preparation */ void SoundInit(void) { short i; for (i = 0; i < SOUND_MAXFILES; i++) { /* VAB opening and transmission to sound buffer */ if ((Sounds[i].VHptr != NULL) && (Sounds[i].VBptr != NULL)) { Sounds[i].VabId = SsVabTransfer( (unsigned char *)Sounds[i].VHptr, (unsigned char *)Sounds[i].VBptr, -1, 1); if (Sounds[i].VabId < 0) printf("SsVabTransfer(i = %d) failed (VabId = %d)\n", i, Sounds[i].VabId); } else { Sounds[i].VabId = -1; } /* SEQ opening */ if (Sounds[i].SEQptr != NULL) { Sounds[i].SeqId = SsSeqOpen( Sounds[i].SEQptr, Sounds[i].VabId); if (Sounds[i].SeqId < 0) printf("SsSeqOpen(i = %d) failed (VabId = %d)\n", i, Sounds[i].SeqId); } else { Sounds[i].SeqId = -1; } } /* Initialize saucer voices */ for (i = 0; i < SOUND_VC_MAXNO; i++) { Voices[i].VabId = Sounds[ Voices[i].SoundIndex ].VabId; } /* Initialize voice FIFO queue */ SoundVoiceQInit(); /* Set the main volume */ SsSetMVol(SOUND_MAIN_VOLUME, SOUND_MAIN_VOLUME); return; } /* Sound playback start */ void SoundPlayMusic(void) { /* Set Volume for the sequence */ SsSeqSetVol(Sounds[0].SeqId, SOUND_MUSIC_VOLUME, SOUND_MUSIC_VOLUME); /* Start play back of game music */ SsSeqPlay(Sounds[0].SeqId, SSPLAY_PLAY, SSPLAY_INFINITY); return; } /* Sound playback termination */ void SoundStop(void) { short i; /* Release all acquired voices */ SoundVoiceQFlush(); /* Stop the game music */ SsSeqStop(Sounds[0].SeqId); /* Wait for music to stop - give it some time, will you ? */ VSync(0); VSync(0); for (i = 0; i < SOUND_MAXFILES; i++) { /* Release SEQuence ID */ if (Sounds[i].SeqId != -1) SsSeqClose(Sounds[i].SeqId); /* Release VAB ID */ if (Sounds[i].VabId != -1) SsVabClose(Sounds[i].VabId); } return; } /* Initialize the voice FIFO queue */ void SoundVoiceQInit(void) { VoiceQTop = -1; return; } /* Enter the given voice in the voice queue by acquiring a new voice */ void SoundVoiceQPlay(short voice_index) { VOICE *voice = &Voices[ voice_index ]; short i, top = VoiceQTop+1; if (top >= SOUND_VQ_MAXNO) { /* * Stop the oldest voice in the queue currently being * used for sound effect. Release this voice id and * remove the voice from the queue. */ if (VoiceQ[0].VoiceId != -1) { VOICE *tmp = VoiceQ[0].Voice; SsUtKeyOff(VoiceQ[0].VoiceId, tmp->VabId, tmp->Program, tmp->Tone, tmp->Note); } for (i = 1 ; i < top ; i++) { VoiceQ[i-1].VoiceId = VoiceQ[i].VoiceId; VoiceQ[i-1].Voice = VoiceQ[i].Voice; } top --; } /* * Play the sound effect for the given voice by requesting a * new voice id and putting this voice in the voice queue. */ VoiceQ[top].Voice = voice; VoiceQ[top].VoiceId = SsUtKeyOn(voice->VabId, voice->Program, voice->Tone, voice->Note, voice->Fine, voice->LVolume, voice->RVolume); /* Set the new top of the queue */ VoiceQTop = top; return; } /* Flush voice queue */ void SoundVoiceQFlush(void) { short i; for (i = 0 ; i <= VoiceQTop ; i++) { if (VoiceQ[i].VoiceId != -1) { VOICE *tmp = VoiceQ[i].Voice; SsUtKeyOff(VoiceQ[i].VoiceId, tmp->VabId, tmp->Program, tmp->Tone, tmp->Note); } } VoiceQTop = -1; return; } /* * End of File * ---------------------------------------------------------------------------- */