1 #include "pch.h"
2 #include "common/Def_Str.h"
3 #include "common/Gui_Def.h"
4 #include "CGame.h"
5 #include "CHud.h"
6 #include "CGui.h"
7 #include "common/GuiCom.h"
8 #include "common/CScene.h"
9 #include "common/WaterRTT.h"
10 #include "common/data/SceneXml.h"
11 #include "common/data/FluidsXml.h"
12 #include "FollowCamera.h"
13 #include "../road/Road.h"
14 #include "../road/PaceNotes.h"
15 #include "../vdrift/game.h"
16 #include "../vdrift/quickprof.h"
17 #include "../paged-geom/PagedGeometry.h"
18 #include "../network/masterclient.hpp"
19 #include "../network/gameclient.hpp"
20 #include "LinearMath/btDefaultMotionState.h"
21 #include "SplitScreen.h"
22 #include "../shiny/Main/Factory.hpp"
23 #include "../sdl4ogre/sdlinputwrapper.hpp"
24 
25 #include <OgreParticleSystem.h>
26 #include <OgreManualObject.h>
27 #include <OgreMaterialManager.h>
28 #include <OgreSceneNode.h>
29 #include <OgreViewport.h>
30 #include <OgreTimer.h>
31 #include "common/MultiList2.h"
32 #include "common/Slider.h"
33 #include <MyGUI.h>
34 using namespace Ogre;
35 using namespace MyGUI;
36 
37 
38 #define isKey(a)  mInputWrapper->isKeyDown(a)
39 
40 
41 //  simulation (2nd) thread
42 //---------------------------------------------------------------------------------------------------------------
43 
UpdThr()44 void App::UpdThr()
45 {
46 	Ogre::Timer gtim;
47 	//#ifdef _WIN32
48 	//DWORD af = 2;
49 	//gtim.setOption("QueryAffinityMask", &af);
50 	//#endif
51 	gtim.reset();
52 
53 	while (!mShutDown)
54 	{
55 		///  step Game  **
56 
57 		double dt = double(gtim.getMicroseconds()) * 0.000001;
58 		gtim.reset();
59 
60 		if (pSet->multi_thr == 1 && !bLoading && !mShutDown)
61 		{
62 			bSimulating = true;
63 			bool ret = pGame->OneLoop(dt);
64 			if (!ret)
65 				mShutDown = true;  //ShutDown();
66 
67 			DoNetworking();
68 			bSimulating = false;
69 		}
70 		boost::this_thread::sleep(boost::posix_time::milliseconds(pSet->thread_sleep));
71 	}
72 }
73 
74 
isTweakTab()75 bool App::isTweakTab()
76 {
77 	int tt = !gui->tabTweak ? 0 : gui->tabTweak->getIndexSelected();
78 	return isTweak() && tt != 1 && tt != 2;
79 }
80 
81 
82 ///  Newtork update  . . . .
DoNetworking()83 void App::DoNetworking()
84 {
85 	bool doNetworking = (mClient && mClient->getState() == P2PGameClient::GAME);
86 
87 	//  no pause in networked game
88 	int tt = !gui->tabTweak ? 0 : gui->tabTweak->getIndexSelected();
89 	bool gui = isFocGui || isTweakTab();
90 	pGame->pause = bRplPlay ? (bRplPause || gui) : (gui && !doNetworking);
91 
92 	//  handle networking stuff
93 	if (doNetworking)
94 	{
95 		PROFILER.beginBlock("-network");
96 
97 		//  update the local car's state to the client
98 		protocol::CarStatePackage cs;  // FIXME: Handles only one local car
99 		for (CarModels::const_iterator it = carModels.begin(); it != carModels.end(); ++it)
100 		{
101 			if ((*it)->eType == CarModel::CT_LOCAL)
102 			{
103 				cs = (*it)->pCar->GetCarStatePackage();
104 				cs.trackPercent = uint8_t( (*it)->trackPercent / 100.f * 255.f);  // pack to uint8
105 				break;
106 			}
107 		}
108 		mClient->setLocalCarState(cs);
109 
110 		//  check for new car states
111 		protocol::CarStates states = mClient->getReceivedCarStates();
112 		for (protocol::CarStates::const_iterator it = states.begin(); it != states.end(); ++it)
113 		{
114 			int8_t id = it->first;  // Car number  // FIXME: Various places assume carModels[0] is local
115 			if (id == 0)  id = mClient->getId();
116 
117 			CarModel* cm = carModels[id];
118 			if (cm && cm->pCar)
119 			{
120 				cm->pCar->UpdateCarState(it->second);
121 				cm->trackPercent = cm->pCar->trackPercentCopy;  // got from client
122 			}
123 		}
124 		PROFILER.endBlock("-network");
125 	}
126 }
127 
128 
129 //  Frame Start
130 //---------------------------------------------------------------------------------------------------------------
131 
frameStart(Real time)132 bool App::frameStart(Real time)
133 {
134 	PROFILER.beginBlock(" frameSt");
135 	fLastFrameDT = time;
136 
137 
138 	//  input
139 	for (int i=0; i<4; ++i)
140 	{
141 		boost::lock_guard<boost::mutex> lock(input->mPlayerInputStateMutex);
142 		for (int a = 0; a < NumPlayerActions; ++a)
143 			input->mPlayerInputState[i][a] = mInputCtrlPlayer[i]->getChannel(a)->getValue();
144 	}
145 
146 	if (imgBack && pGame)  // show/hide background image
147 	{
148 		bool backImgVis = !bLoading && pGame->cars.empty();
149 		imgBack->setVisible(backImgVis);
150 	}
151 
152 
153 	//  multi thread
154 	if (pSet->multi_thr == 1 && pGame && !bLoading)
155 	{
156 		updatePoses(time);
157 	}
158 
159 	///  graphs update  -._/\_-.
160 	if (pSet->show_graphs && graphs.size() > 0)
161 	{
162 		GraphsNewVals();
163 		UpdateGraphs();
164 	}
165 
166 	//...................................................................
167 	///* tire edit */
168 	if ((pSet->graphs_type == Gh_TireEdit || pSet->graphs_type == Gh_Tires4Edit) &&
169 		carModels.size() > 0 && !mWndTweak->getVisible())
170 	{
171 		int k = (isKey(SDL_SCANCODE_1) || isKey(SDL_SCANCODE_KP_DIVIDE)  ? -1 : 0)
172 			  + (isKey(SDL_SCANCODE_2) || isKey(SDL_SCANCODE_KP_MULTIPLY) ? 1 : 0);
173 		if (k)
174 		{
175 			double mul = shift ? 0.2 : (ctrl ? 4.0 : 1.0);
176 			mul *= 0.005;  // par
177 
178 			CARDYNAMICS& cd = carModels[0]->pCar->dynamics;
179 			CARTIRE* tire = cd.GetTire(FRONT_LEFT);
180 			if (iEdTire == 1)  // longit |
181 			{
182 				Dbl& val = tire->longitudinal[iCurLong];  // modify 1st
183 				val += mul*k * (1 + abs(val));
184 				for (int i=1; i<4; ++i)
185 					cd.GetTire(WHEEL_POSITION(i))->longitudinal[iCurLong] = val;  // copy for rest
186 			}
187 			else if (iEdTire == 0)  // lateral --
188 			{
189 				Dbl& val = tire->lateral[iCurLat];
190 				val += mul*k * (1 + abs(val));
191 				for (int i=1; i<4; ++i)
192 					cd.GetTire(WHEEL_POSITION(i))->lateral[iCurLat] = val;
193 			}
194 			else  // align o
195 			{
196 				Dbl& val = tire->aligning[iCurAlign];
197 				val += mul*k * (1 + abs(val));
198 				for (int i=1; i<4; ++i)
199 					cd.GetTire(WHEEL_POSITION(i))->aligning[iCurAlign] = val;
200 			}
201 
202 			//  update hat, 1st
203 			tire->CalculateSigmaHatAlphaHat();
204 			for (int i=1; i<4; ++i)  // copy for rest
205 			{	cd.GetTire(WHEEL_POSITION(i))->sigma_hat = tire->sigma_hat;
206 				cd.GetTire(WHEEL_POSITION(i))->alpha_hat = tire->alpha_hat;
207 			}
208 			iUpdTireGr = 1;
209 		}
210 	}
211 	//...................................................................
212 
213 
214 	///  gui
215 	gui->GuiUpdate();
216 
217 
218 	if (bWindowResized)
219 	{	bWindowResized = false;
220 
221 		gcom->ResizeOptWnd();
222 		gcom->SizeGUI();
223 		gcom->updTrkListDim();
224 		gui->updChampListDim();  // resize lists
225 		gui->slSSS(0);
226 		gui->listCarChng(gui->carList,0);  // had wrong size
227 		bRecreateHUD = true;
228 
229 		if (mSplitMgr)  //  reassign car cameras from new viewports
230 		{	std::list<Camera*>::iterator it = mSplitMgr->mCameras.begin();
231 			for (int i=0; i < carModels.size(); ++i)
232 				if (carModels[i]->fCam && it != mSplitMgr->mCameras.end())
233 				{	carModels[i]->fCam->mCamera = *it;  ++it;  }
234 		}
235 		if (!mSplitMgr->mCameras.empty())
236 		{
237 			Camera* cam1 = *mSplitMgr->mCameras.begin();
238 			scn->mWaterRTT->setViewerCamera(cam1);
239 			if (scn->grass)  scn->grass->setCamera(cam1);
240 			if (scn->trees)  scn->trees->setCamera(cam1);
241 		}
242 
243 		///gui->InitCarPrv();
244 	}
245 
246 	//  hud update sizes, after res change
247 	if (bRecreateHUD)
248 	{	bRecreateHUD = false;
249 
250 		hud->Destroy();  hud->Create();
251 	}
252 	if (bSizeHUD)
253 	{	bSizeHUD = false;
254 
255 		hud->Size();
256 	}
257 
258 
259 	if (bLoading)
260 	{
261 		NewGameDoLoad();
262 		PROFILER.endBlock(" frameSt");
263 		return true;
264 	}
265 	else
266 	{
267 		///  loading end  ------
268 		const int iFr = 3;
269 		if (iLoad1stFrames >= 0)
270 		{	++iLoad1stFrames;
271 			if (iLoad1stFrames == iFr)
272 			{
273 				LoadingOff();  // hide loading overlay
274 				mSplitMgr->mGuiViewport->setClearEveryFrame(true, FBT_DEPTH);
275 				gui->Ch_LoadEnd();
276 				bLoadingEnd = true;
277 				iLoad1stFrames = -1;  // for refl
278 			}
279 		}else if (iLoad1stFrames >= -1)
280 		{
281 			--iLoad1stFrames;  // -2 end
282 
283 			imgLoad->setVisible(false);  // hide back imgs
284 			if (imgBack)
285 				imgBack->setVisible(false);
286 		}
287 
288 
289 		//  input
290 		if (isFocGui && pSet->inMenu == MNU_Options && !pSet->isMain &&
291 			mWndTabsOpts->getIndexSelected() == TABo_Input)
292 			gui->UpdateInputBars();
293 
294 
295 		//  keys up/dn, for lists
296 		static float dirU = 0.f,dirD = 0.f;
297 		if (isFocGui && !pSet->isMain && !isTweak())
298 		{
299 			if (isKey(SDL_SCANCODE_UP)  ||isKey(SDL_SCANCODE_KP_8))	dirD += time;  else
300 			if (isKey(SDL_SCANCODE_DOWN)||isKey(SDL_SCANCODE_KP_2))	dirU += time;  else
301 			{	dirU = 0.f;  dirD = 0.f;  }
302 			int d = ctrl ? 4 : 1;
303 			if (dirU > 0.0f) {  gui->LNext( d);  dirU = -0.2f;  }
304 			if (dirD > 0.0f) {  gui->LNext(-d);  dirD = -0.2f;  }
305 		}
306 
307 		///  Gui updates from Networking
308 		gui->UpdGuiNetw();
309 
310 
311 		//  replay forward,backward keys
312 		if (bRplPlay)
313 		{
314 			isFocRpl = ctrl;
315 			bool le = isKey(SDL_SCANCODE_LEFTBRACKET), ri = isKey(SDL_SCANCODE_RIGHTBRACKET), ctrlN = ctrl && (le || ri);
316 			int ta = ((le || gui->bRplBack) ? -2 : 0) + ((ri || gui->bRplFwd) ? 2 : 0);
317 			if (ta)
318 			{	double tadd = ta;
319 				tadd *= (shift ? 0.2 : 1) * (ctrlN ? 4 : 1) * (alt ? 8 : 1);  // multipliers
320 				if (!bRplPause)  tadd -= 1;  // play compensate
321 				double t = pGame->timer.GetReplayTime(0), len = replay.GetTimeLength();
322 				t += tadd * time;  // add
323 				if (t < 0.0)  t += len;  // cycle
324 				if (t > len)  t -= len;
325 				pGame->timer.SetReplayTime(0, t);
326 			}
327 		}
328 
329 		if (!pGame)
330 		{
331 			PROFILER.endBlock(" frameSt");
332 			return false;
333 		}
334 
335 
336 		if (pSet->multi_thr == 0)
337 			DoNetworking();
338 
339 
340 		//  single thread, sim on draw
341 		bool ret = true;
342 		if (pSet->multi_thr == 0)
343 		{
344 			ret = pGame->OneLoop(time);
345 			if (!ret)
346 				ShutDown();
347 			updatePoses(time);
348 		}
349 
350 		// align checkpoint arrow
351 		// move in front of camera
352 		if (pSet->check_arrow && hud->arrow.node && !bRplPlay && !carModels.empty())
353 		{
354 			FollowCamera* cam = carModels[0]->fCam;
355 
356 			Vector3 pos = cam->mCamera->getPosition();
357 			Vector3 dir = cam->mCamera->getDirection();  dir.normalise();
358 			Vector3 up = cam->mCamera->getUp();  up.normalise();
359 			Vector3 arrowPos = pos + 10.0f * dir + 3.5f*up;
360 			hud->arrow.node->setPosition(arrowPos);
361 
362 			// animate
363 			bool bFirstFrame = carModels.front()->bGetStPos;
364 			if (bFirstFrame) // 1st frame: dont animate
365 				hud->arrow.qCur = hud->arrow.qEnd;
366 			else
367 				hud->arrow.qCur = Quaternion::Slerp(time*5, hud->arrow.qStart, hud->arrow.qEnd, true);
368 			hud->arrow.nodeRot->setOrientation(hud->arrow.qCur);
369 
370 			// look down -y a bit so we can see the arrow better
371 			hud->arrow.nodeRot->pitch(Degree(-20), SceneNode::TS_LOCAL);
372 		}
373 
374 		//  cam info text
375 		if (pSet->show_cam && !carModels.empty() && hud->txCamInfo)
376 		{	FollowCamera* cam = carModels[0]->fCam;
377 			if (cam)
378 			{	bool vis = cam->updInfo(time) && !isFocGui;
379 				if (vis)
380 					hud->txCamInfo->setCaption(String(cam->ss));
381 				hud->txCamInfo->setVisible(vis);
382 		}	}
383 
384 
385 		//  update all cube maps
386 		PROFILER.beginBlock("g.refl");
387 		for (std::vector<CarModel*>::iterator it=carModels.begin(); it!=carModels.end(); it++)
388 		if (!(*it)->isGhost() && (*it)->pReflect)
389 			(*it)->pReflect->Update(iLoad1stFrames == -1);
390 		PROFILER.endBlock("g.refl");
391 
392 
393 		//  trees
394 		PROFILER.beginBlock("g.veget");
395 		if (scn->road) {
396 			if (scn->grass)  scn->grass->update();
397 			if (scn->trees)  scn->trees->update();  }
398 		PROFILER.endBlock("g.veget");
399 
400 
401 		//  road upd lods
402 		if (scn->road)
403 		{
404 			//PROFILER.beginBlock("g.road");  // below 0.0 ms
405 
406 			//  more than 1: in pre viewport, each frame
407 			if (mSplitMgr->mNumViewports == 1)
408 			{
409 				roadUpdTm += time;
410 				if (roadUpdTm > 0.1f)  // interval [sec]
411 				{
412 					roadUpdTm = 0.f;
413 					scn->road->UpdLodVis(pSet->road_dist);
414 				}
415 			}
416 			//PROFILER.endBlock("g.road");
417 		}
418 
419 		//[]()  pace upd vis  ~ ~ ~
420 		if (scn->pace)
421 		{
422 			const CarModel* cm = *carModels.begin();
423 			Vector3 p = cm->pMainNode->getPosition();
424 			float vel = cm->pCar->GetSpeedometer();
425 			scn->pace->carVel = vel;
426 			scn->pace->rewind = cm->pCar->bRewind;
427 			scn->pace->UpdVis(p);
428 		}
429 
430 
431 		//**  bullet bebug draw
432 		if (dbgdraw)  {							// DBG_DrawWireframe
433 			dbgdraw->setDebugMode(pSet->bltDebug ? 1 /*+(1<<13) 255*/ : 0);
434 			dbgdraw->step();  }
435 
436 
437 		///  terrain mtr from blend maps
438 		// now in CarModel::Update
439 		//UpdWhTerMtr(pCar);
440 
441 		// stop rain/snow when paused
442 		if (scn->pr && scn->pr2 && pGame)
443 		{
444 			if (pGame->pause)
445 				{	 scn->pr->setSpeedFactor(0.f);  scn->pr2->setSpeedFactor(0.f);  }
446 			else{	 scn->pr->setSpeedFactor(1.f);  scn->pr2->setSpeedFactor(1.f);  }
447 		}
448 
449 
450 		//  update shader time
451 		mTimer += time;
452 		mFactory->setSharedParameter("windTimer",  sh::makeProperty <sh::FloatValue>(new sh::FloatValue(mTimer)));
453 		mFactory->setSharedParameter("waterTimer", sh::makeProperty <sh::FloatValue>(new sh::FloatValue(mTimer)));
454 
455 
456 		///()  grass sphere pos
457 		bool hasCars = !carModels.empty();
458 		if (hasCars)
459 		{
460 			Real r = 1.7;  r *= r;  //par
461 			const Vector3* p = &carModels[0]->posSph[0];
462 			mFactory->setSharedParameter("posSph0", sh::makeProperty <sh::Vector4>(new sh::Vector4(p->x,p->y,p->z,r)));
463 			p = &carModels[0]->posSph[1];
464 			mFactory->setSharedParameter("posSph1", sh::makeProperty <sh::Vector4>(new sh::Vector4(p->x,p->y,p->z,r)));
465 		}else
466 		{	mFactory->setSharedParameter("posSph0", sh::makeProperty <sh::Vector4>(new sh::Vector4(0,0,500,-1)));
467 			mFactory->setSharedParameter("posSph1", sh::makeProperty <sh::Vector4>(new sh::Vector4(0,0,500,-1)));
468 		}
469 
470 		///~~  fluid fog, send params to shaders
471 		if (hasCars  && pSet->game.local_players == 1)
472 		{
473 			int fi = carModels[0]->iCamFluid;
474 			float p = carModels[0]->fCamFl;
475 			//? if (fi != idFlOld)  {
476 			if (fi >= 0)
477 			{	const FluidBox* fb = &scn->sc->fluids[fi];
478 				const FluidParams& fp = scn->sc->pFluidsXml->fls[fb->id];
479 
480 				mFactory->setSharedParameter("fogFluidH", sh::makeProperty <sh::Vector4>(new sh::Vector4(
481 					fb->pos.y +p /*+0.5f par? ofsH..*/, 1.f / fp.fog.dens, fp.fog.densH +p*0.5f, 0)));
482 
483 				mFactory->setSharedParameter("fogFluidClr", sh::makeProperty <sh::Vector4>(new sh::Vector4(
484 					fp.fog.r, fp.fog.g, fp.fog.b, fp.fog.a)));
485 			}else
486 				mFactory->setSharedParameter("fogFluidH", sh::makeProperty <sh::Vector4>(new sh::Vector4(
487 					-900.f, 1.f/17.f, 0.15f, 0)));
488 
489 		}// no else, set in setFog default
490 
491 
492 		//  Signal loading finished to the peers
493 		if (mClient && bLoadingEnd)
494 		{
495 			bLoadingEnd = false;
496 			mClient->loadingFinished();
497 		}
498 
499 		PROFILER.endBlock(" frameSt");
500 
501 		return ret;
502 	}
503 	PROFILER.endBlock(" frameSt");
504 }
505 
frameEnd(Real time)506 bool App::frameEnd(Real time)
507 {
508 	//  sleep when in Gui
509 	if (isFocGui && pSet->gui_sleep >= 0)  // && gui && gui->bGI)
510 		//!pSet->isMain && pSet->inMenu == MNU_Single && mWndTabsGame->getIndexSelected() == TAB_Multi)
511 		boost::this_thread::sleep(boost::posix_time::milliseconds(pSet->gui_sleep));
512 
513 	return true;
514 }
515