1 #include "pch.h"
2 #include "../ogre/common/Def_Str.h"
3 #include "../vdrift/dbl.h"
4 #include "Road.h"
5 #include <OgreTimer.h>
6 using namespace Ogre;
7 using std::vector;  using std::min;  using std::max;
8 
9 
10 
11 ///  rebuild for Pace  ~ ~
RebuildRoadPace()12 void SplineRoad::RebuildRoadPace()
13 {
14 	Ogre::Timer ti;
15 	vPace.clear();
16 
17 	DataRoad DR(false, true);
18 	PrepassRange(DR);
19 
20 	LogR("");
21 	LogR("LOD: -1 pace ---");
22 	// lod -1 is only for pacenotes data
23 
24 	DataLod DL;
25 	StatsLod ST;
26 
27 	PrepassLod(DR,DL0,DL,ST, -1, false);
28 
29 	DataLodMesh DLM;
30 
31 	///  Segment
32 	int sNum = DR.sMax - DR.sMin,
33 		segM = DR.sMin;
34 
35 	while (sNum > 0)
36 	{
37 		DataSeg DS;
38 
39 		BuildSeg(DR,DL0,DL,ST,DLM, DS, segM, true);
40 
41 		--sNum;  ++segM;  // next
42 	}
43 
44 	LogO(String("::: Time Road Pace Rebuild: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
45 }
46 
47 
48 ///  Rebuild geometry
49 //--------------------------------------------------------------------------------------------------------------------------
50 
RebuildRoadInt(bool editorAlign,bool bulletFull)51 bool SplineRoad::RebuildRoadInt(bool editorAlign, bool bulletFull)
52 {
53 
54 	if (!rebuild && !(editorAlign || bulletFull))  return false;
55 	rebuild = false;
56 
57 	UpdRot(); //
58 
59 	Ogre::Timer ti;
60 
61 
62 	DataRoad DR(editorAlign, bulletFull);
63 
64 	PrepassRange(DR);
65 
66 
67 	//  full rebuild
68 	bool full = iDirtyId == -1;
69 	if (full)
70 	{
71 		DestroyRoad();
72 		for (int seg=0; seg < DR.segs; ++seg)
73 		{
74 			RoadSeg rs;  rs.empty = true;
75 			vSegs.push_back(rs);
76 		}
77 	}
78 
79 
80 	//  Auto angles
81 	PrepassAngles(DR);
82 
83 
84 	///  LOD
85 	//-----------------------------
86 	DL0.Clear();
87 
88 	for (int lod = 0; lod < LODs; ++lod)
89 	{
90 		LogR("");
91 		LogR("LOD: "+toStr(lod)+" ---");
92 
93 		DataLod DL;
94 		StatsLod ST;
95 
96 		PrepassLod(DR,DL0,DL,ST, lod, editorAlign);
97 
98 		DataLodMesh DLM;
99 
100 		///  Segment
101 		//-----------------------------------
102 		int sNum = DR.sMax - DR.sMin,
103 			segM = DR.sMin;
104 
105 		while (sNum > 0)
106 		{
107 			DataSeg DS;
108 
109 			BuildSeg(DR,DL0,DL,ST,DLM, DS, segM, full);
110 
111 			--sNum;  ++segM;  // next
112 		}
113 
114 		EndStats(DR,ST);
115 	}
116 	//-----------------------------
117 
118 
119 	UpdLodVis(fLodBias);
120 	if (full)
121 		iOldHide = -1;
122 
123 
124 	if (full)
125 		LogO(String("::: Time Road Rebuild: ") + fToStr(ti.getMilliseconds(),0,3) + " ms");
126 
127 	return full;
128 }
129 
130 
131 //  Prepass Range
132 //---------------------------------------------------------------------------------------
PrepassRange(DataRoad & DR)133 void SplineRoad::PrepassRange(DataRoad& DR)
134 {
135 	//  segments range
136 	DR.segs = getNumPoints();
137 	DR.sMin = 0;  DR.sMax = DR.segs;
138 	if (DR.segs == 0 || DR.segs == 1)  return;
139 
140 
141 	if (vSegs.size() != DR.segs || DR.editorAlign || DR.bulletFull)
142 		iDirtyId = -1;  // force full
143 
144 	//  update 4 segs only (fast)
145 	if (iDirtyId != -1 && DR.segs >= 4)
146 	{
147 		DR.sMin = iDirtyId-2;
148 		DR.sMax = iDirtyId+2;
149 		if (!isLooped)
150 			DR.sMin = std::max(0, DR.sMin);
151 	}
152 	if (!isLooped)  // 1 seg less
153 		DR.sMax = std::min(DR.segs-1, DR.sMax);
154 }
155 
156 //  Auto Angles Prepass  ~~~
157 //---------------------------------------------------------------------------------------
PrepassAngles(DataRoad & DR)158 void SplineRoad::PrepassAngles(DataRoad& DR)
159 {
160 	if (DR.segs > 2)
161 	for (int seg=0; seg < DR.segs; ++seg)
162 	{
163 		int seg0 = getPrev(seg);
164 
165 		if (mP[seg].aType == AT_Manual)
166 		{	mP[seg].aYaw = mP[seg].mYaw;  mP[seg].aRoll = mP[seg].mRoll;  }
167 		else
168 		{	mP[seg].aRoll = 0.f;
169 			/// ... roll getangle?, +180 loops?, len
170 			const Real dist = 0.1f;
171 			Vector3 vl = GetLenDir(seg, 0.f, dist) + GetLenDir(seg0, 1.f-dist, 1.f);  //vl.normalise();
172 			Vector3 vw = Vector3(vl.z, 0.f, -vl.x);  //vw.normalise();
173 			mP[seg].aYaw = TerUtil::GetAngle(vw.x, vw.z) *180.f/PI_d;
174 
175 			if (mP[seg].aType == AT_Both)
176 			{	mP[seg].aYaw += mP[seg].mYaw;  mP[seg].aRoll += mP[seg].mRoll;  }
177 		}
178 	}
179 }
180 
181 ///  Prepass LOD,  data for segments
182 //---------------------------------------------------------------------------------------
183 const int ciLodDivs[LODs] = {1,2,4,8};
184 
185 ///par []()  pacenotes prepass
186 const int pace_iDiv = 4, pace_iW = 2;
187 const float pace_fLen = 12.f;
188 
189 
PrepassLod(const DataRoad & DR,DataLod0 & DL0,DataLod & DL,StatsLod & ST,int lod,bool editorAlign)190 void SplineRoad::PrepassLod(
191 	const DataRoad& DR,
192 	DataLod0& DL0, DataLod& DL, StatsLod& ST,
193 	int lod, bool editorAlign)
194 {
195 	DL.lod = lod;
196 	DL.isLod0 = lod == 0;
197 	DL.isPace = lod == -1;
198 
199 	int iLodDiv = DL.isPace ? pace_iDiv :  ciLodDivs[lod];
200 	DL.fLenDim =  DL.isPace ? pace_fLen :  g_LenDim0 * iLodDiv;
201 	DL.tcLen = 0.f;
202 	int inLoop = 0;
203 
204 	//if (isLod0)?
205 	LogR("--- Lod segs prepass ---");
206 	for (int seg=0; seg < DR.segs; ++seg)
207 	{
208 		int seg1 = getNext(seg), seg0 = getPrev(seg);
209 
210 		//  width steps  pipe  --
211 		Real sp = mP[seg].pipe, sp1 = mP[seg1].pipe, sp0 = mP[seg0].pipe;
212 		Real p = sp * g_P_iw_mul, pl = max(sp, sp1)* g_P_iw_mul/4;
213 		if (p < 0.f)  p = 1.f;  else  p = 1.f + p;
214 		if (pl< 0.f)  pl= 1.f;  else  pl= 1.f + pl;
215 		bool pipe = sp > 0.f || sp1 > 0.f;
216 		//int wmin = pipe ? 5 : 1;  // min w steps  //par
217 
218 		//  road  --
219 		int iw = DL.isPace ? pace_iW :
220 			max(1/*wmin*/, (int)(p * g_iWidthDiv0 / iLodDiv));  //* wid/widDiv..
221 		DL.v_iW.push_back(iw);
222 		int iwl = max(1, (int)(pl * g_iWidthDiv0 / iLodDiv));
223 
224 		//  length steps  |
225 		Real len = GetSegLen(seg);
226 		int  il = int(len / DL.fLenDim) / iwl * iwl + iwl;
227 		Real lenAdd = 1.f / il;
228 
229 		DL.v_iL.push_back(il);
230 		DL.v_len.push_back(len);
231 
232 		if (!mP[seg].notReal)
233 		{	//  add len
234 			ST.roadLen += len;  //#
235 			if (pipe)
236 			{	ST.rdPipe += len; //#
237 				if (mP[seg].onPipe)  ST.rdOnPipe += len;  //#
238 		}	}
239 
240 		///-  Merge conditions
241 		DL.sumLenMrg += len;
242 		//  mtr changes
243 		int hid = mP[seg].idMtr, hid1 = mP[seg1].idMtr, hid0 = mP[seg0].idMtr;
244 
245 		//  merge road and pipe segs, don't merge transitions
246 		if (sp != sp1 || sp != sp0  ||  hid != hid1 || hid != hid0)
247 		{	DL.sumLenMrg = 0.f;  ++DL.mrgCnt;
248 			DL.v_bMerge.push_back(1);
249 		}
250 		else  //  onTer change
251 		if (mP[seg].onTer != mP[seg1].onTer || mP[seg].onTer != mP[seg0].onTer)
252 		{	DL.sumLenMrg = 0.f;  ++DL.mrgCnt;
253 			DL.v_bMerge.push_back(1);
254 		}
255 		else  if (DL.sumLenMrg >= g_MergeLen)
256 		{	DL.sumLenMrg -= g_MergeLen;  ++DL.mrgCnt;
257 			DL.v_bMerge.push_back(1);  // bNew
258 		}else
259 			DL.v_bMerge.push_back(0);  // merged
260 
261 		LogR("seg " + iToStr(seg,3) + "  iw " + iToStr(iw,3) + "  il " + iToStr(il,3) +
262 			"  pipe prv" + toStr(sp0) + "  cur " + toStr(sp) + "  nxt" + toStr(sp1));
263 
264 		if (DL.isLod0)
265 		{
266 			int l = mP[seg].loop;  // type
267 			if (l > 0)	///[]()
268 			if (inLoop == 0)  inLoop = l;
269 			else  inLoop = 0;
270 
271 			DL0.v0_iL.push_back(il);
272 			DL0.v0_Loop.push_back(inLoop);
273 		}
274 
275 		///  length <dir>  |
276 		Vector3 vl = GetLenDir(seg, 0, lenAdd), vw;  vl.normalise();
277 		Real ay = mP[seg].aYaw, ar = mP[seg].aRoll;
278 
279 		///  width <dir>   ---
280 		if (mP[seg].onTer && mP[seg1].onTer)  //  perpendicular on xz
281 		{	vw = Vector3(vl.z, 0, -vl.x);  vw.normalise();
282 		}else
283 			vw = GetRot(ay,ar);  // from angles
284 
285 		///  normal <dir>  /
286 		if (DL.isLod0)
287 		{	Vector3 vn = vl.crossProduct(vw);  vn.normalise();
288 			//  on pipe inv
289 			if (mP[seg].onPipe==2)
290 				vn = -vn;
291 			DL0.v0_N.push_back(vn);
292 		}
293 
294 		//  width
295 		{
296 		Real wiMul = mP[seg].width;
297 		if (editorAlign)  // wider road for align terrain tool
298 			wiMul = wiMul*ed_Wmul + ed_Wadd;
299 		vw *= wiMul;
300 		DL.v_W.push_back(vw);
301 		}
302 
303 		ST.avgWidth += mP[seg].width * len;  //#
304 		if (!mP[seg].onTer || !mP[seg1].onTer)
305 			ST.rdOnT += len;  //#
306 
307 
308 		//  tc  seg il * len
309 		Real l = 0.f;
310 		for (int i = 0; i < il; ++i)  // length +1
311 		{
312 			//  length dir
313 			Vector3 vl = GetLenDir(seg, l, l+lenAdd);
314 			l += lenAdd;  DL.tcLen += vl.length();
315 		}
316 		DL.v_tc.push_back(DL.tcLen);
317 		if (DL.isLod0)
318 			DL0.v0_tc.push_back(DL.tcLen);
319 	}
320 
321 
322 	LogR("--- seg prepass2  viwLS  ---");
323 	for (int seg=0; seg < DR.segs; ++seg)
324 	{
325 		int seg1 = getNext(seg);
326 		int il = DL.v_iL[seg];
327 		std::vector<int> viwL;
328 
329 		//  width steps per length point in cur seg
330 		int iw0 = DL.v_iW[seg], iw1 = DL.v_iW[seg1];
331 		//String ss="";
332 		for (int i = -1; i <= il+1; ++i)  // length +1  +2-gap
333 		{
334 			int ii = max(0, min(il, i));
335 			int iw = iw0 + (int)( Real(ii)/Real(il) * (iw1-iw0) );
336 			//if (i==0 || i == il)
337 			//	ss += toStr(iw)+" ";
338 			viwL.push_back(iw);
339 		}
340 		int eq = iw1==iw0 ? 1 : 0;
341 
342 		DL.v_iwEq.push_back(eq);
343 		DL.v_iWL.push_back(viwL);
344 		//if (!eq)  vbSegMrg[seg] = 1;
345 		//LogR("seg "+toStr(seg)+"  >> "+ss);
346 	}
347 
348 	//  stats done at lod 0 and full rebuild
349 	ST.stats = DL.isLod0 && iDirtyId == -1;
350 	End0Stats(DL,ST);
351 }
352 
353 
354 
355 //---------------------------------------------------------------------------------------
Clear()356 void SplineRoad::DataLodMesh::Clear()
357 {	iLmrg = 0;	iLmrgW = 0;  iLmrgC = 0;  iLmrgB = 0;
358 
359 	pos.clear();  norm.clear();  tcs.clear();  clr.clear();
360 	posW.clear(); normW.clear(); tcsW.clear();
361 	posC.clear(); normC.clear(); tcsC.clear();
362 	posB.clear(); normB.clear(); tcsB.clear(); clrB.clear();
363 }
364 
365 
End0Stats(const DataLod & DL,const StatsLod & ST)366 void SplineRoad::End0Stats(const DataLod& DL, const StatsLod& ST)
367 {
368 	//#  stats  at lod0, whole road
369 	if (!ST.stats)  return;
370 
371 	st.Length = ST.roadLen;  st.WidthAvg = ST.avgWidth / ST.roadLen;
372 	st.OnTer = ST.rdOnT / ST.roadLen * 100.f;
373 	st.Pipes = ST.rdPipe / ST.roadLen * 100.f;
374 	st.OnPipe = ST.rdOnPipe / ST.roadLen * 100.f;
375 	st.segsMrg = DL.mrgCnt;
376 }
377 
EndStats(const DataRoad & DR,const StatsLod & ST)378 void SplineRoad::EndStats(const DataRoad& DR, const StatsLod& ST)
379 {	//#  stats
380 	if (!ST.stats)  return;
381 
382 	st.HeightDiff = max(0.f, ST.stMaxH - ST.stMinH);
383 	st.bankAvg = ST.bankAvg / DR.segs;
384 	st.bankMax = ST.bankMax;
385 	//LogO("RD bank angle:  avg "+fToStr(st.bankAvg,1,3)+"  max "+fToStr(st.bankMax,1,3));
386 }
387