RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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 
33 using namespace Ogre;
34 using namespace RoR;
35 
36 static int id_counter = 0;
37 
38 ProceduralRoad::ProceduralRoad()
39 {
40  mid = id_counter++;
41 }
42 
43 ProceduralRoad::~ProceduralRoad()
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 
61 void ProceduralRoad::finish(Ogre::SceneNode* groupingSceneNode)
62 {
63  Vector3 pts[8];
64  computePoints(pts, lastpos, lastrot, lasttype, lastwidth, lastbwidth, lastbheight);
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 
85 void 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)
98  type = RoadType::ROAD_FLAT;
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)
102  type = RoadType::ROAD_RIGHT;
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)
106  type = RoadType::ROAD_BRIDGE;
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);
123  computePoints(lpts, lastpos, lastrot, lasttype, lastwidth, lastbwidth, lastbheight);
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 
131  if (type == RoadType::ROAD_FLAT && lasttype == RoadType::ROAD_FLAT)
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  }
149  if (type == RoadType::ROAD_BRIDGE || lasttype == RoadType::ROAD_BRIDGE || type == RoadType::ROAD_MONORAIL || lasttype == RoadType::ROAD_MONORAIL)
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),
226  TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, 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),
232  TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, 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),
238  TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, 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),
244  TextureFit::TEXFIT_CONCRETETOP, pos, lastpos, 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 
280 void 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 
350 inline 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 
362 void 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  {
380  tris[tricount * 3] = vertexcount;
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  {
389  tris[tricount * 3] = vertexcount;
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 
407 void 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  }
444  if (texfit == TextureFit::TEXFIT_CONCRETEWALL)
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  }
452  if (texfit == TextureFit::TEXFIT_CONCRETEWALLI)
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  };
524  if (texfit == TextureFit::TEXFIT_CONCRETEUNDER)
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 
542 void 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 
567 void 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  {
576  App::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_TERRN, Console::CONSOLE_SYSTEM_WARNING,
577  fmt::format("ProceduralRoad::addCollisionQuad() - ground model '{}' does not exist", gm_name));
578  }
579 }
580 
581 void ProceduralRoad::createMesh()
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 
Script2Game::ROAD_LEFT
@ ROAD_LEFT
Definition: ProceduralRoadClass.h:16
GameContext.h
Game state manager and message-queue provider.
Script2Game::TEXFIT_CONCRETEUNDER
@ TEXFIT_CONCRETEUNDER
Definition: ProceduralRoadClass.h:35
Script2Game::ROAD_AUTOMATIC
@ ROAD_AUTOMATIC
Definition: ProceduralRoadClass.h:14
Script2Game::TEXFIT_BRICKWALL
@ TEXFIT_BRICKWALL
Definition: ProceduralRoadClass.h:26
Script2Game::TEXFIT_CONCRETEWALLI
@ TEXFIT_CONCRETEWALLI
Definition: ProceduralRoadClass.h:33
y
float y
Definition: (ValueTypes) quaternion.h:6
Script2Game::TEXFIT_ROAD
@ TEXFIT_ROAD
Definition: ProceduralRoadClass.h:29
format
Truck file format(technical spec)
Script2Game::TEXFIT_ROADS2
@ TEXFIT_ROADS2
Definition: ProceduralRoadClass.h:28
Console.h
RoR::ProceduralRoad::CoVertice_t::texcoord
Ogre::Vector2 texcoord
Definition: ProceduralRoad.h:92
RoR::Console::putMessage
void putMessage(MessageArea area, MessageType type, std::string const &msg, std::string icon="")
Definition: Console.cpp:103
RoR::Collisions::registerCollisionMesh
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.
Definition: Collisions.cpp:1488
Script2Game::ROAD_RIGHT
@ ROAD_RIGHT
Definition: ProceduralRoadClass.h:17
Script2Game::TEXFIT_ROADS3
@ TEXFIT_ROADS3
Definition: ProceduralRoadClass.h:30
RoR::Collisions::removeCollisionTri
void removeCollisionTri(int number)
Definition: Collisions.cpp:356
Actor.h
RoR::TextureFit
TextureFit
Definition: ProceduralRoad.h:44
RoR::GfxScene::GetSceneManager
Ogre::SceneManager * GetSceneManager()
Definition: GfxScene.h:83
Script2Game::ROAD_BOTH
@ ROAD_BOTH
Definition: ProceduralRoadClass.h:18
ProceduralRoad.h
Script2Game::ROAD_BRIDGE
@ ROAD_BRIDGE
Definition: ProceduralRoadClass.h:19
RoR::RoadType
RoadType
Definition: ProceduralRoad.h:33
RoR::Str
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition: Str.h:35
RoR::Collisions::getGroundModelByString
ground_model_t * getGroundModelByString(const Ogre::String name)
Definition: Collisions.cpp:365
Script2Game::ROAD_FLAT
@ ROAD_FLAT
Definition: ProceduralRoadClass.h:15
RoR::Terrain::getHeightAt
float getHeightAt(float x, float z)
Definition: Terrain.cpp:505
id_counter
static int id_counter
Definition: ProceduralRoad.cpp:36
RoR::Str::ToCStr
const char * ToCStr() const
Definition: Str.h:46
RoR::Terrain::GetCollisions
Collisions * GetCollisions()
Definition: Terrain.h:85
GfxScene.h
RoR::Collisions::addCollisionTri
int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t *gm)
Definition: Collisions.cpp:557
Script2Game::TEXFIT_ROADS1
@ TEXFIT_ROADS1
Definition: ProceduralRoadClass.h:27
Script2Game::TEXFIT_CONCRETEWALL
@ TEXFIT_CONCRETEWALL
Definition: ProceduralRoadClass.h:32
Application.h
Central state/object manager and communications hub.
RoR::App::GetConsole
Console * GetConsole()
Definition: Application.cpp:286
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:296
Script2Game::TEXFIT_ROADS4
@ TEXFIT_ROADS4
Definition: ProceduralRoadClass.h:31
Script2Game::TEXFIT_NONE
@ TEXFIT_NONE
Definition: ProceduralRoadClass.h:25
by
or anywhere else will not be considered a but parsed as regular data ! Each line is treated as values separated by separators Possible i e animators Multiline description Single does not affect it Directive usualy set global attributes or change behavior of the parsing Directive may appear in any block section Modularity The elements can be grouped into modules Each module must belong to one or more configurations Directives sectionconfig specify truck configurations the user can choose from Exactly one must be selected If the first defined is used lettercase matches original docs(parsing is insensitive). NAME TYPE NOTES advdrag BLOCK add_animation DIRECTIVE Special syntax airbrakes BLOCK animators BLOCK Special syntax IF(values[0]=="") bad trailing chars are silently ignored no space at the end Items delimited by
Definition: ReadMe.txt:293
Script2Game::TEXFIT_CONCRETETOP
@ TEXFIT_CONCRETETOP
Definition: ProceduralRoadClass.h:34
RoR::ground_model_t
Surface friction properties.
Definition: SimData.h:703
Terrain.h
Ogre
Definition: ExtinguishableFireAffector.cpp:35
Collisions.h
RoR::App::diag_terrn_log_roads
CVar * diag_terrn_log_roads
Definition: Application.cpp:157
Script2Game::ROAD_MONORAIL
@ ROAD_MONORAIL
Definition: ProceduralRoadClass.h:20
RoR::ProceduralRoad::CoVertice_t
Definition: ProceduralRoad.h:88
RoR
Definition: AppContext.h:36
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:292
Log
quaternion Log() const
RoR::GameContext::GetTerrain
const TerrainPtr & GetTerrain()
Definition: GameContext.h:117