/** Used to get the normal vector of the road (pointing upward). Local coordinates are used to locate the point where to get the road normal vector. The vector is normalized. @ingroup tracktools @param p Local position @param norm Returned normalized road normal vector */ void RtTrackSurfaceNormalL(tTrkLocPos *p, t3Dd *norm) { tTrkLocPos p1; t3Dd px1, px2, py1, py2; t3Dd v1, v2; tdble lg; p1.seg = p->seg; p1.toStart = 0; p1.toRight = p->toRight; RtTrackLocal2Global(&p1, &px1.x, &px1.y, TR_TORIGHT); px1.z = RtTrackHeightL(&p1); if (p1.seg->type == TR_STR) { p1.toStart = p1.seg->length; } else { p1.toStart = p1.seg->arc; } RtTrackLocal2Global(&p1, &px2.x, &px2.y, TR_TORIGHT); px2.z = RtTrackHeightL(&p1); p1.toRight = 0; p1.toStart = p->toStart; RtTrackLocal2Global(&p1, &py1.x, &py1.y, TR_TORIGHT); py1.z = RtTrackHeightL(&p1); p1.toRight = p1.seg->width; RtTrackLocal2Global(&p1, &py2.x, &py2.y, TR_TORIGHT); py2.z = RtTrackHeightL(&p1); v1.x = px2.x - px1.x; v1.y = px2.y - px1.y; v1.z = px2.z - px1.z; v2.x = py2.x - py1.x; v2.y = py2.y - py1.y; v2.z = py2.z - py1.z; norm->x = v1.y * v2.z - v2.y * v1.z; norm->y = v2.x * v1.z - v1.x * v2.z; norm->z = v1.x * v2.y - v2.x * v1.y; lg = sqrt(norm->x * norm->x + norm->y * norm->y + norm->z * norm->z); if (lg == 0.0) { lg = 1.0f; } else { lg = 1.0f / lg; } norm->x *= lg; norm->y *= lg; norm->z *= lg; }
void PTrackManager::CorrectCars() { for (int i = 0; i < nCars; i++) { tCarElt* curCar = &carList[i]; // If current car on first segment, prevent from leaving segment if (curCar->pub.trkPos.seg->id == 0) { if (curCar->pub.trkPos.toStart < 10) { curCar->pub.trkPos.toStart = 10; RtTrackLocal2Global(&(curCar->_trkPos), &(curCar->_pos_X), &(curCar->_pos_Y), TR_TORIGHT); raceManager->_reSimItf.config(curCar, raceManager); } } } }
void PTrackManager::InitCars() { // Get pointer to car list carList = raceManager->carList; // Retrieve number of cars in race nCars = raceManager->s->raceInfo.ncars; // Start segment tTrackSeg* startSeg = track->GetStart(); // Array of positions tTrkLocPos* positions = new tTrkLocPos[nCars]; for (int i = 0; i < nCars; i++) positions[i] = tTrkLocPos(); // Spacing between cars tdble carXSpacing = (startSeg->width / 2) - 3; // Assuming 3 is around average car width tdble carYSpacing = 20; /* Starting grid positons are calculated regardless of pole position as follows: Y |---------| | P1 P2 | | P3 P4 | | P5 P6 | | P7 P8 | | P9 P10 | |---------| - X */ // Calculate position grid here if (nCars > 1) { int row = 1; for (int i = 0; i < nCars; i++) // Grid Y { tTrkLocPos* curPos = &positions[i]; curPos->seg = startSeg; curPos->toStart = startSeg->length - (carYSpacing * row); if (i % 2 > 0) // RIGHT POS curPos->toMiddle = carXSpacing; else if (i % 2 == 0) // LEFT POS { curPos->toMiddle = -carXSpacing; row++; } } } else { positions[0].seg = startSeg; positions[0].toStart = startSeg->length - carYSpacing; positions[0].toMiddle = carXSpacing; } // Assign car positions for (int i = 0; i < nCars; i++) { // Get the car tCarElt* curCar = &carList[i]; // Assign the car the correct position curCar->pub.trkPos = positions[i]; // Convert the local position to a global one, and assign to car's actual global position RtTrackLocal2Global(&(curCar->_trkPos), &(curCar->_pos_X), &(curCar->_pos_Y), TR_TOMIDDLE); } // Set up cars in physics sim for (int i = 0; i < nCars; i++) { tCarElt* curCar = &carList[i]; raceManager->_reSimItf.config(curCar, raceManager); } delete[] positions; }
/* * Function * initStartingGrid * * Description * Place the cars on the starting grid * * Parameters * Race Information structure initialized * * Return * none */ static void initStartingGrid(void) { char path[64]; int i; tTrackSeg *curseg; int rows; tdble a, b; //tdble wi2; // Never used. tdble d1, d2,d3; tdble startpos, tr, ts; tdble speedInit; tdble heightInit; tCarElt *car; const char *pole; void *trHdle = ReInfo->track->params; void *params = ReInfo->params; snprintf(path, sizeof(path), "%s/%s", ReInfo->_reRaceName, RM_SECT_STARTINGGRID); /* Search for the first turn for find the pole side */ curseg = ReInfo->track->seg->next; while (curseg->type == TR_STR) { /* skip the straight segments */ curseg = curseg->next; } /* Set the pole for the inside of the first turn */ if (curseg->type == TR_LFT) { pole = GfParmGetStr(params, path, RM_ATTR_POLE, "left"); } else { pole = GfParmGetStr(params, path, RM_ATTR_POLE, "right"); } /* Tracks definitions can force the pole side */ pole = GfParmGetStr(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_POLE, pole); if (strcmp(pole, "left") == 0) { a = ReInfo->track->width; b = -a; } else { a = 0; b = ReInfo->track->width; } //wi2 = ReInfo->track->width * 0.5f; // Never used. rows = (int)GfParmGetNum(params, path, RM_ATTR_ROWS, (char*)NULL, 2); rows = (int)GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_ROWS, (char*)NULL, (tdble)rows); d1 = GfParmGetNum(params, path, RM_ATTR_TOSTART, (char*)NULL, 10); d1 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_TOSTART, (char*)NULL, d1); d2 = GfParmGetNum(params, path, RM_ATTR_COLDIST, (char*)NULL, 10); d2 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_COLDIST, (char*)NULL, d2); d3 = GfParmGetNum(params, path, RM_ATTR_COLOFFSET, (char*)NULL, 5); d3 = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_COLOFFSET, (char*)NULL, d3); speedInit = GfParmGetNum(params, path, RM_ATTR_INITSPEED, (char*)NULL, 0.0); heightInit = GfParmGetNum(params, path, RM_ATTR_INITHEIGHT, (char*)NULL, 0.3f); heightInit = GfParmGetNum(trHdle, RM_SECT_STARTINGGRID, RM_ATTR_INITHEIGHT, (char*)NULL, heightInit); if (rows < 1) { rows = 1; } for (i = 0; i < ReInfo->s->_ncars; i++) { car = &(ReInfo->carList[i]); car->_speed_x = speedInit; startpos = ReInfo->track->length - (d1 + (i / rows) * d2 + (i % rows) * d3); tr = a + b * ((i % rows) + 1) / (rows + 1); curseg = ReInfo->track->seg; /* last segment */ while (startpos < curseg->lgfromstart) { curseg = curseg->prev; } ts = startpos - curseg->lgfromstart; car->_trkPos.seg = curseg; car->_trkPos.toRight = tr; switch (curseg->type) { case TR_STR: car->_trkPos.toStart = ts; RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT); car->_yaw = curseg->angle[TR_ZS]; break; case TR_RGT: car->_trkPos.toStart = ts / curseg->radius; RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT); car->_yaw = curseg->angle[TR_ZS] - car->_trkPos.toStart; break; case TR_LFT: car->_trkPos.toStart = ts / curseg->radius; RtTrackLocal2Global(&(car->_trkPos), &(car->_pos_X), &(car->_pos_Y), TR_TORIGHT); car->_yaw = curseg->angle[TR_ZS] + car->_trkPos.toStart; break; } car->_pos_Z = RtTrackHeightL(&(car->_trkPos)) + heightInit; FLOAT_NORM0_2PI(car->_yaw); RePhysicsEngine().configureCar(car); } }
static void RemoveCar(tCar *car, tSituation *s) { int i; tCarElt *carElt; tTrkLocPos trkPos; int trkFlag; tdble travelTime; tdble dang; #define PULL_Z_OFFSET 3.0 #define PULL_SPD 0.5 carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_PULLUP) { carElt->_pos_Z += car->restPos.vel.z * SimDeltaTime; carElt->_yaw += car->restPos.vel.az * SimDeltaTime; carElt->_roll += car->restPos.vel.ax * SimDeltaTime; carElt->_pitch += car->restPos.vel.ay * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z > (car->restPos.pos.z + PULL_Z_OFFSET)) { carElt->_state &= ~RM_CAR_STATE_PULLUP; carElt->_state |= RM_CAR_STATE_PULLSIDE; travelTime = DIST(car->restPos.pos.x, car->restPos.pos.y, carElt->_pos_X, carElt->_pos_Y) / PULL_SPD; car->restPos.vel.x = (car->restPos.pos.x - carElt->_pos_X) / travelTime; car->restPos.vel.y = (car->restPos.pos.y - carElt->_pos_Y) / travelTime; } return; } if (carElt->_state & RM_CAR_STATE_PULLSIDE) { carElt->_pos_X += car->restPos.vel.x * SimDeltaTime; carElt->_pos_Y += car->restPos.vel.y * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if ((fabs(car->restPos.pos.x - carElt->_pos_X) < 0.5) && (fabs(car->restPos.pos.y - carElt->_pos_Y) < 0.5)) { carElt->_state &= ~RM_CAR_STATE_PULLSIDE; carElt->_state |= RM_CAR_STATE_PULLDN; } return; } if (carElt->_state & RM_CAR_STATE_PULLDN) { carElt->_pos_Z -= car->restPos.vel.z * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, RAD2DEG(carElt->_yaw), RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z < car->restPos.pos.z) { carElt->_state &= ~RM_CAR_STATE_PULLDN; carElt->_state |= RM_CAR_STATE_OUT; } return; } if (carElt->_state & RM_CAR_STATE_NO_SIMU) { return; } if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { carElt->_state |= RM_CAR_STATE_BROKEN; } else { carElt->_state |= RM_CAR_STATE_OUTOFGAS; } carElt->_gear = car->transmission.gearbox.gear = 0; carElt->_enginerpm = car->engine.rads = 0; if (!(carElt->_state & RM_CAR_STATE_DNF)) { if (fabs(carElt->_speed_x) > 1.0) { return; } } carElt->_state |= RM_CAR_STATE_PULLUP; carElt->priv.collision = car->collision = 0; for(i = 0; i < 4; i++) { carElt->_skid[i] = 0; carElt->_wheelSpinVel(i) = 0; carElt->_brakeTemp(i) = 0; } carElt->pub.DynGC = car->DynGC; carElt->_speed_x = 0; /* compute the target zone for the wrecked car */ trkPos = car->trkPos; if (trkPos.toRight > trkPos.seg->width / 2.0) { while (trkPos.seg->lside != 0) { trkPos.seg = trkPos.seg->lside; } trkPos.toLeft = -3.0; trkFlag = TR_TOLEFT; } else { while (trkPos.seg->rside != 0) { trkPos.seg = trkPos.seg->rside; } trkPos.toRight = -3.0; trkFlag = TR_TORIGHT; } trkPos.type = TR_LPOS_SEGMENT; RtTrackLocal2Global(&trkPos, &(car->restPos.pos.x), &(car->restPos.pos.y), trkFlag); car->restPos.pos.z = RtTrackHeightL(&trkPos) + carElt->_statGC_z; car->restPos.pos.az = RtTrackSideTgAngleL(&trkPos); car->restPos.pos.ax = 0; car->restPos.pos.ay = 0; car->restPos.vel.z = PULL_SPD; travelTime = (car->restPos.pos.z + PULL_Z_OFFSET - carElt->_pos_Z) / car->restPos.vel.z; dang = car->restPos.pos.az - carElt->_yaw; NORM_PI_PI(dang); car->restPos.vel.az = dang / travelTime; dang = car->restPos.pos.ax - carElt->_roll; NORM_PI_PI(dang); car->restPos.vel.ax = dang / travelTime; dang = car->restPos.pos.ay - carElt->_pitch; NORM_PI_PI(dang); car->restPos.vel.ay = dang / travelTime; }
void grCustomizePits(void) { tTrackPitInfo *pits; int i; tdble x, y; tdble x2, y2, z2; ThePits = new ssgBranch(); PitsAnchor->addKid(ThePits); pits = &(grTrack->pits); /* draw the pit identification */ switch (pits->type) { case TR_PIT_ON_TRACK_SIDE: for (i = 0; i < pits->nMaxPits; i++) { char buf[256]; t3Dd normalvector; sgVec3 vtx; sgVec4 clr = {0,0,0,1}; sgVec3 nrm; sgVec2 tex; ssgState *st; ssgVertexArray *pit_vtx = new ssgVertexArray(4); ssgTexCoordArray *pit_tex = new ssgTexCoordArray(4); ssgColourArray *pit_clr = new ssgColourArray(1); ssgNormalArray *pit_nrm = new ssgNormalArray(1); pit_clr->add(clr); if (pits->driversPits[i].car[0]) { // If we have more than one car in the pit use the team pit logo of driver 0. if (pits->driversPits[i].freeCarIndex == 1) { // One car assigned to the pit. sprintf(buf, "drivers/%s/%d;drivers/%s;data/textures;data/img;.", pits->driversPits[i].car[0]->_modName, pits->driversPits[i].car[0]->_driverIndex, pits->driversPits[i].car[0]->_modName); } else { // Multiple cars assigned to the pit. sprintf(buf, "drivers/%s;data/textures;data/img;.", pits->driversPits[i].car[0]->_modName); } } else { sprintf(buf, "data/textures;data/img;."); } st = grSsgLoadTexStateEx("logo.rgb", buf, FALSE, FALSE); ((ssgSimpleState*)st)->setShininess(50); RtTrackLocal2Global(&(pits->driversPits[i].pos), &x, &y, pits->driversPits[i].pos.type); RtTrackSideNormalG(pits->driversPits[i].pos.seg, x, y, pits->side, &normalvector); x2 = x - pits->width/2.0 * normalvector.x + pits->len/2.0 * normalvector.y; y2 = y - pits->width/2.0 * normalvector.y - pits->len/2.0 * normalvector.x; z2 = RtTrackHeightG(pits->driversPits[i].pos.seg, x2, y2); nrm[0] = normalvector.x; nrm[1] = normalvector.y; nrm[2] = 0; pit_nrm->add(nrm); tex[0] = -0.7; tex[1] = 0.33; vtx[0] = x2; vtx[1] = y2; vtx[2] = z2; pit_tex->add(tex); pit_vtx->add(vtx); tex[0] = -0.7; tex[1] = 1.1; vtx[0] = x2; vtx[1] = y2; vtx[2] = z2 + 4.8; pit_tex->add(tex); pit_vtx->add(vtx); x2 = x - pits->width/2.0 * normalvector.x - pits->len/2.0 * normalvector.y; y2 = y - pits->width/2.0 * normalvector.y + pits->len/2.0 * normalvector.x; z2 = RtTrackHeightG(pits->driversPits[i].pos.seg, x2, y2); tex[0] = 1.3; tex[1] = 0.33; vtx[0] = x2; vtx[1] = y2; vtx[2] = z2; pit_tex->add(tex); pit_vtx->add(vtx); tex[0] = 1.3; tex[1] = 1.1; vtx[0] = x2; vtx[1] = y2; vtx[2] = z2 + 4.8; pit_tex->add(tex); pit_vtx->add(vtx); ssgVtxTable *pit = new ssgVtxTable(GL_TRIANGLE_STRIP, pit_vtx, pit_nrm, pit_tex, pit_clr); pit->setState(st); pit->setCullFace(0); ThePits->addKid(pit); } break; case TR_PIT_ON_SEPARATE_PATH: break; case TR_PIT_NONE: break; } }
static void RemoveCar(tCar *car, tSituation *s) { int i; tCarElt *carElt; tTrkLocPos trkPos; int trkFlag; tdble travelTime; tdble dang; static tdble PULL_Z_OFFSET = 3.0; static tdble PULL_SPD = 0.5; carElt = car->carElt; if (carElt->_state & RM_CAR_STATE_PULLUP) { carElt->_pos_Z += car->restPos.vel.z * SimDeltaTime; carElt->_yaw += car->restPos.vel.az * SimDeltaTime; carElt->_roll += car->restPos.vel.ax * SimDeltaTime; carElt->_pitch += car->restPos.vel.ay * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z > (car->restPos.pos.z + PULL_Z_OFFSET)) { carElt->_state &= ~RM_CAR_STATE_PULLUP; carElt->_state |= RM_CAR_STATE_PULLSIDE; // Moved pullside velocity computation down due to floating point error accumulation. } return; } if (carElt->_state & RM_CAR_STATE_PULLSIDE) { // Recompute speed to avoid missing the parking point due to error accumulation (the pos might be // in the 0-10000 range, depending on the track and vel*dt is around 0-0.001, so basically all // but the most significant digits are lost under bad conditions, happens e.g on e-track-4). // Should not lead to a division by zero because the pullside process stops if the car is within // [0.5, 0.5]. Do not move it back. travelTime = DIST(car->restPos.pos.x, car->restPos.pos.y, carElt->_pos_X, carElt->_pos_Y) / PULL_SPD; car->restPos.vel.x = (car->restPos.pos.x - carElt->_pos_X) / travelTime; car->restPos.vel.y = (car->restPos.pos.y - carElt->_pos_Y) / travelTime; carElt->_pos_X += car->restPos.vel.x * SimDeltaTime; carElt->_pos_Y += car->restPos.vel.y * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if ((fabs(car->restPos.pos.x - carElt->_pos_X) < 0.5) && (fabs(car->restPos.pos.y - carElt->_pos_Y) < 0.5)) { carElt->_state &= ~RM_CAR_STATE_PULLSIDE; carElt->_state |= RM_CAR_STATE_PULLDN; } return; } if (carElt->_state & RM_CAR_STATE_PULLDN) { carElt->_pos_Z -= car->restPos.vel.z * SimDeltaTime; sgMakeCoordMat4(carElt->pub.posMat, carElt->_pos_X, carElt->_pos_Y, carElt->_pos_Z - carElt->_statGC_z, (float) RAD2DEG(carElt->_yaw), (float) RAD2DEG(carElt->_roll), (float) RAD2DEG(carElt->_pitch)); if (carElt->_pos_Z < car->restPos.pos.z) { carElt->_state &= ~RM_CAR_STATE_PULLDN; carElt->_state |= RM_CAR_STATE_OUT; } return; } if (carElt->_state & (RM_CAR_STATE_NO_SIMU & ~RM_CAR_STATE_PIT)) { return; } if (carElt->_state & RM_CAR_STATE_PIT) { if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { // Broken during pit stop. carElt->_state &= ~RM_CAR_STATE_PIT; carElt->_pit->pitCarIndex = TR_PIT_STATE_FREE; } else { return; } } if ((s->_maxDammage) && (car->dammage > s->_maxDammage)) { carElt->_state |= RM_CAR_STATE_BROKEN; } else { carElt->_state |= RM_CAR_STATE_OUTOFGAS; } carElt->_gear = car->transmission.gearbox.gear = 0; carElt->_enginerpm = car->engine.rads = 0; if (!(carElt->_state & RM_CAR_STATE_DNF)) { if (fabs(carElt->_speed_x) > 1.0) { return; } } carElt->_state |= RM_CAR_STATE_PULLUP; // RM_CAR_STATE_NO_SIMU evaluates to > 0 from here, so we remove the car from the // collision detection. SimCollideRemoveCar(car, s->_ncars); carElt->priv.collision = car->collision = 0; for(i = 0; i < 4; i++) { carElt->_skid[i] = 0; carElt->_wheelSpinVel(i) = 0; carElt->_brakeTemp(i) = 0; } carElt->pub.DynGC = car->DynGC; carElt->_speed_x = 0; // Compute the target zone for the wrecked car. trkPos = car->trkPos; if (trkPos.toRight > trkPos.seg->width / 2.0) { while (trkPos.seg->lside != 0) { trkPos.seg = trkPos.seg->lside; } trkPos.toLeft = -3.0; trkFlag = TR_TOLEFT; } else { while (trkPos.seg->rside != 0) { trkPos.seg = trkPos.seg->rside; } trkPos.toRight = -3.0; trkFlag = TR_TORIGHT; } trkPos.type = TR_LPOS_SEGMENT; RtTrackLocal2Global(&trkPos, &(car->restPos.pos.x), &(car->restPos.pos.y), trkFlag); car->restPos.pos.z = RtTrackHeightL(&trkPos) + carElt->_statGC_z; car->restPos.pos.az = RtTrackSideTgAngleL(&trkPos); car->restPos.pos.ax = 0; car->restPos.pos.ay = 0; car->restPos.vel.z = PULL_SPD; travelTime = (car->restPos.pos.z + PULL_Z_OFFSET - carElt->_pos_Z) / car->restPos.vel.z; dang = car->restPos.pos.az - carElt->_yaw; FLOAT_NORM_PI_PI(dang); car->restPos.vel.az = dang / travelTime; dang = car->restPos.pos.ax - carElt->_roll; FLOAT_NORM_PI_PI(dang); car->restPos.vel.ax = dang / travelTime; dang = car->restPos.pos.ay - carElt->_pitch; FLOAT_NORM_PI_PI(dang); car->restPos.vel.ay = dang / travelTime; }