RigsofRods
Soft-body Physics Simulation
Collisions.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  Copyright 2013-2020 Petr Ohlidal
6 
7  For more information, see http://www.rigsofrods.org/
8 
9  Rigs of Rods is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License version 3, as
11  published by the Free Software Foundation.
12 
13  Rigs of Rods is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20 */
21 
22 #include "Collisions.h"
23 
24 #include "Application.h"
25 #include "ApproxMath.h"
26 #include "Actor.h"
27 #include "ActorManager.h"
28 #include "ErrorUtils.h"
29 #include "GameContext.h"
30 #include "GfxScene.h"
31 #include "Landusemap.h"
32 #include "Language.h"
33 #include "MovableText.h"
34 #include "PlatformUtils.h"
35 #include "ScriptEngine.h"
36 #include "Terrain.h"
37 
38 using namespace RoR;
39 
40 // some gcc fixes
41 #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
42 #pragma GCC diagnostic ignored "-Wfloat-equal"
43 #endif //OGRE_PLATFORM_LINUX
44 
45 //hash function SBOX
46 //from http://home.comcast.net/~bretm/hash/10.html
47 unsigned int sbox[] =
48 {
49  0xF53E1837, 0x5F14C86B, 0x9EE3964C, 0xFA796D53,
50  0x32223FC3, 0x4D82BC98, 0xA0C7FA62, 0x63E2C982,
51  0x24994A5B, 0x1ECE7BEE, 0x292B38EF, 0xD5CD4E56,
52  0x514F4303, 0x7BE12B83, 0x7192F195, 0x82DC7300,
53  0x084380B4, 0x480B55D3, 0x5F430471, 0x13F75991,
54  0x3F9CF22C, 0x2FE0907A, 0xFD8E1E69, 0x7B1D5DE8,
55  0xD575A85C, 0xAD01C50A, 0x7EE00737, 0x3CE981E8,
56  0x0E447EFA, 0x23089DD6, 0xB59F149F, 0x13600EC7,
57  0xE802C8E6, 0x670921E4, 0x7207EFF0, 0xE74761B0,
58  0x69035234, 0xBFA40F19, 0xF63651A0, 0x29E64C26,
59  0x1F98CCA7, 0xD957007E, 0xE71DDC75, 0x3E729595,
60  0x7580B7CC, 0xD7FAF60B, 0x92484323, 0xA44113EB,
61  0xE4CBDE08, 0x346827C9, 0x3CF32AFA, 0x0B29BCF1,
62  0x6E29F7DF, 0xB01E71CB, 0x3BFBC0D1, 0x62EDC5B8,
63  0xB7DE789A, 0xA4748EC9, 0xE17A4C4F, 0x67E5BD03,
64  0xF3B33D1A, 0x97D8D3E9, 0x09121BC0, 0x347B2D2C,
65  0x79A1913C, 0x504172DE, 0x7F1F8483, 0x13AC3CF6,
66  0x7A2094DB, 0xC778FA12, 0xADF7469F, 0x21786B7B,
67  0x71A445D0, 0xA8896C1B, 0x656F62FB, 0x83A059B3,
68  0x972DFE6E, 0x4122000C, 0x97D9DA19, 0x17D5947B,
69  0xB1AFFD0C, 0x6EF83B97, 0xAF7F780B, 0x4613138A,
70  0x7C3E73A6, 0xCF15E03D, 0x41576322, 0x672DF292,
71  0xB658588D, 0x33EBEFA9, 0x938CBF06, 0x06B67381,
72  0x07F192C6, 0x2BDA5855, 0x348EE0E8, 0x19DBB6E3,
73  0x3222184B, 0xB69D5DBA, 0x7E760B88, 0xAF4D8154,
74  0x007A51AD, 0x35112500, 0xC9CD2D7D, 0x4F4FB761,
75  0x694772E3, 0x694C8351, 0x4A7E3AF5, 0x67D65CE1,
76  0x9287DE92, 0x2518DB3C, 0x8CB4EC06, 0xD154D38F,
77  0xE19A26BB, 0x295EE439, 0xC50A1104, 0x2153C6A7,
78  0x82366656, 0x0713BC2F, 0x6462215A, 0x21D9BFCE,
79  0xBA8EACE6, 0xAE2DF4C1, 0x2A8D5E80, 0x3F7E52D1,
80  0x29359399, 0xFEA1D19C, 0x18879313, 0x455AFA81,
81  0xFADFE838, 0x62609838, 0xD1028839, 0x0736E92F,
82  0x3BCA22A3, 0x1485B08A, 0x2DA7900B, 0x852C156D,
83  0xE8F24803, 0x00078472, 0x13F0D332, 0x2ACFD0CF,
84  0x5F747F5C, 0x87BB1E2F, 0xA7EFCB63, 0x23F432F0,
85  0xE6CE7C5C, 0x1F954EF6, 0xB609C91B, 0x3B4571BF,
86  0xEED17DC0, 0xE556CDA0, 0xA7846A8D, 0xFF105F94,
87  0x52B7CCDE, 0x0E33E801, 0x664455EA, 0xF2C70414,
88  0x73E7B486, 0x8F830661, 0x8B59E826, 0xBB8AEDCA,
89  0xF3D70AB9, 0xD739F2B9, 0x4A04C34A, 0x88D0F089,
90  0xE02191A2, 0xD89D9C78, 0x192C2749, 0xFC43A78F,
91  0x0AAC88CB, 0x9438D42D, 0x9E280F7A, 0x36063802,
92  0x38E8D018, 0x1C42A9CB, 0x92AAFF6C, 0xA24820C5,
93  0x007F077F, 0xCE5BC543, 0x69668D58, 0x10D6FF74,
94  0xBE00F621, 0x21300BBE, 0x2E9E8F46, 0x5ACEA629,
95  0xFA1F86C7, 0x52F206B8, 0x3EDF1A75, 0x6DA8D843,
96  0xCF719928, 0x73E3891F, 0xB4B95DD6, 0xB2A42D27,
97  0xEDA20BBF, 0x1A58DBDF, 0xA449AD03, 0x6DDEF22B,
98  0x900531E6, 0x3D3BFF35, 0x5B24ABA2, 0x472B3E4C,
99  0x387F2D75, 0x4D8DBA36, 0x71CB5641, 0xE3473F3F,
100  0xF6CD4B7F, 0xBF7D1428, 0x344B64D0, 0xC5CDFCB6,
101  0xFE2E0182, 0x2C37A673, 0xDE4EB7A3, 0x63FDC933,
102  0x01DC4063, 0x611F3571, 0xD167BFAF, 0x4496596F,
103  0x3DEE0689, 0xD8704910, 0x7052A114, 0x068C9EC5,
104  0x75D0E766, 0x4D54CC20, 0xB44ECDE2, 0x4ABC653E,
105  0x2C550A21, 0x1A52C0DB, 0xCFED03D0, 0x119BAFE2,
106  0x876A6133, 0xBC232088, 0x435BA1B2, 0xAE99BBFA,
107  0xBB4F08E4, 0xA62B5F49, 0x1DA4B695, 0x336B84DE,
108  0xDC813D31, 0x00C134FB, 0x397A98E6, 0x151F0E64,
109  0xD9EB3E69, 0xD3C7DF60, 0xD2F2C336, 0x2DDD067B,
110  0xBD122835, 0xB0B3BD3A, 0xB0D54E46, 0x8641F1E4,
111  0xA0B38F96, 0x51D39199, 0x37A6AD75, 0xDF84EE41,
112  0x3C034CBA, 0xACDA62FC, 0x11923B8B, 0x45EF170A,
113 };
114 
115 using namespace Ogre;
116 using namespace RoR;
117 
118 Collisions::Collisions(Ogre::Vector3 terrn_size):
119  forcecam(false)
120  , free_eventsource(0)
121  , hashmask(0)
122  , landuse(0)
123  , m_terrain_size(terrn_size)
124  , collision_version(0)
125  , forcecampos(Ogre::Vector3::ZERO)
126 {
127  for (int i=0; i < HASH_POWER; i++)
128  {
129  hashmask = hashmask << 1;
130  hashmask++;
131  }
132 
134  defaultgm = getGroundModelByString("concrete");
136 
137  hashtable_height.fill(std::numeric_limits<float>::min());
138 }
139 
141 {
142  if (landuse) delete landuse;
143 }
144 
146 {
147  return loadGroundModelsConfigFile(PathCombine(App::sys_config_dir->getStr(), "ground_models.cfg"));
148 }
149 
150 int Collisions::loadGroundModelsConfigFile(Ogre::String filename)
151 {
152  String group = "";
153  try
154  {
155  group = ResourceGroupManager::getSingleton().findGroupContainingResource(filename);
156  }
157  catch (...)
158  {
159  // we wont catch anything, since the path could be absolute as well, then the group is not found
160  }
161 
162  Ogre::ConfigFile cfg;
163  try
164  {
165  // try to load directly otherwise via resource group
166  if (group == "")
167  cfg.loadDirect(filename);
168  else
169  cfg.loadFromResourceSystem(filename, group, "\x09:=", true);
170  }
171  catch (Ogre::Exception& e)
172  {
173  ErrorUtils::ShowError("Error while loading ground model", e.getFullDescription());
174  return 1;
175  }
176 
177  // parse the whole config
178  parseGroundConfig(&cfg);
179 
180  // after it was parsed, resolve the dependencies
181  std::map<Ogre::String, ground_model_t>::iterator it;
182  for (it=ground_models.begin(); it!=ground_models.end(); it++)
183  {
184  if (!strlen(it->second.basename)) continue; // no base, normal material
185  String bname = String(it->second.basename);
186  if (ground_models.find(bname) == ground_models.end()) continue; // base not found!
187  // copy the values from the base if not set otherwise
188  ground_model_t *thisgm = &(it->second);
189  ground_model_t *basegm = &ground_models[bname];
190  memcpy(thisgm, basegm, sizeof(ground_model_t));
191  // re-set the name
192  strncpy(thisgm->name, it->first.c_str(), 255);
193  // after that we need to reload the config to overwrite settings of the base
194  parseGroundConfig(&cfg, it->first);
195  }
196  // check the version
198  {
199  ErrorUtils::ShowError(_L("Configuration error"), _L("Your ground configuration is too old, please copy skeleton/config/ground_models.cfg to My Documents/Rigs of Rods/config"));
200  exit(124);
201  }
202  return 0;
203 }
204 
205 
206 void Collisions::parseGroundConfig(Ogre::ConfigFile *cfg, String groundModel)
207 {
208  Ogre::ConfigFile::SectionIterator seci = cfg->getSectionIterator();
209 
210  Ogre::String secName, kname, kvalue;
211  while (seci.hasMoreElements())
212  {
213  secName = seci.peekNextKey();
214  Ogre::ConfigFile::SettingsMultiMap *settings = seci.getNext();
215 
216  if (!groundModel.empty() && secName != groundModel) continue;
217 
218  Ogre::ConfigFile::SettingsMultiMap::iterator i;
219  for (i = settings->begin(); i != settings->end(); ++i)
220  {
221  kname = i->first;
222  kvalue = i->second;
223  // we got all the data available now, processing now
224  if (secName == "general" || secName == "config")
225  {
226  // set some class properties accoring to the information in this section
227  if (kname == "version") this->collision_version = StringConverter::parseInt(kvalue);
228  } else
229  {
230  // we assume that all other sections are separate ground types!
231  if (ground_models.find(secName) == ground_models.end())
232  {
233  // ground models not known yet, init it!
234  ground_models[secName] = ground_model_t();
235  // clear it
236  memset(&ground_models[secName], 0, sizeof(ground_model_t));
237  // set some default values
238  ground_models[secName].alpha = 2.0f;
239  ground_models[secName].strength = 1.0f;
240  // some fx defaults
241  ground_models[secName].fx_particle_amount = 20;
242  ground_models[secName].fx_particle_min_velo = 5;
243  ground_models[secName].fx_particle_max_velo = 99999;
244  ground_models[secName].fx_particle_velo_factor = 0.7f;
245  ground_models[secName].fx_particle_fade = -1;
246  ground_models[secName].fx_particle_timedelta = 1;
247  ground_models[secName].fx_particle_ttl = 2;
248  strncpy(ground_models[secName].name, secName.c_str(), 255);
249 
250  }
251 
252  if (kname == "adhesion velocity") ground_models[secName].va = StringConverter::parseReal(kvalue);
253  else if (kname == "static friction coefficient") ground_models[secName].ms = StringConverter::parseReal(kvalue);
254  else if (kname == "sliding friction coefficient") ground_models[secName].mc = StringConverter::parseReal(kvalue);
255  else if (kname == "hydrodynamic friction") ground_models[secName].t2 = StringConverter::parseReal(kvalue);
256  else if (kname == "stribeck velocity") ground_models[secName].vs = StringConverter::parseReal(kvalue);
257  else if (kname == "alpha") ground_models[secName].alpha = StringConverter::parseReal(kvalue);
258  else if (kname == "strength") ground_models[secName].strength = StringConverter::parseReal(kvalue);
259  else if (kname == "base") strncpy(ground_models[secName].basename, kvalue.c_str(), 255);
260  else if (kname == "fx_type")
261  {
262  if (kvalue == "PARTICLE")
263  ground_models[secName].fx_type = FX_PARTICLE;
264  else if (kvalue == "HARD")
265  ground_models[secName].fx_type = FX_HARD;
266  else if (kvalue == "DUSTY")
267  ground_models[secName].fx_type = FX_DUSTY;
268  else if (kvalue == "CLUMPY")
269  ground_models[secName].fx_type = FX_CLUMPY;
270  }
271  else if (kname == "fx_particle_name") strncpy(ground_models[secName].particle_name, kvalue.c_str(), 255);
272  else if (kname == "fx_colour") ground_models[secName].fx_colour = StringConverter::parseColourValue(kvalue);
273  else if (kname == "fx_particle_amount") ground_models[secName].fx_particle_amount = StringConverter::parseInt(kvalue);
274  else if (kname == "fx_particle_min_velo") ground_models[secName].fx_particle_min_velo = StringConverter::parseReal(kvalue);
275  else if (kname == "fx_particle_max_velo") ground_models[secName].fx_particle_max_velo = StringConverter::parseReal(kvalue);
276  else if (kname == "fx_particle_fade") ground_models[secName].fx_particle_fade = StringConverter::parseReal(kvalue);
277  else if (kname == "fx_particle_timedelta") ground_models[secName].fx_particle_timedelta = StringConverter::parseReal(kvalue);
278  else if (kname == "fx_particle_velo_factor") ground_models[secName].fx_particle_velo_factor = StringConverter::parseReal(kvalue);
279  else if (kname == "fx_particle_ttl") ground_models[secName].fx_particle_ttl = StringConverter::parseReal(kvalue);
280 
281 
282  else if (kname == "fluid density") ground_models[secName].fluid_density = StringConverter::parseReal(kvalue);
283  else if (kname == "flow consistency index") ground_models[secName].flow_consistency_index = StringConverter::parseReal(kvalue);
284  else if (kname == "flow behavior index") ground_models[secName].flow_behavior_index = StringConverter::parseReal(kvalue);
285  else if (kname == "solid ground level") ground_models[secName].solid_ground_level = StringConverter::parseReal(kvalue);
286  else if (kname == "drag anisotropy") ground_models[secName].drag_anisotropy = StringConverter::parseReal(kvalue);
287 
288  }
289  }
290 
291  if (!groundModel.empty()) break; // we dont need to go through the other sections
292  }
293 }
294 
295 Ogre::Vector3 Collisions::calcCollidedSide(const Ogre::Vector3& pos, const Ogre::Vector3& lo, const Ogre::Vector3& hi)
296 {
297  Ogre::Real min = pos.x - lo.x;
298  Ogre::Vector3 newPos = Ogre::Vector3(lo.x, pos.y, pos.z);
299 
300  Ogre::Real t = pos.y - lo.y;
301  if (t < min) {
302  min=t;
303  newPos = Ogre::Vector3(pos.x, lo.y, pos.z);
304  }
305 
306  t = pos.z - lo.z;
307  if (t < min) {
308  min=t;
309  newPos = Ogre::Vector3(pos.x, pos.y, lo.z);
310  }
311 
312  t = hi.x - pos.x;
313  if (t < min) {
314  min=t;
315  newPos = Ogre::Vector3(hi.x, pos.y, pos.z);
316  }
317 
318  t = hi.y - pos.y;
319  if (t < min) {
320  min=t;
321  newPos = Ogre::Vector3(pos.x, hi.y, pos.z);
322  }
323 
324  t = hi.z - pos.z;
325  if (t < min) {
326  min=t;
327  newPos = Ogre::Vector3(pos.x, pos.y, hi.z);
328  }
329 
330  return newPos;
331 }
332 
333 void Collisions::setupLandUse(const char *configfile)
334 {
335 #ifdef USE_PAGED
336  if (landuse) return;
337  landuse = new Landusemap(configfile);
338 #else
339  LOG("RoR was not compiled with PagedGeometry support. You cannot use Landuse maps with it.");
340 #endif //USE_PAGED
341 }
342 
344 {
345  if (number > -1 && number < m_collision_boxes.size())
346  {
347  m_collision_boxes[number].enabled = false;
348  if (m_collision_boxes[number].eventsourcenum >= 0 && m_collision_boxes[number].eventsourcenum < free_eventsource)
349  {
350  eventsources[m_collision_boxes[number].eventsourcenum].es_enabled = false;
351  }
352  // Is it worth to update the hashmap? ~ ulteq 01/19
353  }
354 }
355 
357 {
358  if (number > -1 && number < m_collision_tris.size())
359  {
360  m_collision_tris[number].enabled = false;
361  // Is it worth to update the hashmap? ~ ulteq 01/19
362  }
363 }
364 
366 {
367  if (!ground_models.size() || ground_models.find(name) == ground_models.end())
368  return 0;
369 
370  return &ground_models[name];
371 }
372 
373 unsigned int Collisions::hashfunc(unsigned int cellid)
374 {
375  unsigned int hash = 0;
376  for (int i=0; i < 4; i++)
377  {
378  hash ^= sbox[((unsigned char*)&cellid)[i]];
379  hash *= 3;
380  }
381  return hash&hashmask;
382 }
383 
384 void Collisions::hash_add(int cell_x, int cell_z, int value, float h)
385 {
386  unsigned int cell_id = (cell_x << 16) + cell_z;
387  unsigned int pos = hashfunc(cell_id);
388 
389  hashtable[pos].emplace_back(cell_id, value);
390  hashtable_height[pos] = std::max(hashtable_height[pos], h);
391 }
392 
393 int Collisions::hash_find(int cell_x, int cell_z)
394 {
395  unsigned int cellid = (cell_x << 16) + cell_z;
396  unsigned int pos = hashfunc(cellid);
397 
398  return static_cast<int>(pos);
399 }
400 
401 int Collisions::addCollisionBox(bool rotating, bool virt, Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String &eventname, const Ogre::String &instancename, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc /* = Vector3::UNIT_SCALE */, Ogre::Vector3 dr /* = Vector3::ZERO */, CollisionEventFilter event_filter /* = EVENT_ALL */, int scripthandler /* = -1 */)
402 {
403  Quaternion rotation = Quaternion(Degree(rot.x), Vector3::UNIT_X) * Quaternion(Degree(rot.y), Vector3::UNIT_Y) * Quaternion(Degree(rot.z), Vector3::UNIT_Z);
404  Quaternion direction = Quaternion(Degree(dr.x), Vector3::UNIT_X) * Quaternion(Degree(dr.y), Vector3::UNIT_Y) * Quaternion(Degree(dr.z), Vector3::UNIT_Z);
405  int coll_box_index = (int)m_collision_boxes.size();
406  collision_box_t coll_box;
407 
408  coll_box.enabled = true;
409 
410  // set refined box anyway
411  coll_box.relo = l*sc;
412  coll_box.rehi = h*sc;
413 
414  // calculate selfcenter anyway
415  coll_box.selfcenter = coll_box.relo;
416  coll_box.selfcenter += coll_box.rehi;
417  coll_box.selfcenter *= 0.5;
418 
419  // and center too (we need it)
420  coll_box.center = pos;
421  coll_box.virt = virt;
422  coll_box.event_filter = event_filter;
423 
424  // camera stuff
425  coll_box.camforced = forcecam;
426  if (forcecam)
427  {
428  coll_box.campos = coll_box.center + rotation * campos;
429  }
430 
431  // first, self-rotate
432  if (rotating)
433  {
434  // we have a self-rotated block
435  coll_box.selfrotated = true;
436  coll_box.selfrot = Quaternion(Degree(sr.x), Vector3::UNIT_X) * Quaternion(Degree(sr.y), Vector3::UNIT_Y) * Quaternion(Degree(sr.z), Vector3::UNIT_Z);
437  coll_box.selfunrot = coll_box.selfrot.Inverse();
438  } else
439  {
440  coll_box.selfrotated = false;
441  }
442 
443  coll_box.eventsourcenum = -1;
444 
445  if (!eventname.empty())
446  {
447  //LOG("COLL: adding "+TOSTRING(free_eventsource)+" "+String(instancename)+" "+String(eventname));
448  // this is event-generating
452  eventsources[free_eventsource].es_cbox = coll_box_index;
455  coll_box.eventsourcenum = free_eventsource;
457  }
458 
459  // next, global rotate
460  if (fabs(rot.x) < 0.0001f && fabs(rot.y) < 0.0001f && fabs(rot.z) < 0.0001f)
461  {
462  // unrefined box
463  coll_box.refined = false;
464  } else
465  {
466  // refined box
467  coll_box.refined = true;
468  // build rotation
469  coll_box.rot = rotation;
470  coll_box.unrot = rotation.Inverse();
471  }
472 
473  // set raw box
474  // 8 points of a cube
475  if (coll_box.selfrotated || coll_box.refined)
476  {
477  coll_box.debug_verts[0] = Ogre::Vector3(l.x, l.y, l.z) * sc;
478  coll_box.debug_verts[1] = Ogre::Vector3(h.x, l.y, l.z) * sc;
479  coll_box.debug_verts[2] = Ogre::Vector3(l.x, h.y, l.z) * sc;
480  coll_box.debug_verts[3] = Ogre::Vector3(h.x, h.y, l.z) * sc;
481  coll_box.debug_verts[4] = Ogre::Vector3(l.x, l.y, h.z) * sc;
482  coll_box.debug_verts[5] = Ogre::Vector3(h.x, l.y, h.z) * sc;
483  coll_box.debug_verts[6] = Ogre::Vector3(l.x, h.y, h.z) * sc;
484  coll_box.debug_verts[7] = Ogre::Vector3(h.x, h.y, h.z) * sc;
485 
486  // rotate box
487  if (coll_box.selfrotated)
488  for (int i=0; i < 8; i++)
489  {
490  coll_box.debug_verts[i]=coll_box.debug_verts[i]-coll_box.selfcenter;
491  coll_box.debug_verts[i]=coll_box.selfrot*coll_box.debug_verts[i];
492  coll_box.debug_verts[i]=coll_box.debug_verts[i]+coll_box.selfcenter;
493  }
494  if (coll_box.refined)
495  {
496  for (int i=0; i < 8; i++)
497  {
498  coll_box.debug_verts[i] = coll_box.rot * coll_box.debug_verts[i];
499  }
500  }
501  // find min/max
502  coll_box.lo = coll_box.debug_verts[0];
503  coll_box.hi = coll_box.debug_verts[0];
504  for (int i=1; i < 8; i++)
505  {
506  coll_box.lo.makeFloor(coll_box.debug_verts[i]);
507  coll_box.hi.makeCeil(coll_box.debug_verts[i]);
508  }
509  // set absolute coords
510  coll_box.lo += pos;
511  coll_box.hi += pos;
512  } else
513  {
514  // unrefined box
515  coll_box.lo = pos + coll_box.relo;
516  coll_box.hi = pos + coll_box.rehi;
517  Vector3 d = (coll_box.rehi - coll_box.relo);
518  coll_box.debug_verts[0] = coll_box.relo;
519  coll_box.debug_verts[1] = coll_box.relo; coll_box.debug_verts[1].x += d.x;
520  coll_box.debug_verts[2] = coll_box.relo; coll_box.debug_verts[2].y += d.y;
521  coll_box.debug_verts[3] = coll_box.relo; coll_box.debug_verts[3].x += d.x; coll_box.debug_verts[3].y += d.y;
522  coll_box.debug_verts[4] = coll_box.relo; coll_box.debug_verts[4].z += d.z;
523  coll_box.debug_verts[5] = coll_box.relo; coll_box.debug_verts[5].x += d.x; coll_box.debug_verts[5].z += d.z;
524  coll_box.debug_verts[6] = coll_box.relo; coll_box.debug_verts[6].y += d.y; coll_box.debug_verts[6].z += d.z;
525  coll_box.debug_verts[7] = coll_box.relo; coll_box.debug_verts[7].x += d.x; coll_box.debug_verts[7].y += d.y; coll_box.debug_verts[7].z += d.z;
526  }
527 
528  // register this collision box in the index
529  Vector3 ilo = Ogre::Vector3(coll_box.lo / Ogre::Real(CELL_SIZE));
530  Vector3 ihi = Ogre::Vector3(coll_box.hi / Ogre::Real(CELL_SIZE));
531 
532  // clamp between 0 and MAXIMUM_CELL;
533  ilo.makeCeil(Ogre::Vector3(0.0f));
534  ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
535  ihi.makeCeil(Ogre::Vector3(0.0f));
536  ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
537 
538  for (int i = ilo.x; i <= ihi.x; i++)
539  {
540  for (int j = ilo.z; j <= ihi.z; j++)
541  {
542  hash_add(i, j, coll_box_index,coll_box.hi.y);
543  }
544  }
545 
546  m_collision_aab.merge(AxisAlignedBox(coll_box.lo, coll_box.hi));
547  m_collision_boxes.push_back(coll_box);
548  return coll_box_index;
549 }
550 
551 int Collisions::addCollisionTri(Vector3 p1, Vector3 p2, Vector3 p3, ground_model_t* gm)
552 {
553  int new_tri_index = (int)m_collision_tris.size();
554  collision_tri_t new_tri;
555  new_tri.a=p1;
556  new_tri.b=p2;
557  new_tri.c=p3;
558  new_tri.gm=gm;
559  new_tri.enabled=true;
560  // compute transformations
561  // base construction
562  Vector3 bx=p2-p1;
563  Vector3 by=p3-p1;
564  Vector3 bz=bx.crossProduct(by);
565  bz.normalise();
566  // coordinates change matrix
567  new_tri.reverse.SetColumn(0, bx);
568  new_tri.reverse.SetColumn(1, by);
569  new_tri.reverse.SetColumn(2, bz);
570  new_tri.forward=new_tri.reverse.Inverse();
571 
572  // compute tri AAB
573  new_tri.aab.merge(p1);
574  new_tri.aab.merge(p2);
575  new_tri.aab.merge(p3);
576  new_tri.aab.setMinimum(new_tri.aab.getMinimum() - 0.1f);
577  new_tri.aab.setMaximum(new_tri.aab.getMaximum() + 0.1f);
578 
579  // register this collision tri in the index
580  Ogre::Vector3 ilo(new_tri.aab.getMinimum() / Ogre::Real(CELL_SIZE));
581  Ogre::Vector3 ihi(new_tri.aab.getMaximum() / Ogre::Real(CELL_SIZE));
582 
583  // clamp between 0 and MAXIMUM_CELL;
584  ilo.makeCeil(Ogre::Vector3(0.0f));
585  ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
586  ihi.makeCeil(Ogre::Vector3(0.0f));
587  ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
588 
589  for (int i = ilo.x; i <= ihi.x; i++)
590  {
591  for (int j = ilo.z; j<=ihi.z; j++)
592  {
593  hash_add(i, j, new_tri_index + hash_coll_element_t::ELEMENT_TRI_BASE_INDEX, new_tri.aab.getMaximum().y);
594  }
595  }
596 
597  m_collision_aab.merge(new_tri.aab);
598  m_collision_tris.push_back(new_tri);
599  return new_tri_index;
600 }
601 
603 {
604 #ifdef USE_ANGELSCRIPT
605  // check if this box is active anymore
607  return;
608 
609  if (node)
610  {
611  // An actor is activating the eventbox
612  // Duplicate invocation is prevented by `Actor::m_active_eventboxes` cache.
614  }
615  else
616  {
617  // A character is activating the eventbox
618  // this prevents that the same callback gets called at 2k FPS all the time, serious hit on FPS ...
619  if (std::find(std::begin(m_last_called_cboxes), std::end(m_last_called_cboxes), cbox) == m_last_called_cboxes.end())
620  {
622  m_last_called_cboxes.push_back(cbox);
623  }
624  }
625 #endif //USE_ANGELSCRIPT
626 }
627 
628 std::pair<bool, Ogre::Real> Collisions::intersectsTris(Ogre::Ray ray)
629 {
630  int steps = ray.getDirection().length() / (float)CELL_SIZE;
631 
632  int lhash = -1;
633 
634  for (int i = 0; i <= steps; i++)
635  {
636  Vector3 pos = ray.getPoint((float)i / (float)steps);
637 
638  // find the correct cell
639  int refx = (int)(pos.x / (float)CELL_SIZE);
640  int refz = (int)(pos.z / (float)CELL_SIZE);
641  int hash = hash_find(refx, refz);
642 
643  if (hash == lhash)
644  continue;
645 
646  lhash = hash;
647 
648  size_t num_elements = hashtable[hash].size();
649  for (size_t k = 0; k < num_elements; k++)
650  {
651  if (hashtable[hash][k].IsCollisionTri())
652  {
653  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
654  collision_tri_t *ctri = &m_collision_tris[ctri_index];
655 
656  if (!ctri->enabled)
657  continue;
658 
659  auto result = Ogre::Math::intersects(ray, ctri->a, ctri->b, ctri->c);
660  if (result.first && result.second < 1.0f)
661  {
662  return result;
663  }
664  }
665  }
666  }
667 
668  return std::make_pair(false, 0.0f);
669 }
670 
671 float Collisions::getSurfaceHeight(float x, float z)
672 {
673  return getSurfaceHeightBelow(x, z, std::numeric_limits<float>::max());
674 }
675 
676 float Collisions::getSurfaceHeightBelow(float x, float z, float height)
677 {
678  float surface_height = App::GetGameContext()->GetTerrain()->GetHeightAt(x, z);
679 
680  // find the correct cell
681  int refx = (int)(x / (float)CELL_SIZE);
682  int refz = (int)(z / (float)CELL_SIZE);
683  int hash = hash_find(refx, refz);
684 
685  Vector3 origin = Vector3(x, hashtable_height[hash], z);
686  Ray ray(origin, -Vector3::UNIT_Y);
687 
688  size_t num_elements = hashtable[hash].size();
689  for (size_t k = 0; k < num_elements; k++)
690  {
691  if (hashtable[hash][k].IsCollisionBox())
692  {
693  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
694 
695  if (!cbox->enabled)
696  continue;
697 
698  if (!cbox->virt && surface_height < cbox->hi.y)
699  {
700  if (x > cbox->lo.x && z > cbox->lo.z && x < cbox->hi.x && z < cbox->hi.z)
701  {
702  Vector3 pos = origin - cbox->center;
703  Vector3 dir = -Vector3::UNIT_Y;
704  if (cbox->refined)
705  {
706  pos = cbox->unrot * pos;
707  dir = cbox->unrot * dir;
708  }
709  if (cbox->selfrotated)
710  {
711  pos = pos - cbox->selfcenter;
712  pos = cbox->selfunrot * pos;
713  pos = pos + cbox->selfcenter;
714  dir = cbox->selfunrot * dir;
715  }
716  auto result = Ogre::Math::intersects(Ray(pos, dir), AxisAlignedBox(cbox->relo, cbox->rehi));
717  if (result.first)
718  {
719  Vector3 hit = pos + dir * result.second;
720  if (cbox->selfrotated)
721  {
722  hit = cbox->selfrot * hit;
723  }
724  if (cbox->refined)
725  {
726  hit = cbox->rot * hit;
727  }
728  hit += cbox->center;
729  if (hit.y < height)
730  {
731  surface_height = std::max(surface_height, hit.y);
732  }
733  }
734  }
735  }
736  }
737  else // The element is a triangle
738  {
739  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
740  collision_tri_t *ctri = &m_collision_tris[ctri_index];
741 
742  if (!ctri->enabled)
743  continue;
744 
745  auto lo = ctri->aab.getMinimum();
746  auto hi = ctri->aab.getMaximum();
747  if (surface_height >= hi.y)
748  continue;
749  if (x < lo.x || z < lo.z || x > hi.x || z > hi.z)
750  continue;
751 
752  auto result = Ogre::Math::intersects(ray, ctri->a, ctri->b, ctri->c);
753  if (result.first)
754  {
755  if (origin.y - result.second < height)
756  {
757  surface_height = std::max(surface_height, origin.y - result.second);
758  }
759  }
760  }
761  }
762 
763  return surface_height;
764 }
765 
766 bool Collisions::collisionCorrect(Vector3 *refpos, bool envokeScriptCallbacks)
767 {
768  // find the correct cell
769  int refx = (int)(refpos->x / (float)CELL_SIZE);
770  int refz = (int)(refpos->z / (float)CELL_SIZE);
771  int hash = hash_find(refx, refz);
772 
773  if (refpos->y > hashtable_height[hash])
774  return false;
775 
776  collision_tri_t *minctri = 0;
777  float minctridist = 100.0f;
778  Vector3 minctripoint;
779 
780  bool contacted = false;
781  bool isScriptCallbackEnvoked = false;
782 
783  size_t num_elements = hashtable[hash].size();
784  for (size_t k = 0; k < num_elements; k++)
785  {
786  if (hashtable[hash][k].IsCollisionBox())
787  {
788  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
789 
790  if (!cbox->enabled)
791  continue;
792  if (!(*refpos > cbox->lo && *refpos < cbox->hi))
793  continue;
794 
795  if (cbox->refined || cbox->selfrotated)
796  {
797  // we may have a collision, do a change of repere
798  Vector3 Pos = *refpos - cbox->center;
799  if (cbox->refined)
800  {
801  Pos = cbox->unrot * Pos;
802  }
803  if (cbox->selfrotated)
804  {
805  Pos = Pos - cbox->selfcenter;
806  Pos = cbox->selfunrot * Pos;
807  Pos = Pos + cbox->selfcenter;
808  }
809  // now test with the inner box
810  if (Pos > cbox->relo && Pos < cbox->rehi)
811  {
812  if (cbox->eventsourcenum!=-1 && permitEvent(nullptr, cbox->event_filter) && envokeScriptCallbacks)
813  {
814  envokeScriptCallback(cbox);
815  isScriptCallbackEnvoked = true;
816  }
817  if (cbox->camforced && !forcecam)
818  {
819  forcecam = true;
820  forcecampos = cbox->campos;
821  }
822  if (!cbox->virt)
823  {
824  // collision, process as usual
825  // we have a collision
826  contacted = true;
827  // determine which side collided
828  Pos = calcCollidedSide(Pos, cbox->relo, cbox->rehi);
829 
830  // resume repere
831  if (cbox->selfrotated)
832  {
833  Pos = Pos - cbox->selfcenter;
834  Pos = cbox->selfrot * Pos;
835  Pos = Pos + cbox->selfcenter;
836  }
837  if (cbox->refined)
838  {
839  Pos = cbox->rot * Pos;
840  }
841  *refpos = Pos + cbox->center;
842  }
843  }
844 
845  } else
846  {
847  if (cbox->eventsourcenum!=-1 && permitEvent(nullptr, cbox->event_filter) && envokeScriptCallbacks)
848  {
849  envokeScriptCallback(cbox);
850  isScriptCallbackEnvoked = true;
851  }
852  if (cbox->camforced && !forcecam)
853  {
854  forcecam = true;
855  forcecampos = cbox->campos;
856  }
857  if (!cbox->virt)
858  {
859  // we have a collision
860  contacted = true;
861  // determine which side collided
862  (*refpos) = calcCollidedSide((*refpos), cbox->lo, cbox->hi);
863  }
864  }
865  }
866  else // The element is a triangle
867  {
868  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
869  collision_tri_t *ctri = &m_collision_tris[ctri_index];
870  if (!ctri->enabled)
871  continue;
872  if (!ctri->aab.contains(*refpos))
873  continue;
874  // check if this tri is minimal
875  // transform
876  Vector3 point = ctri->forward * (*refpos-ctri->a);
877  // test if within tri collision volume (potential cause of bug!)
878  if (point.x >= 0 && point.y >= 0 && (point.x + point.y) <= 1.0 && point.z < 0 && point.z > -0.1)
879  {
880  if (-point.z < minctridist)
881  {
882  minctri = ctri;
883  minctridist = -point.z;
884  minctripoint = point;
885  }
886  }
887  }
888  }
889 
890  if (envokeScriptCallbacks && !isScriptCallbackEnvoked)
891  clearEventCache();
892 
893  // process minctri collision
894  if (minctri)
895  {
896  // we have a contact
897  contacted = true;
898  // correct point
899  minctripoint.z = 0;
900  // reverse transform
901  *refpos = (minctri->reverse * minctripoint) + minctri->a;
902  }
903  return contacted;
904 }
905 
907 {
908  switch (filter)
909  {
910  case EVENT_ALL:
911  return true;
912  case EVENT_AVATAR:
913  return !b;
914  case EVENT_TRUCK:
915  case EVENT_TRUCK_WHEELS: // The wheelnode check must be done separately
916  return b && b->ar_driveable == TRUCK;
917  case EVENT_AIRPLANE:
918  return b && b->ar_driveable == AIRPLANE;
919  case EVENT_BOAT:
920  return b && b->ar_driveable == BOAT;
921  default:
922  return false;
923  }
924 }
925 
926 bool Collisions::nodeCollision(node_t *node, float dt)
927 {
928  // find the correct cell
929  int refx = (int)(node->AbsPosition.x / CELL_SIZE);
930  int refz = (int)(node->AbsPosition.z / CELL_SIZE);
931  int hash = hash_find(refx, refz);
932  unsigned int cell_id = (refx << 16) + refz;
933 
934  if (node->AbsPosition.y > hashtable_height[hash])
935  return false;
936 
937  collision_tri_t *minctri = 0;
938  float minctridist = 100.0;
939  Vector3 minctripoint;
940 
941  bool contacted = false;
942  bool isScriptCallbackEnvoked = false;
943 
944  size_t num_elements = hashtable[hash].size();
945  for (size_t k=0; k < num_elements; k++)
946  {
947  if (hashtable[hash][k].cell_id != cell_id)
948  {
949  continue;
950  }
951  else if (hashtable[hash][k].IsCollisionBox())
952  {
953  collision_box_t *cbox = &m_collision_boxes[hashtable[hash][k].element_index];
954 
955  if (!cbox->enabled)
956  continue;
957 
958  if (node->AbsPosition > cbox->lo && node->AbsPosition < cbox->hi)
959  {
960  if (cbox->refined || cbox->selfrotated)
961  {
962  // we may have a collision, do a change of repere
963  Vector3 Pos = node->AbsPosition-cbox->center;
964  if (cbox->refined)
965  {
966  Pos = cbox->unrot * Pos;
967  }
968  if (cbox->selfrotated)
969  {
970  Pos = Pos - cbox->selfcenter;
971  Pos = cbox->selfunrot * Pos;
972  Pos = Pos + cbox->selfcenter;
973  }
974  // now test with the inner box
975  if (Pos > cbox->relo && Pos < cbox->rehi)
976  {
977  if (cbox->camforced && !forcecam)
978  {
979  forcecam = true;
980  forcecampos = cbox->campos;
981  }
982  if (!cbox->virt)
983  {
984  // collision, process as usual
985  // we have a collision
986  contacted = true;
987  // determine which side collided
988  float t = cbox->rehi.z - Pos.z;
989  float min = Pos.z - cbox->relo.z;
990  Vector3 normal = Vector3(0, 0, -1);
991  if (t < min) { min = t; normal = Vector3(0,0,1);}; //north
992  t = Pos.x - cbox->relo.x;
993  if (t < min) { min = t; normal = Vector3(-1,0,0);}; //west
994  t = cbox->rehi.x - Pos.x;
995  if (t < min) { min = t; normal = Vector3(1,0,0);}; //east
996  t = Pos.y - cbox->relo.y;
997  if (t < min) { min = t; normal = Vector3(0,-1,0);}; //down
998  t = cbox->rehi.y - Pos.y;
999  if (t < min) { min = t; normal = Vector3(0,1,0);}; //up
1000 
1001  // resume repere for the normal
1002  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1003  if (cbox->refined) normal = cbox->rot * normal;
1004 
1005  // collision boxes are always out of concrete as it seems
1006  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1008  }
1009  }
1010  } else
1011  {
1012  if (cbox->camforced && !forcecam)
1013  {
1014  forcecam = true;
1015  forcecampos = cbox->campos;
1016  }
1017  if (!cbox->virt)
1018  {
1019  // we have a collision
1020  contacted=true;
1021  // determine which side collided
1022  float t = cbox->hi.z - node->AbsPosition.z;
1023  float min = node->AbsPosition.z - cbox->lo.z;
1024  Vector3 normal = Vector3(0, 0, -1);
1025  if (t < min) {min = t; normal = Vector3(0,0,1);}; //north
1026  t = node->AbsPosition.x - cbox->lo.x;
1027  if (t < min) {min = t; normal = Vector3(-1,0,0);}; //west
1028  t = cbox->hi.x - node->AbsPosition.x;
1029  if (t < min) {min = t; normal = Vector3(1,0,0);}; //east
1030  t = node->AbsPosition.y - cbox->lo.y;
1031  if (t < min) {min = t; normal = Vector3(0,-1,0);}; //down
1032  t = cbox->hi.y - node->AbsPosition.y;
1033  if (t < min) {min = t; normal = Vector3(0,1,0);}; //up
1034 
1035  // resume repere for the normal
1036  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1037  if (cbox->refined) normal = cbox->rot * normal;
1038 
1039  // collision boxes are always out of concrete as it seems
1040  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1042  }
1043  }
1044  }
1045  }
1046  else
1047  {
1048  // tri collision
1049  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
1050  collision_tri_t *ctri = &m_collision_tris[ctri_index];
1051  if (!ctri->enabled)
1052  continue;
1053  if (node->AbsPosition.y > ctri->aab.getMaximum().y || node->AbsPosition.y < ctri->aab.getMinimum().y ||
1054  node->AbsPosition.x > ctri->aab.getMaximum().x || node->AbsPosition.x < ctri->aab.getMinimum().x ||
1055  node->AbsPosition.z > ctri->aab.getMaximum().z || node->AbsPosition.z < ctri->aab.getMinimum().z)
1056  continue;
1057  // check if this tri is minimal
1058  // transform
1059  Vector3 point = ctri->forward * (node->AbsPosition - ctri->a);
1060  // test if within tri collision volume (potential cause of bug!)
1061  if (point.x >= 0 && point.y >= 0 && (point.x + point.y) <= 1.0 && point.z < 0 && point.z > -0.1)
1062  {
1063  if (-point.z < minctridist)
1064  {
1065  minctri = ctri;
1066  minctridist = -point.z;
1067  minctripoint = point;
1068  }
1069  }
1070  }
1071  }
1072 
1073  // process minctri collision
1074  if (minctri)
1075  {
1076  // we have a contact
1077  contacted=true;
1078  // we need the normal
1079  // resume repere for the normal
1080  Vector3 normal = minctri->reverse * Vector3::UNIT_Z;
1081  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, minctri->gm);
1082  node->nd_last_collision_gm = minctri->gm;
1083  }
1084 
1085  return contacted;
1086 }
1087 
1089 {
1090  // Find collision cells occupied by the actor (remember 'Y' is 'up').
1091  // Remember there's a dedicated bounding box `ar_evboxes_bounding_box`.
1092  // ----------------------------------------------------------------------
1093 
1094  const AxisAlignedBox aabb = actor->ar_evboxes_bounding_box;
1095  const int cell_lo_x = (int)(aabb.getMinimum().x / (float)CELL_SIZE);
1096  const int cell_lo_z = (int)(aabb.getMinimum().z / (float)CELL_SIZE);
1097  const int cell_hi_x = (int)(aabb.getMaximum().x / (float)CELL_SIZE);
1098  const int cell_hi_z = (int)(aabb.getMaximum().z / (float)CELL_SIZE);
1099 
1100  // Loop the collision cells
1101  for (int refx = cell_lo_x; refx <= cell_hi_x; refx++)
1102  {
1103  for (int refz = cell_lo_z; refz <= cell_hi_z; refz++)
1104  {
1105  // Find current cell
1106  const int hash = this->hash_find(refx, refz);
1107  const unsigned int cell_id = (refx << 16) + refz;
1108 
1109  // Find eligible event boxes in the cell
1110  for (size_t k = 0; k < hashtable[hash].size(); k++)
1111  {
1112  if (hashtable[hash][k].cell_id != cell_id)
1113  {
1114  continue;
1115  }
1116  else if (hashtable[hash][k].IsCollisionBox())
1117  {
1118  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
1119 
1120  if (!cbox->enabled)
1121  continue;
1122 
1123  if (cbox->eventsourcenum != -1 && this->permitEvent(actor, cbox->event_filter))
1124  {
1125  out_boxes.push_back(cbox);
1126  }
1127  }
1128  }
1129  }
1130  }
1131 }
1132 
1133 Vector3 Collisions::getPosition(const Ogre::String &inst, const Ogre::String &box)
1134 {
1135  for (int i=0; i<free_eventsource; i++)
1136  {
1137  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1138  {
1140  }
1141  }
1142  return Vector3::ZERO;
1143 }
1144 
1145 Quaternion Collisions::getDirection(const Ogre::String &inst, const Ogre::String &box)
1146 {
1147  for (int i=0; i<free_eventsource; i++)
1148  {
1149  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1150  {
1152  }
1153  }
1154  return Quaternion::ZERO;
1155 }
1156 
1157 collision_box_t *Collisions::getBox(const Ogre::String &inst, const Ogre::String &box)
1158 {
1159  for (int i=0; i<free_eventsource; i++)
1160  {
1161  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1162  {
1164  }
1165  }
1166  return NULL;
1167 }
1168 
1169 bool Collisions::isInside(Ogre::Vector3 pos, const Ogre::String &inst, const Ogre::String &box, float border)
1170 {
1171  collision_box_t *cbox = getBox(inst, box);
1172 
1173  return isInside(pos, cbox, border);
1174 }
1175 
1176 bool Collisions::isInside(Ogre::Vector3 pos, collision_box_t *cbox, float border)
1177 {
1178  if (!cbox) return false;
1179 
1180  if (pos + border > cbox->lo
1181  && pos - border < cbox->hi)
1182  {
1183  if (cbox->refined || cbox->selfrotated)
1184  {
1185  // we may have a collision, do a change of repere
1186  Vector3 rpos = pos - cbox->center;
1187  if (cbox->refined)
1188  {
1189  rpos = cbox->unrot * rpos;
1190  }
1191  if (cbox->selfrotated)
1192  {
1193  rpos = rpos - cbox->selfcenter;
1194  rpos = cbox->selfunrot * rpos;
1195  rpos = rpos + cbox->selfcenter;
1196  }
1197 
1198  // now test with the inner box
1199  if (rpos > cbox->relo
1200  && rpos < cbox->rehi)
1201  {
1202  return true;
1203  }
1204  } else
1205  {
1206  return true;
1207  }
1208  }
1209  return false;
1210 }
1211 
1213 {
1214  Real v = App::GetGameContext()->GetTerrain()->GetHeightAt(node->AbsPosition.x, node->AbsPosition.z);
1215  if (v > node->AbsPosition.y)
1216  {
1217  ground_model_t* ogm = landuse ? landuse->getGroundModelAt(node->AbsPosition.x, node->AbsPosition.z) : nullptr;
1218  // when landuse fails or we don't have it, use the default value
1219  if (!ogm) ogm = defaultgroundgm;
1220  Ogre::Vector3 normal = App::GetGameContext()->GetTerrain()->GetNormalAt(node->AbsPosition.x, v, node->AbsPosition.z);
1221  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, ogm, v - node->AbsPosition.y);
1222  node->nd_last_collision_gm = ogm;
1223  return true;
1224  }
1225  return false;
1226 }
1227 
1228 Vector3 RoR::primitiveCollision(node_t *node, Ogre::Vector3 velocity, float mass, Ogre::Vector3 normal, float dt, ground_model_t* gm, float penetration)
1229 {
1230  Vector3 force = Vector3::ZERO;
1231  float Vnormal = velocity.dotProduct(normal);
1232  float Fnormal = node->Forces.dotProduct(normal);
1233 
1234  // if we are inside the fluid (solid ground is below us)
1235  if (gm->solid_ground_level != 0.0f && penetration >= 0)
1236  {
1237  float Vsquared = velocity.squaredLength();
1238  // First of all calculate power law fluid viscosity
1239  float m = gm->flow_consistency_index * approx_pow(Vsquared, (gm->flow_behavior_index - 1.0f) * 0.5f);
1240 
1241  // Then calculate drag based on above. We'are using a simplified Stokes' drag.
1242  // Per node fluid drag surface coefficient set by node property applies here
1243  Vector3 Fdrag = velocity * (-m * node->surface_coef);
1244 
1245  // If we have anisotropic drag
1246  if (gm->drag_anisotropy < 1.0f && Vnormal > 0)
1247  {
1248  float da_factor;
1249  if (Vsquared > gm->va * gm->va)
1250  da_factor = 1.0;
1251  else
1252  da_factor = Vsquared / (gm->va * gm->va);
1253  Fdrag += (Vnormal * m * (1.0f - gm->drag_anisotropy) * da_factor) * normal;
1254  }
1255  force += Fdrag;
1256 
1257  // Now calculate upwards force based on a simplified boyancy equation;
1258  // If the fluid is pseudoplastic then boyancy is constrained to only "stopping" a node from going downwards
1259  // Buoyancy per node volume coefficient set by node property applies here
1260  float Fboyancy = gm->fluid_density * penetration * (-DEFAULT_GRAVITY) * node->volume_coef;
1261  if (gm->flow_behavior_index < 1.0f && Vnormal >= 0.0f)
1262  {
1263  if (Fnormal < 0 && Fboyancy>-Fnormal)
1264  {
1265  Fboyancy = -Fnormal;
1266  }
1267  }
1268  force += Fboyancy * normal;
1269  }
1270 
1271  // if we are inside or touching the solid ground
1272  if (penetration >= gm->solid_ground_level)
1273  {
1274  // steady force
1275  float Freaction = -Fnormal;
1276  // impact force
1277  if (Vnormal < 0)
1278  {
1279  float penetration_depth = gm->solid_ground_level - penetration;
1280  Freaction -= (0.8f * Vnormal + 0.2f * penetration_depth / dt) * mass / dt; // Newton's second law
1281  }
1282  if (Freaction > 0)
1283  {
1284  Vector3 slipf = node->Forces - Fnormal * normal;
1285  Vector3 slip = velocity - Vnormal * normal;
1286  float slipv = slip.normalise();
1287  // If the velocity that we slip is lower than adhesion velocity and
1288  // we have a downforce and the slip forces are lower than static friction
1289  // forces then it's time to go into static friction physics mode.
1290  // This code is a direct translation of textbook static friction physics
1291  float Greaction = Freaction * gm->strength * node->friction_coef; //General moderated reaction
1292  float msGreaction = gm->ms * Greaction;
1293  if (slipv < gm->va && Greaction > 0.0f && slipf.squaredLength() <= msGreaction * msGreaction)
1294  {
1295  // Static friction model (with a little smoothing to help the integrator deal with it)
1296  float ff = -msGreaction * (1.0f - approx_exp(-slipv / gm->va));
1297  force += Freaction * normal + ff * slip - slipf;
1298  } else
1299  {
1300  // Stribek model. It also comes directly from textbooks.
1301  float g = gm->mc + (gm->ms - gm->mc) * approx_exp(-approx_pow(slipv / gm->vs, gm->alpha));
1302  float ff = -(g + std::min(gm->t2 * slipv, 5.0f)) * Greaction;
1303  force += Freaction * normal + ff * slip;
1304  }
1305  node->nd_avg_collision_slip = node->nd_avg_collision_slip * 0.995 + slipv * 0.005f;
1306  node->nd_last_collision_slip = slipv * slip;
1307  node->nd_last_collision_force = std::min(-Freaction, 0.0f) * normal;
1308  }
1309  }
1310 
1311  return force;
1312 }
1313 
1314 void Collisions::createCollisionDebugVisualization(Ogre::SceneNode* root_node, Ogre::AxisAlignedBox const& area_limit, std::vector<Ogre::SceneNode*>& out_nodes)
1315 {
1316  LOG("COLL: Creating collision debug visualization ...");
1317 
1318 
1319 
1320  for (int x=0; x<(int)(m_terrain_size.x); x+=(int)CELL_SIZE)
1321  {
1322  for (int z=0; z<(int)(m_terrain_size.z); z+=(int)CELL_SIZE)
1323  {
1324 
1325  if (!area_limit.contains(Ogre::Vector3(x, 0.f, z)))
1326  continue;
1327 
1328  int cellx = (int)(x/(float)CELL_SIZE);
1329  int cellz = (int)(z/(float)CELL_SIZE);
1330  const int hash = hash_find(cellx, cellz);
1331 
1332  bool used = std::find_if(hashtable[hash].begin(), hashtable[hash].end(), [&](hash_coll_element_t const &c) {
1333  return c.cell_id == (cellx << 16) + cellz;
1334  }) != hashtable[hash].end();
1335 
1336  if (used)
1337  {
1338  float groundheight = -9999;
1339  float x2 = x+CELL_SIZE;
1340  float z2 = z+CELL_SIZE;
1341 
1342  // find a good ground height for all corners of the cell ...
1343  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x, z));
1344  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x2, z));
1345  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x, z2));
1346  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x2, z2));
1347  groundheight += 0.1; // 10 cm hover
1348 
1349  float percentd = static_cast<float>(hashtable[hash].size()) / static_cast<float>(CELL_BLOCKSIZE);
1350  if (percentd > 1) percentd = 1;
1351 
1352  // see `RoR::GUI::CollisionsDebug::GenerateCellDebugMaterials()`
1353  String matName = "mat-coll-dbg-"+TOSTRING((int)(percentd*100));
1354  String cell_name="("+TOSTRING(cellx)+","+ TOSTRING(cellz)+")";
1355 
1356  ManualObject *mo = App::GetGfxScene()->GetSceneManager()->createManualObject("collisionDebugVisualization"+cell_name);
1357  SceneNode *mo_node = root_node->createChildSceneNode("collisionDebugVisualization_node"+cell_name);
1358 
1359  mo->begin(matName, Ogre::RenderOperation::OT_TRIANGLE_LIST);
1360 
1361  // 1st tri
1362  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1363  mo->textureCoord(0,0);
1364 
1365  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1366  mo->textureCoord(1,1);
1367 
1368  mo->position(CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1369  mo->textureCoord(1,0);
1370 
1371  // 2nd tri
1372  mo->position(-CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1373  mo->textureCoord(0,1);
1374 
1375  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1376  mo->textureCoord(1,1);
1377 
1378  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1379  mo->textureCoord(0,0);
1380 
1381  mo->end();
1382  mo->setBoundingBox(AxisAlignedBox(0, 0, 0, CELL_SIZE, 1, CELL_SIZE));
1383  mo->setRenderingDistance(200.f);
1384  mo_node->attachObject(mo);
1385 
1386 #if 0
1387  // setup the label
1388  String labelName = "label_"+cell_name;
1389  String labelCaption = cell_name+" "+TOSTRING(percent*100,2) + "% usage ("+TOSTRING(cc)+"/"+TOSTRING(CELL_BLOCKSIZE)+") DEEP: " + TOSTRING(deep);
1390  MovableText *mt = new MovableText(labelName, labelCaption);
1392  mt->setFontName("CyberbitEnglish");
1393  mt->setAdditionalHeight(1);
1394  mt->setCharacterHeight(0.3);
1395  mt->setColor(ColourValue::White);
1396  mo_node->attachObject(mt);
1397 #endif
1398 
1399  mo_node->setVisible(true);
1400  mo_node->setPosition(Vector3(x+CELL_SIZE/(float)2.0, groundheight, z+CELL_SIZE/(float)2.0));
1401 
1402  out_nodes.push_back(mo_node);
1403  }
1404  }
1405  }
1406 }
1407 
1408 void Collisions::addCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, Ogre::Quaternion const& q, Ogre::Vector3 const& scale, ground_model_t *gm, std::vector<int> *collTris)
1409 {
1410  Entity *ent = App::GetGfxScene()->GetSceneManager()->createEntity(meshname);
1411  ent->setMaterialName("tracks/debug/collision/mesh");
1412 
1413  if (!gm)
1414  {
1415  gm = getGroundModelByString("concrete");
1416  }
1417 
1418  // Analyze the mesh
1419  size_t vertex_count,index_count;
1420  Vector3* vertices;
1421  unsigned* indices;
1422 
1423  getMeshInformation(ent->getMesh().getPointer(),vertex_count,vertices,index_count,indices, pos, q, scale);
1424 
1425  // Generate collision triangles
1426  int collision_tri_start = (int)m_collision_tris.size();
1427  for (int i=0; i<(int)index_count/3; i++)
1428  {
1429  int triID = addCollisionTri(vertices[indices[i*3]], vertices[indices[i*3+1]], vertices[indices[i*3+2]], gm);
1430  if (collTris)
1431  collTris->push_back(triID);
1432  }
1433 
1434  // Submit the mesh record
1435  collision_mesh_t rec;
1436  rec.mesh_name = meshname;
1437  rec.source_name = srcname;
1438  rec.position = pos;
1439  rec.orientation = q;
1440  rec.scale = scale;
1441  rec.ground_model = gm;
1442  rec.num_verts = vertex_count;
1443  rec.num_indices = index_count;
1444  rec.collision_tri_start = collision_tri_start;
1445  rec.collision_tri_count = (int)m_collision_tris.size() - collision_tri_start;
1446  rec.bounding_box = ent->getMesh()->getBounds();
1447  m_collision_meshes.push_back(rec);
1448 
1449  // Clean up
1450  delete[] vertices;
1451  delete[] indices;
1452  App::GetGfxScene()->GetSceneManager()->destroyEntity(ent);
1453 }
1454 
1455 void Collisions::registerCollisionMesh(Ogre::String const& srcname, Ogre::String const& meshname, Ogre::Vector3 const& pos, AxisAlignedBox bounding_box, ground_model_t* gm, int ctri_start, int ctri_count)
1456 {
1457  // Submit the mesh record
1458  collision_mesh_t rec;
1459  rec.mesh_name = meshname;
1460  rec.source_name = srcname;
1461  rec.position = pos;
1462  rec.ground_model = gm;
1463  rec.collision_tri_start = ctri_start;
1464  rec.collision_tri_count = ctri_count;
1465  rec.bounding_box = bounding_box;
1466  m_collision_meshes.push_back(rec);
1467 }
1468 
1469 void Collisions::getMeshInformation(Mesh* mesh,size_t &vertex_count,Ogre::Vector3* &vertices,
1470  size_t &index_count, unsigned* &indices, const Ogre::Vector3 &position,
1471  const Ogre::Quaternion &orient, const Ogre::Vector3 &scale)
1472 {
1473  vertex_count = index_count = 0;
1474 
1475  bool added_shared = false;
1476  size_t current_offset = vertex_count;
1477  size_t shared_offset = vertex_count;
1478  size_t next_offset = vertex_count;
1479  size_t index_offset = index_count;
1480  //size_t prev_vert = vertex_count;
1481  //size_t prev_ind = index_count;
1482 
1483  // Calculate how many vertices and indices we're going to need
1484  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1485  {
1486  SubMesh* submesh = mesh->getSubMesh(i);
1487 
1488  // We only need to add the shared vertices once
1489  if (submesh->useSharedVertices)
1490  {
1491  if (!added_shared)
1492  {
1493  VertexData* vertex_data = mesh->sharedVertexData;
1494  vertex_count += vertex_data->vertexCount;
1495  added_shared = true;
1496  }
1497  } else
1498  {
1499  VertexData* vertex_data = submesh->vertexData;
1500  vertex_count += vertex_data->vertexCount;
1501  }
1502 
1503  // Add the indices
1504  Ogre::IndexData* index_data = submesh->indexData;
1505  index_count += index_data->indexCount;
1506  }
1507 
1508  // Allocate space for the vertices and indices
1509  vertices = new Vector3[vertex_count];
1510  indices = new unsigned[index_count];
1511 
1512  added_shared = false;
1513 
1514  // Run through the sub-meshes again, adding the data into the arrays
1515  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1516  {
1517  SubMesh* submesh = mesh->getSubMesh(i);
1518 
1519  Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
1520  if ((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
1521  {
1522  if (submesh->useSharedVertices)
1523  {
1524  added_shared = true;
1525  shared_offset = current_offset;
1526  }
1527 
1528  const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
1529  Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
1530  unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1531  Ogre::Real* pReal;
1532 
1533  for (size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
1534  {
1535  posElem->baseVertexPointerToElement(vertex, &pReal);
1536 
1537  Vector3 pt;
1538 
1539  pt.x = (*pReal++);
1540  pt.y = (*pReal++);
1541  pt.z = (*pReal++);
1542 
1543  pt = (orient * (pt * scale)) + position;
1544 
1545  vertices[current_offset + j].x = pt.x;
1546  vertices[current_offset + j].y = pt.y;
1547  vertices[current_offset + j].z = pt.z;
1548  }
1549  vbuf->unlock();
1550  next_offset += vertex_data->vertexCount;
1551  }
1552 
1553  Ogre::IndexData* index_data = submesh->indexData;
1554 
1555  size_t numTris = index_data->indexCount / 3;
1556  unsigned short* pShort = 0;
1557  unsigned int* pInt = 0;
1558  Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
1559 
1560  bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
1561 
1562  if (use32bitindexes)
1563  pInt = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1564  else
1565  pShort = static_cast<unsigned short*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1566 
1567  for (size_t k = 0; k < numTris; ++k)
1568  {
1569  size_t offset = (submesh->useSharedVertices)?shared_offset:current_offset;
1570 
1571  unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
1572  indices[index_offset + 0] = vindex + (unsigned int)offset;
1573  vindex = use32bitindexes? *pInt++ : *pShort++;
1574  indices[index_offset + 1] = vindex + (unsigned int)offset;
1575  vindex = use32bitindexes? *pInt++ : *pShort++;
1576  indices[index_offset + 2] = vindex + (unsigned int)offset;
1577 
1578  index_offset += 3;
1579  }
1580  ibuf->unlock();
1581  current_offset = next_offset;
1582  }
1583 }
1584 
1586 {
1587 }
RoR::MovableText::setTextAlignment
void setTextAlignment(const HorizontalAlignment &horizontalAlignment, const VerticalAlignment &verticalAlignment)
Definition: MovableText.cpp:144
RoR::Collisions::m_terrain_size
const Ogre::Vector3 m_terrain_size
Definition: Collisions.h:158
GameContext.h
Game state manager and message-queue provider.
RoR::MovableText::setColor
void setColor(const Ogre::ColourValue &color)
Definition: MovableText.cpp:117
RoR::Collisions::FX_PARTICLE
@ FX_PARTICLE
Definition: Collisions.h:92
RoR::ground_model_t::solid_ground_level
float solid_ground_level
how deep the solid ground is
Definition: SimData.h:758
RoR::Collisions::parseGroundConfig
void parseGroundConfig(Ogre::ConfigFile *cfg, Ogre::String groundModel="")
Definition: Collisions.cpp:206
RoR::Collisions::landuse
Landusemap * landuse
Definition: Collisions.h:154
RoR::Actor
Softbody object; can be anything from soda can to a space shuttle Constructed from a truck definition...
Definition: Actor.h:49
RoR::primitiveCollision
Ogre::Vector3 primitiveCollision(node_t *node, Ogre::Vector3 velocity, float mass, Ogre::Vector3 normal, float dt, ground_model_t *gm, float penetration=0)
Definition: Collisions.cpp:1228
RoR::Collisions::hash_coll_element_t
Definition: Collisions.h:104
RoR::collision_tri_t::enabled
bool enabled
Definition: Collisions.h:59
RoR::node_t::Velocity
Ogre::Vector3 Velocity
Definition: SimData.h:295
RoR::ground_model_t::strength
float strength
ground strength
Definition: SimData.h:747
RoR::Collisions::FX_CLUMPY
@ FX_CLUMPY
Definition: Collisions.h:91
RoR::Collisions::MAXIMUM_CELL
static const int MAXIMUM_CELL
Definition: Collisions.h:129
RoR::MovableText::H_CENTER
@ H_CENTER
Definition: MovableText.h:43
RoR::TRUCK
@ TRUCK
its a truck (or other land vehicle)
Definition: SimData.h:93
RoR::node_t::nd_avg_collision_slip
Ogre::Real nd_avg_collision_slip
Physics state; average slip velocity across the last few physics frames.
Definition: SimData.h:323
RoR::node_t::nd_last_collision_gm
ground_model_t * nd_last_collision_gm
Physics state; last collision 'ground model' (surface definition)
Definition: SimData.h:326
RoR::ground_model_t::va
float va
adhesion velocity
Definition: SimData.h:741
RoR::collision_tri_t::reverse
Ogre::Matrix3 reverse
Definition: Collisions.h:57
RoR::EVENT_AIRPLANE
@ EVENT_AIRPLANE
'airplane' ~ Triggered by any node of airplane (ActorType::AIRPLANE)
Definition: SimData.h:53
RoR::node_t::AbsPosition
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition: SimData.h:294
RoR::collision_tri_t
Definition: Collisions.h:50
RoR::EVENT_TRUCK_WHEELS
@ EVENT_TRUCK_WHEELS
'truck_wheels' ~ Triggered only by wheel nodes of land vehicle (ActorType::TRUCK)
Definition: SimData.h:52
RoR::Collisions::addCollisionBox
int addCollisionBox(bool rotating, bool virt, Ogre::Vector3 pos, Ogre::Vector3 rot, Ogre::Vector3 l, Ogre::Vector3 h, Ogre::Vector3 sr, const Ogre::String &eventname, const Ogre::String &instancename, bool forcecam, Ogre::Vector3 campos, Ogre::Vector3 sc=Ogre::Vector3::UNIT_SCALE, Ogre::Vector3 dr=Ogre::Vector3::ZERO, CollisionEventFilter event_filter=EVENT_ALL, int scripthandler=-1)
Definition: Collisions.cpp:401
RoR::collision_box_t::virt
bool virt
Definition: SimData.h:716
RoR::collision_box_t::enabled
bool enabled
Definition: SimData.h:720
RoR::eventsource_t::es_instance_name
std::string es_instance_name
Specified by user when calling "GameScript::spawnObject()".
Definition: Collisions.h:42
z
float z
Definition: (ValueTypes) quaternion.h:7
RoR::collision_mesh_t
Records which collision triangles belong to which mesh.
Definition: Collisions.h:64
RoR::Collisions::getSurfaceHeightBelow
float getSurfaceHeightBelow(float x, float z, float height)
Definition: Collisions.cpp:676
RoR::CollisionEventFilter
CollisionEventFilter
Specified in terrain object (.ODEF) file, syntax: 'event <type> <filter>'.
Definition: SimData.h:46
RoR::node_t::surface_coef
Ogre::Real surface_coef
Definition: SimData.h:301
RoR::Collisions::defaultgm
ground_model_t * defaultgm
Definition: Collisions.h:174
RoR::Collisions::free_eventsource
int free_eventsource
Definition: Collisions.h:150
RoR::collision_box_t::lo
Ogre::Vector3 lo
absolute collision box
Definition: SimData.h:723
RoR::Collisions::groundCollision
bool groundCollision(node_t *node, float dt)
Definition: Collisions.cpp:1212
RoR::Collisions::clearEventCache
void clearEventCache()
Definition: Collisions.h:201
RoR::Collisions::findPotentialEventBoxes
void findPotentialEventBoxes(Actor *actor, CollisionBoxPtrVec &out_boxes)
Definition: Collisions.cpp:1088
sbox
unsigned int sbox[]
Definition: Collisions.cpp:47
RoR::Collisions::HASH_POWER
static const int HASH_POWER
Definition: Collisions.h:124
RoR::Collisions::collision_version
int collision_version
Definition: Collisions.h:155
RoR::collision_mesh_t::bounding_box
Ogre::AxisAlignedBox bounding_box
Definition: Collisions.h:71
RoR::collision_box_t::eventsourcenum
short eventsourcenum
Definition: SimData.h:722
RoR::collision_box_t::hi
Ogre::Vector3 hi
absolute collision box
Definition: SimData.h:724
RoR::Collisions::getPosition
Ogre::Vector3 getPosition(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1133
RoR::MovableText::setFontName
void setFontName(const Ogre::UTFString &fontName)
Definition: MovableText.cpp:73
RoR::Collisions::CELL_BLOCKSIZE
static const int CELL_BLOCKSIZE
Definition: Collisions.h:170
RoR::EVENT_BOAT
@ EVENT_BOAT
'boat' ~ Triggered by any node of boats (ActorType::BOAT)
Definition: SimData.h:54
RoR::CollisionBoxPtrVec
std::vector< collision_box_t * > CollisionBoxPtrVec
Definition: SimData.h:736
RoR::collision_mesh_t::scale
Ogre::Vector3 scale
Definition: Collisions.h:70
RoR::Collisions::FX_DUSTY
@ FX_DUSTY
Definition: Collisions.h:90
RoR::EVENT_AVATAR
@ EVENT_AVATAR
'avatar' ~ Triggered by the character only
Definition: SimData.h:50
MovableText.h
This creates a billboarding object that displays a text.
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:1455
RoR::Collisions::addCollisionMesh
void addCollisionMesh(Ogre::String const &srcname, Ogre::String const &meshname, Ogre::Vector3 const &pos, Ogre::Quaternion const &q, Ogre::Vector3 const &scale, ground_model_t *gm=0, std::vector< int > *collTris=0)
generate collision tris from existing mesh resource
Definition: Collisions.cpp:1408
RoR::collision_tri_t::gm
ground_model_t * gm
Definition: Collisions.h:58
RoR::Collisions::collisionCorrect
bool collisionCorrect(Ogre::Vector3 *refpos, bool envokeScriptCallbacks=true)
Definition: Collisions.cpp:766
approx_exp
float approx_exp(const float x)
Definition: ApproxMath.h:68
RoR::ground_model_t::alpha
float alpha
steady-steady
Definition: SimData.h:746
RoR::collision_box_t::selfrotated
bool selfrotated
Definition: SimData.h:718
RoR::Collisions::hashtable_height
std::array< float, HASH_SIZE > hashtable_height
Definition: Collisions.h:142
Language.h
RoR::collision_box_t
Definition: SimData.h:714
RoR::collision_box_t::unrot
Ogre::Quaternion unrot
rotation
Definition: SimData.h:727
RoR::Collisions::calcCollidedSide
Ogre::Vector3 calcCollidedSide(const Ogre::Vector3 &pos, const Ogre::Vector3 &lo, const Ogre::Vector3 &hi)
Definition: Collisions.cpp:295
RoR::EVENT_TRUCK
@ EVENT_TRUCK
'truck' ~ Triggered by any node of land vehicle (ActorType::TRUCK)
Definition: SimData.h:51
RoR::Collisions::removeCollisionTri
void removeCollisionTri(int number)
Definition: Collisions.cpp:356
RoR::ground_model_t::mc
float mc
sliding friction coefficient
Definition: SimData.h:743
ActorManager.h
Actor.h
RoR::collision_box_t::center
Ogre::Vector3 center
center of rotation
Definition: SimData.h:725
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:279
RoR::Landusemap::getGroundModelAt
ground_model_t * getGroundModelAt(int x, int z)
Definition: Landusemap.cpp:57
RoR::GfxScene::GetSceneManager
Ogre::SceneManager * GetSceneManager()
Definition: GfxScene.h:64
RoR::ground_model_t::vs
float vs
stribeck velocity (m/s)
Definition: SimData.h:745
RoR::Collisions::hash_find
int hash_find(int cell_x, int cell_z)
Definition: Collisions.cpp:393
RoR::Collisions::loadDefaultModels
int loadDefaultModels()
Definition: Collisions.cpp:145
RoR::Terrain::GetHeightAt
float GetHeightAt(float x, float z)
Definition: Terrain.cpp:503
RoR::collision_tri_t::a
Ogre::Vector3 a
Definition: Collisions.h:52
RoR::Terrain::GetNormalAt
Ogre::Vector3 GetNormalAt(float x, float y, float z)
Definition: Terrain.cpp:508
RoR::Collisions::loadGroundModelsConfigFile
int loadGroundModelsConfigFile(Ogre::String filename)
Definition: Collisions.cpp:150
RoR::collision_box_t::event_filter
CollisionEventFilter event_filter
Definition: SimData.h:721
RoR::collision_mesh_t::collision_tri_count
int collision_tri_count
Definition: Collisions.h:74
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::collision_box_t::rehi
Ogre::Vector3 rehi
relative collision box
Definition: SimData.h:732
RoR::Collisions::intersectsTris
std::pair< bool, Ogre::Real > intersectsTris(Ogre::Ray ray)
Definition: Collisions.cpp:628
RoR::collision_tri_t::forward
Ogre::Matrix3 forward
Definition: Collisions.h:56
RoR::collision_mesh_t::collision_tri_start
int collision_tri_start
Definition: Collisions.h:73
RoR::MovableText
Definition: MovableText.h:39
RoR::collision_mesh_t::num_indices
int num_indices
Definition: Collisions.h:76
RoR::Collisions::removeCollisionBox
void removeCollisionBox(int number)
Definition: Collisions.cpp:343
RoR::Collisions::getGroundModelByString
ground_model_t * getGroundModelByString(const Ogre::String name)
Definition: Collisions.cpp:365
RoR::eventsource_t::es_box_name
std::string es_box_name
Specified in ODEF file as "event".
Definition: Collisions.h:43
approx_pow
float approx_pow(const float x, const float y)
Definition: ApproxMath.h:91
RoR::PathCombine
std::string PathCombine(std::string a, std::string b)
Definition: PlatformUtils.h:48
RoR::collision_box_t::selfcenter
Ogre::Vector3 selfcenter
center of self rotation
Definition: SimData.h:728
RoR::Collisions::getBox
collision_box_t * getBox(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1157
RoR::Collisions::envokeScriptCallback
void envokeScriptCallback(collision_box_t *cbox, node_t *node=0)
Definition: Collisions.cpp:602
RoR::collision_box_t::relo
Ogre::Vector3 relo
relative collision box
Definition: SimData.h:731
ErrorUtils.h
RoR::Collisions::forcecampos
Ogre::Vector3 forcecampos
Definition: Collisions.h:173
ScriptEngine.h
RoR::Collisions::hashmask
unsigned int hashmask
Definition: Collisions.h:156
RoR::collision_mesh_t::ground_model
ground_model_t * ground_model
Definition: Collisions.h:72
RoR::eventsource_t::es_cbox
int es_cbox
Collision box ID.
Definition: Collisions.h:46
RoR::ScriptEngine::envokeCallback
void envokeCallback(int functionId, eventsource_t *source, NodeNum_t nodenum=NODENUM_INVALID, int type=0)
Definition: ScriptEngine.cpp:443
RoR::node_t::pos
NodeNum_t pos
This node's index in Actor::ar_nodes array.
Definition: SimData.h:304
GfxScene.h
PlatformUtils.h
Platform-specific utilities. We use narrow UTF-8 encoded strings as paths. Inspired by http://utf8eve...
RoR::Collisions::ground_models
std::map< Ogre::String, ground_model_t > ground_models
Definition: Collisions.h:146
RoR::collision_box_t::refined
bool refined
Definition: SimData.h:717
RoR::Collisions::addCollisionTri
int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t *gm)
Definition: Collisions.cpp:551
RoR::Collisions::hashtable
std::vector< hash_coll_element_t > hashtable[HASH_SIZE]
Definition: Collisions.h:143
RoR::collision_tri_t::aab
Ogre::AxisAlignedBox aab
Definition: Collisions.h:55
Application.h
Central state/object manager and communications hub.
RoR::node_t::nd_last_collision_force
Ogre::Vector3 nd_last_collision_force
Physics state; last collision force.
Definition: SimData.h:325
RoR::node_t
Physics: A vertex in the softbody structure.
Definition: SimData.h:286
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::collision_box_t::camforced
bool camforced
Definition: SimData.h:719
RoR::ground_model_t::name
char name[256]
Definition: SimData.h:763
RoR::node_t::friction_coef
Ogre::Real friction_coef
Definition: SimData.h:300
RoR::AIRPLANE
@ AIRPLANE
its an airplane
Definition: SimData.h:94
RoR::Collisions::m_collision_tris
CollisionTriVec m_collision_tris
Definition: Collisions.h:136
RoR::collision_box_t::campos
Ogre::Vector3 campos
camera position
Definition: SimData.h:733
RoR::eventsource_t::es_script_handler
int es_script_handler
AngelScript function ID.
Definition: Collisions.h:45
RoR::Collisions::getSurfaceHeight
float getSurfaceHeight(float x, float z)
Definition: Collisions.cpp:671
RoR::ground_model_t::t2
float t2
hydrodynamic friction (s/m)
Definition: SimData.h:744
RoR::node_t::nd_last_collision_slip
Ogre::Vector3 nd_last_collision_slip
Physics state; last collision slip vector.
Definition: SimData.h:324
ApproxMath.h
RoR::ground_model_t::ms
float ms
static friction coefficient
Definition: SimData.h:742
RoR::App::sys_config_dir
CVar * sys_config_dir
Definition: Application.cpp:164
RoR::collision_box_t::selfrot
Ogre::Quaternion selfrot
self rotation
Definition: SimData.h:729
RoR::Collisions::Collisions
Collisions(Ogre::Vector3 terrn_size)
Definition: Collisions.cpp:118
RoR::Collisions::forcecam
bool forcecam
Definition: Collisions.h:172
RoR::Collisions::FX_HARD
@ FX_HARD
Definition: Collisions.h:89
RoR::Collisions::nodeCollision
bool nodeCollision(node_t *node, float dt)
Definition: Collisions.cpp:926
RoR::node_t::volume_coef
Ogre::Real volume_coef
Definition: SimData.h:302
RoR::Collisions::getMeshInformation
void getMeshInformation(Ogre::Mesh *mesh, size_t &vertex_count, Ogre::Vector3 *&vertices, size_t &index_count, unsigned *&indices, const Ogre::Vector3 &position=Ogre::Vector3::ZERO, const Ogre::Quaternion &orient=Ogre::Quaternion::IDENTITY, const Ogre::Vector3 &scale=Ogre::Vector3::UNIT_SCALE)
Definition: Collisions.cpp:1469
RoR::Collisions::m_collision_meshes
CollisionMeshVec m_collision_meshes
Definition: Collisions.h:137
RoR::Collisions::createCollisionDebugVisualization
void createCollisionDebugVisualization(Ogre::SceneNode *root_node, Ogre::AxisAlignedBox const &area_limit, std::vector< Ogre::SceneNode * > &out_nodes)
Definition: Collisions.cpp:1314
RoR::ground_model_t::flow_behavior_index
float flow_behavior_index
if flow_behavior_index<1 then liquid is Pseudoplastic (ketchup, whipped cream, paint) if =1 then liqu...
Definition: SimData.h:755
RoR::Collisions::LATEST_GROUND_MODEL_VERSION
static const int LATEST_GROUND_MODEL_VERSION
Definition: Collisions.h:120
RoR::MovableText::setCharacterHeight
void setCharacterHeight(Ogre::Real height)
Definition: MovableText.cpp:126
RoR::Actor::ar_driveable
ActorType ar_driveable
Sim attr; marks vehicle type and features.
Definition: Actor.h:372
RoR::collision_mesh_t::num_verts
int num_verts
Definition: Collisions.h:75
_L
#define _L
Definition: ErrorUtils.cpp:34
RoR::Collisions::defaultgroundgm
ground_model_t * defaultgroundgm
Definition: Collisions.h:174
RoR::Collisions::hash_coll_element_t::ELEMENT_TRI_BASE_INDEX
static const int ELEMENT_TRI_BASE_INDEX
Definition: Collisions.h:106
RoR::collision_box_t::rot
Ogre::Quaternion rot
rotation
Definition: SimData.h:726
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
RoR::ground_model_t::fluid_density
float fluid_density
Density of liquid.
Definition: SimData.h:749
RoR::collision_box_t::selfunrot
Ogre::Quaternion selfunrot
self rotation
Definition: SimData.h:730
RoR::Collisions::permitEvent
bool permitEvent(Actor *actor, CollisionEventFilter filter)
Definition: Collisions.cpp:906
RoR::Collisions::getDirection
Ogre::Quaternion getDirection(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1145
RoR::ground_model_t
Surface friction properties.
Definition: SimData.h:739
RoR::ground_model_t::drag_anisotropy
float drag_anisotropy
Upwards/Downwards drag anisotropy.
Definition: SimData.h:759
RoR::Collisions::m_last_called_cboxes
std::vector< collision_box_t * > m_last_called_cboxes
Definition: Collisions.h:133
RoR::Collisions::setupLandUse
void setupLandUse(const char *configfile)
Definition: Collisions.cpp:333
Terrain.h
RoR::MovableText::setAdditionalHeight
void setAdditionalHeight(Ogre::Real height)
Definition: MovableText.cpp:158
RoR::Collisions::isInside
bool isInside(Ogre::Vector3 pos, const Ogre::String &inst, const Ogre::String &box, float border=0)
Definition: Collisions.cpp:1169
RoR::EVENT_ALL
@ EVENT_ALL
(default) ~ Triggered by any node on any vehicle
Definition: SimData.h:49
RoR::collision_tri_t::b
Ogre::Vector3 b
Definition: Collisions.h:53
RoR::collision_box_t::debug_verts
Ogre::Vector3 debug_verts[8]
box corners in absolute world position
Definition: SimData.h:734
Ogre
Definition: ExtinguishableFireAffector.cpp:35
DEFAULT_GRAVITY
static const float DEFAULT_GRAVITY
earth gravity
Definition: SimConstants.h:50
RoR::Collisions::hash_add
void hash_add(int cell_x, int cell_z, int value, float h)
Definition: Collisions.cpp:384
RoR::ground_model_t::flow_consistency_index
float flow_consistency_index
general drag coefficient
Definition: SimData.h:750
Landusemap.h
RoR::Collisions::m_collision_aab
Ogre::AxisAlignedBox m_collision_aab
Definition: Collisions.h:139
RoR::eventsource_t::es_direction
Ogre::Quaternion es_direction
Definition: Collisions.h:44
RoR::collision_mesh_t::orientation
Ogre::Quaternion orientation
Definition: Collisions.h:69
Collisions.h
RoR::Collisions::finishLoadingTerrain
void finishLoadingTerrain()
Definition: Collisions.cpp:1585
RoR::Collisions::hashfunc
unsigned int hashfunc(unsigned int cellid)
Returns index to 'hashtable'.
Definition: Collisions.cpp:373
RoR::collision_mesh_t::source_name
std::string source_name
Definition: Collisions.h:67
ErrorUtils::ShowError
static int ShowError(Ogre::UTFString title, Ogre::UTFString message)
shows a simple error message box
Definition: ErrorUtils.cpp:43
RoR::node_t::mass
Ogre::Real mass
Definition: SimData.h:298
RoR::BOAT
@ BOAT
its a boat
Definition: SimData.h:95
RoR::eventsource_t::es_enabled
bool es_enabled
Definition: Collisions.h:47
RoR::Collisions::hash_coll_element_t::cell_id
unsigned int cell_id
Definition: Collisions.h:113
RoR::Actor::ar_evboxes_bounding_box
Ogre::AxisAlignedBox ar_evboxes_bounding_box
bounding box around nodes eligible for eventbox triggering
Definition: Actor.h:301
RoR::collision_tri_t::c
Ogre::Vector3 c
Definition: Collisions.h:54
RoR
Definition: AppContext.h:36
RoR::Collisions::CELL_SIZE
static const int CELL_SIZE
Definition: Collisions.h:128
x
float x
Definition: (ValueTypes) quaternion.h:5
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:276
RoR::Collisions::eventsources
eventsource_t eventsources[MAX_EVENT_SOURCE]
Definition: Collisions.h:149
RoR::Collisions::m_collision_boxes
CollisionBoxVec m_collision_boxes
Definition: Collisions.h:132
RoR::Landusemap
Definition: Landusemap.h:33
RoR::collision_mesh_t::position
Ogre::Vector3 position
Definition: Collisions.h:68
RoR::MovableText::V_ABOVE
@ V_ABOVE
Definition: MovableText.h:44
RoR::collision_mesh_t::mesh_name
std::string mesh_name
Definition: Collisions.h:66
RoR::GameContext::GetTerrain
const TerrainPtr & GetTerrain()
Definition: GameContext.h:117
RoR::node_t::Forces
Ogre::Vector3 Forces
Definition: SimData.h:296
RoR::Collisions::~Collisions
~Collisions()
Definition: Collisions.cpp:140