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