1 #include "pch.h"
2 #include "../ogre/common/Def_Str.h"
3 #include "../ogre/common/RenderConst.h"
4 #include "../ogre/common/GuiCom.h"
5 #include "../ogre/common/CScene.h"
6 #include "settings.h"
7 #include "CApp.h"
8 #include "CGui.h"
9 #include "../road/Road.h"
10 #include "../vdrift/pathmanager.h"
11 
12 #include <btBulletCollisionCommon.h>
13 #include <btBulletDynamicsCommon.h>
14 #include <BulletCollision/CollisionDispatch/btCollisionWorld.h>
15 
16 #include <OgreTimer.h>
17 #include <OgreTerrain.h>
18 #include <OgreRenderWindow.h>
19 #include <OgreManualObject.h>
20 #include <OgreHardwarePixelBuffer.h>
21 #include <OgreRectangle2D.h>
22 #include <OgreCamera.h>
23 #include <OgreTextureManager.h>
24 #include <OgreRenderTexture.h>
25 #include <OgreViewport.h>
26 #include <OgreMaterialManager.h>
27 #include <OgreSceneNode.h>
28 using namespace Ogre;
29 
30 
31 //  Setup render 2 texture (road maps)
32 // . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Rnd2TexSetup()33 void App::Rnd2TexSetup()
34 {
35 	///  RT:  0 road minimap,  1 road for grass,  2 terrain minimap,  3 track preview full
36 	const uint32 visMask[RTs] =
37 		{ RV_Road, RV_Road+RV_Objects, RV_Terrain+RV_Objects, RV_MaskAll-RV_Hud };
38 	const int dim[RTs] =  //1025: sc->td.iVertsX
39 		{ 1024, 1025, 1024, 1024 };
40 
41 	asp = float(mWindow->getWidth())/float(mWindow->getHeight());
42 	Real sz = pSet->size_minimap;
43 	xm1 = 1-sz/asp, ym1 = -1+sz, xm2 = 1.0, ym2 = -1.0;
44 	AxisAlignedBox aab;  aab.setInfinite();
45 
46 	for (int i=0; i < RTs+RTsAdd; ++i)
47 	{
48 		SRndTrg& r = rt[i];  bool full = i==3;
49 		String si = toStr(i), sMtr = /*i==3 ? "road_mini_add" :*/ "road_mini_"+si;
50 		if (i < RTs)
51 		{
52 			String sTex = "RttTex"+si, sCam = "RttCam"+si;
53 
54 			TextureManager::getSingleton().remove(sTex);
55 			mSceneMgr->destroyCamera(sCam);  // dont destroy old - const tex sizes opt..
56 
57 			///  rnd to tex - same dim as Hmap	// after track load
58 			Real fDim = scn->sc->td.fTerWorldSize;  // world dim  ..vdr
59 			TexturePtr texture = TextureManager::getSingleton().createManual(
60 				sTex, rgDef, TEX_TYPE_2D,
61 				dim[i], dim[i], 0, PF_R8G8B8A8, TU_RENDERTARGET);
62 
63 			r.cam = mSceneMgr->createCamera(sCam);  // up
64 			r.cam->setPosition(Vector3(0,1000,0/*-300..*/));  r.cam->setOrientation(Quaternion(0.5,-0.5,0.5,0.5));
65 			r.cam->setNearClipDistance(0.5);	r.cam->setFarClipDistance(50000);
66 			r.cam->setAspectRatio(1.0);			if (!full)  r.cam->setProjectionType(PT_ORTHOGRAPHIC);
67 			r.cam->setOrthoWindow(fDim,fDim);	//rt[i].rndCam->setPolygonMode(PM_WIREFRAME);
68 
69 			r.tex = texture->getBuffer()->getRenderTarget();
70 			r.tex->setAutoUpdated(false);	r.tex->addListener(this);
71 			Viewport* rvp = r.tex->addViewport(r.cam);
72 			rvp->setClearEveryFrame(true);   rvp->setBackgroundColour(ColourValue(0,0,0,0));
73 			rvp->setOverlaysEnabled(false);  rvp->setSkiesEnabled(full);
74 			rvp->setVisibilityMask(visMask[i]);
75 			rvp->setShadowsEnabled(false);
76 
77 			if (i != 3)  rvp->setMaterialScheme("reflection");
78 		}
79 		///  minimap  . . . . . . . . . . . . . . . . . . . . . . . . . . .
80 		if (r.ndMini)  mSceneMgr->destroySceneNode(r.ndMini);
81 		ResourcePtr mt = MaterialManager::getSingleton().getByName(sMtr);
82 		if (!mt.isNull())  mt->reload();
83 
84 		r.mini = new Rectangle2D(true);  // screen rect preview
85 		if (i == RTs)  r.mini->setCorners(-1/asp, 1, 1/asp, -1);  // fullscr,square
86 		else  r.mini->setCorners(xm1, ym1, xm2, ym2);  //+i*sz*all
87 
88 		r.mini->setBoundingBox(aab);
89 		r.ndMini = mSceneMgr->getRootSceneNode()->createChildSceneNode("Minimap"+si);
90 		r.ndMini->attachObject(r.mini);	r.mini->setCastShadows(false);
91 		r.mini->setMaterial(i == RTs+1 ? "BrushPrvMtr" : sMtr);
92 		r.mini->setRenderQueueGroup(RQG_Hud2);
93 		r.mini->setVisibilityFlags(i == RTs ? RV_MaskPrvCam : RV_Hud);
94 	}
95 
96 	//  pos dot on minimap  . . . . . . . .
97 	if (!ndPos)
98 	{	mpos = Create2D("hud/CarPos", 0.2f, true);  // dot size
99 		mpos->setVisibilityFlags(RV_Hud);
100 		mpos->setRenderQueueGroup(RQG_Hud3 /*RENDER_QUEUE_OVERLAY+1*/);
101 		ndPos = mSceneMgr->getRootSceneNode()->createChildSceneNode(
102 			Vector3(xm1+(xm2-xm1)/2, ym1+(ym2-ym1)/2, 0));
103 		float fHudSize = 0.04f;
104 		ndPos->scale(fHudSize, fHudSize, 1);
105 		ndPos->attachObject(mpos);
106 	}
107 	if (ndPos)   ndPos->setVisible(pSet->trackmap);
108 	UpdMiniVis();
109 }
110 
UpdMiniVis()111 void App::UpdMiniVis()
112 {
113 	for (int i=0; i < RTs+RTsAdd; ++i)
114 		if (rt[i].ndMini)
115 			rt[i].ndMini->setVisible(pSet->trackmap && (i == pSet->num_mini));
116 }
117 
118 
119 ///  Image from road
120 ///  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
SaveGrassDens()121 void App::SaveGrassDens()
122 {
123 	Ogre::Timer ti;
124 
125 	for (int i=0; i < RTs-1; ++i)  //-1 preview camera manual
126 	{
127 		if (!rt[i].tex)  return;
128 		rt[i].tex->update();  // all have to exist
129 	}
130 
131 	int w = rt[1].tex->getWidth(), h = rt[1].tex->getHeight();
132 	using Ogre::uint;
133 	uint *rd = new uint[w*h];   // road render
134 	uint *gd = new uint[w*h];   // grass dens
135 	PixelBox pb_rd(w,h,1, PF_BYTE_RGBA, rd);
136 	rt[1].tex->copyContentsToMemory(pb_rd, RenderTarget::FB_FRONT);
137 
138 	const int f = std::max(0, scn->sc->grDensSmooth);
139 	float sum = 0.f;
140 	register int v,i,j,x,y, a,b,d,m;
141 
142 	//  gauss kernel for smoothing
143 	int *mask = new int[(f*2+1)*(f*2+1)];  m = 0;
144 	if (f==0)
145 	{	mask[0] = 256.f;  sum = 256.f;  }
146 	else
147 	for (j = -f; j <= f; ++j)
148 	for (i = -f; i <= f; ++i, ++m)
149 	{
150 		v = std::max(0.f, (1.f - sqrtf((float)(i*i+j*j)) / float(f)) * 256.f);
151 		mask[m] = v;  sum += v;
152 	}
153 	sum = 2.f / sum;  //par normally would be 1.f - but road needs to stay black and be smooth outside
154 	//  change smooth to distance from road with fade ?..
155 
156 	///  road - rotate, smooth  -----------
157 	for (y = f; y < h-f; ++y) {  a = y*w +f;
158 	for (x = f; x < w-f; ++x, ++a)
159 	{	b = x*w + (h-y);  // rot 90 ccw  b=a
160 
161 		//  sum kernel
162 		v = 0;  m = 0;
163 		for (j = -f; j <= f; ++j) {  d = b -f + j*w;
164 		for (i = -f; i <= f; ++i, ++d, ++m)
165 			v += ((rd[d] >> 16) & 0xFF) * mask[m] / 256;  }
166 
167 		v = std::max(0, (int)(255.f * (1.f - v * sum) ));  // avg, inv, clamp
168 
169 		gd[a] = 0xFF000000 + v;  // write
170 	}	}
171 
172 	v = 0xFF0000FF;  //  frame f []  todo: get from rd[b] not clear..
173 	for (y = 0;  y <= f; ++y)	for (x=0; x < w; ++x)	gd[y*w+x] = v;  // - up
174 	for (y=h-f-1; y < h; ++y)	for (x=0; x < w; ++x)	gd[y*w+x] = v;  // - down
175 	for (x = 0;  x <= f; ++x)	for (y=0; y < h; ++y)	gd[y*w+x] = v;  // | left
176 	for (x=w-f-1; x < w; ++x)	for (y=0; y < h; ++y)	gd[y*w+x] = v;  // | right
177 
178 	LogO(String("::: Time road dens: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");  ti.reset();
179 
180 	if (!IsVdrTrack())  // vdr trk no grass, only previews
181 	{
182 		Image im;  // for trees, before grass angle and height
183 		im.loadDynamicImage((uchar*)gd, w,h,1, PF_BYTE_RGBA);
184 		im.save(gcom->TrkDir()+"objects/roadDensity.png");
185 	}
186 	delete[] rd;  delete[] gd;  delete[] mask;
187 
188 	//  road, terrain  ----------------
189 	int u = pSet->allow_save ? pSet->gui.track_user : 1;
190 	rt[0].tex->writeContentsToFile(gcom->pathTrk[u] + pSet->gui.track + "/preview/road.png");
191 	rt[2].tex->writeContentsToFile(gcom->pathTrk[u] + pSet->gui.track + "/preview/terrain.jpg");
192 
193 	LogO(String("::: Time save prv : ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
194 }
195 
196 
197 ///  pre and post  rnd to tex
198 //-----------------------------------------------------------------------------------------------------------
preRenderTargetUpdate(const RenderTargetEvent & evt)199 void App::preRenderTargetUpdate(const RenderTargetEvent &evt)
200 {
201 	const String& s = evt.source->getName();
202 	int num = atoi(s.substr(s.length()-1, s.length()-1).c_str());
203 
204 	if (num == 3)  // full
205 	{
206 		rt[3].cam->setPosition(mCamera->getPosition());
207 		rt[3].cam->setDirection(mCamera->getDirection());
208 	}
209 	else if (scn->road)
210 		scn->road->SetForRnd(num == 0 ? "render_clr" : "render_grass");
211 }
212 
postRenderTargetUpdate(const RenderTargetEvent & evt)213 void App::postRenderTargetUpdate(const RenderTargetEvent &evt)
214 {
215 	const String& s = evt.source->getName();
216 	int num = atoi(s.substr(s.length()-1, s.length()-1).c_str());
217 
218 	if (num == 3)  // full
219 	{
220 	}
221 	else if (scn->road)
222 	{	scn->road->UnsetForRnd();
223 		scn->road->UpdLodVis(pSet->road_dist);
224 	}
225 
226 	//  restore shadows splits todo...
227 	//mCamera->setFarClipDistance(pSet->view_distance*1.1f);
228 	//mCamera->setNearClipDistance(0.1f);
229 	//UpdPSSMMaterials();
230 }
231 
232 
233 ///  save water depth map
234 //-----------------------------------------------------------------------------------------------------------
SaveWaterDepth()235 void App::SaveWaterDepth()
236 {
237 	if (scn->sc->fluids.empty())
238 	{
239 		gui->Delete(gcom->TrkDir()+"objects/waterDepth.png");  // no tex if no fluids
240 		return;
241 	}
242 	Ogre::Timer ti;
243 
244 	//  2048 for bigger terrains ?
245 	int w = 1024, h = w;  float fh = h-1, fw = w-1;
246 	using Ogre::uint;
247 	uint *wd = new uint[w*h];   // water depth
248 	register int x,y,a,i,ia,id;
249 	register float fa,fd;
250 
251 	///  write to img  -----------
252 	//  get ter height to fluid height difference for below
253 	for (y = 0; y < h; ++y) {  a = y*w;
254 	for (x = 0; x < w; ++x, ++a)
255 	{
256 		//  pos 0..1
257 		float fx = float(y)/fh, fz = float(x)/fw;
258 		//  pos on ter  -terSize..terSize
259 		float w = scn->sc->td.fTerWorldSize;
260 		float wx = (fx-0.5f) * w, wz = -(fz-0.5f) * w;
261 
262 		fa = 0.f;  // fluid y pos
263 		for (i=0; i < scn->sc->fluids.size(); ++i)
264 		{
265 			const FluidBox& fb = scn->sc->fluids[i];
266 			const float sizex = fb.size.x*0.5f, sizez = fb.size.z*0.5f;
267 			//  check rect 2d - no rot !  todo: make 2nd type circle..
268 			if (wx > fb.pos.x - sizex && wx < fb.pos.x + sizex &&
269 				wz > fb.pos.z - sizez && wz < fb.pos.z + sizez)
270 			{
271 				float f = fb.pos.y - scn->terrain->getHeightAtTerrainPosition(fx,fz);
272 				if (f > fa)  fa = f;
273 			}
274 		}		//par
275 		fd = fa * 0.4f * 255.f;  // depth far  full at 2.5 m
276 		fa = fa * 8.f * 255.f;  // alpha near  full at 1/8 m
277 
278 		ia = std::max(0, std::min(255, (int)fa ));  // clamp
279 		id = std::max(0, std::min(255, (int)fd ));
280 
281 		wd[a] = 0xFF000000 + /*0x01 */ ia + 0x0100 * id;  // write
282 	}	}
283 
284 	Image im;  // save img
285 	im.loadDynamicImage((uchar*)wd, w,h,1, PF_BYTE_RGBA);
286 	im.save(gcom->TrkDir()+"objects/waterDepth.png");
287 	delete[] wd;
288 
289 	try {
290 	TexturePtr tex = TextureManager::getSingleton().getByName("waterDepth.png");
291 	if (!tex.isNull())
292 		tex->reload();
293 	else  // 1st fluid after start, refresh matdef ?..
294 		TextureManager::getSingleton().load("waterDepth.png", rgDef);
295 	} catch(...) {  }
296 
297 	LogO(String("::: Time WaterDepth: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
298 }
299 
300 
301 
302 ///  . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
303 ///  align terrain to road selected segments
304 //-----------------------------------------------------------------------------------------------------------
305 struct RayResult : public btCollisionWorld::RayResultCallback
306 {
RayResultRayResult307 	RayResult(const btVector3& rayFromWorld, const btVector3& rayToWorld)
308 		: m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld)
309 	{	}
310 
311 	btVector3	m_rayFromWorld;//used to calculate hitPointWorld from hitFraction
312 	btVector3	m_rayToWorld;
313 
314 	btVector3	m_hitNormalWorld;
315 	btVector3	m_hitPointWorld;
316 
addSingleResultRayResult317 	virtual	btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace)
318 	{
319 		const btCollisionObject* obj = rayResult.m_collisionObject;
320 		if (obj->getUserPointer() != (void*)111)  // allow only road
321 			return 1.0;
322 
323 		//caller already does the filter on the m_closestHitFraction
324 		btAssert(rayResult.m_hitFraction <= m_closestHitFraction);
325 
326 		m_closestHitFraction = rayResult.m_hitFraction;
327 		m_collisionObject = obj;
328 
329 		if (normalInWorldSpace)
330 			m_hitNormalWorld = rayResult.m_hitNormalLocal;
331 		else  ///need to transform normal into worldspace
332 			m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal;
333 
334 		m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction);
335 		return rayResult.m_hitFraction;
336 	}
337 };
338 
AlignTerToRoad()339 void App::AlignTerToRoad()
340 {
341 	SplineRoad* road = scn->road;
342 	if (road->vSel.empty())  return;
343 	Ogre::Timer ti;
344 
345 	///  create bullet road for selected segments
346 	road->ed_Wmul = pSet->al_w_mul;
347 	road->ed_Wadd = pSet->al_w_add;
348 	road->RebuildRoadInt(true);
349 
350 	//  terrain
351 	float *fHmap = scn->terrain->getHeightData();
352 	const int w = scn->sc->td.iVertsX, h = w;
353 	const float fh = h-1, fw = w-1;
354 
355 	float *rd = new float[w*h];  // road depth
356 	bool  *rh = new bool[w*h];  // road hit
357 
358 	const float ws = scn->sc->td.fTerWorldSize;
359 	const float Len = 400;  // max ray length
360 	register int x,y,a;
361 	register float v,k, fx,fz, wx,wz;
362 
363 	///  ray casts  -----------
364 	for (y = 0; y < h; ++y) {  a = y*w;
365 	for (x = 0; x < w; ++x, ++a)
366 	{
367 		//  pos 0..1
368 		fx = float(x)/fh;  fz = float(y)/fw;
369 		//  pos on ter  -terSize..terSize
370 		wx = (fx-0.5f) * ws;  wz = (fz-0.5f) * ws;
371 
372 		btVector3 from(wx,wz,Len), to(wx,wz,-Len);  // x -z y
373 		RayResult rayRes(from, to);
374 		world->rayTest(from, to, rayRes);
375 
376 		//  terrain height if not hit
377 		rh[a] = rayRes.hasHit();
378 		rd[a] = rayRes.hasHit() ? rayRes.m_hitPointWorld.getZ() : fHmap[a];
379 	}	}
380 
381 	//  smooth edges, road-terrain border
382 	const float fv = pSet->al_smooth;
383 	if (fv > 0.5f)
384 	{
385 		const int f = std::ceil(fv);
386 		const unsigned int fs = (f*2+1)*(f*2+1);
387 		float ff = 0.f;
388 		register int i,j,m,d,b;
389 
390 		//  gauss kernel for smoothing
391 		float *mask = new float[fs];  m = 0;
392 		for (j = -f; j <= f; ++j)
393 		for (i = -f; i <= f; ++i, ++m)
394 		{
395 			v = std::max(0.f, 1.f - sqrtf((float)(i*i+j*j)) / fv );
396 			mask[m] = v;  ff += v;
397 		}
398 		ff = 1.f / ff;  // smooth, outside (>1.f)
399 
400 		//  sum kernel
401 		for (y = f; y < h-f; ++y) {  a = y*w +f;
402 		for (x = f; x < w-f; ++x, ++a)
403 		{
404 			v = 0;  m = 0;  b = 0;
405 			for (j = -f; j <= f; ++j) {  d = a -f + j*w;
406 			for (i = -f; i <= f; ++i, ++d, ++m)
407 			{	k = mask[m];  //maskB ?
408 				v += rd[d] * k;
409 				if (rh[d] && k > 0.1f)  ++b;
410 			}	}
411 			if (b > 0 && b < fs*0.8f)  //par?
412 				rd[a] = v * ff;
413 		}	}
414 		delete[] mask;
415 	}
416 
417 	//  set new hmap
418 	for (y = 0; y < h; ++y) {  a = y*w;
419 	for (x = 0; x < w; ++x, ++a)
420 	{
421 		fHmap[a] = rd[a];
422 	}	}
423 
424 	delete[] rd;  delete[] rh;
425 
426 
427 
428 	//  clear bullet world
429 	for (int i=0; i < road->vbtTriMesh.size(); ++i)
430 		delete road->vbtTriMesh[i];
431 	road->vbtTriMesh.clear();
432 
433 	for (int i = world->getNumCollisionObjects() - 1; i >= 0; i--)
434 	{
435 		btCollisionObject* obj = world->getCollisionObjectArray()[i];
436 		if (obj->getUserPointer() == (void*)111)  // only road
437 		{
438 			delete obj->getCollisionShape();  //?
439 
440 			btRigidBody* body = btRigidBody::upcast(obj);
441 			if (body && body->getMotionState())
442 				delete body->getMotionState();
443 
444 			world->removeCollisionObject(obj);
445 			delete obj;
446 		}
447 	}
448 
449 
450 	//  update terrain
451 	scn->terrain->dirty();  //rect..
452 	scn->UpdBlendmap();
453 	bTerUpd = true;
454 
455 
456 	//  put sel segs on terrain
457 	for (std::set<int>::const_iterator it = scn->road->vSel.begin(); it != scn->road->vSel.end(); ++it)
458 		scn->road->mP[*it].onTer = true;
459 
460 	//  restore orig road width
461 	scn->road->Rebuild(true);
462 
463 	// todo: ?restore road sel after load F5..
464 
465 	LogO(String("::: Time Ter Align: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
466 }
467