#include "header.h" // **** 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, 6, (u_long*)getScratchAddr(0)); // Put object in OTable ready for drawing }; // **** draw the entire track on screen void DrawTrack(Track_Header0 *tTrack, GsOT *tOTable, u_long tOffset) { u_long tTemp1; long tTemp2 = 32; u_long IsTransparent; MATRIX tLocalWorld, tLocalScreen; // create two MATRIX structures int tCounter; for (tTemp1 = 0; tTemp1 < tTemp2; tTemp1++) { // go through every cell in data array tCounter = (tTemp1 + tOffset + GROUND_OBJECTS -1) % GROUND_OBJECTS; 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 if ((RawGroundArray[tCounter] == TREE_L) || (RawGroundArray[tCounter] == TREE_R)) { IsTransparent = TRANSPARENCY + (1<<28) + (1<<29); } else IsTransparent = 0; if ((RawGroundArray[tCounter] == LEFT) || (RawGroundArray[tCounter] == RIGHT)) tTemp2 -=4; if (RawGroundArray[tCounter] == TUNNEL) tTemp2 -=4; // if ((labs(CarModel.Object_Coord.coord.t[0] - GroundCheck1[tCounter][0])) < (GROUND_SIZE<<1) && // (labs(CarModel.Object_Coord.coord.t[2] - GroundCheck1[tCounter][1])) < (GROUND_SIZE<<1)) if ((tCounter == ((tOffset) % GROUND_OBJECTS)) && ((RawGroundArray[tCounter] != LEFT) && (RawGroundArray[tCounter] != RIGHT))) { tTrack->Object_Handler[tCounter].attribute = GsDIV1 + IsTransparent; } else { tTrack->Object_Handler[tCounter].attribute = IsTransparent; }; GsSortObject4( &tTrack->Object_Handler[tCounter], tOTable, 4, (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() { SetVideoMode(MODE_PAL); // define screen as PAL // SetVideoMode(MODE_NTSC); // define screen as NTSC 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 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 }; // **** 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 // tObject->Object_Handler.attribute += (1<<30); }; // **** Add information to track header t specify a 3d model to be associated with it void AddModelToTrack(Track_Header0 *tTrack, int tX, int tY, int tZ, u_long *tMemAddress) { u_long tNumber = tTrack->numberObjects; 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, 96, 96); // define light InitLight(&LightSource, 0, -1, 1, 0, 96, 127, 96); // define light // GsSetAmbient(0, 0, 0); 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; }; // **** 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 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 = 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 }; // **** Rotate an object about it's own center void RotateModelTo(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 = tXr % ONE; // set up rotation about the axes tObject->rotation.vy = tYr % ONE; 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 };