1 #include "pch.h"
2 #include "../vdrift/par.h"
3 #include "common/Def_Str.h"
4 #include "common/RenderConst.h"
5 #include "CarModel.h"
6 #include "../vdrift/pathmanager.h"
7 #include "../vdrift/mathvector.h"
8 #include "../vdrift/track.h"
9 #include "../vdrift/game.h"
10 #include "common/data/SceneXml.h"
11 #include "common/CScene.h"
12 #include "CGame.h"
13 #include "SplitScreen.h"
14 #include "FollowCamera.h"
15 #include "CarReflection.h"
16 #include "../road/Road.h"
17 #include "../vdrift/par.h"
18
19 #include <OgreRoot.h>
20 #include <OgreTerrain.h>
21 #include <OgreEntity.h>
22 #include <OgreManualObject.h>
23 #include <OgreMaterialManager.h>
24 #include <OgreParticleSystem.h>
25 #include <OgreParticleEmitter.h>
26 #include <OgreParticleAffector.h>
27 #include <OgreRibbonTrail.h>
28 #include <OgreBillboardSet.h>
29 #include <OgreSceneNode.h>
30 #include <OgreTechnique.h>
31 #include <OgreViewport.h>
32 #include <MyGUI_TextBox.h>
33 using namespace Ogre;
34
35
setVisible(bool vis)36 void CarModel::setVisible(bool vis)
37 {
38 mbVisible = vis;
39 hideTime = 0.f;
40
41 pMainNode->setVisible(vis);
42 if (brakes)
43 brakes->setVisible(bBraking && vis);
44 for (int w=0; w < numWheels; ++w)
45 ndWh[w]->setVisible(vis);
46
47 UpdParsTrails(vis);
48 }
49
UpdNextCheck()50 void CarModel::UpdNextCheck()
51 {
52 updTimes = true;
53 if (eType != CarModel::CT_LOCAL) return;
54 if (!ndNextChk || !pApp || !pApp->scn->road) return;
55 if (pApp->scn->road->mChks.empty()) return;
56
57 Vector3 p;
58 if (iNumChks == pApp->scn->road->mChks.size() && iCurChk != -1)
59 {
60 bool hasLaps = pSet->game.local_players > 1 || pSet->game.champ_num >= 0 || pSet->game.chall_num >= 0 || pApp->mClient;
61 int lap = pGame->timer.GetCurrentLap(iIndex) + 1, laps = pSet->game.num_laps;
62 String smtr = "checkpoint_lap";
63 if (hasLaps)
64 if (lap == laps - 1) smtr = "checkpoint_lastlap";
65 else if (lap == laps) smtr = "checkpoint_finish";
66 p = vStartPos; // finish
67 sChkMtr = smtr;
68 bChkUpd = true;
69 }
70 else
71 {
72 p = pApp->scn->road->mChks[iNextChk].pos;
73 sChkMtr = "checkpoint_normal";
74 bChkUpd = true;
75 }
76
77 p.y -= gPar.chkBeamSy; // lower
78 ndNextChk->setPosition(p);
79 ndNextChk->setScale(gPar.chkBeamSx, gPar.chkBeamSy, gPar.chkBeamSx);
80 ndNextChk->setVisible(pSet->check_beam && !pApp->bHideHudBeam);
81 }
ShowNextChk(bool visible)82 void CarModel::ShowNextChk(bool visible)
83 {
84 if (ndNextChk)
85 ndNextChk->setVisible(visible && !pApp->bHideHudBeam);
86 }
87
88
ResetChecks(bool bDist)89 void CarModel::ResetChecks(bool bDist) // needs to be done after road load!
90 {
91 updTimes = true;
92 iCurChk = -1; iNumChks = 0; // reset lap, chk vars
93 iLoopChk = -1; iLoopLastCam = -1;
94 trackPercent = 0.f;
95 if (!pApp || !pApp->scn->road) return;
96
97 const SplineRoad* road = pApp->scn->road;
98 iNextChk = pSet->game.trackreverse ? road->iChkId1Rev : road->iChkId1;
99 UpdNextCheck();
100
101 // percent const ------
102 if (bDist && !road->mChks.empty())
103 {
104 const Vector3& firstC = road->mChks[road->iChkId1].pos, lastC = road->mChks[road->iChkId1Rev].pos;
105
106 Vector3 vFirst = vStartPos - firstC; distFirst = vFirst.length();
107 Vector3 vLast = lastC - vStartPos; distLast = vLast.length();
108 distTotal = distFirst + distLast + road->chksRoadLen;
109 //LogO("Chk first: "+toStr(distFirst)+" last: "+toStr(distLast)+" total: "+toStr(distTotal));
110 }
111 }
112
113 // get track driven dist part in %
114 //--------------------------------------------------------------------------------------------------------
UpdTrackPercent()115 void CarModel::UpdTrackPercent()
116 {
117 if (!pApp || !pApp->scn->road) return;
118 const SplineRoad* road = pApp->scn->road;
119
120 float perc = 0.f;
121 if (road && !road->mChks.empty() && !isGhost())
122 {
123 const Vector3& car = pMainNode->getPosition(), next = road->mChks[iNextChk].pos,
124 start = vStartPos, curr = road->mChks[std::max(0,iCurChk)].pos;
125 bool bRev = pSet->game.trackreverse;
126 Real firstD = bRev ? distLast : distFirst;
127 Real nextR = road->mChks[iNextChk].r; // chk .r radius to tweak when entering chk..
128
129 Real dist = 0.f;
130 if (iNumChks > 0) dist = firstD; // already after 1st chk
131 if (iNumChks > 1) dist += // after 1st to 2nd chk or more
132 road->mChks[iNumChks-2].dist[bRev ? 1 : 0];
133
134
135 float dist01 = 0.f; // smooth dist part
136 // start to 1st chk
137 if (iNumChks == 0)
138 {
139 Vector3 curDist = car - start;
140 Vector3 chksDist = next - start; // first
141 dist01 = (curDist.length() /*- nextR*/) / (chksDist.length() - nextR);
142
143 float percD = std::min(1.f, std::max(0.f, dist01 )); // clamp to 0..1
144 dist += percD * firstD;
145 }
146 // last chk to finish
147 else if (iNumChks == road->mChks.size())
148 {
149 Vector3 curDist = start - car;
150 Vector3 chksDist = curr - start; // last
151 dist01 = 1.f - (curDist.length() /*- nextR*/) / (chksDist.length() - nextR);
152
153 float percD = std::min(1.f, std::max(0.f, dist01 )); // clamp to 0..1
154 dist += percD * (bRev ? distFirst : distLast); //lastD;
155 }
156 else // between 2 checks
157 {
158 Vector3 curDist = car - next; // car dist to next checkpoint
159 Vector3 chksDist = curr - next; // divide by (cur to next) checks distance
160 Real ckD = chksDist.length();
161
162 dist01 = 1.f - (curDist.length() - nextR) / (ckD - road->mChks[iCurChk].r);
163
164 float percD = std::min(1.f, std::max(0.f, dist01 )); // clamp to 0..1
165 dist += percD * (ckD + road->mChks[iCurChk].r*0.8f); //road->mChks[iNumChks-1].dist;
166 }
167 perc = 100.f * dist / distTotal;
168
169 if (perc > trackPercent)
170 trackPercent = perc;
171 }
172 }
173
174
175 //-------------------------------------------------------------------------------------------------------
176 // Update
177 //-------------------------------------------------------------------------------------------------------
Update(PosInfo & posInfo,PosInfo & posInfoCam,float time)178 void CarModel::Update(PosInfo& posInfo, PosInfo& posInfoCam, float time)
179 {
180 pReflect->camPosition = pMainNode->getPosition();
181 int w,i;
182
183 // upd chk mtr
184 if (bChkUpd && entNextChk)
185 {
186 MaterialPtr mtr = MaterialManager::getSingleton().getByName(sChkMtr);
187 if (!mtr.isNull())
188 entNextChk->setMaterial(mtr);
189 }
190
191 // stop/resume par sys
192 float fa = pGame->pause ? 0.f : 1.f;
193 for (w=0; w < numWheels; ++w)
194 {
195 for (i=0; i < PAR_ALL; ++i)
196 if (par[i][w]) par[i][w]->setSpeedFactor(fa);
197 if (w < PAR_BOOST && parBoost[w]) parBoost[w]->setSpeedFactor(fa);
198 if (parHit) parHit->setSpeedFactor(fa);
199 }
200 for (w=0; w < PAR_THRUST*2; ++w)
201 if (parThrust[w]) parThrust[w]->setSpeedFactor(fa);
202
203
204 if (!posInfo.bNew) return; // new only ?
205 posInfo.bNew = false;
206 /// dont get anything from pCar or car.dynamics here
207 /// all must be read from posInfo (it is filled from vdrift car or from replay)
208
209 if (!pMainNode) return;
210
211 // set car pos and rot
212 pMainNode->setPosition(posInfo.pos);
213 if (vtype == V_Sphere)
214 pMainNode->setOrientation(Quaternion(Quaternion(Degree(-posInfo.hov_roll),Vector3::UNIT_Y)));
215 else
216 if (vtype == V_Spaceship) // roll vis only
217 pMainNode->setOrientation(posInfo.rot * Quaternion(Degree(posInfo.hov_roll),Vector3::UNIT_X));
218 else
219 pMainNode->setOrientation(posInfo.rot);
220
221 ///() grass sphere pos
222 Vector3 vx(1,0,0); // car x dir
223 vx = posInfo.rot * vx * 1.1; //par
224 posSph[0] = posInfo.pos + vx; posSph[0].y += 0.5f;
225 posSph[1] = posInfo.pos - vx; posSph[1].y += 0.5f;
226 if (ndSph) // sph test
227 { ndSph->setPosition(posSph[0]);
228 ndSph->setScale(Vector3::UNIT_SCALE * 1.7 *2/0.6f); //par
229 }
230
231 // set camera view
232 if (fCam)
233 { fCam->Apply(posInfoCam);
234
235 ///~~ camera in fluid fog, detect and compute
236 iCamFluid = -1; fCamFl = 0.f; // none
237 const size_t sf = sc->fluids.size();
238 if (sf > 0 && pSet->game.local_players == 1)
239 {
240 const Vector3& p = posInfo.camPos;
241 const float r = 0.2f; //par, near cam?
242
243 // check if any fluid box overlaps camera pos sphere
244 bool srch = true; size_t f = 0;
245 while (srch && f < sf)
246 {
247 const FluidBox& fb = sc->fluids[f];
248 const Vector3& fp = fb.pos;
249 Vector3 fs = fb.size; fs.x *= 0.5f; fs.z *= 0.5f;
250
251 bool inFl = // p +r -fs fp +fs -r p
252 p.y +r > fp.y - fs.y && p.y -r < fp.y &&
253 p.x +r > fp.x - fs.x && p.x -r < fp.x + fs.x &&
254 p.z +r > fp.z - fs.z && p.z -r < fp.z + fs.z;
255
256 if (inFl) // 1st only
257 { iCamFluid = f; fCamFl = std::min(1.f, std::max(0.f, fp.y - p.y)) * 3.f;
258 srch = false; }
259 ++f;
260 }
261 } }
262
263 // upd rotY for minimap
264 if (vtype == V_Sphere)
265 angCarY = posInfo.hov_roll * 180.f / PI_d + 180.f;
266 else
267 { Quaternion q = posInfo.rot * Quaternion(Degree(90),Vector3(0,1,0));
268 angCarY = q.getYaw().valueDegrees() + 90.f;
269 }
270
271 // brake state
272 #ifndef CAR_PRV
273 bool braking = posInfo.braking > 0;
274 if (bBraking != braking)
275 {
276 bBraking = braking;
277 UpdateBraking();
278 }
279 #endif
280
281 // terrain lightmap enable/disable (depending on distance to terrain)
282 #define MAX_TERRAIN_DIST 2.0 // meters
283 bool changed = false;
284 if (terrain)
285 {
286 Vector3 carPos = pMainNode->getPosition();
287 float terrainHeight = terrain->getHeightAtWorldPosition(carPos);
288 float diff = std::abs(carPos.y - terrainHeight);
289 if (diff > MAX_TERRAIN_DIST)
290 {
291 if (bLightMapEnabled)
292 { changed = true; bLightMapEnabled = false; }
293 }
294 else if (!bLightMapEnabled)
295 { changed = true; bLightMapEnabled = true; }
296 }
297 // if no terrain, disable
298 else if (bLightMapEnabled)
299 { changed = true; bLightMapEnabled = false; }
300
301 if (changed)
302 UpdateLightMap();
303
304
305 // update particle emitters
306 if (pSet->particles && pCar)
307 {
308 // boost
309 for (i=0; i < PAR_BOOST; ++i) if (parBoost[i])
310 {
311 /// <><> damage reduce
312 float dmg = pCar->dynamics.fDamage >= 80.f ? 0.f : std::max(0.f, 1.4f - pCar->dynamics.fDamage*0.01f);
313 float emitB = posInfo.fboost * 40.f * dmg; // par
314 ParticleEmitter* pe = parBoost[i]->getEmitter(0);
315 pe->setEmissionRate(emitB);
316 }
317 // spaceship thrusters
318 for (i=0; i < PAR_THRUST*2; ++i) if (parThrust[i])
319 {
320 float dmg = 1.f - 0.5f * pCar->dynamics.fDamage*0.01f;
321 float emitT = posInfo.hov_throttle * 60.f * dmg; // par
322 ParticleEmitter* pe = parThrust[i]->getEmitter(0);
323 pe->setEmissionRate(emitT);
324 }
325 }
326
327 // world hit
328 if (parHit)
329 { ParticleEmitter* pe = parHit->getEmitter(0);
330 if (posInfo.fHitTime > 0.f && pSet->particles)
331 {
332 pe->setPosition(posInfo.vHitPos);
333 pe->setDirection(posInfo.vHitNorm);
334
335 pe->setEmissionRate(pSet->particles_len * std::min(160.f, posInfo.fParIntens) * posInfo.fHitTime);
336 pe->setParticleVelocity(posInfo.fParVel);
337 }else
338 pe->setEmissionRate(0.f);
339 }
340
341 // wheels ------------------------------------------------------------------------
342 const float trlH = sc->ter ? 0.90f : 0.76f; // vdr needs up (ter bumps), no ter ..get from wheel contact ?rpl
343
344 for (w=0; w < numWheels; ++w)
345 {
346 float wR = whRadius[w];
347 #ifdef CAM_TILT_DBG // cam debug test only
348 if (fCam)
349 ndWh[w]->setPosition(fCam->posHit[w]);
350 ndWh[w]->setScale(0.5f*Vector3::UNIT_SCALE);
351 #else
352 ndWh[w]->setPosition(posInfo.whPos[w]);
353 #endif
354 ndWh[w]->setOrientation(posInfo.whRot[w]);
355
356 /// Update particles and trails
357 if (isGhostTrk())
358 continue; // doesnt have any
359
360 int whMtr = posInfo.whTerMtr[w];
361 int whRd = posInfo.whRoadMtr[w];
362
363 bool pipe = whRd >= 30 && whRd < 60; //old: whRd == 2;
364 //todo: road,pipe 4mtr [whRd] layer params..
365 float whVel = posInfo.whVel[w] * 3.6f; //kmh
366 float slide = posInfo.whSlide[w], squeal = posInfo.whSqueal[w];
367 //LogO(" slide:"+fToStr(slide,3,5)+" squeal:"+fToStr(squeal,3,5));
368 float onGr = slide < 0.f ? 0.f : 1.f;
369
370 // wheel temp
371 whTemp[w] += std::min(12.f, std::max(0.f, squeal*8 - slide*2 + squeal*slide*2)*time);
372 whTemp[w] = std::min(1.5f, whTemp[w]); ///*
373 whTemp[w] -= time*7.f; if (whTemp[w] < 0.f) whTemp[w] = 0.f;
374 //LogO(toStr(w)+" wht "+fToStr(wht[w],3,5));
375
376 /// emit rates +
377 Real sq = squeal* std::min(1.f, whTemp[w]), l = pSet->particles_len * onGr;
378 Real emitS = sq * (whVel * 30) * l * 0.45f; ///*
379 Real emitM = slide < 1.4f ? 0.f : (8.f * sq * std::min(5.f, slide) * l);
380 Real emitD = (std::min(140.f, whVel) / 3.5f + slide * 1.f ) * l;
381 Real sizeD = (0.8f + 0.6f * std::min(140.f, whVel) / 140.f) * (w < 2 ? 0.7f : 1.1f);
382
383 // ter mtr factors
384 int mtr = std::max(0, std::min(whMtr-1, (int)(sc->td.layers.size()-1)));
385 int rd = sc->td.road1mtr ? 0 : std::max(0, std::min(3, whRd));
386
387 TerLayer& lay = whMtr==0 ? sc->td.layerRoad[rd] : sc->td.layersAll[sc->td.layers[mtr]];
388 emitD *= lay.dust; emitM *= lay.mud; sizeD *= lay.dustS; emitS *= lay.smoke;
389
390 if (pipe) emitD = 0; // no dust in pipes
391 if (posInfo.whH[w] > 0.1f) emitD = 0; // no dust in fluids
392
393 bool ghost = isGhost(); // opt dis for ghost
394 bool ghPar = !(ghost && !pSet->rpl_ghostpar);
395 if (!ghPar)
396 { emitD = 0.f; emitM = 0.f; emitS = 0.f; }
397
398 /// emit particles
399 Vector3 vpos = posInfo.whPos[w];
400 if (pSet->particles)
401 {
402 ParticleSystem* ps = par[PAR_Smoke][w];
403 if (ps) // smoke
404 { ParticleEmitter* pe = ps->getEmitter(0);
405 pe->setPosition(vpos + posInfo.carY * wR*0.7f); ///*
406 ps->getAffector(0)->setParameter("alpha", toStr(-0.2f - 0.023f * whVel)); // fade out speed
407 pe->setTimeToLive( std::max(0.12f, 2.f - whVel * 0.06f) ); // live time
408 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitS);
409 }
410 ps = par[PAR_Mud][w];
411 if (ps) // mud
412 { ParticleEmitter* pe = ps->getEmitter(0);
413 //pe->setDimensions(sizeM,sizeM);
414 pe->setPosition(vpos + posInfo.carY * wR*0.7f);
415 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitM);
416 }
417 ps = par[PAR_Dust][w];
418 if (ps) // dust
419 { ps->setDefaultDimensions(sizeD,sizeD);
420 ParticleEmitter* pe = ps->getEmitter(0);
421 pe->setPosition(vpos + posInfo.carY * wR*0.31f);
422 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitD);
423 }
424
425 // fluids .::.
426 ps = par[PAR_Water][w];
427 int idPar = posInfo.whP[w];
428 if (ps) // Water ~
429 {
430 float vel = posInfo.speed; // depth.. only on surface?
431 bool e = idPar == 0 && ghPar && vel > 10.f && posInfo.whH[w] < 1.f;
432 float emitW = e ? std::min(80.f, 5.0f * vel) : 0.f;
433
434 ParticleEmitter* pe = ps->getEmitter(0);
435 pe->setPosition(vpos + posInfo.carY * wR*0.51f);
436 pe->setMinParticleVelocity(0.07* vel);
437 pe->setMaxParticleVelocity(0.20* vel);
438 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitW * pSet->particles_len);
439 }
440 ps = par[PAR_MudHard][w];
441 if (ps) // Mud ^
442 {
443 float vel = Math::Abs(posInfo.whAngVel[w]);
444 bool e = idPar == 2 && ghPar && vel > 30.f;
445 float emitM = e ? posInfo.whH[w] * std::min(80.f, 1.5f * vel) : 0.f;
446
447 ParticleEmitter* pe = ps->getEmitter(0);
448 pe->setPosition(vpos + posInfo.carY * wR*0.51f);
449 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitM * pSet->particles_len);
450 }
451 ps = par[PAR_MudSoft][w];
452 if (ps) // Mud soft ^
453 {
454 float vel = Math::Abs(posInfo.whAngVel[w]);
455 bool e = idPar == 1 && ghPar && vel > 30.f;
456 float emitM = e ? posInfo.whH[w] * std::min(160.f, 3.f * vel) : 0.f;
457
458 ParticleEmitter* pe = ps->getEmitter(0);
459 pe->setPosition(vpos + posInfo.carY * wR*0.51f);
460 pe->setDirection(-posInfo.carY); pe->setEmissionRate(emitM * pSet->particles_len);
461 }
462 }
463
464 // update trails h+
465 if (pSet->trails)
466 { if (ndWhE[w])
467 { Vector3 vp = vpos + posInfo.carY * wR*trlH;
468 if (terrain && whMtr > 0)
469 vp.y = terrain->getHeightAtWorldPosition(vp) + 0.02f; // 0.05f
470 //if (/*whOnRoad[w]*/whMtr > 0 && road) // on road, add ofs
471 // vp.y += road->fHeight; }/**/
472 ndWhE[w]->setPosition(vp);
473 ndWhE[w]->setOrientation(posInfo.rot);
474 }
475 // const trail alpha
476 float ac = pipe ? 0.f : /*own par..*/lay.smoke < 0.5f ? 0.14f : 0.f;
477 float al = (ac + 0.6f * std::min(1.f, 0.7f * whTemp[w]) ) * onGr; // par+
478 if (whTrail[w])
479 { whTrail[w]->setInitialColour(0,
480 lay.tcl.x, lay.tcl.y, lay.tcl.z, lay.tcl.w * al/**/);
481 if (iFirst > 10) //par
482 whTrail[w]->setInitialWidth(0, whWidth[w]);
483 }
484 }
485 }
486
487 // blendmap
488 UpdWhTerMtr();
489
490 // update brake meshes orientation
491 for (w=0; w < numWheels; ++w)
492 {
493 if (ndBrake[w])
494 {
495 ndBrake[w]->_setDerivedOrientation( pMainNode->getOrientation() );
496
497 // this transformation code is just so the brake mesh can have the same alignment as the wheel mesh
498 ndBrake[w]->yaw(Degree(-90), Node::TS_LOCAL);
499 if (w%2 == 1)
500 ndBrake[w]->setScale(-1, 1, 1);
501
502 ndBrake[w]->pitch(Degree(180), Node::TS_LOCAL);
503
504 if (w < 2) // turn only front wheels
505 ndBrake[w]->yaw(-Degree(posInfo.whSteerAng[w]));
506 }
507 }
508
509 if (iFirst <= 10) ++iFirst; //par
510
511 UpdateKeys();
512 }
513
514 //-------------------------------------------------------------------------------------------------------
First()515 void CarModel::First()
516 {
517 if (fCam) fCam->First();
518 iFirst = 0;
519
520 for (int w=0; w < numWheels; ++w) // hide trails
521 if (whTrail[w])
522 whTrail[w]->setInitialWidth(0, 0.f);
523 }
524
UpdateKeys()525 void CarModel::UpdateKeys()
526 {
527 if (!pCar) return;
528
529 /// goto last checkp - reset cam
530 if (pCar->bLastChk && !bLastChkOld)
531 First();
532
533 bLastChkOld = pCar->bLastChk;
534
535 /// change Cameras ---------------------------------
536 //if (!pApp->isFocGui)
537 int iC = pCar->iCamNext; // iRplCarOfs..
538 if (iC != 0 && iCamNextOld == 0)
539 {
540 // with ctrl - change current camera car index (mouse move camera for many players)
541 if (pApp->ctrl && iIndex == 0)
542 pApp->iCurCam = (pApp->iCurCam + iC + pSet->game.local_players) % pSet->game.local_players;
543 else
544 {
545 int visMask = 255;
546 pApp->roadUpdTm = 1.f;
547
548 if (fCam)
549 { fCam->Next(iC < 0, pApp->shift);
550 pApp->carsCamNum[iIndex] = fCam->miCurrent +1; // save for pSet
551 visMask = fCam->ca->mHideGlass ? RV_MaskAll-RV_CarGlass : RV_MaskAll;
552 for (std::list<Viewport*>::iterator it = pApp->mSplitMgr->mViewports.begin();
553 it != pApp->mSplitMgr->mViewports.end(); ++it)
554 (*it)->setVisibilityMask(visMask);
555 }
556 }
557 }
558 iCamNextOld = iC;
559 }
560
561
562
563 //-------------------------------------------------------------------------------------------------------
564 // utility
565 //-------------------------------------------------------------------------------------------------------
UpdateLightMap()566 void CarModel::UpdateLightMap()
567 {
568 MaterialPtr mtr;
569 for (int i=0; i < NumMaterials; ++i)
570 {
571 mtr = MaterialManager::getSingleton().getByName(sMtr[i]);
572 if (!mtr.isNull())
573 { Material::TechniqueIterator techIt = mtr->getTechniqueIterator();
574 while (techIt.hasMoreElements())
575 { Technique* tech = techIt.getNext();
576 Technique::PassIterator passIt = tech->getPassIterator();
577 while (passIt.hasMoreElements())
578 { Pass* pass = passIt.getNext();
579 if (pass->hasFragmentProgram())
580 {
581 GpuProgramParametersSharedPtr params = pass->getFragmentProgramParameters();
582 params->setIgnoreMissingParams(true); // don't throw exception if material doesnt use lightmap
583 params->setNamedConstant("enableTerrainLightMap", bLightMapEnabled ? 1.f : 0.f);
584 } } } } }
585 }
586
UpdateBraking()587 void CarModel::UpdateBraking()
588 {
589 if (brakes)
590 brakes->setVisible(bBraking && mbVisible);
591
592 std::string texName = sDirname + (bBraking ? "_body00_brake.png" : "_body00_add.png");
593
594 MaterialPtr mtr = MaterialManager::getSingleton().getByName(sMtr[Mtr_CarBody]);
595 if (!mtr.isNull())
596 { Material::TechniqueIterator techIt = mtr->getTechniqueIterator();
597 while (techIt.hasMoreElements())
598 { Technique* tech = techIt.getNext();
599 Technique::PassIterator passIt = tech->getPassIterator();
600 while (passIt.hasMoreElements())
601 { Pass* pass = passIt.getNext();
602 Pass::TextureUnitStateIterator tusIt = pass->getTextureUnitStateIterator();
603 while (tusIt.hasMoreElements())
604 {
605 TextureUnitState* tus = tusIt.getNext();
606 if (tus->getName() == "diffuseMap")
607 { tus->setTextureName( texName ); return; }
608 } } } }
609 }
610
611
UpdParsTrails(bool visible)612 void CarModel::UpdParsTrails(bool visible)
613 {
614 bool vis = visible && pSet->particles;
615 for (int w=0; w < numWheels; ++w)
616 {
617 uint8 grp = RQG_CarTrails; //9=road after glass
618 if (w < PAR_BOOST && parBoost[w]) { parBoost[w]->setVisible(vis); parBoost[w]->setRenderQueueGroup(grp); }
619 if (whTrail[w]){ whTrail[w]->setVisible(visible && pSet->trails); whTrail[w]->setRenderQueueGroup(grp); }
620 grp = RQG_CarParticles;
621 for (int p=0; p < PAR_ALL; ++p)
622 if (par[p][w]){ par[p][w]->setVisible(vis); par[p][w]->setRenderQueueGroup(grp); }
623 if (parHit && w==0) { parHit->setVisible(vis); parHit->setRenderQueueGroup(grp); }
624 }
625 for (int w=0; w < PAR_THRUST*2; ++w)
626 if (parThrust[w]) { parThrust[w]->setVisible(vis); parThrust[w]->setRenderQueueGroup(RQG_CarTrails); }
627 }
628
629
630 /// just to display info on wheel surfaces
631 //-------------------------------------------------------------------------------------------------------
UpdWhTerMtr()632 void CarModel::UpdWhTerMtr()
633 {
634 if (!pCar || !ndWh[0]) return;
635 //int t = blendMapSize;
636 //Real tws = sc->td.fTerWorldSize;
637
638 txtDbgSurf = "";
639 for (int i=0; i < pCar->numWheels; ++i)
640 {
641 //Vector3 w = ndWh[i]->getPosition();
642 //int mx = (w.x + 0.5*tws)/tws*t, my = (-w.z + 0.5*tws)/tws*t;
643 //mx = std::max(0,std::min(t-1, mx)), my = std::max(0,std::min(t-1, my));
644
645 //int mtr = pCar->dynamics.bWhOnRoad[i] ? 0 : blendMtr[my*t + mx];
646 //whTerMtr[i] = mtr;
647 //whRoadMtr[i] = pCar->dynamics.bWhOnRoad[i];
648
649 const CARDYNAMICS& cd = pCar->dynamics; int iRd = cd.iWhOnRoad[i];
650 float d = 0.5f * cd.wheel_contact[i].GetDepth() / cd.wheel[i].GetRadius();
651
652 const TRACKSURFACE* tsu = cd.GetWheelContact(WHEEL_POSITION(i)).GetSurfacePtr();
653 //pCar->dynamics.bTerrain = true;
654
655 if (pSet->car_dbgsurf) // dbg info surf -------
656 {
657 //TerLayer& lay = /*mtr == 0 ? sc->td.layerRoad :*/ sc->td.layersAll[ sc->td.layers[ std::min((int)sc->td.layers.size()-1, mtr-1) ] ];
658 txtDbgSurf += //"mx " + toStr(mx) + " my " + toStr(my) +
659 ( iRd == 0 ? ( "T" + toStr(cd.whTerMtr[i]) ) // Terrain/Pipe/Road
660 : ( (iRd==2 ? "P" : "R") + toStr(cd.whRoadMtr[i]) ) ) +
661 (!tsu ? " --" : (
662 " " + tsu->name + " " + csTRKsurf[tsu->type] + //" [" + lay.texFile + "] " +
663 "\n "+ tsu->tireName + "\n "+
664 " d= " + fToStr(d, 2,5) + " dr " + fToStr(tsu->rollingDrag, 0,3) + " rr " + fToStr(tsu->rollingResist, 1,3) +
665 " fr " + fToStr(tsu->friction, 2,4) +
666 " ba " + fToStr(tsu->bumpAmplitude, 2,4) + " bw " + fToStr(tsu->bumpWaveLength, 2,4) +
667 " b0 " + fToStr(tsu->tire->longitudinal[0], 3,5)
668 //,lay.dust, lay.mud, lay.dustS //,lay.tclr.r, lay.tclr.g, lay.tclr.b, lay.tclr.a
669 )) + "\n";
670 }
671 }
672 }
673
674
675 // utils
676 //-------------------------------------------------------------------------------------------------------
677
ChangeClr()678 void CarModel::ChangeClr()
679 {
680 int i = iColor;
681 float c_h = pSet->gui.car_hue[i], c_s = pSet->gui.car_sat[i],
682 c_v = pSet->gui.car_val[i], gloss = pSet->gui.car_gloss[i], refl = pSet->gui.car_refl[i];
683 color.setHSB(1-c_h, c_s, c_v); //set, mini pos clr
684
685 MaterialPtr mtr = MaterialManager::getSingleton().getByName(sMtr[Mtr_CarBody]);
686 if (!mtr.isNull())
687 { Material::TechniqueIterator techIt = mtr->getTechniqueIterator();
688 while (techIt.hasMoreElements())
689 { Technique* tech = techIt.getNext();
690 Technique::PassIterator passIt = tech->getPassIterator();
691 while (passIt.hasMoreElements())
692 { Pass* pass = passIt.getNext();
693 if (pass->hasFragmentProgram())
694 {
695 GpuProgramParametersSharedPtr params = pass->getFragmentProgramParameters();
696 params->setNamedConstant("carColour", color);
697 params->setNamedConstant("glossiness", 1 - gloss);
698 params->setNamedConstant("reflectiveness", refl);
699 } } } }
700
701 if (pNickTxt)
702 pNickTxt->setTextColour(MyGUI::Colour(color.r,color.g,color.b));
703
704 // opp list text and mini pos colors - auto in hud update
705 }
706