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