TORCS  1.3.9
The Open Racing Car Simulator
collide.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : collide.cpp
4  created : Sun Mar 19 00:06:19 CET 2000
5  copyright : (C) 2000-2017 by Eric Espie, Bernhard Wymann
6  email : torcs@free.fr
7  version : $Id$
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  * *
13  * This program is free software; you can redistribute it and/or modify *
14  * it under the terms of the GNU General Public License as published by *
15  * the Free Software Foundation; either version 2 of the License, or *
16  * (at your option) any later version. *
17  * *
18  ***************************************************************************/
19 
20 #include "sim.h"
21 
22 #define CAR_DAMMAGE 0.1
23 
24 
25 void SimCarCollideZ(tCar *car)
26 {
27  int i;
28  const float CRASH_THRESHOLD = -5.0f;
29 
30  if (car->carElt->_state & RM_CAR_STATE_NO_SIMU) {
31  return;
32  }
33 
34  // Calculate transformation matrix to transform the surface normal into the car body local coordinate system.
35  // Because this is just a rotation matrix the inverse is the transposed matrix.
36  sgMat4 dst;
37  sgMakeRotMat4(dst, RAD2DEG(car->DynGC.pos.az), RAD2DEG(car->DynGC.pos.ax), RAD2DEG(car->DynGC.pos.ay));
38  sgTransposeNegateMat4(dst);
39 
40  // Get the normal of the surface under the center of gravity of the car. Beware, TR_LPOS_SEGMENT must
41  // be set to get this result.
42  t3Dd normal;
43  tTrkLocPos normalPos;
44  RtTrackGlobal2Local(car->trkPos.seg, car->DynGCg.pos.x, car->DynGCg.pos.y, &normalPos, TR_LPOS_SEGMENT);
45  RtTrackSurfaceNormalL(&normalPos, &normal);
46 
47  // Now transform the normal to the car body coordinate system.
48  sgVec3 dstVec;
49  sgXformVec3(dstVec, (float *) &normal.x, dst);
50  tdble sumdz = 0.0f;
51 
52  // Check if any car corners are below the surface. If so, try to rotate the corner out of the ground.
53  for (i = 0; i < 4; i++) {
54  tTrkLocPos cornerPos;
55  RtTrackGlobal2Local(car->trkPos.seg, car->corner[i].pos.ax, car->corner[i].pos.ay, &cornerPos, TR_LPOS_SEGMENT);
56  tdble z = RtTrackHeightL(&cornerPos);
57  tdble dz = car->corner[i].pos.az - z;
58  sumdz += dz;
59 
60  // Car corner below surface
61  if (dz < 0.0f) {
62  tdble dPosAy = dz/car->corner[i].pos.x*fabs(dstVec[0]);
63  car->DynGCg.pos.ay += dPosAy;
64  tdble dPosAx = dz/car->corner[i].pos.y*fabs(dstVec[1]);
65  car->DynGCg.pos.ax -= dPosAx;
67  }
68  }
69 
70  if (sumdz > 0.0f) sumdz = 0.0f;
71 
72  // The above part cannot resolve the collision in all cases, e.g. when all corners are below the surface.
73  // For this case we check if the car floor below the center of gravity is eventually below the ground too.
74  tdble z = RtTrackHeightG(car->trkPos.seg, car->DynGCg.pos.x, car->DynGCg.pos.y);
75  tdble dz = car->DynGCg.pos.z - (car->statGC.z - sumdz)/normal.z - z;
76 
77  if (dz < 0.0f) {
78  tdble dotProd = (car->DynGCg.vel.x * normal.x + car->DynGCg.vel.y * normal.y + car->DynGCg.vel.z * normal.z);
79  if (dotProd < 0.0f) {
80  if (dotProd < CRASH_THRESHOLD) {
82  }
84  car->DynGCg.vel.x -= normal.x * dotProd;
85  car->DynGCg.vel.y -= normal.y * dotProd;
86  car->DynGCg.vel.z -= normal.z * dotProd;
87 
88  if ((car->carElt->_state & RM_CAR_STATE_FINISH) == 0) {
89  car->dammage += (int)(normalPos.seg->surface->kDammage * fabs(dotProd) * rulesDamageFactor * simDammageFactor[car->carElt->_skillLevel]);
90  }
91  }
92  }
93 }
94 
95 const tdble BorderFriction = 0.0f;
96 
97 // Collision of car/track borders.
98 // Be aware that it does not work for convex edges (e.g. e-track-2, end of the straight, left),
99 // because under these conditions it is possible that all car corners are on the track and
100 // the car body is partially outside the track.
102 {
103  tTrackSeg *seg = car->trkPos.seg;
104  tTrkLocPos trkpos;
105  int i;
106  tDynPt *corner;
107  tdble initDotProd;
108  tdble dotProd, cx, cy, dotprod2;
109  tTrackBarrier *curBarrier;
110  tdble dmg;
111 
112  if (car->carElt->_state & RM_CAR_STATE_NO_SIMU) {
113  return;
114  }
115 
116  corner = &(car->corner[0]);
117  for (i = 0; i < 4; i++, corner++) {
118  seg = car->trkPos.seg;
119  RtTrackGlobal2Local(seg, corner->pos.ax, corner->pos.ay, &trkpos, TR_LPOS_TRACK);
120  seg = trkpos.seg;
121  tdble toSide;
122 
123  if (trkpos.toRight < 0.0) {
124  // collision with right border.
125  curBarrier = seg->barrier[TR_SIDE_RGT];
126  toSide = trkpos.toRight;
127  } else if (trkpos.toLeft < 0.0) {
128  // collision with left border.
129  curBarrier = seg->barrier[TR_SIDE_LFT];
130  toSide = trkpos.toLeft;
131  } else {
132  continue;
133  }
134 
135  const tdble& nx = curBarrier->normal.x;
136  const tdble& ny = curBarrier->normal.y;
137 
138  car->DynGCg.pos.x -= nx * toSide;
139  car->DynGCg.pos.y -= ny * toSide;
140 
141  // Corner position relative to center of gravity.
142  cx = corner->pos.ax - car->DynGCg.pos.x;
143  cy = corner->pos.ay - car->DynGCg.pos.y;
144 
145  car->blocked = 1;
146  car->collision |= SEM_COLLISION;
147 
148  // Impact speed perpendicular to barrier (of corner).
149  initDotProd = nx * corner->vel.x + ny * corner->vel.y;
150 
151  // Compute dmgDotProd (base value for later damage) with a heuristic.
152  tdble absvel = MAX(1.0, sqrt(car->DynGCg.vel.x*car->DynGCg.vel.x + car->DynGCg.vel.y*car->DynGCg.vel.y));
153  tdble GCgnormvel = car->DynGCg.vel.x*nx + car->DynGCg.vel.y*ny;
154  tdble cosa = GCgnormvel/absvel;
155  tdble dmgDotProd = GCgnormvel*cosa;
156 
157  dotProd = initDotProd * curBarrier->surface->kFriction;
158  car->DynGCg.vel.x -= nx * dotProd;
159  car->DynGCg.vel.y -= ny * dotProd;
160  dotprod2 = (nx * cx + ny * cy);
161 
162  // Angular velocity change caused by friction of colliding car part with wall.
163  static tdble VELSCALE = 10.0f;
164  static tdble VELMAX = 6.0f;
165  car->DynGCg.vel.az -= dotprod2 * dotProd / VELSCALE;
166  if (fabs(car->DynGCg.vel.az) > VELMAX) {
167  car->DynGCg.vel.az = SIGN(car->DynGCg.vel.az) * VELMAX;
168  }
169 
170  // Damage.
171  dotProd = initDotProd;
172  if (dotProd < 0.0f && (car->carElt->_state & RM_CAR_STATE_FINISH) == 0) {
173  dmg = curBarrier->surface->kDammage * (0.5f*dmgDotProd*dmgDotProd + 0.005f*fabs(1.0f-cosa)*absvel) * rulesDamageFactor * simDammageFactor[car->carElt->_skillLevel];
174  car->dammage += (int) dmg;
175  } else {
176  dmg = 0.0f;
177  }
178 
179  dotProd *= curBarrier->surface->kRebound;
180 
181  // If the car moves toward the barrier, rebound.
182  if (dotProd < 0.0f) {
184  car->normal.x = nx * dmg;
185  car->normal.y = ny * dmg;
186  car->collpos.x = corner->pos.ax;
187  car->collpos.y = corner->pos.ay;
188  car->DynGCg.vel.x -= nx * dotProd;
189  car->DynGCg.vel.y -= ny * dotProd;
190  }
191  }
192 }
193 
194 
195 static void SimCarCollideResponse(void * /*dummy*/, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData)
196 {
197  sgVec2 n; // Collision normal delivered by solid: Global(point1) - Global(point2)
198  tCar *car[2]; // The cars.
199  sgVec2 p[2]; // Collision points delivered by solid, in body local coordinates.
200  sgVec2 r[2]; // Collision point relative to center of gravity.
201  sgVec2 vp[2]; // Speed of collision point in world coordinate system.
202  sgVec3 pt[2]; // Collision points in global coordinates.
203 
204  int i;
205 
206  car[0] = (tCar*)obj1;
207  car[1] = (tCar*)obj2;
208 
209  // Handle cars collisions during pit stops as well.
210  static const int NO_SIMU_WITHOUT_PIT = RM_CAR_STATE_NO_SIMU & ~RM_CAR_STATE_PIT;
211 
212  if ((car[0]->carElt->_state & NO_SIMU_WITHOUT_PIT) ||
213  (car[1]->carElt->_state & NO_SIMU_WITHOUT_PIT))
214  {
215  return;
216  }
217 
218  if (car[0]->carElt->index < car[1]->carElt->index) {
219  // vector conversion from double to float.
220  p[0][0] = (float)collData->point1[0];
221  p[0][1] = (float)collData->point1[1];
222  p[1][0] = (float)collData->point2[0];
223  p[1][1] = (float)collData->point2[1];
224  n[0] = (float)collData->normal[0];
225  n[1] = (float)collData->normal[1];
226  } else {
227  // swap the cars (not the same for the simu).
228  car[0] = (tCar*)obj2;
229  car[1] = (tCar*)obj1;
230  p[0][0] = (float)collData->point2[0];
231  p[0][1] = (float)collData->point2[1];
232  p[1][0] = (float)collData->point1[0];
233  p[1][1] = (float)collData->point1[1];
234  n[0] = -(float)collData->normal[0];
235  n[1] = -(float)collData->normal[1];
236  }
237 
238  sgNormaliseVec2(n);
239 
240  // Because of the type conversion and the transformation to 2D the length of the normal might be 0 now, which could cause NaN
241  if (isnan(n[0]) || isnan(n[1])) {
242  return;
243  }
244 
245  sgVec2 rg[2]; // radius oriented in global coordinates, still relative to CG (rotated aroung CG).
246  tCarElt *carElt;
247 
248  for (i = 0; i < 2; i++) {
249  // vector GP (Center of gravity to collision point). p1 and p2 are delivered from solid as
250  // points in the car coordinate system.
251  sgSubVec2(r[i], p[i], (const float*)&(car[i]->statGC));
252 
253  // Speed of collision points, linear motion of center of gravity (CG) plus rotational
254  // motion around the CG.
255  carElt = car[i]->carElt;
256  float sina = sin(carElt->_yaw);
257  float cosa = cos(carElt->_yaw);
258  rg[i][0] = r[i][0]*cosa - r[i][1]*sina;
259  rg[i][1] = r[i][0]*sina + r[i][1]*cosa;
260 
261  vp[i][0] = car[i]->DynGCg.vel.x - car[i]->DynGCg.vel.az * rg[i][1];
262  vp[i][1] = car[i]->DynGCg.vel.y + car[i]->DynGCg.vel.az * rg[i][0];
263  }
264 
265  // Relative speed of collision points.
266  sgVec2 v1ab;
267  sgSubVec2(v1ab, vp[0], vp[1]);
268 
269  // try to separate the cars. The computation is necessary because dtProceed is not called till
270  // the collision is resolved.
271  for (i = 0; i < 2; i++) {
272  sgCopyVec2(pt[i], r[i]);
273  pt[i][2] = 0.0f;
274  // Transform points relative to cars local coordinate system into global coordinates.
275  sgFullXformPnt3(pt[i], car[i]->carElt->_posMat);
276  }
277 
278  // Compute distance of collision points.
279  sgVec3 pab;
280  sgSubVec2(pab, pt[1], pt[0]);
281  float distpab = sgLengthVec2(pab);
282 
283  sgVec2 tmpv;
284 
285  sgScaleVec2(tmpv, n, MIN(distpab, 0.05));
286  // No "for" loop here because of subtle difference AddVec/SubVec.
287  if (car[0]->blocked == 0 && !(car[0]->carElt->_state & RM_CAR_STATE_NO_SIMU)) {
288  sgAddVec2((float*)&(car[0]->DynGCg.pos), tmpv);
289  car[0]->blocked = 1;
290  }
291  if (car[1]->blocked == 0 && !(car[1]->carElt->_state & RM_CAR_STATE_NO_SIMU)) {
292  sgSubVec2((float*)&(car[1]->DynGCg.pos), tmpv);
293  car[1]->blocked = 1;
294  }
295 
296  // Doing no dammage and correction if the cars are moving out of each other.
297  if (sgScalarProductVec2(v1ab, n) > 0) {
298  return;
299  }
300 
301  // impulse.
302  float rpn[2];
303  rpn[0] = sgScalarProductVec2(rg[0], n);
304  rpn[1] = sgScalarProductVec2(rg[1], n);
305 
306  // Pseudo cross product to find out if we are left or right.
307  // TODO: SIGN, scrap value?
308  float rpsign[2];
309  rpsign[0] = n[0]*rg[0][1] - n[1]*rg[0][0];
310  rpsign[1] = -n[0]*rg[1][1] + n[1]*rg[1][0];
311 
312  const float e = 1.0f; // energy restitution
313 
314  float j = -(1.0f + e) * sgScalarProductVec2(v1ab, n) /
315  ((car[0]->Minv + car[1]->Minv) +
316  rpn[0] * rpn[0] * car[0]->Iinv.z + rpn[1] * rpn[1] * car[1]->Iinv.z);
317 
318  for (i = 0; i < 2; i++) {
319  if (car[i]->carElt->_state & RM_CAR_STATE_NO_SIMU) {
320  continue;
321  }
322 
323  // Damage.
324  tdble damFactor, atmp;
325  atmp = atan2(r[i][1], r[i][0]);
326  if (fabs(atmp) < (PI / 3.0)) {
327  // Front collision gives more damage.
328  damFactor = 1.5f;
329  } else {
330  // Rear collision gives less damage.
331  damFactor = 1.0f;
332  }
333 
334  if ((car[i]->carElt->_state & RM_CAR_STATE_FINISH) == 0) {
335  car[i]->dammage += (int)(CAR_DAMMAGE * fabs(j) * damFactor * rulesDamageFactor * simDammageFactor[car[i]->carElt->_skillLevel]);
336  }
337 
338  // Compute collision velocity.
339  const float ROT_K = 1.0f;
340 
341  float js = (i == 0) ? j : -j;
342  sgScaleVec2(tmpv, n, js * car[i]->Minv);
343  sgVec2 v2a;
344 
345  if (car[i]->collision & SEM_COLLISION_CAR) {
346  sgAddVec2(v2a, (const float*)&(car[i]->VelColl.x), tmpv);
347  car[i]->VelColl.az = car[i]->VelColl.az + js * rpsign[i] * rpn[i] * car[i]->Iinv.z * ROT_K;
348  } else {
349  sgAddVec2(v2a, (const float*)&(car[i]->DynGCg.vel), tmpv);
350  car[i]->VelColl.az = car[i]->DynGCg.vel.az + js * rpsign[i] * rpn[i] * car[i]->Iinv.z * ROT_K;
351  }
352 
353  static float VELMAX = 3.0f;
354  if (fabs(car[i]->VelColl.az) > VELMAX) {
355  car[i]->VelColl.az = SIGN(car[i]->VelColl.az) * VELMAX;
356  }
357 
358  sgCopyVec2((float*)&(car[i]->VelColl.x), v2a);
359 
360  // Move the car for the collision lib.
361  tCarElt *carElt = car[i]->carElt;
362  sgMakeCoordMat4(carElt->pub.posMat, car[i]->DynGCg.pos.x, car[i]->DynGCg.pos.y,
363  car[i]->DynGCg.pos.z - carElt->_statGC_z, RAD2DEG(carElt->_yaw),
364  RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch));
365  dtSelectObject(car[i]);
366  dtLoadIdentity();
367  dtMultMatrixf((const float *)(carElt->_posMat));
368 
369  car[i]->collision |= SEM_COLLISION_CAR;
370  }
371 }
372 
373 
374 // Collision response for walls.
375 // TODO: Separate common code with car-car collision response.
376 static void SimCarWallCollideResponse(void *clientdata, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData)
377 {
378  tCar* car; // The car colliding with the wall.
379  float nsign; // Normal direction correction for collision plane.
380  sgVec2 p; // Cars collision point delivered by solid.
381 
382  // TODO: If other movable objects are added which could collide with the wall, it will be
383  // necessary to validate if the object is actually a car.
384 
385  if (obj1 == clientdata) {
386  car = (tCar*) obj2;
387  nsign = -1.0f;
388  p[0] = (float) collData->point2[0];
389  p[1] = (float) collData->point2[1];
390  } else {
391  car = (tCar*) obj1;
392  nsign = 1.0f;
393  p[0] = (float) collData->point1[0];
394  p[1] = (float) collData->point1[1];
395  }
396 
397  sgVec2 n; // Collision normal delivered by solid, corrected such that it points away from the wall.
398  n[0] = nsign * (float) collData->normal[0];
399  n[1] = nsign * (float) collData->normal[1];
400  float pdist = sgLengthVec2(n); // Distance of collision points.
401  sgNormaliseVec2(n);
402 
403  // Because of the type conversion and the transformation to 2D the length of the normal might be 0 now, which could cause NaN
404  if (isnan(n[0]) || isnan(n[1])) {
405  return;
406  }
407 
408  sgVec2 r;
409  sgSubVec2(r, p, (const float*)&(car->statGC));
410 
411  tCarElt *carElt = car->carElt;
412 
413  sgVec2 vp; // Speed of car collision point in global frame of reference.
414  sgVec2 rg; // raduis oriented in global coordinates, still relative to CG (rotated aroung CG).
415 
416  float sina = sin(carElt->_yaw);
417  float cosa = cos(carElt->_yaw);
418  rg[0] = r[0]*cosa - r[1]*sina;
419  rg[1] = r[0]*sina + r[1]*cosa;
420 
421  vp[0] = car->DynGCg.vel.x - car->DynGCg.vel.az * rg[1];
422  vp[1] = car->DynGCg.vel.y + car->DynGCg.vel.az * rg[0];
423 
424  sgVec2 tmpv;
425  static const float CAR_MIN_MOVEMENT = 0.02f;
426  static const float CAR_MAX_MOVEMENT = 0.05f;
427  sgScaleVec2(tmpv, n, MIN(MAX(pdist, CAR_MIN_MOVEMENT), CAR_MAX_MOVEMENT));
428  if (car->blocked == 0) {
429  sgAddVec2((float*)&(car->DynGCg.pos), tmpv);
430  car->blocked = 1;
431  }
432 
433  // Doing no dammage and correction if the cars are moving out of each other.
434  if (sgScalarProductVec2(vp, n) > 0) {
435  return;
436  }
437 
438  float rp = sgScalarProductVec2(rg, n);
439 
440  // Pesudo cross product to find out if we are left or right.
441  // TODO: SIGN, scrap value?
442  float rpsign = n[0]*rg[1] - n[1]*rg[0];
443 
444  const float e = 1.0f; // energy restitution
445  float j = -(1.0f + e) * sgScalarProductVec2(vp, n) / (car->Minv + rp * rp * car->Iinv.z);
446  const float ROT_K = 0.5f;
447 
448  // Damage.
449  tdble damFactor, atmp;
450  atmp = atan2(r[1], r[0]);
451  if (fabs(atmp) < (PI / 3.0)) {
452  // Front collision gives more damage.
453  damFactor = 1.5f;
454  } else {
455  // Rear collision gives less damage.
456  damFactor = 1.0f;
457  }
458 
459  static const float DMGFACTOR = 0.00002f;
460  if ((car->carElt->_state & RM_CAR_STATE_FINISH) == 0) {
461  car->dammage += (int)(CAR_DAMMAGE * (DMGFACTOR*j*j) * damFactor * rulesDamageFactor * simDammageFactor[car->carElt->_skillLevel]);
462  }
463 
464  sgScaleVec2(tmpv, n, j * car->Minv);
465  sgVec2 v2a;
466 
467  if (car->collision & SEM_COLLISION_CAR) {
468  sgAddVec2(v2a, (const float*)&(car->VelColl.x), tmpv);
469  car->VelColl.az = car->VelColl.az + j * rp * rpsign * car->Iinv.z * ROT_K;
470  } else {
471  sgAddVec2(v2a, (const float*)&(car->DynGCg.vel), tmpv);
472  car->VelColl.az = car->DynGCg.vel.az + j * rp * rpsign * car->Iinv.z * ROT_K;
473  }
474 
475  static float VELMAX = 3.0f;
476  if (fabs(car->VelColl.az) > VELMAX) {
477  car->VelColl.az = SIGN(car->VelColl.az) * VELMAX;
478  }
479 
480  sgCopyVec2((float*)&(car->VelColl.x), v2a);
481 
482  // Move the car for the collision lib.
483  sgMakeCoordMat4(carElt->pub.posMat, car->DynGCg.pos.x, car->DynGCg.pos.y,
484  car->DynGCg.pos.z - carElt->_statGC_z, RAD2DEG(carElt->_yaw),
485  RAD2DEG(carElt->_roll), RAD2DEG(carElt->_pitch));
486  dtSelectObject(car);
487  dtLoadIdentity();
488  dtMultMatrixf((const float *)(carElt->_posMat));
489 
491 }
492 
493 
494 // Remove wrecked cars to avoid glitches in collision detection and to improve performance.
495 // Called by RemoveCar.
496 void SimCollideRemoveCar(tCar *car, int nbcars)
497 {
498  // Find the car to remove.
499  int i;
500  for (i = 0; i < nbcars; i++) {
501  if (&SimCarTable[i] == car) {
502  break;
503  }
504  }
505 
506  // Remove it.
507  if (SimCarTable[i].shape != NULL) {
509  dtDeleteShape(SimCarTable[i].shape);
510  SimCarTable[i].shape = NULL;
511  }
512 }
513 
514 
515 // Static object and shape list.
516 // TODO: Dynamic implementation.
518 // Id to the next free slot in fixedobjects.
519 static unsigned int fixedid;
520 
521 
522 void SimCarCollideShutdown(int nbcars)
523 {
524  int i;
525 
526  for (i = 0; i < nbcars; i++) {
527  // Check if car has not been removed already (wrecked).
528  if (SimCarTable[i].shape != NULL) {
530  dtDeleteShape(SimCarTable[i].shape);
531  }
532  }
533 
534  unsigned int j;
535  for (j = 0; j < fixedid; j++) {
539  }
540  fixedid = 0;
541 
543 }
544 
545 
546 // Searching backwards for the first non wall segments to start.
547 // Used for the creation of collision detection model of the wall.
548 static tTrackSeg *getFirstWallStart(tTrackSeg *start, int side)
549 {
550  tTrackSeg *first = start;
551 
552  // Moving backward out of wall.
553  do {
554  // A wall is a wall on the track if it is not the barrier at the same time.
555  if (first->side[side] != NULL && first->side[side]->style == TR_WALL &&
556  first->side[side]->side[side] != NULL)
557  {
558  first = first->prev;
559  } else {
560  break;
561  }
562  } while (first != start);
563 
564  // Searching forward for the first wall segment.
565  start = first;
566  do {
567  if (first->side[side] != NULL && first->side[side]->style == TR_WALL &&
568  first->side[side]->side[side] != NULL)
569  {
570  return first;
571  } else {
572  first = first->next;
573  }
574  } while (first != start);
575 
576  return NULL;
577 }
578 
579 
580 // Create the left walls, start must point to a segment with a wall on the left and a leading
581 // non wall segment.
582 // FIXME: Does not work for a closed ring "by design".
583 void buildWalls(tTrackSeg *start, int side) {
584 
585  if (start == NULL) {
586  return;
587  }
588 
589  tTrackSeg *current = start;
590  bool close = false;
591 
592  // Going down the wall.
593  do {
594  tTrackSeg* s = current->side[side];
595  tTrackSeg* p = current->prev->side[side];
596  tTrackSeg* n = current->next->side[side];
597 
598  // Current segment is a wall?
599  if (s != NULL && s->style == TR_WALL && s->side[side] != NULL) {
600 
601  float h = s->height;
602  t3Dd svl = s->vertex[TR_SL];
603  t3Dd svr = s->vertex[TR_SR];
604  t3Dd evl = s->vertex[TR_EL];
605  t3Dd evr = s->vertex[TR_ER];
606  static float weps = 0.01f;
607 
608  // Close the start with a ploygon?
609  if (p == NULL || p->style != TR_WALL ||
610  (fabs(p->vertex[TR_EL].x - svl.x) > weps) ||
611  (fabs(p->vertex[TR_ER].x - svr.x) > weps) ||
612  (fabs(h - p->height) > weps) ||
613  fixedid == 0)
614  {
615  // Enough space in array?
616  if (fixedid >= sizeof(fixedobjects)/sizeof(fixedobjects[0])) {
617  GfError("fixedobjects full in %s, line %d\n", __FILE__, __LINE__);
618  return;
619  }
620 
621  if (close == true) {
623  GfError("Shape not closed %s, line %d\n", __FILE__, __LINE__);
624  }
625 
626  // Start new shape.
628  fixedid++;
629  close = true;
630 
632  dtVertex(svl.x, svl.y, svl.z);
633  dtVertex(svr.x, svr.y, svr.z);
634  dtVertex(svr.x, svr.y, svr.z + h);
635  dtVertex(svl.x, svl.y, svl.z + h);
636  dtEnd();
637  }
638 
639  // Build sides, left, top, right. Depending on how we want to use it we
640  // can remove top perhaps.
641  // TODO: do we want the top poly?
642  if (close == true) {
643  // Left.
645  dtVertex(svl.x, svl.y, svl.z);
646  dtVertex(svl.x, svl.y, svl.z + h);
647  dtVertex(evl.x, evl.y, evl.z + h);
648  dtVertex(evl.x, evl.y, evl.z);
649  dtEnd();
650  /*
651  // Top.
652  dtBegin(DT_POLYGON);
653  dtVertex(svl.x, svl.y, svl.z + h);
654  dtVertex(svr.x, svr.y, svr.z + h);
655  dtVertex(evr.x, evr.y, evr.z + h);
656  dtVertex(evl.x, evl.y, evl.z + h);
657  dtEnd();*/
658  // Right.
660  dtVertex(svr.x, svr.y, svr.z + h);
661  dtVertex(svr.x, svr.y, svr.z);
662  dtVertex(evr.x, evr.y, evr.z);
663  dtVertex(evr.x, evr.y, evr.z + h);
664  dtEnd();
665  } else {
666  GfError("Shape not open %s, line %d\n", __FILE__, __LINE__);
667  }
668 
669  // Close the end with a ploygon?
670  if (n == NULL || n->style != TR_WALL ||
671  (fabs(n->vertex[TR_SL].x - evl.x) > weps) ||
672  (fabs(n->vertex[TR_SR].x - evr.x) > weps) ||
673  (fabs(h - n->height) > weps))
674  {
675  if (close == true) {
677  dtVertex(svl.x, svl.y, svl.z);
678  dtVertex(svr.x, svr.y, svr.z);
679  dtVertex(svr.x, svr.y, svr.z + h);
680  dtVertex(svl.x, svl.y, svl.z + h);
681  dtEnd();
682 
684  close = false;
685  } else {
686  GfError("Shape not open %s, line %d\n", __FILE__, __LINE__);
687  }
688  }
689 
690  }
691 
692  current = current->next;
693 
694  } while (current != start);
695 
696 }
697 
698 
699 void
701 {
702  tCarElt *carElt;
703 
704  // Create car collision objects.
705  carElt = car->carElt;
706  // The current car shape is a box...
707  car->shape = dtBox(carElt->_dimension_x, carElt->_dimension_y, carElt->_dimension_z);
708  dtCreateObject(car, car->shape);
709 
710  car->collisionAware = 1;
711 
712  // Create fixed track collision objects (just pit wall for now).
713  // TODO: car body/curbs collision.
714  // TODO: car body/flat wall collision (e.g. for pavement, sidewalk).
715  // TODO: define static objects in XML file/tTrack, collide with them as well.
716 }
717 
718 
719 void
721 {
723  // Hmm, why is caching disabled, are our objects too fast, so it does not work?
724  // TODO: understand this and reconsider caching.
726  dtSetTolerance(0.001);
727 
728  fixedid = 0;
729 
730  if (track != NULL) {
731  tTrackSeg *firstleft = getFirstWallStart(track->seg, TR_SIDE_LFT);
732  tTrackSeg *firstright = getFirstWallStart(track->seg, TR_SIDE_RGT);
733 
734  buildWalls(firstleft, TR_SIDE_LFT);
735  buildWalls(firstright, TR_SIDE_RGT);
736 
737  unsigned int i;
738  for (i = 0; i < fixedid; i++) {
741  }
742  }
743 }
744 
745 
746 // TODO: Rename, because actually the dtProceed handles all solid managed objects, e.g. walls.
747 void
749 {
750  tCar *car;
751  tCarElt *carElt;
752  int i;
753 
754  for (i = 0; i < s->_ncars; i++) {
755  carElt = s->cars[i];
756  if (carElt->_state & RM_CAR_STATE_NO_SIMU) {
757  continue;
758  }
759 
760  car = &(SimCarTable[carElt->index]);
761  dtSelectObject(car);
762  // Fit the bounding box around the car, statGC's are the static offsets.
763  dtLoadIdentity();
764  // Place the bounding box such that it fits the car in the world.
765  dtMultMatrixf((const float *)(carElt->_posMat));
766  memset(&(car->VelColl), 0, sizeof(tPosd));
767  }
768 
769  // Running the collision detection. If no collision is detected, call dtProceed.
770  // dtProceed just works if all objects are disjoint.
771  if (dtTest() == 0) {
772  dtProceed();
773  }
774 
775  for (i = 0; i < s->_ncars; i++) {
776  carElt = s->cars[i];
777  if (carElt->_state & RM_CAR_STATE_NO_SIMU) {
778  continue;
779  }
780  car = &(SimCarTable[carElt->index]);
781  if (car->collision & SEM_COLLISION_CAR) {
782  car->DynGCg.vel.x = car->VelColl.x;
783  car->DynGCg.vel.y = car->VelColl.y;
784  car->DynGCg.vel.az = car->VelColl.az;
785  }
786  }
787 }
788 
T x
Definition: v2_t.h:83
tdble RtTrackHeightL(tTrkLocPos *p)
Returns the absolute height in meters of the road at the Local position p.
Definition: rttrack.cpp:314
#define GfError
Definition: tgf.h:351
void SimCarCollideCars(tSituation *s)
Definition: collide.cpp:748
#define TR_SR
Start-Right corner.
Definition: track.h:333
tDynPt corner[4]
Definition: carstruct.h:74
int collision
Definition: carstruct.h:75
void dtDeleteObject(DtObjectRef object)
Definition: C-api.cpp:206
tDynPt DynGC
Definition: carstruct.h:64
#define TR_ER
End_Right corner.
Definition: track.h:335
cars situation used to inform the GUI and the drivers
Definition: raceman.h:85
tdble toRight
Distance (+ to left, - to right) relative to the right side of segment.
Definition: track.h:432
sgMat4 posMat
position matrix
Definition: car.h:195
tdble y
y coordinate
Definition: tgf.h:132
tdble RtTrackHeightG(tTrackSeg *seg, tdble X, tdble Y)
Returns the absolute height in meters of the road at the Global position (segment, X, Y)
Definition: rttrack.cpp:443
tCarElt ** cars
list of cars
Definition: raceman.h:90
#define SEM_COLLISION_Z_CRASH
Definition: car.h:694
Location on the track in local coordinates.
Definition: track.h:418
tdble Minv
Definition: carstruct.h:57
Car structure (tCarElt).
Definition: car.h:455
#define TR_SL
Start-Left corner.
Definition: track.h:332
#define SIGN(x)
Sign of the expression.
Definition: tgf.h:78
Definition: carstruct.h:35
Track structure.
Definition: track.h:502
DtVector point1
Definition: solid.h:56
void SimCarCollideShutdown(int nbcars)
Definition: collide.cpp:522
void dtLoadIdentity()
Definition: C-api.cpp:228
vec2f normal
Definition: track.h:264
void dtSetObjectResponse(DtObjectRef object, DtResponse response, DtResponseType type, void *client_data)
Definition: C-api.cpp:259
void dtVertex(DtScalar x, DtScalar y, DtScalar z)
Definition: C-api.cpp:124
const double PI
PI.
Definition: tgf.h:69
#define SEM_COLLISION_CAR
Definition: car.h:692
#define TR_SIDE_LFT
Definition: track.h:403
void dtProceed()
Definition: C-api.cpp:288
tdble ay
angle along y axis
Definition: tgf.h:135
#define RM_CAR_STATE_NO_SIMU
Do not simulate the car.
Definition: car.h:217
tdble kRebound
Coefficient of energy restitution.
Definition: track.h:248
void SimCarCollideZ(tCar *car)
Definition: collide.cpp:25
#define RAD2DEG(x)
Radian to degree conversion.
Definition: tgf.h:75
void buildWalls(tTrackSeg *start, int side)
Definition: collide.cpp:583
void SimCarCollideConfig(tCar *car, tTrack *track)
Definition: collide.cpp:700
t3Dd Iinv
Definition: carstruct.h:60
void RtTrackGlobal2Local(tTrackSeg *segment, tdble X, tdble Y, tTrkLocPos *p, int type)
Convert a Global (segment, X, Y) position into a Local one (segment, toRight, toStart)The segment in ...
Definition: rttrack.cpp:156
tCar * SimCarTable
Definition: simu.cpp:34
void dtBegin(DtPolyType type)
Definition: C-api.cpp:118
void dtSetTolerance(DtScalar tol)
Definition: C-api.cpp:306
tTrackBarrier * barrier[2]
Segment barriers.
Definition: track.h:395
tTrackSurface * surface
Barrier surface.
Definition: track.h:263
tdble toLeft
Distance (- to left, + to right) relative to left side of segment.
Definition: track.h:434
void dtClearObjectResponse(DtObjectRef object)
Definition: C-api.cpp:264
void dtMultMatrixf(const float *m)
Definition: C-api.cpp:240
static DtShapeRef fixedobjects[100]
Definition: collide.cpp:517
tdble rulesDamageFactor
Definition: simu.cpp:40
float tdble
Floating point type used in TORCS.
Definition: tgf.h:48
tTrkLocPos trkPos
Definition: carstruct.h:68
DtShapeRef dtNewComplexShape()
Definition: C-api.cpp:100
Definition: Endpoint.h:36
void SimCarCollideXYScene(tCar *car)
Definition: collide.cpp:101
static jsJoystick * js[NUM_JOY]
static void SimCarCollideResponse(void *, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData)
Definition: collide.cpp:195
static void SimCarWallCollideResponse(void *clientdata, DtObjectRef obj1, DtObjectRef obj2, const DtCollData *collData)
Definition: collide.cpp:376
struct trackSeg * side[2]
Definition: track.h:407
tdble x
x coordinate
Definition: tgf.h:131
Barrier.
Definition: track.h:259
static Point p[4]
Definition: Convex.cpp:54
T y
Definition: v2_t.h:83
tCarElt * carElt
Definition: carstruct.h:40
tPublicCar pub
public
Definition: car.h:459
DtShapeRef shape
Definition: carstruct.h:81
void dtDisableCaching()
Definition: C-api.cpp:304
tdble y
y coordinate
Definition: tgf.h:117
t3Dd collpos
Definition: carstruct.h:77
tdble z
z coordinate
Definition: tgf.h:118
DtVector normal
Definition: solid.h:58
6 DOF position.
Definition: tgf.h:130
t3Dd vertex[4]
Coordinates of the 4 corners of the segment.
Definition: track.h:325
tDynPt DynGCg
Definition: carstruct.h:65
void dtSelectObject(DtObjectRef object)
Definition: C-api.cpp:198
int index
car index
Definition: car.h:457
const tdble BorderFriction
Definition: collide.cpp:95
#define TR_SIDE_RGT
Definition: track.h:404
tdble simDammageFactor[]
Definition: categories.cpp:30
tdble height
Max height for curbs.
Definition: track.h:363
void SimCarCollideInit(tTrack *track)
Definition: collide.cpp:720
tTrackSeg * seg
Track segment.
Definition: track.h:420
t3Dd normal
Definition: carstruct.h:76
#define TR_EL
End-Left corner.
Definition: track.h:334
Track segment (tTrackSeg) The segments can be straights (type TR_STR): (the track goes from the right...
Definition: track.h:276
int track(tModInfo *modInfo)
Definition: trackitf.cpp:85
void dtDeleteShape(DtShapeRef shape)
Definition: C-api.cpp:170
DtVector point2
Definition: solid.h:57
void dtEndComplexShape()
Definition: C-api.cpp:105
int collisionAware
Definition: carstruct.h:87
#define RM_CAR_STATE_PIT
Car currently stopped in pits.
Definition: car.h:211
tdble az
angle along z axis
Definition: tgf.h:136
tPosd vel
velocity
Definition: tgf.h:145
struct trackSeg * prev
Previous segment.
Definition: track.h:398
tTrackSurface * surface
Segment surface.
Definition: track.h:394
static unsigned int fixedid
Definition: collide.cpp:519
tdble kDammage
Dammages in case of collision.
Definition: track.h:252
struct trackSeg * next
Next segment.
Definition: track.h:397
#define TR_LPOS_SEGMENT
Relative to the segment which the point is located, including border and sides, mostly used for conta...
Definition: track.h:428
int dammage
Definition: carstruct.h:83
tPosd VelColl
Definition: carstruct.h:66
Definition: Endpoint.h:36
3D point.
Definition: tgf.h:115
int blocked
Definition: carstruct.h:82
t3Dd statGC
Definition: carstruct.h:59
tdble ax
angle along x axis
Definition: tgf.h:134
void * DtObjectRef
Definition: solid.h:39
static tRmRaceParam rp
Definition: racemanmenu.cpp:47
#define SEM_COLLISION_XYSCENE
Definition: car.h:691
void SimCollideRemoveCar(tCar *car, int nbcars)
Definition: collide.cpp:496
Dynamic point structure.
Definition: tgf.h:142
int style
Border and barrier segments style:
Definition: track.h:302
DtCount dtTest()
Definition: C-api.cpp:346
void * DtShapeRef
Definition: solid.h:40
void RtTrackSurfaceNormalL(tTrkLocPos *p, t3Dd *norm)
Used to get the normal vector of the road (pointing upward).
Definition: rttrack.cpp:540
#define TR_LPOS_TRACK
Local position relative to the outermost barriers, mostly used for collision detection with barrier...
Definition: track.h:429
#define SEM_COLLISION_Z
Definition: car.h:693
tPosd pos
position
Definition: tgf.h:144
void dtEnd()
Definition: C-api.cpp:119
tdble kFriction
Coefficient of friction.
Definition: track.h:247
DtShapeRef dtBox(DtScalar x, DtScalar y, DtScalar z)
Definition: C-api.cpp:84
static tTrackSeg * getFirstWallStart(tTrackSeg *start, int side)
Definition: collide.cpp:548
tdble x
x coordinate
Definition: tgf.h:116
#define CAR_DAMMAGE
Definition: collide.cpp:22
void dtClearDefaultResponse()
Definition: C-api.cpp:255
void dtCreateObject(DtObjectRef object, DtShapeRef shape)
Definition: C-api.cpp:193
#define SEM_COLLISION
Definition: car.h:690
#define RM_CAR_STATE_FINISH
Car having passed the finish line.
Definition: car.h:210
tdble z
z coordinate
Definition: tgf.h:133
void dtSetDefaultResponse(DtResponse response, DtResponseType type, void *client_data)
Definition: C-api.cpp:250
#define TR_WALL
Wall (barrier only)
Definition: track.h:311