1
2 /***************************************************************************
3
4 file : grcar.cpp
5 created : Mon Aug 21 18:24:02 CEST 2000
6 copyright : (C) 2000 by Eric Espie
7 email : torcs@free.fr
8 version : $Id: grcar.cpp,v 1.42.2.9 2012/06/06 13:56:39 berniw Exp $
9
10 ***************************************************************************/
11
12 /***************************************************************************
13 * *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
18 * *
19 ***************************************************************************/
20
21 #include <math.h>
22 #include <stdlib.h>
23 #include <sys/types.h>
24 #include <stdio.h>
25 #include <ctype.h>
26 #ifdef WIN32
27 #include <windows.h>
28 #endif
29 #include <GL/glut.h>
30 #include <plib/ssg.h>
31
32 #include <tgfclient.h>
33 #include <track.h>
34 #include <car.h>
35 #include <graphic.h>
36 #include <robottools.h>
37 #include <portability.h>
38
39 #include "grmain.h"
40 #include "grshadow.h"
41 #include "grskidmarks.h"
42 #include "grsmoke.h"
43 #include "grcar.h"
44 #include "grcam.h"
45 #include "grscene.h"
46 #include "grboard.h"
47 #include "grssgext.h"
48 #include "grutil.h"
49 #include "grcarlight.h"
50
51 extern ssgEntity *grssgLoadAC3D ( const char *fname, const ssgLoaderOptions* options );
52 extern ssgEntity *grssgCarLoadAC3D ( const char *fname, const ssgLoaderOptions* options,int index );
53 extern double carTrackRatioX;
54 extern double carTrackRatioY;
55
56 ssgBranch *CarsAnchorTmp = 0;
57
58
59 static int grCarIndex;
60
61 static ssgSimpleState *brakeState = NULL;
62 static ssgSimpleState *commonState = NULL;
63
grInitCommonState(void)64 void grInitCommonState(void)
65 {
66 // brake
67 if (brakeState == NULL) {
68 brakeState = new ssgSimpleState;
69 brakeState->ref();
70 brakeState->disable(GL_LIGHTING);
71 brakeState->disable(GL_TEXTURE_2D);
72 }
73
74 if (commonState == NULL) {
75 commonState = new ssgSimpleState;
76 commonState->ref();
77 commonState->disable(GL_LIGHTING);
78 commonState->disable(GL_TEXTURE_2D);
79 commonState->setColourMaterial(GL_AMBIENT_AND_DIFFUSE);
80 }
81 }
82
83
84
85
initWheel(tCarElt * car,int wheel_index)86 static ssgTransform *initWheel(tCarElt *car, int wheel_index)
87 {
88 int i, j, k;
89 float alpha;
90 sgVec3 vtx;
91 sgVec4 clr;
92 sgVec3 nrm;
93 sgVec2 tex;
94 tdble b_offset = 0.0f;
95 tdble curAngle = 0.0f;
96
97 #define BRK_BRANCH 16
98 #define BRK_ANGLE (2.0 * M_PI / (tdble)BRK_BRANCH)
99 #define BRK_OFFSET 0.2
100
101 switch(wheel_index) {
102 case FRNT_RGT:
103 curAngle = -(M_PI / 2.0 + BRK_ANGLE);
104 b_offset = BRK_OFFSET - car->_tireWidth(wheel_index) / 2.0;
105 break;
106 case FRNT_LFT:
107 curAngle = -(M_PI / 2.0 + BRK_ANGLE);
108 b_offset = car->_tireWidth(wheel_index) / 2.0 - BRK_OFFSET;
109 break;
110 case REAR_RGT:
111 curAngle = (M_PI / 2.0 - BRK_ANGLE);
112 b_offset = BRK_OFFSET - car->_tireWidth(wheel_index) / 2.0;
113 break;
114 case REAR_LFT:
115 curAngle = (M_PI / 2.0 - BRK_ANGLE);
116 b_offset = car->_tireWidth(wheel_index) / 2.0 - BRK_OFFSET;
117 break;
118 }
119
120 /* hub */
121 ssgVertexArray *brk_vtx = new ssgVertexArray(BRK_BRANCH + 1);
122 ssgColourArray *brk_clr = new ssgColourArray(1);
123 ssgNormalArray *brk_nrm = new ssgNormalArray(1);
124 tdble hubRadius;
125
126 /* center */
127 vtx[0] = vtx[2] = 0.0;
128 vtx[1] = b_offset;
129 brk_vtx->add(vtx);
130
131 hubRadius = car->_brakeDiskRadius(wheel_index) * 0.6;
132 for (i = 0; i < BRK_BRANCH; i++) {
133 alpha = (float)i * 2.0 * M_PI / (float)(BRK_BRANCH - 1);
134 vtx[0] = hubRadius * cos(alpha);
135 vtx[1] = b_offset;
136 vtx[2] = hubRadius * sin(alpha);
137 brk_vtx->add(vtx);
138 }
139
140
141 clr[0] = clr[1] = clr[2] = 0.0;
142 clr[3] = 1.0;
143 brk_clr->add(clr);
144 nrm[0] = nrm[2] = 0.0;
145
146 // Make normal point outside to have proper lighting.
147 switch(wheel_index) {
148 case FRNT_RGT:
149 case REAR_RGT:
150 nrm[1] = -1.0;
151 break;
152 case FRNT_LFT:
153 case REAR_LFT:
154 nrm[1] = 1.0;
155 break;
156 }
157
158 brk_nrm->add(nrm);
159
160 ssgVtxTable *brk = new ssgVtxTable(GL_TRIANGLE_FAN, brk_vtx, brk_nrm, NULL, brk_clr);
161 brk->setCullFace(0);
162 brk->setState(commonState);
163
164 ssgTransform *wheel = new ssgTransform;
165 wheel->addKid(brk);
166
167 /* Brake disk */
168 brk_vtx = new ssgVertexArray(BRK_BRANCH + 4);
169 brk_clr = new ssgColourArray(1);
170 brk_nrm = new ssgNormalArray(1);
171
172 for (i = 0; i < (BRK_BRANCH / 2 + 2); i++) {
173 alpha = curAngle + (float)i * 2.0 * M_PI / (float)(BRK_BRANCH - 1);
174 vtx[0] = car->_brakeDiskRadius(wheel_index) * cos(alpha);
175 vtx[1] = b_offset;
176 vtx[2] = car->_brakeDiskRadius(wheel_index) * sin(alpha);
177 brk_vtx->add(vtx);
178 vtx[0] = car->_brakeDiskRadius(wheel_index) * cos(alpha) * 0.6;
179 vtx[1] = b_offset;
180 vtx[2] = car->_brakeDiskRadius(wheel_index) * sin(alpha) * 0.6;
181 brk_vtx->add(vtx);
182 }
183
184
185 clr[0] = clr[1] = clr[2] = 0.1;
186 clr[3] = 1.0;
187 brk_clr->add(clr);
188 //nrm[0] = nrm[2] = 0.0;
189 //nrm[1] = 1.0;
190 brk_nrm->add(nrm);
191
192 brk = new ssgVtxTable(GL_TRIANGLE_STRIP, brk_vtx, brk_nrm, NULL, brk_clr);
193 brk->setCullFace(0);
194 brk->setState(brakeState);
195 grCarInfo[grCarIndex].brkColor[wheel_index] = brk_clr;
196
197 wheel->addKid(brk);
198
199 /* Brake caliper */
200 brk_vtx = new ssgVertexArray(BRK_BRANCH - 4);
201 brk_clr = new ssgColourArray(1);
202 brk_nrm = new ssgNormalArray(1);
203
204 for (i = 0; i < (BRK_BRANCH / 2 - 2); i++) {
205 alpha = - curAngle + (float)i * 2.0 * M_PI / (float)(BRK_BRANCH - 1);
206 vtx[0] = (car->_brakeDiskRadius(wheel_index) + 0.02) * cos(alpha);
207 vtx[1] = b_offset;
208 vtx[2] = (car->_brakeDiskRadius(wheel_index) + 0.02) * sin(alpha);
209 brk_vtx->add(vtx);
210 vtx[0] = car->_brakeDiskRadius(wheel_index) * cos(alpha) * 0.6;
211 vtx[1] = b_offset;
212 vtx[2] = car->_brakeDiskRadius(wheel_index) * sin(alpha) * 0.6;
213 brk_vtx->add(vtx);
214 }
215
216
217 clr[0] = 0.2;
218 clr[1] = 0.2;
219 clr[2] = 0.2;
220 clr[3] = 1.0;
221 brk_clr->add(clr);
222 //nrm[0] = nrm[2] = 0.0;
223 //nrm[1] = 1.0;
224 brk_nrm->add(nrm);
225
226 brk = new ssgVtxTable(GL_TRIANGLE_STRIP, brk_vtx, brk_nrm, NULL, brk_clr);
227 brk->setCullFace(0);
228 brk->setState(commonState);
229
230 wheel->addKid(brk);
231
232 DBG_SET_NAME(wheel, "Wheel", grCarIndex, wheel_index);
233
234 grCarInfo[grCarIndex].wheelPos[wheel_index] = wheel;
235
236 /* wheels */
237 ssgTransform *whrotation = new ssgTransform;
238 grCarInfo[grCarIndex].wheelRot[wheel_index] = whrotation;
239 wheel->addKid(whrotation);
240 ssgSelector *whselector = new ssgSelector;
241 whrotation->addKid(whselector);
242 grCarInfo[grCarIndex].wheelselector[wheel_index] = whselector;
243
244 float wheelRadius = car->_rimRadius(wheel_index) + car->_tireHeight(wheel_index);
245
246 // Create wheels for 4 speeds (stillstanding - fast --> motion blur, look at the texture).
247 for (j = 0; j < 4; j++) {
248 ssgBranch *whl_branch = new ssgBranch;
249 ssgEntity *whl3d = 0;
250
251 // load speed-dependant 3D wheels if available and if detailed wheels are desired.
252 // wheel data files are located in the wheels directory. first set directory.
253 if (grUseDetailedWheels == DETAILED) {
254 const int bufsize = 1024;
255 char buf[bufsize];
256 const char* wheel_dir = GfParmGetStr(car->_carHandle, SECT_GROBJECTS, PRM_WHEEL_3D_DIR, 0);
257 if (wheel_dir != 0) {
258 snprintf(buf, bufsize, "wheels/%s", wheel_dir);
259 ssgModelPath(buf);
260 ssgTexturePath(buf);
261 }
262
263 // set basename for wheel file 0..3 gets appended
264 const char* wheel_obj = GfParmGetStr(car->_carHandle, SECT_GROBJECTS, PRM_WHEEL_3D, 0);
265 if (wheel_obj != 0 && wheel_dir != 0) {
266 snprintf(buf, bufsize, "%s%d.acc", wheel_obj, j);
267 whl3d = grssgCarLoadAC3D(buf, NULL, car->index);
268 }
269 }
270
271 // if we have a 3D wheel, use it. otherwise use normal generated wheel...
272 if (whl3d) {
273 // Adapt size of the wheel
274 ssgTransform *whl_size = new ssgTransform;
275 sgMat4 wheelsz;
276
277 sgSetVec4(wheelsz[0], wheelRadius * 2, SG_ZERO, SG_ZERO, SG_ZERO) ;
278 sgSetVec4(wheelsz[1], SG_ZERO, car->_tireWidth(wheel_index), SG_ZERO, SG_ZERO) ;
279 sgSetVec4(wheelsz[2], SG_ZERO, SG_ZERO, wheelRadius * 2, SG_ZERO) ;
280 sgSetVec4(wheelsz[3], SG_ZERO, SG_ZERO, SG_ZERO, SG_ONE) ;
281
282 whl_size->setTransform(wheelsz);
283
284 whl_size->addKid(whl3d);
285 whl3d = whl_size;
286
287 if (wheel_index == FRNT_RGT || wheel_index == REAR_RGT) {
288 // flip wheel around so it faces the right way
289 ssgTransform *whl_mesh_transform = new ssgTransform;
290 sgCoord wheelpos;
291 sgSetCoord(&wheelpos, 0, 0, 0, 180, 0, 0);
292 whl_mesh_transform->setTransform( &wheelpos);
293 whl_mesh_transform->addKid(whl3d);
294 whl_branch->addKid(whl_mesh_transform);
295 } else {
296 whl_branch->addKid(whl3d);
297 }
298 } else {
299 static sgVec2 toffset[4] = { {0.0, 0.5}, {0.5, 0.5}, {0.0, 0.0}, {0.5, 0.0} };
300 // TORCS's standard generated wheel
301 const int WHL_BRANCH = 16;
302
303 /* Tread */
304 {
305 ssgVertexArray *whl_vtx = new ssgVertexArray(2 * WHL_BRANCH);
306 ssgColourArray *whl_clr = new ssgColourArray(2 * WHL_BRANCH);
307 ssgNormalArray *whl_nrm = new ssgNormalArray(1);
308
309 whl_nrm->add(nrm);
310 clr[3] = 1.0;
311 for (i = 0; i < WHL_BRANCH; i++) {
312 alpha = (float)i * 2.0 * M_PI / (float)(WHL_BRANCH - 1);
313 vtx[0] = wheelRadius * cos(alpha);
314 vtx[2] = wheelRadius * sin(alpha);
315 vtx[1] = - car->_tireWidth(wheel_index) / 2.0;
316 whl_vtx->add(vtx);
317 vtx[1] = car->_tireWidth(wheel_index) / 2.0;
318 whl_vtx->add(vtx);
319 if (i % 2) {
320 clr[0] = clr[1] = clr[2] = 0.15;
321 } else {
322 clr[0] = clr[1] = clr[2] = 0.0;
323 }
324 whl_clr->add(clr);
325 whl_clr->add(clr);
326 }
327 ssgVtxTable *whl = new ssgVtxTable(GL_TRIANGLE_STRIP, whl_vtx, whl_nrm, NULL, whl_clr);
328 whl->setState(commonState);
329 whl->setCullFace(0);
330
331 // stripify wheel, should improve performance
332 ssgStripify(whl);
333
334 whl_branch->addKid(whl);
335 }
336
337 /* Rim */
338 switch(wheel_index) {
339 case FRNT_RGT:
340 case REAR_RGT:
341 b_offset = -0.05;
342 break;
343 case FRNT_LFT:
344 case REAR_LFT:
345 b_offset = 0.05;
346 break;
347 }
348
349 // Make inside rim very dark and take care of normals.
350 float colorfactor[2];
351 float norm_orig = nrm[1];
352
353 if (nrm[1] > 0.0f) {
354 colorfactor[0] = 0.3f;
355 colorfactor[1] = 1.0f;
356 nrm[1] *= -1.0f;
357 } else {
358 colorfactor[0] = 1.0f;
359 colorfactor[1] = 0.3f;
360 }
361
362 for (k = 0; k < 2; k++) {
363 ssgVertexArray *whl_vtx = new ssgVertexArray(WHL_BRANCH + 1);
364 ssgTexCoordArray *whl_tex = new ssgTexCoordArray(WHL_BRANCH + 1);
365 ssgColourArray *whl_clr = new ssgColourArray(1);
366 ssgNormalArray *whl_nrm = new ssgNormalArray(1);
367
368 clr[0] = 0.8f*colorfactor[k];
369 clr[1] = 0.8f*colorfactor[k];
370 clr[2] = 0.8f*colorfactor[k];
371 clr[3] = 1.0f;
372
373 whl_clr->add(clr);
374 whl_nrm->add(nrm);
375 vtx[0] = vtx[2] = 0.0;
376 vtx[1] = (float)(2 * k - 1) * car->_tireWidth(wheel_index) / 2.0 - b_offset;
377 whl_vtx->add(vtx);
378 tex[0] = 0.25 + toffset[j][0];
379 tex[1] = 0.25 + toffset[j][1];
380 whl_tex->add(tex);
381 vtx[1] = (float)(2 * k - 1) * car->_tireWidth(wheel_index) / 2.0;
382 for (i = 0; i < WHL_BRANCH; i++) {
383 alpha = (float)i * 2.0 * M_PI / (float)(WHL_BRANCH - 1);
384 vtx[0] = wheelRadius * cos(alpha);
385 vtx[2] = wheelRadius * sin(alpha);
386 whl_vtx->add(vtx);
387 tex[0] = 0.25 + 0.25 * cos(alpha) + toffset[j][0];
388 tex[1] = 0.25 + 0.25 * sin(alpha) + toffset[j][1];
389 whl_tex->add(tex);
390 }
391 ssgVtxTable *whl = new ssgVtxTable(GL_TRIANGLE_FAN, whl_vtx, whl_nrm, whl_tex, whl_clr);
392 whl->setState(grCarInfo[grCarIndex].wheelTexture);
393 whl->setCullFace(0);
394
395 // stripify rim, should improve performance
396 ssgStripify(whl);
397
398 whl_branch->addKid(whl);
399
400 // Swap normal for "inside" rim face.
401 nrm[1] *= -1.0;
402 }
403
404 nrm[1] = norm_orig;
405 }
406
407 whselector->addKid(whl_branch);
408 }
409
410 return wheel;
411 }
412
413
414 static const int GR_SHADOW_POINTS = 6;
415
grInitShadow(tCarElt * car)416 void grInitShadow(tCarElt *car)
417 {
418 const int BUFSIZE = 256;
419 char buf[BUFSIZE];
420 const char *shdTexName;
421 int i;
422 float x;
423 sgVec3 vtx;
424 sgVec4 clr;
425 sgVec3 nrm;
426 sgVec2 tex;
427 ssgVertexArray *shd_vtx = new ssgVertexArray(GR_SHADOW_POINTS+1);
428 ssgColourArray *shd_clr = new ssgColourArray(1);
429 ssgNormalArray *shd_nrm = new ssgNormalArray(1);
430 ssgTexCoordArray *shd_tex = new ssgTexCoordArray(GR_SHADOW_POINTS+1);
431
432 snprintf(buf, BUFSIZE, "cars/%s;", car->_carName);
433 grFilePath = buf;
434
435 shdTexName = GfParmGetStr(car->_carHandle, SECT_GROBJECTS, PRM_SHADOW_TEXTURE, "");
436
437 grCarInfo[car->index].shadowAnchor = new ssgBranch();
438
439 clr[0] = clr[1] = clr[2] = 1.0;
440 clr[3] = 1.0;
441 shd_clr->add(clr);
442 nrm[0] = nrm[1] = 0.0;
443 nrm[2] = 1.0;
444 shd_nrm->add(nrm);
445
446 /* vertices */
447 #define MULT 1.1
448 vtx[2] = 0.0;
449 for (i = 0, x = car->_dimension_x * MULT / 2.0; i < GR_SHADOW_POINTS / 2; i++, x -= car->_dimension_x * MULT / (float)(GR_SHADOW_POINTS - 2) * 2.0) {
450 vtx[0] = x;
451 tex[0] = 1.0 - (float)i / (float)((GR_SHADOW_POINTS - 2) / 2.0);
452
453 vtx[1] = -car->_dimension_y * MULT / 2.0;
454 shd_vtx->add(vtx);
455 tex[1] = 0.0;
456 shd_tex->add(tex);
457
458 vtx[1] = car->_dimension_y * MULT / 2.0;
459 shd_vtx->add(vtx);
460 tex[1] = 1.0;
461 shd_tex->add(tex);
462
463 };
464
465 grCarInfo[car->index].shadowBase = new ssgVtxTableShadow(GL_TRIANGLE_STRIP, shd_vtx, shd_nrm, shd_tex, shd_clr);
466 grMipMap = 0;
467 grCarInfo[car->index].shadowBase->setState(grSsgLoadTexState(shdTexName));
468 grCarInfo[car->index].shadowCurr = (ssgVtxTableShadow *)grCarInfo[car->index].shadowBase->clone(SSG_CLONE_GEOMETRY);
469 grCarInfo[car->index].shadowAnchor->addKid(grCarInfo[car->index].shadowCurr);
470 ShadowAnchor->addKid(grCarInfo[car->index].shadowAnchor);
471 grCarInfo[car->index].shadowBase->ref();
472 }
473
474
475
476
grPropagateDamage(ssgEntity * l,sgVec3 poc,sgVec3 force,int cnt)477 void grPropagateDamage (ssgEntity* l, sgVec3 poc, sgVec3 force, int cnt)
478 {
479 //showEntityType (l);
480 if (l->isAKindOf (ssgTypeBranch())) {
481
482 ssgBranch* br = (ssgBranch*) l;
483
484 for (int i = 0 ; i < br -> getNumKids () ; i++ ) {
485 ssgEntity* ln = br->getKid (i);
486 grPropagateDamage(ln, poc, force, cnt+1);
487 }
488 }
489
490 if (l->isAKindOf (ssgTypeVtxTable())) {
491 sgVec3* v;
492 int Nv;
493 ssgVtxTable* vt = (ssgVtxTable*) l;
494 Nv = vt->getNumVertices();
495 vt->getVertexList ((void**) &v);
496 tdble sigma = sgLengthVec3 (force);
497 tdble invSigma = 5.0;
498
499 for (int i=0; i<Nv; i++) {
500 tdble r = sgDistanceSquaredVec3 (poc, v[i]);
501 tdble f = exp(-r*invSigma)*5.0;
502 v[i][0] += force[0]*f;
503 v[i][1] += force[1]*f;
504 // use sigma as a random number generator (!)
505 v[i][2] += (force[2]+0.02*sin(2.0*r + 10.0*sigma))*f;
506 //printf ("(%f %f %f)\n", v[i][0], v[i][1], v[i][2]);
507 }
508 }
509 }
510
511
512 void
grInitCar(tCarElt * car)513 grInitCar(tCarElt *car)
514 {
515 const int BUFSIZE=4096;
516 char buf[BUFSIZE];
517 int index;
518 int selIndex;
519 ssgEntity *carEntity;
520 ssgSelector *LODSel;
521 ssgTransform *wheel[4];
522 int nranges;
523 int i, j;
524 void *handle;
525 const char *param;
526 int lg;
527 const int PATHSIZE=256;
528 char path[PATHSIZE];
529 myLoaderOptions options;
530 sgVec3 lightPos;
531 int lightNum;
532 const char *lightType;
533 int lightTypeNum;
534
535
536 if (!CarsAnchorTmp) {
537 CarsAnchorTmp = new ssgBranch();
538 }
539
540 grInitBoardCar(car);
541
542 TRACE_GL("loadcar: start");
543
544 ssgSetCurrentOptions ( &options ) ;
545
546 grCarIndex = index = car->index; /* current car's index */
547 handle = car->_carHandle;
548
549 /* Load visual attributes */
550 car->_exhaustNb = GfParmGetEltNb(handle, SECT_EXHAUST);
551 car->_exhaustNb = MIN(car->_exhaustNb, 2);
552 car->_exhaustPower = GfParmGetNum(handle, SECT_EXHAUST, PRM_POWER, NULL, 1.0);
553 for (i = 0; i < car->_exhaustNb; i++) {
554 snprintf(path, PATHSIZE, "%s/%d", SECT_EXHAUST, i + 1);
555 car->_exhaustPos[i].x = GfParmGetNum(handle, path, PRM_XPOS, NULL, -car->_dimension_x / 2.0);
556 car->_exhaustPos[i].y = -GfParmGetNum(handle, path, PRM_YPOS, NULL, car->_dimension_y / 2.0);
557 car->_exhaustPos[i].z = GfParmGetNum(handle, path, PRM_ZPOS, NULL, 0.1);
558 }
559
560 snprintf(path, PATHSIZE, "%s/%s", SECT_GROBJECTS, SECT_LIGHT);
561 lightNum = GfParmGetEltNb(handle, path);
562 for (i = 0; i < lightNum; i++) {
563 snprintf(path, PATHSIZE, "%s/%s/%d", SECT_GROBJECTS, SECT_LIGHT, i + 1);
564 lightPos[0] = GfParmGetNum(handle, path, PRM_XPOS, NULL, 0);
565 lightPos[1] = GfParmGetNum(handle, path, PRM_YPOS, NULL, 0);
566 lightPos[2] = GfParmGetNum(handle, path, PRM_ZPOS, NULL, 0);
567 lightType = GfParmGetStr(handle, path, PRM_TYPE, "");
568 lightTypeNum = LIGHT_NO_TYPE;
569 if (!strcmp(lightType, VAL_LIGHT_HEAD1)) {
570 lightTypeNum = LIGHT_TYPE_FRONT;
571 } else if (!strcmp(lightType, VAL_LIGHT_HEAD2)) {
572 lightTypeNum = LIGHT_TYPE_FRONT2;
573 } else if (!strcmp(lightType, VAL_LIGHT_BRAKE)) {
574 lightTypeNum = LIGHT_TYPE_BRAKE;
575 } else if (!strcmp(lightType, VAL_LIGHT_BRAKE2)) {
576 lightTypeNum = LIGHT_TYPE_BRAKE2;
577 } else if (!strcmp(lightType, VAL_LIGHT_REAR)) {
578 lightTypeNum = LIGHT_TYPE_REAR;
579 }
580 grAddCarlight(car, lightTypeNum, lightPos, GfParmGetNum(handle, path, PRM_SIZE, NULL, 0.2));
581 }
582
583 grLinkCarlights(car);
584
585
586 GfOut("[gr] Init(%d) car %s for driver %s index %d\n", index, car->_carName, car->_modName, car->_driverIndex);
587
588 grFilePath = (char*)malloc(BUFSIZE);
589 lg = 0;
590 lg += snprintf(grFilePath + lg, BUFSIZE - lg, "drivers/%s/%d/%s;", car->_modName, car->_driverIndex, car->_carName);
591 lg += snprintf(grFilePath + lg, BUFSIZE - lg, "drivers/%s/%d;", car->_modName, car->_driverIndex);
592 lg += snprintf(grFilePath + lg, BUFSIZE - lg, "drivers/%s/%s;", car->_modName, car->_carName);
593 lg += snprintf(grFilePath + lg, BUFSIZE - lg, "drivers/%s;", car->_modName);
594 lg += snprintf(grFilePath + lg, BUFSIZE - lg, "cars/%s", car->_carName);
595
596 param = GfParmGetStr(handle, SECT_GROBJECTS, PRM_WHEEL_TEXTURE, "");
597 if (strlen(param) != 0) {
598 grGammaValue = 1.8;
599 grMipMap = 0;
600 grCarInfo[index].wheelTexture = grSsgLoadTexState(param);
601 grCarInfo[index].wheelTexture->ref();
602 }
603
604 grCarInfo[index].envSelector = (ssgStateSelector*)grEnvSelector->clone();
605 grCarInfo[index].envSelector->ref();
606
607 /* the base transformation of the car (rotation + translation) */
608 grCarInfo[index].carTransform = new ssgTransform;
609 DBG_SET_NAME(grCarInfo[index].carTransform, car->_modName, index, -1);
610
611 /* Level of details */
612 grCarInfo[index].LODSelector = LODSel = new ssgSelector;
613 grCarInfo[index].carTransform->addKid(LODSel);
614 snprintf(path, PATHSIZE, "%s/%s", SECT_GROBJECTS, LST_RANGES);
615 nranges = GfParmGetEltNb(handle, path) + 1;
616 if (nranges < 2) {
617 GfOut("Error not enough levels of detail\n");
618 FREEZ(grFilePath);
619 return;
620 }
621
622 /* First LOD */
623 ssgBranch *carBody = new ssgBranch;
624 DBG_SET_NAME(carBody, "LOD", index, 0);
625 LODSel->addKid(carBody);
626
627 /* The car's model is under cars/<model> */
628 snprintf(buf, BUFSIZE, "cars/%s", car->_carName);
629 ssgModelPath(buf);
630 snprintf(buf, BUFSIZE, "drivers/%s/%d;drivers/%s;cars/%s", car->_modName, car->_driverIndex, car->_modName, car->_carName);
631 ssgTexturePath(buf);
632 grTexturePath = strdup(buf);
633
634 /* loading raw car level 0*/
635 selIndex = 0; /* current selector index */
636 snprintf(buf, BUFSIZE, "%s.ac", car->_carName); /* default car name */
637 snprintf(path, PATHSIZE, "%s/%s/1", SECT_GROBJECTS, LST_RANGES);
638 param = GfParmGetStr(handle, path, PRM_CAR, buf);
639 grCarInfo[index].LODThreshold[selIndex] = GfParmGetNum(handle, path, PRM_THRESHOLD, NULL, 0.0);
640 /*carEntity = ssgLoad(param);*/
641 carEntity = grssgCarLoadAC3D(param, NULL, index);
642 grCarInfo[index].carEntity = carEntity;
643
644 /* Set a selector on the driver */
645 char* stmp = strdup("DRIVER");
646 ssgBranch *b = (ssgBranch *)carEntity->getByName(stmp);
647 free(stmp);
648
649 grCarInfo[index].driverSelector = new ssgSelector;
650 if (b) {
651 ssgBranch *bp = b->getParent(0);
652 bp->addKid(grCarInfo[index].driverSelector);
653 grCarInfo[index].driverSelector->addKid(b);
654 bp->removeKid(b);
655 grCarInfo[index].driverSelector->select(1);
656 grCarInfo[index].driverSelectorinsg = true;
657 } else {
658 grCarInfo[index].driverSelectorinsg = false;
659 }
660
661
662 DBG_SET_NAME(carEntity, "Body", index, -1);
663 carBody->addKid(carEntity);
664 /* add wheels */
665 for (i = 0; i < 4; i++){
666 wheel[i] = initWheel(car, i);
667 carBody->addKid(wheel[i]);
668 }
669 grCarInfo[index].LODSelectMask[0] = 1 << selIndex; /* car mask */
670 selIndex++;
671 grCarInfo[index].sx=carTrackRatioX;
672 grCarInfo[index].sy=carTrackRatioY;
673
674 /* Other LODs */
675 for (i = 2; i < nranges; i++) {
676 carBody = new ssgBranch;
677 snprintf(buf, BUFSIZE, "%s/%s/%d", SECT_GROBJECTS, LST_RANGES, i);
678 param = GfParmGetStr(handle, buf, PRM_CAR, "");
679 grCarInfo[index].LODThreshold[selIndex] = GfParmGetNum(handle, buf, PRM_THRESHOLD, NULL, 0.0);
680 /* carEntity = ssgLoad(param); */
681 carEntity = grssgCarLoadAC3D(param, NULL, index);;
682 DBG_SET_NAME(carEntity, "LOD", index, i-1);
683 carBody->addKid(carEntity);
684 if (!strcmp(GfParmGetStr(handle, buf, PRM_WHEELSON, "no"), "yes")) {
685 /* add wheels */
686 for (j = 0; j < 4; j++){
687 carBody->addKid(wheel[j]);
688 }
689 }
690 LODSel->addKid(carBody);
691 grCarInfo[index].LODSelectMask[i-1] = 1 << selIndex; /* car mask */
692 selIndex++;
693 }
694 /* default range selection */
695 LODSel->select(grCarInfo[index].LODSelectMask[0]);
696
697 CarsAnchor->addKid(grCarInfo[index].carTransform);
698
699 //grCarInfo[index].carTransform->print(stdout, "-", 1);
700
701 FREEZ(grTexturePath);
702 FREEZ(grFilePath);
703 options.endLoad();
704
705 TRACE_GL("loadcar: end");
706 }
707
708 static void
grDrawShadow(tCarElt * car,int visible)709 grDrawShadow(tCarElt *car, int visible)
710 {
711 int i;
712 ssgVtxTableShadow *shadow;
713 sgVec3 *vtx;
714
715 if (grCarInfo[car->index].shadowAnchor->getNumKids() != 0) {
716 grCarInfo[car->index].shadowAnchor->removeKid(grCarInfo[car->index].shadowCurr);
717 }
718
719 if (visible) {
720 shadow = (ssgVtxTableShadow *)grCarInfo[car->index].shadowBase->clone(SSG_CLONE_GEOMETRY);
721 /* shadow->setState(shadowState); */
722 shadow->setCullFace(TRUE);
723 shadow->getVertexList((void**)&vtx);
724
725 shadow->transform(grCarInfo[car->index].carPos);
726
727 for (i = 0; i < GR_SHADOW_POINTS; i++) {
728 vtx[i][2] = RtTrackHeightG(car->_trkPos.seg, vtx[i][0], vtx[i][1]) + 0.00;
729 }
730
731 grCarInfo[car->index].shadowCurr = shadow;
732 grCarInfo[car->index].shadowAnchor->addKid(shadow);
733 }
734 }
735
736
737
738
grGetDistToStart(tCarElt * car)739 tdble grGetDistToStart(tCarElt *car)
740 {
741 tTrackSeg *seg;
742 tdble lg;
743
744 seg = car->_trkPos.seg;
745 lg = seg->lgfromstart;
746
747 switch (seg->type) {
748 case TR_STR:
749 lg += car->_trkPos.toStart;
750 break;
751 default:
752 lg += car->_trkPos.toStart * seg->radius;
753 break;
754 }
755 return lg;
756 }
757
758
759
760
grDrawCar(tCarElt * car,tCarElt * curCar,int dispCarFlag,int dispDrvFlag,double curTime,class cGrPerspCamera * curCam)761 void grDrawCar(tCarElt *car, tCarElt *curCar, int dispCarFlag, int dispDrvFlag, double curTime, class cGrPerspCamera *curCam)
762 {
763 sgCoord wheelpos;
764 int index, i, j;
765 static float maxVel[3] = { 20.0, 40.0, 70.0 };
766 float lod;
767
768 TRACE_GL("cggrDrawCar: start");
769
770 index = car->index;
771 if (car->priv.collision_state.collision_count > 0) {
772 tCollisionState* collision_state = &car->priv.collision_state;
773 grPropagateDamage (grCarInfo[index].carEntity, collision_state->pos, collision_state->force, 0);
774 collision_state->collision_count = 0;
775 }
776
777 grCarInfo[index].distFromStart=grGetDistToStart(car);
778 grCarInfo[index].envAngle=RAD2DEG(car->_yaw);
779
780 if ((car == curCar) && (dispCarFlag != 1)) {
781 grCarInfo[index].LODSelector->select(0);
782 } else {
783 lod = curCam->getLODFactor(car->_pos_X, car->_pos_Y, car->_pos_Z);
784 i = 0;
785 while (lod < grCarInfo[index].LODThreshold[i] * grLodFactorValue) {
786 i++;
787 }
788 if ((car->_state & RM_CAR_STATE_DNF) && (grCarInfo[index].LODThreshold[i] > 0.0)) {
789 i++;
790 }
791 grCarInfo[index].LODSelector->select(grCarInfo[index].LODSelectMask[i]);
792 if (dispDrvFlag) {
793 grCarInfo[index].driverSelector->select(1);
794 } else {
795 grCarInfo[index].driverSelector->select(0);
796 }
797 }
798
799 sgCopyMat4(grCarInfo[index].carPos, car->_posMat);
800 grCarInfo[index].px=car->_pos_X;
801 grCarInfo[index].py=car->_pos_Y;
802
803 grCarInfo[index].carTransform->setTransform(grCarInfo[index].carPos);
804
805 if ((car == curCar) && (dispCarFlag != 1)) {
806 grDrawShadow(car, 0);
807 } else {
808 grDrawShadow(car, 1);
809 }
810
811 grUpdateSkidmarks(car, curTime);
812 grDrawSkidmarks(car);
813 grAddSmoke(car, curTime);
814
815 if ((car == curCar) && (dispCarFlag != 1)) {
816 grUpdateCarlight(car, curCam, 0);
817 } else {
818 grUpdateCarlight(car, curCam, 1);
819 }
820
821 /* Env mapping selection by the position on the track */
822 grCarInfo[index].envSelector->selectStep(car->_trkPos.seg->envIndex);
823
824 /* wheels */
825 for (i = 0; i < 4; i++) {
826 float *clr;
827
828 sgSetCoord(&wheelpos, car->priv.wheel[i].relPos.x, car->priv.wheel[i].relPos.y, car->priv.wheel[i].relPos.z,
829 RAD2DEG(car->priv.wheel[i].relPos.az), RAD2DEG(car->priv.wheel[i].relPos.ax), 0);
830 grCarInfo[index].wheelPos[i]->setTransform(&wheelpos);
831 sgSetCoord(&wheelpos, 0, 0, 0, 0, 0, RAD2DEG(car->priv.wheel[i].relPos.ay));
832 grCarInfo[index].wheelRot[i]->setTransform(&wheelpos);
833 for (j = 0; j < 3; j++) {
834 if (fabs(car->_wheelSpinVel(i)) < maxVel[j])
835 break;
836 }
837 grCarInfo[index].wheelselector[i]->select(1<<j);
838 clr = grCarInfo[index].brkColor[i]->get(0);
839 clr[0] = 0.1 + car->_brakeTemp(i) * 1.5;
840 clr[1] = 0.1 + car->_brakeTemp(i) * 0.3;
841 clr[2] = 0.1 - car->_brakeTemp(i) * 0.3;
842 }
843
844 /* push the car at the end of the display order */
845 CarsAnchorTmp->addKid(grCarInfo[index].carTransform);
846 CarsAnchor->removeKid(grCarInfo[index].carTransform);
847 CarsAnchor->addKid(grCarInfo[index].carTransform);
848 CarsAnchorTmp->removeKid(grCarInfo[index].carTransform);
849
850 TRACE_GL("cggrDrawCar: end");
851 }
852
853