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