Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
ProceduralRoad.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5
6 For more information, see http://www.rigsofrods.org/
7
8 Rigs of Rods is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 3, as
10 published by the Free Software Foundation.
11
12 Rigs of Rods is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#include "ProceduralRoad.h"
22
23#include "Actor.h"
24#include "Application.h"
25#include "Collisions.h"
26#include "Console.h"
27#include "GameContext.h"
28#include "GfxScene.h"
29#include "Terrain.h"
30
31#include <Ogre.h>
32
33using namespace Ogre;
34using namespace RoR;
35
36static int id_counter = 0;
37
42
44{
45 if (snode)
46 {
47 App::GetGfxScene()->GetSceneManager()->destroySceneNode(snode);
48 snode = nullptr;
49 }
50 if (msh)
51 {
52 MeshManager::getSingleton().remove(msh->getName());
53 msh.reset();
54 }
55 for (int number : registeredCollTris)
56 {
58 }
59}
60
61void ProceduralRoad::finish(Ogre::SceneNode* groupingSceneNode)
62{
63 Vector3 pts[8];
65 addQuad(pts[7], pts[6], pts[5], pts[4], TextureFit::TEXFIT_NONE, lastpos, lastpos, lastwidth);
66 addQuad(pts[7], pts[4], pts[3], pts[0], TextureFit::TEXFIT_NONE, lastpos, lastpos, lastwidth);
67 addQuad(pts[3], pts[2], pts[1], pts[0], TextureFit::TEXFIT_NONE, lastpos, lastpos, lastwidth);
68
69 createMesh();
70 String entity_name = String("RoadSystem_Instance-").append(StringConverter::toString(mid));
71 String mesh_name = String("RoadSystem-").append(StringConverter::toString(mid));
72 Entity* ec = App::GetGfxScene()->GetSceneManager()->createEntity(entity_name, mesh_name);
73 snode = groupingSceneNode->createChildSceneNode();
74 snode->attachObject(ec);
75
76 if (collision)
77 {
79 "RoadSystem", mesh_name,
80 ec->getBoundingBox().getCenter(), ec->getMesh()->getBounds(),
81 /*groundmodel:*/nullptr, registeredCollTris[0], (int)registeredCollTris.size());
82 }
83}
84
85void ProceduralRoad::addBlock(Vector3 pos, Quaternion rot, RoadType type, float width, float bwidth, float bheight, int pillartype)
86{
87 if (type == RoadType::ROAD_AUTOMATIC)
88 {
89 width = 10.0;
90 bwidth = 1.4;
91 bheight = 0.2;
92 //define type
93 Vector3 leftv = pos + rot * Vector3(0, 0, bwidth + width / 2.0);
94 Vector3 rightv = pos + rot * Vector3(0, 0, -bwidth - width / 2.0);
95 float dleft = leftv.y - RoR::App::GetGameContext()->GetTerrain()->getHeightAt(leftv.x, leftv.z);
96 float dright = rightv.y - RoR::App::GetGameContext()->GetTerrain()->getHeightAt(rightv.x, rightv.z);
97 if (dleft < bheight + 0.1 && dright < bheight + 0.1)
99 if (dleft < bheight + 0.1 && dright >= bheight + 0.1 && dright < 4.0)
100 type = RoadType::ROAD_LEFT;
101 if (dleft >= bheight + 0.1 && dleft < 4.0 && dright < bheight + 0.1)
103 if (dleft >= bheight + 0.1 && dleft < 4.0 && dright >= bheight + 0.1 && dright < 4.0)
104 type = RoadType::ROAD_BOTH;
105 if (type == RoadType::ROAD_AUTOMATIC)
107 if (type != RoadType::ROAD_FLAT)
108 {
109 width = 10.0;
110 bwidth = 0.4;
111 bheight = 0.5;
112 };
113 }
114
115 Vector3 pts[8];
116 if (!first)
117 {
118 Vector3 lpts[8];
119 if (type == RoadType::ROAD_MONORAIL)
120 pos.y += 2;
121
122 computePoints(pts, pos, rot, type, width, bwidth, bheight);
124
125 //tarmac
126 if (type == RoadType::ROAD_MONORAIL)
127 addQuad(pts[4], lpts[4], lpts[3], pts[3], TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, width);
128 else
129 addQuad(pts[4], lpts[4], lpts[3], pts[3], TextureFit::TEXFIT_ROAD, pos, lastpos, width);
130
132 {
133 //sides (close)
134 addQuad(pts[5], lpts[5], lpts[4], pts[4], TextureFit::TEXFIT_ROADS3, pos, lastpos, width);
135 addQuad(pts[3], lpts[3], lpts[2], pts[2], TextureFit::TEXFIT_ROADS2, pos, lastpos, width);
136 //sides (far)
137 addQuad(pts[6], lpts[6], lpts[5], pts[5], TextureFit::TEXFIT_ROADS4, pos, lastpos, width);
138 addQuad(pts[2], lpts[2], lpts[1], pts[1], TextureFit::TEXFIT_ROADS1, pos, lastpos, width);
139 }
140 else
141 {
142 //sides (close)
143 addQuad(pts[5], lpts[5], lpts[4], pts[4], TextureFit::TEXFIT_CONCRETEWALLI, pos, lastpos, width, (type == RoadType::ROAD_FLAT || type == RoadType::ROAD_LEFT));
144 addQuad(pts[3], lpts[3], lpts[2], pts[2], TextureFit::TEXFIT_CONCRETEWALLI, pos, lastpos, width, !(type == RoadType::ROAD_FLAT || type == RoadType::ROAD_RIGHT));
145 //sides (far)
146 addQuad(pts[6], lpts[6], lpts[5], pts[5], TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, width, (type == RoadType::ROAD_FLAT || type == RoadType::ROAD_LEFT));
147 addQuad(pts[2], lpts[2], lpts[1], pts[1], TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, width, !(type == RoadType::ROAD_FLAT || type == RoadType::ROAD_RIGHT));
148 }
150 {
151 //walls
152 addQuad(pts[1], lpts[1], lpts[0], pts[0], TextureFit::TEXFIT_CONCRETEWALL, pos, lastpos, width);
153 addQuad(lpts[6], pts[6], pts[7], lpts[7], TextureFit::TEXFIT_CONCRETEWALL, pos, lastpos, width);
154 //underside - we flip the underside so it folds gracefully with the top
155 addQuad(pts[0], lpts[0], lpts[7], pts[7], TextureFit::TEXFIT_CONCRETEUNDER, pos, lastpos, width, true);
156 }
157 else
158 {
159 //walls
160 addQuad(pts[1], lpts[1], lpts[0], pts[0], TextureFit::TEXFIT_BRICKWALL, pos, lastpos, width);
161 addQuad(lpts[6], pts[6], pts[7], lpts[7], TextureFit::TEXFIT_BRICKWALL, pos, lastpos, width);
162 }
163 if ((type == RoadType::ROAD_BRIDGE || type == RoadType::ROAD_MONORAIL) && pillartype > 0)
164 {
165 /* this is the basic bridge pillar mod.
166 * it will create on pillar for each segment!
167 * @todo: create only a few pillars instead of so much!
168 */
169 // construct the pillars
170 Vector3 leftv = pos + rot * Vector3(0, 0, bwidth + width / 2.0);
171 Vector3 rightv = pos + rot * Vector3(0, 0, -bwidth - width / 2.0);
172 Vector3 middle = lpts[0] - ((lpts[0] + (pts[1] - lpts[0]) / 2) -
173 (lpts[7] + (pts[6] - lpts[7]) / 2)) * 0.5;
174 float heightleft = RoR::App::GetGameContext()->GetTerrain()->getHeightAt(leftv.x, leftv.z);
175 float heightright = RoR::App::GetGameContext()->GetTerrain()->getHeightAt(rightv.x, rightv.z);
176 float heightmiddle = RoR::App::GetGameContext()->GetTerrain()->getHeightAt(middle.x, middle.z);
177
178 bool builtpillars = true;
179
180 float sidefactor = 0.5; // 0.5 = middle
181 // only re-position short pillars! (< 10 meters)
182 // so big bridge pillars do not get repositioned
183 if (pos.y - heightmiddle < 10)
184 {
185 if (heightleft >= heightright)
186 sidefactor = 0.8;
187 else
188 sidefactor = 0.2;
189 }
190
191 static int pillarcounter = 0;
192 pillarcounter++;
193
194 if (pillartype == 2)
195 {
196 // always in the middle
197 sidefactor = 0.5;
198 // only build every fifth pillar
199 if (pillarcounter % 5)
200 builtpillars = false;
201 }
202
203 middle = lpts[0] - ((lpts[0] + (pts[1] - lpts[0]) / 2) -
204 (lpts[7] + (pts[6] - lpts[7]) / 2)) * sidefactor;
205 float len = middle.y - RoR::App::GetGameContext()->GetTerrain()->getHeightAt(middle.x, middle.z) + 5;
206 float width2 = len / 30;
207
208 if (pillartype == 2 && len > 20)
209 // no over-long pillars
210 builtpillars = false;
211
212 // do not draw too small pillars, the bridge may hold without them ;)
213 if (width2 > 5)
214 width2 = 5;
215
216 if (pillartype == 2)
217 width2 = 0.2;
218
219 if (width2 >= 0.2 && builtpillars)
220 {
221 //sides
222 addQuad(middle + Vector3(-width2, -len, -width2),
223 middle + Vector3(-width2, 0, -width2),
224 middle + Vector3(width2, 0, -width2),
225 middle + Vector3(width2, -len, -width2),
227
228 addQuad(middle + Vector3(width2, -len, width2),
229 middle + Vector3(width2, 0, width2),
230 middle + Vector3(-width2, 0, width2),
231 middle + Vector3(-width2, -len, width2),
233
234 addQuad(middle + Vector3(-width2, -len, width2),
235 middle + Vector3(-width2, 0, width2),
236 middle + Vector3(-width2, 0, -width2),
237 middle + Vector3(-width2, -len, -width2),
239
240 addQuad(middle + Vector3(width2, -len, -width2),
241 middle + Vector3(width2, 0, -width2),
242 middle + Vector3(width2, 0, width2),
243 middle + Vector3(width2, -len, width2),
245 }
246 }
247 }
248 else
249 {
250 first = false;
251 computePoints(pts, pos, rot, type, width, bwidth, bheight);
252 addQuad(pts[0], pts[1], pts[2], pts[3], TextureFit::TEXFIT_NONE, pos, pos, width);
253 addQuad(pts[0], pts[3], pts[4], pts[7], TextureFit::TEXFIT_NONE, pos, pos, width);
254 addQuad(pts[4], pts[5], pts[6], pts[7], TextureFit::TEXFIT_NONE, pos, pos, width);
255 }
256 lastpos = pos;
257 lastrot = rot;
258 lastwidth = width;
259 lastbwidth = bwidth;
260 lastbheight = bheight;
261 lasttype = type;
262
263 if (App::diag_terrn_log_roads->getBool())
264 {
265 Str<2000> msg; msg << "[RoR] Road Block |";
266 msg << " pos=(" << pos.x << " " << pos.y << " " << pos.z << ")";
267 msg << " rot=(" << rot.x << " " << rot.y << " " << rot.z << ")";
268 msg << " width=" << width;
269 msg << " bwidth=" << bwidth;
270 msg << " bheight=" << bheight;
271 msg << " type=" << (int)type;
272 for (int i = 0; i < 8; ++i)
273 {
274 msg << "\n\t Point#" << i << ": " << pts[i].x << " " << pts[i].y << " " << pts[i].z;
275 }
276 Log(msg.ToCStr());
277 }
278}
279
280void ProceduralRoad::computePoints(Vector3* pts, Vector3 pos, Quaternion rot, RoadType type, float width, float bwidth, float bheight)
281{
282 if (type == RoadType::ROAD_FLAT)
283 {
284 pts[1] = pos + rot * Vector3(0, -bheight, bwidth + width / 2.0);
285 pts[0] = baseOf(pts[1]);
286 pts[2] = pos + rot * Vector3(0, -bheight / 4.0, bwidth / 3.0 + width / 2.0);
287 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
288 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
289 pts[5] = pos + rot * Vector3(0, -bheight / 4.0, -bwidth / 3.0 - width / 2.0);
290 pts[6] = pos + rot * Vector3(0, -bheight, -bwidth - width / 2.0);
291 pts[7] = baseOf(pts[6]);
292 }
293 if (type == RoadType::ROAD_BOTH)
294 {
295 pts[1] = pos + rot * Vector3(0, bheight, bwidth + width / 2.0);
296 pts[0] = baseOf(pts[1]);
297 pts[2] = pos + rot * Vector3(0, bheight, width / 2.0);
298 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
299 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
300 pts[5] = pos + rot * Vector3(0, bheight, -width / 2.0);
301 pts[6] = pos + rot * Vector3(0, bheight, -bwidth - width / 2.0);
302 pts[7] = baseOf(pts[6]);
303 }
304 if (type == RoadType::ROAD_LEFT)
305 {
306 pts[1] = pos + rot * Vector3(0, -bheight, bwidth + width / 2.0);
307 pts[0] = baseOf(pts[1]);
308 pts[2] = pos + rot * Vector3(0, -bheight / 4.0, bwidth / 3.0 + width / 2.0);
309 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
310 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
311 pts[5] = pos + rot * Vector3(0, bheight, -width / 2.0);
312 pts[6] = pos + rot * Vector3(0, bheight, -bwidth - width / 2.0);
313 pts[7] = baseOf(pts[6]);
314 }
315 if (type == RoadType::ROAD_RIGHT)
316 {
317 pts[1] = pos + rot * Vector3(0, bheight, bwidth + width / 2.0);
318 pts[0] = baseOf(pts[1]);
319 pts[2] = pos + rot * Vector3(0, bheight, width / 2.0);
320 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
321 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
322 pts[5] = pos + rot * Vector3(0, -bheight / 4.0, -bwidth / 3.0 - width / 2.0);
323 pts[6] = pos + rot * Vector3(0, -bheight, -bwidth - width / 2.0);
324 pts[7] = baseOf(pts[6]);
325 }
326 if (type == RoadType::ROAD_BRIDGE)
327 {
328 pts[0] = pos + rot * Vector3(0, -0.4, bwidth + width / 2.0);
329 pts[1] = pos + rot * Vector3(0, bheight, bwidth + width / 2.0);
330 pts[2] = pos + rot * Vector3(0, bheight, width / 2.0);
331 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
332 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
333 pts[5] = pos + rot * Vector3(0, bheight, -width / 2.0);
334 pts[6] = pos + rot * Vector3(0, bheight, -bwidth - width / 2.0);
335 pts[7] = pos + rot * Vector3(0, -0.4, -bwidth - width / 2.0);
336 }
337 if (type == RoadType::ROAD_MONORAIL)
338 {
339 pts[0] = pos + rot * Vector3(0, -1.4, bwidth + width / 2.0);
340 pts[1] = pos + rot * Vector3(0, bheight, bwidth + width / 2.0);
341 pts[2] = pos + rot * Vector3(0, bheight, width / 2.0);
342 pts[3] = pos + rot * Vector3(0, 0, width / 2.0);
343 pts[4] = pos + rot * Vector3(0, 0, -width / 2.0);
344 pts[5] = pos + rot * Vector3(0, bheight, -width / 2.0);
345 pts[6] = pos + rot * Vector3(0, bheight, -bwidth - width / 2.0);
346 pts[7] = pos + rot * Vector3(0, -1.4, -bwidth - width / 2.0);
347 }
348}
349
350inline Vector3 ProceduralRoad::baseOf(Vector3 p)
351{
352 float y = RoR::App::GetGameContext()->GetTerrain()->getHeightAt(p.x, p.z) - 0.01;
353
354 if (y > p.y)
355 {
356 y = p.y - 0.01;
357 }
358
359 return Vector3(p.x, y, p.z);
360}
361
362void ProceduralRoad::addQuad(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, TextureFit texfit, Vector3 pos, Vector3 lastpos, float width, bool flip)
363{
364 if (vertexcount + 3 >= MAX_VERTEX || tricount * 3 + 3 + 2 >= MAX_TRIS * 3)
365 return;
366 Vector2 texf[4];
367 textureFit(p1, p2, p3, p4, texfit, texf, pos, lastpos, width);
368 //vertexes
369 vertex[vertexcount] = p1;
370 tex[vertexcount] = texf[0];
371 vertex[vertexcount + 1] = p2;
372 tex[vertexcount + 1] = texf[1];
373 vertex[vertexcount + 2] = p3;
374 tex[vertexcount + 2] = texf[2];
375 vertex[vertexcount + 3] = p4;
376 tex[vertexcount + 3] = texf[3];
377 //tris
378 if (flip)
379 {
381 tris[tricount * 3 + 1] = vertexcount + 1;
382 tris[tricount * 3 + 2] = vertexcount + 3;
383 tris[tricount * 3 + 3] = vertexcount + 1;
384 tris[tricount * 3 + 3 + 1] = vertexcount + 2;
385 tris[tricount * 3 + 3 + 2] = vertexcount + 3;
386 }
387 else
388 {
390 tris[tricount * 3 + 1] = vertexcount + 1;
391 tris[tricount * 3 + 2] = vertexcount + 2;
392 tris[tricount * 3 + 3] = vertexcount;
393 tris[tricount * 3 + 3 + 1] = vertexcount + 2;
394 tris[tricount * 3 + 3 + 2] = vertexcount + 3;
395 }
396 if (collision)
397 {
401 addCollisionQuad(p1, p2, p3, p4, gm, flip);
402 }
403 tricount += 2;
404 vertexcount += 4;
405}
406
407void ProceduralRoad::textureFit(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, TextureFit texfit, Vector2* texc, Vector3 pos, Vector3 lastpos, float width)
408{
409 int i;
410
412 {
413 Vector3 ps[4];
414 ps[0] = p1;
415 ps[1] = p2;
416 ps[2] = p3;
417 ps[3] = p4;
418 Vector3 pref1 = pos;
419 Vector3 pref2 = lastpos;
420 //make matrix
421 Vector3 bx = pref2 - pref1;
422 bx.normalise();
423 Vector3 by = Vector3::UNIT_Y;
424 Vector3 bz = bx.crossProduct(by);
425 //coordinates change matrix
426 Matrix3 reverse;
427 reverse.SetColumn(0, bx);
428 reverse.SetColumn(1, by);
429 reverse.SetColumn(2, bz);
430 Matrix3 forward;
431 forward = reverse.Inverse();
432 //transpose
433 for (i = 0; i < 4; i++)
434 {
435 Vector3 trv = forward * (ps[i] - pref1);
436 if (texfit == TextureFit::TEXFIT_BRICKWALL)
437 {
438 float ty = 0.746 - trv.y * 0.25 / 4.5;
439 // fix overlapping
440 if (ty > 1)
441 ty = 1;
442 texc[i] = Vector2(trv.x / 10.0, ty);
443 }
445 {
446 // fix overlapping
447 float ty = 0.496 - (trv.y - 0.7) * 0.25 / 4.5;
448 if (ty > 1)
449 ty = 1;
450 texc[i] = Vector2(trv.x / 10.0, ty);
451 }
453 {
454 float ty = 0.496 + trv.y * 0.25 / 4.5;
455 // fix overlapping
456 if (ty > 1)
457 ty = 1;
458 texc[i] = Vector2(trv.x / 10.0, ty);
459 }
460 }
461 return;
462 }
464 {
465 Vector3 ps[4];
466 ps[0] = p1;
467 ps[1] = p2;
468 ps[2] = p3;
469 ps[3] = p4;
470 Vector3 pref1 = pos;
471 Vector3 pref2 = lastpos;
472 //project
473 for (i = 0; i < 4; i++)
474 ps[i].y = 0;
475 pref1.y = 0;
476 pref2.y = 0;
477 //make matrix
478 Vector3 bx = pref2 - pref1;
479 bx.normalise();
480 Vector3 by = Vector3::UNIT_Y;
481 Vector3 bz = bx.crossProduct(by);
482 //coordinates change matrix
483 Matrix3 reverse;
484 reverse.SetColumn(0, bx);
485 reverse.SetColumn(1, by);
486 reverse.SetColumn(2, bz);
487 Matrix3 forward;
488 forward = reverse.Inverse();
489 //transpose
490 float trvrefz = 0.0;
491 for (i = 0; i < 4; i++)
492 {
493 Vector3 trv = forward * (ps[i] - pref1);
494 if (texfit == TextureFit::TEXFIT_CONCRETETOP)
495 {
496 if (i == 0)
497 trvrefz = trv.z;
498 texc[i] = Vector2(trv.x / 10.0, 0.621 + (trv.z - trvrefz) * 0.25 / 4.5);
499 }
500 else
501 {
502 float v1 = 0.072;
503 float v2 = 0.423;
504 if (texfit == TextureFit::TEXFIT_ROADS1)
505 {
506 v1 = 0.001;
507 v2 = 0.036;
508 };
509 if (texfit == TextureFit::TEXFIT_ROADS2)
510 {
511 v1 = 0.036;
512 v2 = 0.072;
513 };
514 if (texfit == TextureFit::TEXFIT_ROADS3)
515 {
516 v1 = 0.423;
517 v2 = 0.458;
518 };
519 if (texfit == TextureFit::TEXFIT_ROADS4)
520 {
521 v1 = 0.458;
522 v2 = 0.493;
523 };
525 {
526 v1 = 0.496;
527 v2 = 0.745;
528 };
529 if (i < 2)
530 texc[i] = Vector2(trv.x / 10.0, v1);
531 else
532 texc[i] = Vector2(trv.x / 10.0, v2);
533 }
534 }
535 return;
536 }
537 //default
538 for (i = 0; i < 4; i++)
539 texc[i] = Vector2(0, 0);
540}
541
542void ProceduralRoad::addCollisionQuad(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, ground_model_t* gm, bool flip)
543{
544 int triID = 0;
545 if (flip)
546 {
547 triID = App::GetGameContext()->GetTerrain()->GetCollisions()->addCollisionTri(p1, p2, p4, gm);
548 if (triID >= 0)
549 registeredCollTris.push_back(triID);
550
551 triID = App::GetGameContext()->GetTerrain()->GetCollisions()->addCollisionTri(p4, p2, p3, gm);
552 if (triID >= 0)
553 registeredCollTris.push_back(triID);
554 }
555 else
556 {
557 triID = App::GetGameContext()->GetTerrain()->GetCollisions()->addCollisionTri(p1, p2, p3, gm);
558 if (triID >= 0)
559 registeredCollTris.push_back(triID);
560
561 triID = App::GetGameContext()->GetTerrain()->GetCollisions()->addCollisionTri(p1, p3, p4, gm);
562 if (triID >= 0)
563 registeredCollTris.push_back(triID);
564 }
565}
566
567void ProceduralRoad::addCollisionQuad(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, Ogre::Vector3 p4, std::string const& gm_name, bool flip /*= false*/)
568{
570 if (gm)
571 {
572 this->addCollisionQuad(p1, p2, p3, p4, gm, flip);
573 }
574 else
575 {
577 fmt::format("ProceduralRoad::addCollisionQuad() - ground model '{}' does not exist", gm_name));
578 }
579}
580
582{
583 AxisAlignedBox aab;
584 union
585 {
586 float* vertices;
587 CoVertice_t* covertices;
588 };
590 Ogre::String mesh_name = Ogre::String("RoadSystem-").append(Ogre::StringConverter::toString(mid));
591 msh = MeshManager::getSingleton().createManual(mesh_name, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
592
593 mainsub = msh->createSubMesh();
594 mainsub->setMaterialName("road2");
595
597 size_t vbufCount = (2 * 3 + 2) * vertexcount;
598 vertices = (float*)malloc(vbufCount * sizeof(float));
599 int i;
600 //fill values
601 for (i = 0; i < vertexcount; i++)
602 {
603 covertices[i].texcoord = tex[i];
604 covertices[i].vertex = vertex[i];
605 //normals are computed later
606 covertices[i].normal = Vector3::ZERO;
607 aab.merge(vertex[i]);
608 }
609
611 size_t ibufCount = 3 * tricount;
612
613 //compute normals
614 for (i = 0; i < tricount && i * 3 + 2 < MAX_TRIS * 3; i++)
615 {
616 Vector3 v1, v2;
617 v1 = covertices[tris[i * 3 + 1]].vertex - covertices[tris[i * 3]].vertex;
618 v2 = covertices[tris[i * 3 + 2]].vertex - covertices[tris[i * 3]].vertex;
619 v1 = v1.crossProduct(v2);
620 v1.normalise();
621 covertices[tris[i * 3]].normal += v1;
622 covertices[tris[i * 3 + 1]].normal += v1;
623 covertices[tris[i * 3 + 2]].normal += v1;
624 }
625 //normalize
626 for (i = 0; i < vertexcount; i++)
627 {
628 covertices[i].normal.normalise();
629 }
630
632 msh->sharedVertexData = new VertexData();
633 msh->sharedVertexData->vertexCount = vertexcount;
634
636 VertexDeclaration* decl = msh->sharedVertexData->vertexDeclaration;
637 size_t offset = 0;
638 decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
639 offset += VertexElement::getTypeSize(VET_FLOAT3);
640 decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
641 offset += VertexElement::getTypeSize(VET_FLOAT3);
642 decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
643 offset += VertexElement::getTypeSize(VET_FLOAT2);
644
647 HardwareVertexBufferSharedPtr vbuf =
648 HardwareBufferManager::getSingleton().createVertexBuffer(
649 offset, msh->sharedVertexData->vertexCount, HardwareBuffer::HBU_STATIC_WRITE_ONLY);
650
652 vbuf->writeData(0, vbuf->getSizeInBytes(), vertices, true);
653
655 VertexBufferBinding* bind = msh->sharedVertexData->vertexBufferBinding;
656 bind->setBinding(0, vbuf);
657
658 //for the face
660 HardwareIndexBufferSharedPtr ibuf = HardwareBufferManager::getSingleton().
661 createIndexBuffer(
662 HardwareIndexBuffer::IT_16BIT,
663 ibufCount,
664 HardwareBuffer::HBU_STATIC_WRITE_ONLY);
665
667 ibuf->writeData(0, ibuf->getSizeInBytes(), tris, true);
668
670 mainsub->useSharedVertices = true;
671 mainsub->indexData->indexBuffer = ibuf;
672 mainsub->indexData->indexCount = ibufCount;
673 mainsub->indexData->indexStart = 0;
674
675 msh->_setBounds(aab, true);
676
678 msh->load();
679
680 free(vertices);
681};
682
quaternion Log() const
Central state/object manager and communications hub.
Game state manager and message-queue provider.
static int id_counter
void registerCollisionMesh(Ogre::String const &srcname, Ogre::String const &meshname, Ogre::Vector3 const &pos, Ogre::AxisAlignedBox bounding_box, ground_model_t *gm, int ctri_start, int ctri_count)
Mark already generated collision tris as belonging to (virtual) mesh.
int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t *gm)
ground_model_t * getGroundModelByString(const Ogre::String name)
void removeCollisionTri(int number)
@ CONSOLE_MSGTYPE_TERRN
Parsing/spawn/simulation messages for terrain.
Definition Console.h:64
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition Console.cpp:103
@ CONSOLE_SYSTEM_WARNING
Definition Console.h:53
const TerrainPtr & GetTerrain()
Ogre::SceneManager * GetSceneManager()
Definition GfxScene.h:83
static const unsigned int MAX_TRIS
static const unsigned int MAX_VERTEX
Ogre::SceneNode * snode
void textureFit(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, Ogre::Vector3 p4, TextureFit texfit, Ogre::Vector2 *texc, Ogre::Vector3 pos, Ogre::Vector3 lastpos, float width)
uint16_t tris[MAX_TRIS *3]
Ogre::Vector2 tex[MAX_VERTEX]
virtual ~ProceduralRoad() override
void addCollisionQuad(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, Ogre::Vector3 p4, ground_model_t *gm, bool flip=false)
std::vector< int > registeredCollTris
void addBlock(Ogre::Vector3 pos, Ogre::Quaternion rot, RoadType type, float width, float bwidth, float bheight, int pillartype=1)
void addQuad(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, Ogre::Vector3 p4, TextureFit texfit, Ogre::Vector3 pos, Ogre::Vector3 lastpos, float width, bool flip=false)
bool collision
Register collision triangles?
Ogre::Vector3 vertex[MAX_VERTEX]
Ogre::Vector3 baseOf(Ogre::Vector3 p)
Ogre::Vector3 lastpos
Ogre::SubMesh * mainsub
void finish(Ogre::SceneNode *snode)
Ogre::Quaternion lastrot
void computePoints(Ogre::Vector3 *pts, Ogre::Vector3 pos, Ogre::Quaternion rot, RoadType type, float width, float bwidth, float bheight)
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition Str.h:36
const char * ToCStr() const
Definition Str.h:46
float getHeightAt(float x, float z)
Definition Terrain.cpp:512
Collisions * GetCollisions()
Definition Terrain.h:86
GameContext * GetGameContext()
CVar * diag_terrn_log_roads
GfxScene * GetGfxScene()
Console * GetConsole()
Surface friction properties.
Definition SimData.h:704