1 #include "pch.h"
2 #include "../ogre/common/Def_Str.h"
3 #include "../ogre/common/RenderConst.h"
4 #include "../ogre/common/ShapeData.h"
5 #include "../vdrift/dbl.h"
6 #include "Road.h"
7 #ifndef SR_EDITOR
8 	#include "../vdrift/game.h"
9 #else
10 	#include "../editor/CApp.h"
11 	#include <BulletCollision/CollisionShapes/btTriangleMesh.h>
12 	#include <BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h>
13 	#include <BulletCollision/CollisionDispatch/btCollisionObject.h>
14 	#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
15 #endif
16 #include <OgreTerrain.h>
17 #include <OgreMeshManager.h>
18 #include <OgreEntity.h>
19 using namespace Ogre;
20 using std::vector;  using std::min;  using std::max;
21 
22 
23 //  2-1	 6-5
24 //  | 0--7 |
25 //  3______4  front wall indices
26 const static int WFid[6][3] = {{2,1,0},{3,2,0},{5,4,7},{6,5,7}, {7,3,0},{4,3,7}};
27 
28 struct stWiPntW {  Real x,y, uv, nx,ny;  };  // wall width points
29 const static int ciwW = 7;  // wall  width steps - types..
30 const static stWiPntW wiPntW[ciwW+1][3] = {  // section shape
31 	//  normal road                     //  pipe wall
32 	{{-0.5f, -0.0f, 0.0f,  1.0f, 0.0f}, {-0.28f, 0.68f,0.0f, -1.0f, 0.0f}, {-0.14f, 1.5f, 0.0f, -1.0f, 0.0f}},
33 	{{-0.5f,  1.2f, 0.5f,  0.5f, 0.5f}, {-0.28f, 0.5f, 0.2f, -0.5f, 0.5f}, {-0.14f, 1.4f, 0.2f, -0.5f, 0.5f}},
34 	{{-0.56f, 1.2f, 0.2f, -0.5f, 0.5f}, {-0.28f, 0.0f, 0.2f, -0.5f, 0.0f}, {-0.14f, 1.3f, 0.2f, -0.5f, 0.0f}},
35 	{{-0.56f,-0.9f, 1.6f, -0.5f,-0.5f}, {-0.2f, -0.9f, 0.5f, -0.1f,-0.5f}, {-0.1f,  1.2f, 0.5f, -0.1f,-0.5f}},
36 	{{ 0.56f,-0.9f, 3.0f,  0.5f,-0.5f}, { 0.2f, -0.9f, 0.5f,  0.1f,-0.5f}, { 0.1f,  1.2f, 0.5f,  0.1f,-0.5f}},
37 	{{ 0.56f, 1.2f, 1.6f,  0.5f, 0.5f}, { 0.28f, 0.0f, 0.2f,  0.5f, 0.0f}, { 0.14f, 1.3f, 0.2f,  0.5f, 0.0f}},
38 	{{ 0.5f,  1.2f, 0.2f, -0.5f, 0.5f}, { 0.28f, 0.5f, 0.2f,  0.5f, 0.5f}, { 0.14f, 1.4f, 0.2f,  0.5f, 0.5f}},
39 	{{ 0.5f, -0.0f, 0.5f, -1.0f, 0.0f}, { 0.28f, 0.68f,0.2f,  1.0f, 0.0f}, { 0.14f, 1.5f, 0.2f,  1.0f, 0.0f}}};
40 
41 
42 
43 //  Build Segment Geometry
44 //----------------------------------------------------------------------------------------------------------------------------
BuildSeg(const DataRoad & DR,const DataLod0 & DL0,DataLod & DL,StatsLod & ST,DataLodMesh & DLM,DataSeg & DS,int segM,bool full)45 void SplineRoad::BuildSeg(
46 	const DataRoad& DR,
47 	const DataLod0& DL0, DataLod& DL, StatsLod& ST,
48 	DataLodMesh& DLM, DataSeg& DS,
49 	int segM, bool full)
50 {
51 	//  iterators
52 	int seg = (segM + DR.segs) % DR.segs;
53 	int seg1 = getNext(seg), seg0 = getPrev(seg), seg02 = getAdd(seg,-2);
54 	DS.seg = seg;  DS.seg1 = seg1;  DS.seg0 = seg0;  // save
55 
56 	//if (isLod0)
57 	//LogR("[Seg]  cur: " + toStr(seg) + "/" + toStr(sNumO) + "  all:" + toStr(segs));/**/
58 
59 	//  on terrain  (whole seg)
60 	DS.onTer = mP[seg].onTer && mP[seg1].onTer;
61 
62 
63 	///  jump front wall, ends in air
64 	//  0,1 for geometry, 2,1 for pacenotes
65 	//  Test on tracks:  iDir<0: jumps, CrossJumps  iDir>0: Mars, Platforms
66 	DS.jfw0 = iDir < 0 ?
67 		!mP[seg ].onTer && mP[seg0].isnt() :
68 		!mP[seg ].onTer && !mP[seg].isnt() && mP[seg0].isnt();
69 	DS.jfw1 = iDir < 0 ?
70 		!mP[seg1].onTer && mP[seg1].isnt() :
71 		!mP[seg1].onTer && mP[seg1].isnt();
72 	DS.jfw2 = iDir < 0 ?
73 		!mP[seg0].onTer && mP[seg02].isnt() :
74 		!mP[seg0].onTer && !mP[seg0].isnt() && mP[seg02].isnt();
75 
76 
77 	//  on merging segs only for game in whole road rebuild
78 	//  off for editor (partial, 4segs rebuild)
79 	bool bNew = true, bNxt = true;
80 	if (bMerge)
81 	{	bNew = (segM   == DR.sMin/*1st*/)  || DL.v_bMerge[seg];
82 		bNxt = (segM+1 == DR.sMax/*last*/) || DL.v_bMerge[seg1];  // next is new
83 	}
84 
85 	if (bNew)  //> new seg data
86 		DLM.Clear();
87 
88 	//  bullet create
89 	bool blt = true;  // game always
90 	#ifdef SR_EDITOR  // editor only sel segs for align ter tool, or full for objects sim
91 		blt = DR.bulletFull || DR.editorAlign && (vSel.find(seg) != vSel.end());
92 	#endif
93 
94 
95 	///  destroy old
96 	RoadSeg& rs = vSegs[seg];
97 	if (!rs.empty && DL.isLod0)
98 		DestroySeg(seg);
99 
100 
101 	//  material
102 	int mid = mP[seg].idMtr;
103 	DS.mtrId = max(0,mid);
104 	DS.pipe = isPipe(seg);
105 	rs.sMtrRd = DS.pipe ? sMtrPipe[DS.mtrId]
106 						: (sMtrRoad[DS.mtrId] + (DS.onTer ? "_ter" :""));
107 
108 	/// >  blend 2 materials
109 	DS.hasBlend = false;
110 	if (mid != mP[seg1].idMtr && !DS.pipe && !isPipe(seg1))
111 	{
112 		DS.hasBlend = true;
113 		int mtrB = max(0,mP[seg1].idMtr);
114 		rs.sMtrB = sMtrRoad[mtrB] + (DS.onTer ? "_ter" :"");
115 	}
116 
117 	//  skirt /\ not for bridges
118 	bool useSkirt = DS.onTer || DS.pipe;  // pipe own factor..
119 	Real skLen = useSkirt ? g_SkirtLen : 0.f, skH = useSkirt ? g_SkirtH : 0.f;
120 
121 
122 	//  seg params  -----------------
123 	const int iwC = g_ColNSides;  // column  polygon steps
124 
125 	//  steps len
126 	int il = DL.v_iL[seg];
127 	int il0= DL0.v0_iL[seg];
128 	Real la = 1.f / il;
129 	Real la0= 1.f / il0 * skLen;
130 	Real l = -la0;
131 
132 	//  width
133 	//Real wi1 = fabs(mP[seg].width), wi2 = fabs(mP[seg1].width), wi12 = wi2-wi1;
134 
135 	///  angles ()__
136 	Real ay1 = mP[seg].aYaw, ay2 = mP[seg1].aYaw, ay21 = ay2-ay1;
137 	Real ar1 = mP[seg].aRoll,ar2 = mP[seg1].aRoll,ar21 = ar2-ar1;
138 	const Real asw = 180;	// more than 180 swirl - wrong at start/end
139 	while (ay21 > asw)  ay21 -= 2*asw;  while (ay21 <-asw)  ay21 += 2*asw;
140 	while (ar21 > asw)  ar21 -= 2*asw;	while (ar21 <-asw)  ar21 += 2*asw;
141 
142 	//  tc begin,range
143 	Real tcBeg = (seg > 0) ? DL.v_tc[seg-1]  : 0.f,  tcEnd  = DL.v_tc[seg],   tcRng  = tcEnd - tcBeg;
144 	Real tcBeg0= (seg > 0) ? DL0.v0_tc[seg-1]: 0.f,  tcEnd0 = DL0.v0_tc[seg], tcRng0 = tcEnd0 - tcBeg0;
145 	Real tcRmul = tcRng0 / tcRng;
146 
147 
148 	//------------------------------------------------------------------------------------
149 	//  Length  vertices
150 	//------------------------------------------------------------------------------------
151 	//LogR( " __len");
152 	bool vis = mP[seg].idMtr >= 0;  // visible, -1 hides segment
153 	if (vis || DL.isPace)
154 	for (int i = -1; i <= il+1; ++i)  // length +1  +2-gap
155 	{
156 		++DLM.iLmrg;
157 		///  length <dir>  |
158 		Vector3 vL0 = interpolate(seg, l);
159 		Vector3 vl = GetLenDir(seg, l, l+la), vw;
160 		Real len = vl.length();  vl.normalise();
161 
162 		//  len tc
163 		if (i <= 0)  DL.tcLen = 0;
164 		Real tc = DL.tcLen * tcRmul + tcBeg0;
165 		//  skirt tc
166 		if (i == -1)	tc =-skLen* tcRmul + tcBeg0;
167 		if (i == il+1)  tc = skLen* tcRmul + tcEnd0;
168 
169 		///  width <dir>   --
170 		if (mP[seg].onTer && mP[seg1].onTer)
171 		{	vw = Vector3(vl.z, 0, -vl.x);  }
172 		else		/// angles ()__
173 		{	Real ay = ay1 + ay21 * l;  // linear-
174 			Real ar = ar1 + ar21 * l;
175 			vw = GetRot(ay,ar);  // from angles
176 		}
177 		vw.normalise();
178 		Vector3 vwn = vw;
179 
180 		//Real wiMul = wi1 + wi12 * l;  // linear-
181 		Real wiMul = interpWidth(seg, l);  // spline~
182 		if (DR.editorAlign)  // wider road for align terrain tool
183 			wiMul = wiMul*ed_Wmul + ed_Wadd;
184 		vw *= wiMul;
185 
186 		//  on terrain ~~
187 		bool onTer1 = DS.onTer || mP[seg].onTer && i==0 || mP[seg1].onTer && i==il;
188 
189 		///  normal <dir>  /
190 		Vector3 vn;
191 		if (i==0)	vn = DL0.v0_N[seg];  else  // seg start=end
192 		if (i==il)	vn = DL0.v0_N[seg1];
193 		else
194 		{	vn = vl.crossProduct(vw);  vn.normalise();
195 			//  on pipe inv
196 			if (mP[seg].onPipe==2)
197 				vn = -vn;
198 		}
199 
200 
201 		//  width steps <->
202 		int iw = DL.v_iWL[seg][i+1];  //i = -1 .. il+1
203 
204 		//  pipe amount (_)
205 		Real l01 = max(0.f, min(1.f, Real(i)/Real(il) ));
206 		Real p1 = mP[seg].pipe, p2 = mP[seg1].pipe;
207 		Real fPipe = p1 + (p2-p1)*l01;
208 
209 		bool trans = (p1 == 0.f || p2 == 0.f) && !DL.v_iwEq[seg];
210 		Real trp = (p1 == 0.f) ? 1.f - l01 : l01;
211 
212 		//LogR("   il="+toStr(i)+"/"+toStr(il)+"   iw="+toStr(iw)
213 		//	/*+(bNew?"  New ":"") +(bNxt?"  Nxt ":"")/**/);
214 		if (DS.hasBlend && vis)
215 			++DLM.iLmrgB;
216 
217 
218 		///  road ~    Width  vertices
219 		//--------------------------------------------------------------------------------------------
220 		Vector3 vH0, vH1;  //#  positions for bank angle
221 		int w0 = DS.pipe ? iw/4   : 0,
222 			w1 = DS.pipe ? iw*3/4 : iw;
223 
224 		Real tcL = tc * (DS.pipe ? g_tcMulP : g_tcMul);
225 		for (int w=0; w <= iw; ++w)  // width +1
226 		{
227 			//  pos create
228 			Vector3 vP,vN;	Real tcw = Real(w)/Real(iw);
229 
230 			Real yTer = 0.f;
231 			if (fPipe == 0.f)
232 			{	//  flat --
233 				vP = vL0 + vw * (tcw - 0.5);
234 				vN = vn;
235 				yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f;
236 				if (onTer1)  //  onTerrain
237 				{
238 					vP.y = yTer + g_Height * ((w==0 || w==iw) ? 0.15f : 1.f);
239 					vN = mTerrain ? TerUtil::GetNormalAt(mTerrain,
240 						vP.x, vP.z, DL.fLenDim*0.5f /*0.5f*/) : Vector3::UNIT_Y;
241 				}
242 			}else
243 			{	///  pipe (_)
244 				Real oo = (tcw - 0.5)/0.5 * PI_d * fPipe, so = sinf(oo), co = cosf(oo);
245 				vP = vL0 + vw  * 0.5 * so +
246 						 + vn * (0.5 - 0.5 * co) * wiMul;
247 				vN = vn * co + vwn * so;
248 				//LogO(toStr(w)+" "+fToStr(so,2,4));
249 
250 				if (vN.y < 0.f)  vN.y = -vN.y;
251 				if (trans)  //  transition from flat to pipe
252 				{	vP += vw * (tcw - 0.5) * trp;  }
253 				yTer = mTerrain ? mTerrain->getHeightAtWorldPosition(vP.x, 0, vP.z) : 0.f;
254 			}
255 
256 			//  skirt ends, gap patch_
257 			if (i == -1 || i == il+1)
258 				vP -= vn * skH;
259 
260 
261 			/// []()  pace  add marker  ~ ~ ~  ~ ~ ~
262 			if (DL.isPace)
263 			{
264 				if (full && w == 1)  // center
265 				if (i >= 0 && i < il)
266 				{	//  add
267 					PaceM pm;
268 					bool op = mP[seg].onPipe > 0;
269 					bool onP = op && (iDir > 0 ?		// start
270 						mP[seg1].onPipe == 0 && i==il-1 : mP[seg0].onPipe == 0 && i==0);
271 					bool onPe = op && (iDir > 0 ?		// end
272 						mP[seg0].onPipe == 0 && i==0    : mP[seg1].onPipe == 0 && i==il-1);
273 					float h = 3.f;  // above
274 					if (mP[seg].onPipe == 1 && mP[seg].idMtr >= 0 ||
275 						mP[seg0].onPipe == 1 && mP[seg0].idMtr >= 0)
276 						h += wiMul;
277 
278 					pm.pos  = vP + vN * h;  //par  + vw * 0.5f;
279 					pm.pos2 = vP + vN * (h + 1.f) + vw * 0.5f;  // extra, info
280 
281 					pm.onTer = DS.onTer && fPipe < 0.1f;
282 					pm.loop = DL0.v0_Loop[seg];
283 					pm.onPipe = onP;  pm.onPipeE = onPe;
284 					bool no = mP[seg].notReal;
285 					pm.jump = no? 0: DS.jfw2;  pm.jumpR = no? 0: DS.jfw1;
286 
287 					pm.vis = vis;  pm.notReal = no;
288 					vPace.push_back(pm);
289 				}
290 
291 			}else if (vis)
292 			{
293 				///  color  for minimap preview
294 				//  ---~~~====~~~---
295 				Real brdg = min(1.f, std::abs(vP.y - yTer) * 0.4f);  //par ] height diff mul
296 				Real h = max(0.f, 1.f - std::abs(vP.y - yTer) / 30.f);  // for grass dens tex
297 
298 				bool onP = mP[seg].onPipe > 0;
299 				float pp = fPipe * 0.5f + (onP ? 0.5f : 0.f);  // put onP in pipe
300 
301 				Vector4 c(brdg, pp, 1.f, h);
302 				Vector2 vtc(tcw * 1.f /**2p..*/, tcL);
303 
304 
305 				//>  data road
306 				DLM.pos.push_back(vP);   DLM.norm.push_back(vN);
307 				DLM.tcs.push_back(vtc);  DLM.clr.push_back(c);
308 				if (DS.hasBlend)
309 				{	//  alpha, blend 2nd mtr
310 					c.z = std::max(0.f, std::min(1.f, float(i)/il ));
311 					DLM.posB.push_back(vP);   DLM.normB.push_back(vN);
312 					DLM.tcsB.push_back(vtc);  DLM.clrB.push_back(c);
313 				}
314 
315 				//#  stats
316 				if (vP.y < ST.stMinH)  ST.stMinH = vP.y;
317 				if (vP.y > ST.stMaxH)  ST.stMaxH = vP.y;
318 				if (w==w0)  vH0 = vP;  //#
319 				if (w==w1)  vH1 = vP;
320 			}
321 		}	// width
322 
323 
324 		/// []()  normal
325 		if (!DL.isPace && vis)
326 		{
327 			//#  stats  banking angle
328 			if (DL.isLod0 && i==0)
329 			{
330 				float h = (vH0.y - vH1.y), w = vH0.distance(vH1), d = fabs(h/w), a = asin(d)*180.f/PI_d;
331 				ST.bankAvg += a;
332 				if (a > ST.bankMax)  ST.bankMax = a;
333 				//LogO("RD seg :" + toStr(seg)+ "  h " + fToStr(h,1,3)
334 				//	+ "  w " + fToStr(w,1,3)+ "  d " + fToStr(d,1,3)+ "  a " + fToStr(a,1,3) );
335 			}
336 
337 
338 			///  wall ]
339 			//------------------------------------------------------------------------------------
340 			Real uv = 0.f;  // tc
341 			bool onP = mP[seg].onPipe==2;
342 
343 			if (!DS.onTer)
344 			if (i >= 0 && i <= il)  // length +1
345 			{
346 				++DLM.iLmrgW;
347 				Real tcLW = tc * (DS.pipe ? g_tcMulPW : g_tcMulW);
348 				for (int w=0; w <= ciwW; ++w)  // width +1
349 				{
350 					int pp = (p1 > 0.f || p2 > 0.f) ? (onP ? 2 : 1) : 0;  //  pipe wall
351 					stWiPntW wP = wiPntW[w][pp];
352 
353 					if (trans)
354 					{
355 						//  road to pipe, wall transition
356 						wP.x *= 1.f + 0.5f * trp;  // broader
357 						wP.y *= 1.f - 1.f * trp;   // flat
358 						if (!onP)
359 							wP.y -= 0.02f * trp;  //par move start down
360 					}
361 					uv += wP.uv;
362 
363 					Vector3 vP = vL0 + vw * wP.x + vn * wP.y;
364 					Vector3 vN =     vwn * wP.nx + vn * wP.ny;  vN.normalise();
365 
366 					//>  data Wall
367 					DLM.posW.push_back(vP);  DLM.normW.push_back(vN);
368 					DLM.tcsW.push_back(0.25f * Vector2(uv, tcLW));  //par
369 				}
370 			}
371 
372 
373 			///  columns |
374 			//------------------------------------------------------------------------------------
375 			if (!DS.onTer && mP[seg].cols > 0)
376 			if (i == il/2)  // middle-
377 			{
378 				++DLM.iLmrgC;
379 				const Real r = g_ColRadius;  // column radius
380 
381 				for (int h=0; h <= 1; ++h)  // height
382 				for (int w=0; w <= iwC; ++w)  // width +1
383 				{
384 					Real a = Real(w)/iwC *2*PI_d,  //+PI_d/4.f
385 						x = r*cosf(a), y = r*sinf(a);
386 
387 					Vector3 vlXZ(vl.x, 0.f, vl.z);  Real fl = 1.f/max(0.01f, vlXZ.length());
388 					Vector3 vP = vL0 + fl * vl * x + vwn * y;
389 					Real yy;
390 
391 					if (h==0)  // top below road
392 					{	yy = vn.y * (onP ? 1.5f : -0.8f);  //par
393 						vP.y += yy;
394 					}
395 					else  // bottom below ground
396 					{	yy = (mTerrain ? mTerrain->getHeightAtWorldPosition(vP) : 0.f) - 0.3f;
397 						vP.y = yy;
398 					}
399 
400 					Vector3 vN(vP.x-vL0.x, 0.f, vP.z-vL0.z);  vN.normalise();
401 
402 					//>  data Col
403 					DLM.posC.push_back(vP);  DLM.normC.push_back(vN);
404 					DLM.tcsC.push_back(Vector2( Real(w)/iwC * 4, vP.y * g_tcMulC ));  //par
405 				}
406 			}
407 		}
408 
409 
410 		if (i == -1 || i == il)  // add len
411 		{	l += la0;  DL.tcLen += len;  }
412 		else
413 		{	l += la;  DL.tcLen += len;  }
414 	}
415 	//  Length  vertices
416 	//------------------------------------------------------------------------------------
417 
418 
419 	/// []()  pace
420 	if (DL.isPace)
421 		return;  // no mesh
422 
423 
424 	//  lod vis points
425 	if (DL.isLod0)
426 	{	int lps = max(2, (int)(DL.v_len[seg] / g_LodPntLen));
427 
428 		for (int p=0; p <= lps; ++p)
429 		{
430 			Vector3 vp = interpolate(seg, Real(p)/Real(lps));
431 			DLM.posLod.push_back(vp);
432 		}
433 	}
434 
435 
436 	///  create mesh  indices
437 	//------------------------------------------------------------------------------------------------
438 	blendTri = false;
439 	if (bNxt && !DLM.pos.empty())  // Merging
440 	{
441 		bltTri = blt;  blendTri = DS.hasBlend;
442 
443 		createSeg_Meshes(DL,DLM, DS, rs);
444 
445 		//  copy lod points
446 		if (DL.isLod0)
447 		{	for (size_t p=0; p < DLM.posLod.size(); ++p)
448 				rs.lpos.push_back(DLM.posLod[p]);
449 			DLM.posLod.clear();
450 		}
451 		//#  stats--
452 		if (ST.stats)
453 		{
454 			rs.mrgLod = (st.iMrgSegs % 2)*2+1;  //-
455 			st.iMrgSegs++;	 // count, full
456 		}
457 
458 		//  bullet trimesh  at lod 0
459 		if (DL.isLod0 && blt)
460 			createSeg_Collision(DLM,DS);
461 	}
462 }
463 
464 
465 
466 //----------------------------------------------------------------------------------------------------------------------------
467 //   Create Meshes, from merged segments data
468 //----------------------------------------------------------------------------------------------------------------------------
createSeg_Meshes(const DataLod & DL,const DataLodMesh & DLM,DataSeg & DS,RoadSeg & rs)469 void SplineRoad::createSeg_Meshes(
470 	const DataLod& DL,
471 	const DataLodMesh& DLM,
472 	DataSeg& DS, RoadSeg& rs)
473 {
474 	String sEnd = toStr(idStr);  ++idStr;
475 	String sMesh = "rd.mesh." + sEnd, sMeshW = sMesh + "W", sMeshC = sMesh + "C", sMeshB = sMesh + "B";
476 
477 	posBt.clear();
478 	idx.clear();  // set for addTri
479 	idxB.clear();
480 	at_pos = &DLM.pos;  at_size = DLM.pos.size();  at_ilBt = DLM.iLmrg-2;
481 	int seg = DS.seg, seg1 = DS.seg1, seg0 = DS.seg0;
482 
483 	///  road ~
484 	int iiw = 0;  //LogR( " __idx");
485 
486 	//  go through whole merged length
487 	//  equal width
488 	if (DL.v_iwEq[seg]==1)
489 		for (int i = 0; i < DLM.iLmrg-1; ++i)  // length-1 +2gap
490 		{
491 			//  |\|  grid  w-1 x l-1
492 			int iw = DL.v_iW[seg];
493 			for (int w=0; w < iw; ++w)  // width-1
494 			{
495 				//LogR( "   il="+toStr(i)+"/"+toStr(il)+"   iw="+toStr(iw));
496 				int f0 = iiw + w, f1 = f0 + (iw+1);
497 				addTri(f0+0,f1+1,f0+1,i);
498 				addTri(f0+0,f1+0,f1+1,i);
499 			}
500 			iiw += iw + 1;
501 		}
502 	else
503 		///  pipe trans  width steps changing in length
504 		for (int i = 0; i < DLM.iLmrg-1; ++i)  // length-1 +2gap
505 		{
506 			int iw = DL.v_iWL[seg][i], iw1 = DL.v_iWL[seg][i+1];
507 			int d = iw1 - iw, dd = abs(d);
508 
509 			//  comment out //addTris to test
510 			if (i==0)  LogR("");
511 			LogR("   il=" + iToStr(i,3) + " iw=" + iToStr(iw,3) + " d " + toStr(d));
512 
513 			if (d > 0)	//  inc  iw < iw1
514 			for (int w=0; w < iw; ++w)  // width-1
515 			{
516 				int f0 = iiw + w, f1 = f0 + iw+1;
517 				//  |\ |  f0+0  f0+1
518 				//  | \|  f1+0  f1+1
519 				addTri(f0+0,f1+1,f0+1,i);
520 				addTri(f0+0,f1+0,f1+1,i);
521 			}
522 			else		//  dec  iw1 <= iw
523 			for (int w=0; w < iw1; ++w)  // width-1
524 			{
525 				int f0 = iiw + w, f1 = f0 + iw+1;
526 				//  |/|
527 				addTri(f0+0,f1+0,f0+1,i);
528 				addTri(f0+1,f1+0,f1+1,i);
529 			}
530 
531 			///  \|/   fan tris
532 			///  fix edge gaps, when iw changes
533 
534 			if (d > 0)  //  inc  iw < iw1
535 			{
536 				int f0 = iiw + iw;
537 				for (int m=0; m < dd; ++m)
538 				{
539 					int f1 = f0 + iw+1 +m;
540 					addTri(f0,f1,f1+1,i);
541 				}
542 			}
543 			if (d < 0)  //  dec  iw1 < iw
544 			{
545 				int f0 = iiw + iw + iw1+1;
546 				for (int m=0; m < dd; ++m)
547 				{
548 					int f1 = iiw + iw-1 -m;
549 					addTri(f1+1,f1,f0,i);
550 				}
551 			}
552 			iiw += iw + 1;
553 		}
554 
555 	vSegs[seg].nTri[DL.lod] = idx.size()/3;
556 	blendTri = false;
557 
558 
559 	//  create Ogre Mesh
560 	//-----------------------------------------
561 	MeshPtr meshOld = MeshManager::getSingleton().getByName(sMesh);
562 	if (!meshOld.isNull())  LogR("Mesh exists !!!" + sMesh);
563 
564 	AxisAlignedBox aabox;
565 	MeshPtr mesh = MeshManager::getSingleton().createManual(sMesh,"General");
566 	SubMesh* sm = mesh->createSubMesh();
567 
568 	CreateMesh(sm, aabox, DLM.pos,DLM.norm,DLM.clr,DLM.tcs, idx, rs.sMtrRd);
569 
570 	MeshPtr meshW, meshC, meshB;  // ] | >
571 	bool wall = !DLM.posW.empty();
572 	if (wall)
573 	{
574 		meshW = MeshManager::getSingleton().createManual(sMeshW,"General");
575 		meshW->createSubMesh();
576 	}
577 	bool cols = !DLM.posC.empty() && DL.isLod0;  // cols have no lods
578 	if (cols)
579 	{
580 		meshC = MeshManager::getSingleton().createManual(sMeshC,"General");
581 		meshC->createSubMesh();
582 	}
583 	if (DS.hasBlend)
584 	{
585 		meshB = MeshManager::getSingleton().createManual(sMeshB,"General");
586 		sm = meshB->createSubMesh();
587 		CreateMesh(sm, aabox, DLM.posB,DLM.normB,DLM.clrB,DLM.tcsB, idxB, rs.sMtrB);
588 	}
589 	//*=*/wall = 0;  cols = 0;  // test
590 
591 
592 	///  wall ]
593 	//------------------------------------------------------------------------------------
594 	bool pipeGlass = DS.pipe && bMtrPipeGlass[ mP[seg].idMtr ];  // pipe glass mtr
595 	if (wall)
596 	{
597 		idx.clear();
598 		for (int i = 0; i < DLM.iLmrgW-1; ++i)  // length
599 		{	int iiW = i* (ciwW+1);
600 
601 			for (int w=0; w < ciwW; ++w)  // width
602 			{
603 				int f0 = iiW + w, f1 = f0 + (ciwW+1);
604 				idx.push_back(f0+1);  idx.push_back(f1+1);  idx.push_back(f0+0);
605 				idx.push_back(f1+1);  idx.push_back(f1+0);  idx.push_back(f0+0);
606 			}
607 		}
608 
609 		//  front plates start,end  |_|  not in pipes
610 		int i,f, b = DLM.posW.size()-ciwW-1;
611 		if (!DS.pipe)
612 		{
613 			int ff = DS.jfw0 ? 6 : 4;
614 			for (f=0; f < ff; ++f)
615 				for (i=0; i<=2; ++i)  idx.push_back( WFid[f][i] );
616 
617 			ff = DS.jfw1 ? 6 : 4;
618 			for (f=0; f < ff; ++f)
619 				for (i=0; i<=2; ++i)  idx.push_back( WFid[f][2-i]+b );
620 
621 			vSegs[seg].nTri[DL.lod] += idx.size()/3;
622 		}
623 
624 		sm = meshW->getSubMesh(0);   // for glass only..
625 		rs.sMtrWall = !pipeGlass ? sMtrWall : sMtrWallPipe;
626 		if (!DLM.posW.empty())
627 			CreateMesh(sm, aabox, DLM.posW,DLM.normW,DLM.clr0,DLM.tcsW, idx, rs.sMtrWall);
628 	}
629 
630 
631 	///  columns |
632 	//------------------------------------------------------------------------------------
633 	const int iwC = g_ColNSides;
634 	if (cols)
635 	{
636 		idx.clear();
637 		at_pos = &DLM.posC;
638 
639 		for (int l=0; l < DLM.iLmrgC; ++l)
640 		for (int w=0; w < iwC; ++w)
641 		{
642 			int f0 = w + l*(iwC+1)*2, f1 = f0 + iwC+1;
643 			addTri(f0+0, f1+1, f0+1, 1);
644 			addTri(f0+0, f1+0, f1+1, 1);
645 		}
646 		vSegs[DS.seg].nTri[DL.lod] += idx.size()/3;
647 
648 		sm = meshC->getSubMesh(0);
649 		//if (!posC.empty())
650 		CreateMesh(sm, aabox, DLM.posC,DLM.normC,DLM.clr0,DLM.tcsC, idx, sMtrCol);
651 	}
652 
653 
654 	//  add Mesh to Scene  -----------------------------------------
655 	Entity* ent = 0, *entW = 0, *entC = 0, *entB = 0;
656 	SceneNode* node = 0, *nodeW = 0, *nodeC = 0, *nodeB = 0;
657 
658 	//  road
659 	AddMesh(mesh, sMesh, aabox, &ent, &node, "."+sEnd);
660 	if (pipeGlass)
661 		ent->setRenderQueueGroup(RQG_PipeGlass);
662 	else
663 		ent->setRenderQueueGroup(RQG_Road);
664 
665 	if (wall)
666 	{
667 		AddMesh(meshW, sMeshW, aabox, &entW, &nodeW, "W."+sEnd);
668 		entW->setCastShadows(true);
669 	}
670 	if (cols)
671 	{
672 		AddMesh(meshC, sMeshC, aabox, &entC, &nodeC, "C."+sEnd);
673 		entC->setVisible(true);
674 		if (bCastShadow)
675 			entC->setCastShadows(true);
676 	}
677 	if (DS.hasBlend)
678 	{
679 		AddMesh(meshB, sMeshB, aabox, &entB, &nodeB, "B."+sEnd);
680 		entB->setRenderQueueGroup(RQG_RoadBlend);
681 	}
682 
683 	if (bCastShadow && !DS.onTer)
684 		ent->setCastShadows(true);
685 
686 
687 	//>>  store ogre data  ------------
688 	int lod = DL.lod;
689 	rs.road[lod].node = node;	rs.wall[lod].node = nodeW;	 rs.blend[lod].node = nodeB;
690 	rs.road[lod].ent = ent;		rs.wall[lod].ent = entW;	 rs.blend[lod].ent = entB;
691 	rs.road[lod].mesh = mesh;	rs.wall[lod].mesh = meshW;	 rs.blend[lod].mesh = meshB;
692 	rs.road[lod].smesh = sMesh; rs.wall[lod].smesh = sMeshW; rs.blend[lod].smesh = sMeshB;
693 	if (DL.isLod0)  {
694 		rs.col.node = nodeC;
695 		rs.col.ent = entC;
696 		rs.col.mesh = meshC;
697 		rs.col.smesh = sMeshC;  }
698 	rs.empty = false;  // new
699 }
700 
701 
702 //  Create Bullet Collision
703 //----------------------------------------------------------------------------------------------------------------------------
createSeg_Collision(const DataLodMesh & DLM,const DataSeg & DS)704 void SplineRoad::createSeg_Collision(
705 	const DataLodMesh& DLM,
706 	const DataSeg& DS)
707 {
708 	btTriangleMesh* trimesh = new btTriangleMesh();  vbtTriMesh.push_back(trimesh);
709 
710 	#define vToBlt(v)   btVector3(v.x, -v.z, v.y)
711 	#define addTriB(a,b,c)  trimesh->addTriangle(vToBlt(a), vToBlt(b), vToBlt(c))
712 
713 	size_t si = posBt.size(), a=0;  // %3!
714 	for (size_t i=0; i < si/3; ++i,a+=3)
715 		addTriB(posBt[a], posBt[a+1], posBt[a+2]);
716 
717 	// if (cols)  // add columns^..
718 
719 	//  Road  ~
720 	btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true);
721 
722 	size_t su = (DS.pipe ? SU_Pipe : SU_Road) + DS.mtrId;
723 	shape->setUserPointer((void*)su);  // mark as road/pipe + mtrId
724 	shape->setMargin(0.01f);  //?
725 
726 	btCollisionObject* bco = new btCollisionObject();
727 	btTransform tr;  tr.setIdentity();  //tr.setOrigin(pc);
728 
729 	bco->setActivationState(DISABLE_SIMULATION);
730 	bco->setCollisionShape(shape);	bco->setWorldTransform(tr);
731 	bco->setFriction(0.8f);   //+
732 	bco->setRestitution(0.f);
733 	bco->setCollisionFlags(bco->getCollisionFlags() |
734 		btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/);
735 	#ifdef SR_EDITOR
736 		pApp->world->addCollisionObject(bco);
737 		bco->setUserPointer((void*)111);  // mark road
738 	#else
739 		pGame->collision.world->addCollisionObject(bco);
740 		pGame->collision.shapes.push_back(shape);
741 	#endif
742 
743 
744 	//  Wall  ]
745 	#ifndef SR_EDITOR  // in Game
746 	bool wall = !DLM.posW.empty();
747 	if (wall)
748 	{	trimesh = new btTriangleMesh();  vbtTriMesh.push_back(trimesh);
749 
750 		for (int i = 0; i < DLM.iLmrgW-1; ++i)  // length
751 		{	int iiW = i* (ciwW+1);
752 
753 			for (int w=0; w < ciwW; ++w)  // width
754 			if (bRoadWFullCol || w==0 || w == ciwW-1)  // only 2 sides|_| optym+
755 			{
756 				int f0 = iiW + w, f1 = f0 + (ciwW+1);
757 				addTriB(DLM.posW[f0+0], DLM.posW[f1+1], DLM.posW[f0+1]);
758 				addTriB(DLM.posW[f0+0], DLM.posW[f1+0], DLM.posW[f1+1]);
759 			}
760 		}
761 		//  front plates start,end  |_|
762 		int f, b = DLM.posW.size()-ciwW-1;
763 		if (!DS.pipe)
764 		{
765 			int ff = DS.jfw0 ? 6 : 4;
766 			for (f=0; f < ff; ++f)
767 				addTriB(DLM.posW[WFid[f][0]], DLM.posW[WFid[f][1]], DLM.posW[WFid[f][2]]);
768 
769 			ff = DS.jfw1 ? 6 : 4;
770 			for (f=0; f < ff; ++f)
771 				addTriB(DLM.posW[WFid[f][2]+b], DLM.posW[WFid[f][1]+b], DLM.posW[WFid[f][0]+b]);
772 		}
773 
774 		btCollisionShape* shape = new btBvhTriangleMeshShape(trimesh, true);
775 		shape->setUserPointer((void*)SU_RoadWall);  //wall and column same object..
776 
777 		btCollisionObject* bco = new btCollisionObject();
778 		bco->setActivationState(DISABLE_SIMULATION);
779 		bco->setCollisionShape(shape);	bco->setWorldTransform(tr);
780 		bco->setFriction(0.1f);   //+
781 		bco->setRestitution(0.f);
782 		bco->setCollisionFlags(bco->getCollisionFlags() |
783 			btCollisionObject::CF_STATIC_OBJECT | btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT/**/);
784 		pGame->collision.world->addCollisionObject(bco);
785 		pGame->collision.shapes.push_back(shape);
786 	}
787 	#endif
788 }
789