RigsofRods
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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, const Ogre::String& reverb_preset_name, 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  // audio stuff
432  if (!reverb_preset_name.empty())
433  {
434  coll_box.reverb_preset_name = reverb_preset_name;
435  }
436 
437  // first, self-rotate
438  if (rotating)
439  {
440  // we have a self-rotated block
441  coll_box.selfrotated = true;
442  coll_box.selfrot = Quaternion(Degree(sr.x), Vector3::UNIT_X) * Quaternion(Degree(sr.y), Vector3::UNIT_Y) * Quaternion(Degree(sr.z), Vector3::UNIT_Z);
443  coll_box.selfunrot = coll_box.selfrot.Inverse();
444  } else
445  {
446  coll_box.selfrotated = false;
447  }
448 
449  coll_box.eventsourcenum = -1;
450 
451  if (!eventname.empty())
452  {
453  //LOG("COLL: adding "+TOSTRING(free_eventsource)+" "+String(instancename)+" "+String(eventname));
454  // this is event-generating
458  eventsources[free_eventsource].es_cbox = coll_box_index;
461  coll_box.eventsourcenum = free_eventsource;
463  }
464 
465  // next, global rotate
466  if (fabs(rot.x) < 0.0001f && fabs(rot.y) < 0.0001f && fabs(rot.z) < 0.0001f)
467  {
468  // unrefined box
469  coll_box.refined = false;
470  } else
471  {
472  // refined box
473  coll_box.refined = true;
474  // build rotation
475  coll_box.rot = rotation;
476  coll_box.unrot = rotation.Inverse();
477  }
478 
479  // set raw box
480  // 8 points of a cube
481  if (coll_box.selfrotated || coll_box.refined)
482  {
483  coll_box.debug_verts[0] = Ogre::Vector3(l.x, l.y, l.z) * sc;
484  coll_box.debug_verts[1] = Ogre::Vector3(h.x, l.y, l.z) * sc;
485  coll_box.debug_verts[2] = Ogre::Vector3(l.x, h.y, l.z) * sc;
486  coll_box.debug_verts[3] = Ogre::Vector3(h.x, h.y, l.z) * sc;
487  coll_box.debug_verts[4] = Ogre::Vector3(l.x, l.y, h.z) * sc;
488  coll_box.debug_verts[5] = Ogre::Vector3(h.x, l.y, h.z) * sc;
489  coll_box.debug_verts[6] = Ogre::Vector3(l.x, h.y, h.z) * sc;
490  coll_box.debug_verts[7] = Ogre::Vector3(h.x, h.y, h.z) * sc;
491 
492  // rotate box
493  if (coll_box.selfrotated)
494  for (int i=0; i < 8; i++)
495  {
496  coll_box.debug_verts[i]=coll_box.debug_verts[i]-coll_box.selfcenter;
497  coll_box.debug_verts[i]=coll_box.selfrot*coll_box.debug_verts[i];
498  coll_box.debug_verts[i]=coll_box.debug_verts[i]+coll_box.selfcenter;
499  }
500  if (coll_box.refined)
501  {
502  for (int i=0; i < 8; i++)
503  {
504  coll_box.debug_verts[i] = coll_box.rot * coll_box.debug_verts[i];
505  }
506  }
507  // find min/max
508  coll_box.lo = coll_box.debug_verts[0];
509  coll_box.hi = coll_box.debug_verts[0];
510  for (int i=1; i < 8; i++)
511  {
512  coll_box.lo.makeFloor(coll_box.debug_verts[i]);
513  coll_box.hi.makeCeil(coll_box.debug_verts[i]);
514  }
515  // set absolute coords
516  coll_box.lo += pos;
517  coll_box.hi += pos;
518  } else
519  {
520  // unrefined box
521  coll_box.lo = pos + coll_box.relo;
522  coll_box.hi = pos + coll_box.rehi;
523  Vector3 d = (coll_box.rehi - coll_box.relo);
524  coll_box.debug_verts[0] = coll_box.relo;
525  coll_box.debug_verts[1] = coll_box.relo; coll_box.debug_verts[1].x += d.x;
526  coll_box.debug_verts[2] = coll_box.relo; coll_box.debug_verts[2].y += d.y;
527  coll_box.debug_verts[3] = coll_box.relo; coll_box.debug_verts[3].x += d.x; coll_box.debug_verts[3].y += d.y;
528  coll_box.debug_verts[4] = coll_box.relo; coll_box.debug_verts[4].z += d.z;
529  coll_box.debug_verts[5] = coll_box.relo; coll_box.debug_verts[5].x += d.x; coll_box.debug_verts[5].z += d.z;
530  coll_box.debug_verts[6] = coll_box.relo; coll_box.debug_verts[6].y += d.y; coll_box.debug_verts[6].z += d.z;
531  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;
532  }
533 
534  // register this collision box in the index
535  Vector3 ilo = Ogre::Vector3(coll_box.lo / Ogre::Real(CELL_SIZE));
536  Vector3 ihi = Ogre::Vector3(coll_box.hi / Ogre::Real(CELL_SIZE));
537 
538  // clamp between 0 and MAXIMUM_CELL;
539  ilo.makeCeil(Ogre::Vector3(0.0f));
540  ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
541  ihi.makeCeil(Ogre::Vector3(0.0f));
542  ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
543 
544  for (int i = ilo.x; i <= ihi.x; i++)
545  {
546  for (int j = ilo.z; j <= ihi.z; j++)
547  {
548  hash_add(i, j, coll_box_index,coll_box.hi.y);
549  }
550  }
551 
552  m_collision_aab.merge(AxisAlignedBox(coll_box.lo, coll_box.hi));
553  m_collision_boxes.push_back(coll_box);
554  return coll_box_index;
555 }
556 
557 int Collisions::addCollisionTri(Vector3 p1, Vector3 p2, Vector3 p3, ground_model_t* gm)
558 {
559  int new_tri_index = (int)m_collision_tris.size();
560  collision_tri_t new_tri;
561  new_tri.a=p1;
562  new_tri.b=p2;
563  new_tri.c=p3;
564  new_tri.gm=gm;
565  new_tri.enabled=true;
566  // compute transformations
567  // base construction
568  Vector3 bx=p2-p1;
569  Vector3 by=p3-p1;
570  Vector3 bz=bx.crossProduct(by);
571  bz.normalise();
572  // coordinates change matrix
573  new_tri.reverse.SetColumn(0, bx);
574  new_tri.reverse.SetColumn(1, by);
575  new_tri.reverse.SetColumn(2, bz);
576  new_tri.forward=new_tri.reverse.Inverse();
577 
578  // compute tri AAB
579  new_tri.aab.merge(p1);
580  new_tri.aab.merge(p2);
581  new_tri.aab.merge(p3);
582  new_tri.aab.setMinimum(new_tri.aab.getMinimum() - 0.1f);
583  new_tri.aab.setMaximum(new_tri.aab.getMaximum() + 0.1f);
584 
585  // register this collision tri in the index
586  Ogre::Vector3 ilo(new_tri.aab.getMinimum() / Ogre::Real(CELL_SIZE));
587  Ogre::Vector3 ihi(new_tri.aab.getMaximum() / Ogre::Real(CELL_SIZE));
588 
589  // clamp between 0 and MAXIMUM_CELL;
590  ilo.makeCeil(Ogre::Vector3(0.0f));
591  ilo.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
592  ihi.makeCeil(Ogre::Vector3(0.0f));
593  ihi.makeFloor(Ogre::Vector3(MAXIMUM_CELL));
594 
595  for (int i = ilo.x; i <= ihi.x; i++)
596  {
597  for (int j = ilo.z; j<=ihi.z; j++)
598  {
599  hash_add(i, j, new_tri_index + hash_coll_element_t::ELEMENT_TRI_BASE_INDEX, new_tri.aab.getMaximum().y);
600  }
601  }
602 
603  m_collision_aab.merge(new_tri.aab);
604  m_collision_tris.push_back(new_tri);
605  return new_tri_index;
606 }
607 
609 {
610 #ifdef USE_ANGELSCRIPT
611  // check if this box is active anymore
613  return;
614 
615  if (node)
616  {
617  // An actor is activating the eventbox
618  // Duplicate invocation is prevented by `Actor::m_active_eventboxes` cache.
620  }
621  else
622  {
623  // A character is activating the eventbox
624  // this prevents that the same callback gets called at 2k FPS all the time, serious hit on FPS ...
625  if (std::find(std::begin(m_last_called_cboxes), std::end(m_last_called_cboxes), cbox) == m_last_called_cboxes.end())
626  {
628  m_last_called_cboxes.push_back(cbox);
629  }
630  }
631 #endif //USE_ANGELSCRIPT
632 }
633 
634 std::pair<bool, Ogre::Real> Collisions::intersectsTris(Ogre::Ray ray)
635 {
636  int steps = ray.getDirection().length() / (float)CELL_SIZE;
637 
638  int lhash = -1;
639 
640  for (int i = 0; i <= steps; i++)
641  {
642  Vector3 pos = ray.getPoint((float)i / (float)steps);
643 
644  // find the correct cell
645  int refx = (int)(pos.x / (float)CELL_SIZE);
646  int refz = (int)(pos.z / (float)CELL_SIZE);
647  int hash = hash_find(refx, refz);
648 
649  if (hash == lhash)
650  continue;
651 
652  lhash = hash;
653 
654  size_t num_elements = hashtable[hash].size();
655  for (size_t k = 0; k < num_elements; k++)
656  {
657  if (hashtable[hash][k].IsCollisionTri())
658  {
659  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
660  collision_tri_t *ctri = &m_collision_tris[ctri_index];
661 
662  if (!ctri->enabled)
663  continue;
664 
665  auto result = Ogre::Math::intersects(ray, ctri->a, ctri->b, ctri->c);
666  if (result.first && result.second < 1.0f)
667  {
668  return result;
669  }
670  }
671  }
672  }
673 
674  return std::make_pair(false, 0.0f);
675 }
676 
677 std::pair<bool, Ogre::Real> Collisions::intersectsTerrain(Ogre::Ray ray)
678 {
679  const Ogre::Real raydir_length = ray.getDirection().length();
680  const Ogre::Real step_size = Ogre::Real(0.1);
681 
682  /*
683  * Normalise ray's direction vector, follow it and take sample points after each step_size.
684  * Check for an intersection at each sample point.
685  */
686  ray.setDirection(ray.getDirection().normalisedCopy());
687 
688  for (Ogre::Real distance = Ogre::Real(0); distance <= raydir_length; distance += step_size)
689  {
690  Ogre::Vector3 position = ray.getPoint(distance);
691  Ogre::Real terrain_height = App::GetGameContext()->GetTerrain()->getHeightAt(position.x, position.z);
692 
693  if (terrain_height > position.y)
694  {
695  Ogre::Real distance_in_raydir_units = distance / raydir_length;
696 
697  return std::make_pair(true, distance_in_raydir_units);
698  }
699  }
700 
701  return std::make_pair(false, Ogre::Real(0));
702 }
703 
704 float Collisions::getSurfaceHeight(float x, float z)
705 {
706  return getSurfaceHeightBelow(x, z, std::numeric_limits<float>::max());
707 }
708 
709 float Collisions::getSurfaceHeightBelow(float x, float z, float height)
710 {
711  float surface_height = App::GetGameContext()->GetTerrain()->getHeightAt(x, z);
712 
713  // find the correct cell
714  int refx = (int)(x / (float)CELL_SIZE);
715  int refz = (int)(z / (float)CELL_SIZE);
716  int hash = hash_find(refx, refz);
717 
718  Vector3 origin = Vector3(x, hashtable_height[hash], z);
719  Ray ray(origin, -Vector3::UNIT_Y);
720 
721  size_t num_elements = hashtable[hash].size();
722  for (size_t k = 0; k < num_elements; k++)
723  {
724  if (hashtable[hash][k].IsCollisionBox())
725  {
726  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
727 
728  if (!cbox->enabled)
729  continue;
730 
731  if (!cbox->virt && surface_height < cbox->hi.y)
732  {
733  if (x > cbox->lo.x && z > cbox->lo.z && x < cbox->hi.x && z < cbox->hi.z)
734  {
735  Vector3 pos = origin - cbox->center;
736  Vector3 dir = -Vector3::UNIT_Y;
737  if (cbox->refined)
738  {
739  pos = cbox->unrot * pos;
740  dir = cbox->unrot * dir;
741  }
742  if (cbox->selfrotated)
743  {
744  pos = pos - cbox->selfcenter;
745  pos = cbox->selfunrot * pos;
746  pos = pos + cbox->selfcenter;
747  dir = cbox->selfunrot * dir;
748  }
749  auto result = Ogre::Math::intersects(Ray(pos, dir), AxisAlignedBox(cbox->relo, cbox->rehi));
750  if (result.first)
751  {
752  Vector3 hit = pos + dir * result.second;
753  if (cbox->selfrotated)
754  {
755  hit = cbox->selfrot * hit;
756  }
757  if (cbox->refined)
758  {
759  hit = cbox->rot * hit;
760  }
761  hit += cbox->center;
762  if (hit.y < height)
763  {
764  surface_height = std::max(surface_height, hit.y);
765  }
766  }
767  }
768  }
769  }
770  else // The element is a triangle
771  {
772  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
773  collision_tri_t *ctri = &m_collision_tris[ctri_index];
774 
775  if (!ctri->enabled)
776  continue;
777 
778  auto lo = ctri->aab.getMinimum();
779  auto hi = ctri->aab.getMaximum();
780  if (surface_height >= hi.y)
781  continue;
782  if (x < lo.x || z < lo.z || x > hi.x || z > hi.z)
783  continue;
784 
785  auto result = Ogre::Math::intersects(ray, ctri->a, ctri->b, ctri->c);
786  if (result.first)
787  {
788  if (origin.y - result.second < height)
789  {
790  surface_height = std::max(surface_height, origin.y - result.second);
791  }
792  }
793  }
794  }
795 
796  return surface_height;
797 }
798 
799 bool Collisions::collisionCorrect(Vector3 *refpos, bool envokeScriptCallbacks)
800 {
801  // find the correct cell
802  int refx = (int)(refpos->x / (float)CELL_SIZE);
803  int refz = (int)(refpos->z / (float)CELL_SIZE);
804  int hash = hash_find(refx, refz);
805 
806  if (refpos->y > hashtable_height[hash])
807  return false;
808 
809  collision_tri_t *minctri = 0;
810  float minctridist = 100.0f;
811  Vector3 minctripoint;
812 
813  bool contacted = false;
814  bool isScriptCallbackEnvoked = false;
815 
816  size_t num_elements = hashtable[hash].size();
817  for (size_t k = 0; k < num_elements; k++)
818  {
819  if (hashtable[hash][k].IsCollisionBox())
820  {
821  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
822 
823  if (!cbox->enabled)
824  continue;
825  if (!(*refpos > cbox->lo && *refpos < cbox->hi))
826  continue;
827 
828  if (cbox->refined || cbox->selfrotated)
829  {
830  // we may have a collision, do a change of repere
831  Vector3 Pos = *refpos - cbox->center;
832  if (cbox->refined)
833  {
834  Pos = cbox->unrot * Pos;
835  }
836  if (cbox->selfrotated)
837  {
838  Pos = Pos - cbox->selfcenter;
839  Pos = cbox->selfunrot * Pos;
840  Pos = Pos + cbox->selfcenter;
841  }
842  // now test with the inner box
843  if (Pos > cbox->relo && Pos < cbox->rehi)
844  {
845  if (cbox->eventsourcenum!=-1 && permitEvent(nullptr, cbox->event_filter) && envokeScriptCallbacks)
846  {
847  envokeScriptCallback(cbox);
848  isScriptCallbackEnvoked = true;
849  }
850  if (cbox->camforced && !forcecam)
851  {
852  forcecam = true;
853  forcecampos = cbox->campos;
854  }
855  if (!cbox->virt)
856  {
857  // collision, process as usual
858  // we have a collision
859  contacted = true;
860  // determine which side collided
861  Pos = calcCollidedSide(Pos, cbox->relo, cbox->rehi);
862 
863  // resume repere
864  if (cbox->selfrotated)
865  {
866  Pos = Pos - cbox->selfcenter;
867  Pos = cbox->selfrot * Pos;
868  Pos = Pos + cbox->selfcenter;
869  }
870  if (cbox->refined)
871  {
872  Pos = cbox->rot * Pos;
873  }
874  *refpos = Pos + cbox->center;
875  }
876  }
877 
878  } else
879  {
880  if (cbox->eventsourcenum!=-1 && permitEvent(nullptr, cbox->event_filter) && envokeScriptCallbacks)
881  {
882  envokeScriptCallback(cbox);
883  isScriptCallbackEnvoked = true;
884  }
885  if (cbox->camforced && !forcecam)
886  {
887  forcecam = true;
888  forcecampos = cbox->campos;
889  }
890  if (!cbox->virt)
891  {
892  // we have a collision
893  contacted = true;
894  // determine which side collided
895  (*refpos) = calcCollidedSide((*refpos), cbox->lo, cbox->hi);
896  }
897  }
898  }
899  else // The element is a triangle
900  {
901  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
902  collision_tri_t *ctri = &m_collision_tris[ctri_index];
903  if (!ctri->enabled)
904  continue;
905  if (!ctri->aab.contains(*refpos))
906  continue;
907  // check if this tri is minimal
908  // transform
909  Vector3 point = ctri->forward * (*refpos-ctri->a);
910  // test if within tri collision volume (potential cause of bug!)
911  if (point.x >= 0 && point.y >= 0 && (point.x + point.y) <= 1.0 && point.z < 0 && point.z > -0.1)
912  {
913  if (-point.z < minctridist)
914  {
915  minctri = ctri;
916  minctridist = -point.z;
917  minctripoint = point;
918  }
919  }
920  }
921  }
922 
923  if (envokeScriptCallbacks && !isScriptCallbackEnvoked)
924  clearEventCache();
925 
926  // process minctri collision
927  if (minctri)
928  {
929  // we have a contact
930  contacted = true;
931  // correct point
932  minctripoint.z = 0;
933  // reverse transform
934  *refpos = (minctri->reverse * minctripoint) + minctri->a;
935  }
936  return contacted;
937 }
938 
940 {
941  switch (filter)
942  {
943  case EVENT_ALL:
944  return true;
945  case EVENT_AVATAR:
946  return !b;
947  case EVENT_TRUCK:
948  case EVENT_TRUCK_WHEELS: // The wheelnode check must be done separately
949  return b && b->ar_driveable == TRUCK;
950  case EVENT_AIRPLANE:
951  return b && b->ar_driveable == AIRPLANE;
952  case EVENT_BOAT:
953  return b && b->ar_driveable == BOAT;
954  default:
955  return false;
956  }
957 }
958 
959 bool Collisions::nodeCollision(node_t *node, float dt)
960 {
961  // find the correct cell
962  int refx = (int)(node->AbsPosition.x / CELL_SIZE);
963  int refz = (int)(node->AbsPosition.z / CELL_SIZE);
964  int hash = hash_find(refx, refz);
965  unsigned int cell_id = (refx << 16) + refz;
966 
967  if (node->AbsPosition.y > hashtable_height[hash])
968  return false;
969 
970  collision_tri_t *minctri = 0;
971  float minctridist = 100.0;
972  Vector3 minctripoint;
973 
974  bool contacted = false;
975  bool isScriptCallbackEnvoked = false;
976 
977  size_t num_elements = hashtable[hash].size();
978  for (size_t k=0; k < num_elements; k++)
979  {
980  if (hashtable[hash][k].cell_id != cell_id)
981  {
982  continue;
983  }
984  else if (hashtable[hash][k].IsCollisionBox())
985  {
986  collision_box_t *cbox = &m_collision_boxes[hashtable[hash][k].element_index];
987 
988  if (!cbox->enabled)
989  continue;
990 
991  if (node->AbsPosition > cbox->lo && node->AbsPosition < cbox->hi)
992  {
993  if (cbox->refined || cbox->selfrotated)
994  {
995  // we may have a collision, do a change of repere
996  Vector3 Pos = node->AbsPosition-cbox->center;
997  if (cbox->refined)
998  {
999  Pos = cbox->unrot * Pos;
1000  }
1001  if (cbox->selfrotated)
1002  {
1003  Pos = Pos - cbox->selfcenter;
1004  Pos = cbox->selfunrot * Pos;
1005  Pos = Pos + cbox->selfcenter;
1006  }
1007  // now test with the inner box
1008  if (Pos > cbox->relo && Pos < cbox->rehi)
1009  {
1010  if (cbox->camforced && !forcecam)
1011  {
1012  forcecam = true;
1013  forcecampos = cbox->campos;
1014  }
1015  if (!cbox->virt)
1016  {
1017  // collision, process as usual
1018  // we have a collision
1019  contacted = true;
1020  // determine which side collided
1021  float t = cbox->rehi.z - Pos.z;
1022  float min = Pos.z - cbox->relo.z;
1023  Vector3 normal = Vector3(0, 0, -1);
1024  if (t < min) { min = t; normal = Vector3(0,0,1);}; //north
1025  t = Pos.x - cbox->relo.x;
1026  if (t < min) { min = t; normal = Vector3(-1,0,0);}; //west
1027  t = cbox->rehi.x - Pos.x;
1028  if (t < min) { min = t; normal = Vector3(1,0,0);}; //east
1029  t = Pos.y - cbox->relo.y;
1030  if (t < min) { min = t; normal = Vector3(0,-1,0);}; //down
1031  t = cbox->rehi.y - Pos.y;
1032  if (t < min) { min = t; normal = Vector3(0,1,0);}; //up
1033 
1034  // resume repere for the normal
1035  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1036  if (cbox->refined) normal = cbox->rot * normal;
1037 
1038  // collision boxes are always out of concrete as it seems
1039  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1041  }
1042  }
1043  } else
1044  {
1045  if (cbox->camforced && !forcecam)
1046  {
1047  forcecam = true;
1048  forcecampos = cbox->campos;
1049  }
1050  if (!cbox->virt)
1051  {
1052  // we have a collision
1053  contacted=true;
1054  // determine which side collided
1055  float t = cbox->hi.z - node->AbsPosition.z;
1056  float min = node->AbsPosition.z - cbox->lo.z;
1057  Vector3 normal = Vector3(0, 0, -1);
1058  if (t < min) {min = t; normal = Vector3(0,0,1);}; //north
1059  t = node->AbsPosition.x - cbox->lo.x;
1060  if (t < min) {min = t; normal = Vector3(-1,0,0);}; //west
1061  t = cbox->hi.x - node->AbsPosition.x;
1062  if (t < min) {min = t; normal = Vector3(1,0,0);}; //east
1063  t = node->AbsPosition.y - cbox->lo.y;
1064  if (t < min) {min = t; normal = Vector3(0,-1,0);}; //down
1065  t = cbox->hi.y - node->AbsPosition.y;
1066  if (t < min) {min = t; normal = Vector3(0,1,0);}; //up
1067 
1068  // resume repere for the normal
1069  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1070  if (cbox->refined) normal = cbox->rot * normal;
1071 
1072  // collision boxes are always out of concrete as it seems
1073  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1075  }
1076  }
1077  }
1078  }
1079  else
1080  {
1081  // tri collision
1082  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
1083  collision_tri_t *ctri = &m_collision_tris[ctri_index];
1084  if (!ctri->enabled)
1085  continue;
1086  if (node->AbsPosition.y > ctri->aab.getMaximum().y || node->AbsPosition.y < ctri->aab.getMinimum().y ||
1087  node->AbsPosition.x > ctri->aab.getMaximum().x || node->AbsPosition.x < ctri->aab.getMinimum().x ||
1088  node->AbsPosition.z > ctri->aab.getMaximum().z || node->AbsPosition.z < ctri->aab.getMinimum().z)
1089  continue;
1090  // check if this tri is minimal
1091  // transform
1092  Vector3 point = ctri->forward * (node->AbsPosition - ctri->a);
1093  // test if within tri collision volume (potential cause of bug!)
1094  if (point.x >= 0 && point.y >= 0 && (point.x + point.y) <= 1.0 && point.z < 0 && point.z > -0.1)
1095  {
1096  if (-point.z < minctridist)
1097  {
1098  minctri = ctri;
1099  minctridist = -point.z;
1100  minctripoint = point;
1101  }
1102  }
1103  }
1104  }
1105 
1106  // process minctri collision
1107  if (minctri)
1108  {
1109  // we have a contact
1110  contacted=true;
1111  // we need the normal
1112  // resume repere for the normal
1113  Vector3 normal = minctri->reverse * Vector3::UNIT_Z;
1114  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, minctri->gm);
1115  node->nd_last_collision_gm = minctri->gm;
1116  }
1117 
1118  return contacted;
1119 }
1120 
1122 {
1123  // Find collision cells occupied by the actor (remember 'Y' is 'up').
1124  // Remember there's a dedicated bounding box `ar_evboxes_bounding_box`.
1125  // ----------------------------------------------------------------------
1126 
1127  const AxisAlignedBox aabb = actor->ar_evboxes_bounding_box;
1128  const int cell_lo_x = (int)(aabb.getMinimum().x / (float)CELL_SIZE);
1129  const int cell_lo_z = (int)(aabb.getMinimum().z / (float)CELL_SIZE);
1130  const int cell_hi_x = (int)(aabb.getMaximum().x / (float)CELL_SIZE);
1131  const int cell_hi_z = (int)(aabb.getMaximum().z / (float)CELL_SIZE);
1132 
1133  // Loop the collision cells
1134  for (int refx = cell_lo_x; refx <= cell_hi_x; refx++)
1135  {
1136  for (int refz = cell_lo_z; refz <= cell_hi_z; refz++)
1137  {
1138  // Find current cell
1139  const int hash = this->hash_find(refx, refz);
1140  const unsigned int cell_id = (refx << 16) + refz;
1141 
1142  // Find eligible event boxes in the cell
1143  for (size_t k = 0; k < hashtable[hash].size(); k++)
1144  {
1145  if (hashtable[hash][k].cell_id != cell_id)
1146  {
1147  continue;
1148  }
1149  else if (hashtable[hash][k].IsCollisionBox())
1150  {
1151  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
1152 
1153  if (!cbox->enabled)
1154  continue;
1155 
1156  if (cbox->eventsourcenum != -1 && this->permitEvent(actor, cbox->event_filter))
1157  {
1158  out_boxes.push_back(cbox);
1159  }
1160  }
1161  }
1162  }
1163  }
1164 }
1165 
1166 Vector3 Collisions::getPosition(const Ogre::String &inst, const Ogre::String &box)
1167 {
1168  for (int i=0; i<free_eventsource; i++)
1169  {
1170  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1171  {
1173  }
1174  }
1175  return Vector3::ZERO;
1176 }
1177 
1178 Quaternion Collisions::getDirection(const Ogre::String &inst, const Ogre::String &box)
1179 {
1180  for (int i=0; i<free_eventsource; i++)
1181  {
1182  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1183  {
1185  }
1186  }
1187  return Quaternion::ZERO;
1188 }
1189 
1190 collision_box_t *Collisions::getBox(const Ogre::String &inst, const Ogre::String &box)
1191 {
1192  for (int i=0; i<free_eventsource; i++)
1193  {
1194  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1195  {
1197  }
1198  }
1199  return NULL;
1200 }
1201 
1202 bool Collisions::isInside(Ogre::Vector3 pos, const Ogre::String &inst, const Ogre::String &box, float border)
1203 {
1204  collision_box_t *cbox = getBox(inst, box);
1205 
1206  return isInside(pos, cbox, border);
1207 }
1208 
1209 bool Collisions::isInside(Ogre::Vector3 pos, collision_box_t *cbox, float border)
1210 {
1211  if (!cbox) return false;
1212 
1213  if (pos + border > cbox->lo
1214  && pos - border < cbox->hi)
1215  {
1216  if (cbox->refined || cbox->selfrotated)
1217  {
1218  // we may have a collision, do a change of repere
1219  Vector3 rpos = pos - cbox->center;
1220  if (cbox->refined)
1221  {
1222  rpos = cbox->unrot * rpos;
1223  }
1224  if (cbox->selfrotated)
1225  {
1226  rpos = rpos - cbox->selfcenter;
1227  rpos = cbox->selfunrot * rpos;
1228  rpos = rpos + cbox->selfcenter;
1229  }
1230 
1231  // now test with the inner box
1232  if (rpos > cbox->relo
1233  && rpos < cbox->rehi)
1234  {
1235  return true;
1236  }
1237  } else
1238  {
1239  return true;
1240  }
1241  }
1242  return false;
1243 }
1244 
1246 {
1247  Real v = App::GetGameContext()->GetTerrain()->getHeightAt(node->AbsPosition.x, node->AbsPosition.z);
1248  if (v > node->AbsPosition.y)
1249  {
1250  ground_model_t* ogm = landuse ? landuse->getGroundModelAt(node->AbsPosition.x, node->AbsPosition.z) : nullptr;
1251  // when landuse fails or we don't have it, use the default value
1252  if (!ogm) ogm = defaultgroundgm;
1253  Ogre::Vector3 normal = App::GetGameContext()->GetTerrain()->GetNormalAt(node->AbsPosition.x, v, node->AbsPosition.z);
1254  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, ogm, v - node->AbsPosition.y);
1255  node->nd_last_collision_gm = ogm;
1256  return true;
1257  }
1258  return false;
1259 }
1260 
1261 Vector3 RoR::primitiveCollision(node_t *node, Ogre::Vector3 velocity, float mass, Ogre::Vector3 normal, float dt, ground_model_t* gm, float penetration)
1262 {
1263  Vector3 force = Vector3::ZERO;
1264  float Vnormal = velocity.dotProduct(normal);
1265  float Fnormal = node->Forces.dotProduct(normal);
1266 
1267  // if we are inside the fluid (solid ground is below us)
1268  if (gm->solid_ground_level != 0.0f && penetration >= 0)
1269  {
1270  float Vsquared = velocity.squaredLength();
1271  // First of all calculate power law fluid viscosity
1272  float m = gm->flow_consistency_index * approx_pow(Vsquared, (gm->flow_behavior_index - 1.0f) * 0.5f);
1273 
1274  // Then calculate drag based on above. We'are using a simplified Stokes' drag.
1275  // Per node fluid drag surface coefficient set by node property applies here
1276  Vector3 Fdrag = velocity * (-m * node->surface_coef);
1277 
1278  // If we have anisotropic drag
1279  if (gm->drag_anisotropy < 1.0f && Vnormal > 0)
1280  {
1281  float da_factor;
1282  if (Vsquared > gm->va * gm->va)
1283  da_factor = 1.0;
1284  else
1285  da_factor = Vsquared / (gm->va * gm->va);
1286  Fdrag += (Vnormal * m * (1.0f - gm->drag_anisotropy) * da_factor) * normal;
1287  }
1288  force += Fdrag;
1289 
1290  // Now calculate upwards force based on a simplified boyancy equation;
1291  // If the fluid is pseudoplastic then boyancy is constrained to only "stopping" a node from going downwards
1292  // Buoyancy per node volume coefficient set by node property applies here
1293  float Fboyancy = gm->fluid_density * penetration * (-DEFAULT_GRAVITY) * node->volume_coef;
1294  if (gm->flow_behavior_index < 1.0f && Vnormal >= 0.0f)
1295  {
1296  if (Fnormal < 0 && Fboyancy>-Fnormal)
1297  {
1298  Fboyancy = -Fnormal;
1299  }
1300  }
1301  force += Fboyancy * normal;
1302  }
1303 
1304  // if we are inside or touching the solid ground
1305  if (penetration >= gm->solid_ground_level)
1306  {
1307  // steady force
1308  float Freaction = -Fnormal;
1309  // impact force
1310  if (Vnormal < 0)
1311  {
1312  float penetration_depth = gm->solid_ground_level - penetration;
1313  Freaction -= (0.8f * Vnormal + 0.2f * penetration_depth / dt) * mass / dt; // Newton's second law
1314  }
1315  if (Freaction > 0)
1316  {
1317  Vector3 slipf = node->Forces - Fnormal * normal;
1318  Vector3 slip = velocity - Vnormal * normal;
1319  float slipv = slip.normalise();
1320  // If the velocity that we slip is lower than adhesion velocity and
1321  // we have a downforce and the slip forces are lower than static friction
1322  // forces then it's time to go into static friction physics mode.
1323  // This code is a direct translation of textbook static friction physics
1324  float Greaction = Freaction * gm->strength * node->friction_coef; //General moderated reaction
1325  float msGreaction = gm->ms * Greaction;
1326  if (slipv < gm->va && Greaction > 0.0f && slipf.squaredLength() <= msGreaction * msGreaction)
1327  {
1328  // Static friction model (with a little smoothing to help the integrator deal with it)
1329  float ff = -msGreaction * (1.0f - approx_exp(-slipv / gm->va));
1330  force += Freaction * normal + ff * slip - slipf;
1331  } else
1332  {
1333  // Stribek model. It also comes directly from textbooks.
1334  float g = gm->mc + (gm->ms - gm->mc) * approx_exp(-approx_pow(slipv / gm->vs, gm->alpha));
1335  float ff = -(g + std::min(gm->t2 * slipv, 5.0f)) * Greaction;
1336  force += Freaction * normal + ff * slip;
1337  }
1338  node->nd_avg_collision_slip = node->nd_avg_collision_slip * 0.995 + slipv * 0.005f;
1339  node->nd_last_collision_slip = slipv * slip;
1340  node->nd_last_collision_force = std::min(-Freaction, 0.0f) * normal;
1341  }
1342  }
1343 
1344  return force;
1345 }
1346 
1347 void Collisions::createCollisionDebugVisualization(Ogre::SceneNode* root_node, Ogre::AxisAlignedBox const& area_limit, std::vector<Ogre::SceneNode*>& out_nodes)
1348 {
1349  LOG("COLL: Creating collision debug visualization ...");
1350 
1351 
1352 
1353  for (int x=0; x<(int)(m_terrain_size.x); x+=(int)CELL_SIZE)
1354  {
1355  for (int z=0; z<(int)(m_terrain_size.z); z+=(int)CELL_SIZE)
1356  {
1357 
1358  if (!area_limit.contains(Ogre::Vector3(x, 0.f, z)))
1359  continue;
1360 
1361  int cellx = (int)(x/(float)CELL_SIZE);
1362  int cellz = (int)(z/(float)CELL_SIZE);
1363  const int hash = hash_find(cellx, cellz);
1364 
1365  bool used = std::find_if(hashtable[hash].begin(), hashtable[hash].end(), [&](hash_coll_element_t const &c) {
1366  return c.cell_id == (cellx << 16) + cellz;
1367  }) != hashtable[hash].end();
1368 
1369  if (used)
1370  {
1371  float groundheight = -9999;
1372  float x2 = x+CELL_SIZE;
1373  float z2 = z+CELL_SIZE;
1374 
1375  // find a good ground height for all corners of the cell ...
1376  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->getHeightAt(x, z));
1377  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->getHeightAt(x2, z));
1378  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->getHeightAt(x, z2));
1379  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->getHeightAt(x2, z2));
1380  groundheight += 0.1; // 10 cm hover
1381 
1382  float percentd = static_cast<float>(hashtable[hash].size()) / static_cast<float>(CELL_BLOCKSIZE);
1383  if (percentd > 1) percentd = 1;
1384 
1385  // see `RoR::GUI::CollisionsDebug::GenerateCellDebugMaterials()`
1386  String matName = "mat-coll-dbg-"+TOSTRING((int)(percentd*100));
1387  String cell_name="("+TOSTRING(cellx)+","+ TOSTRING(cellz)+")";
1388 
1389  ManualObject *mo = App::GetGfxScene()->GetSceneManager()->createManualObject("collisionDebugVisualization"+cell_name);
1390  SceneNode *mo_node = root_node->createChildSceneNode("collisionDebugVisualization_node"+cell_name);
1391 
1392  mo->begin(matName, Ogre::RenderOperation::OT_TRIANGLE_LIST);
1393 
1394  // 1st tri
1395  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1396  mo->textureCoord(0,0);
1397 
1398  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1399  mo->textureCoord(1,1);
1400 
1401  mo->position(CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1402  mo->textureCoord(1,0);
1403 
1404  // 2nd tri
1405  mo->position(-CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1406  mo->textureCoord(0,1);
1407 
1408  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1409  mo->textureCoord(1,1);
1410 
1411  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1412  mo->textureCoord(0,0);
1413 
1414  mo->end();
1415  mo->setBoundingBox(AxisAlignedBox(0, 0, 0, CELL_SIZE, 1, CELL_SIZE));
1416  mo->setRenderingDistance(200.f);
1417  mo_node->attachObject(mo);
1418 
1419 #if 0
1420  // setup the label
1421  String labelName = "label_"+cell_name;
1422  String labelCaption = cell_name+" "+TOSTRING(percent*100,2) + "% usage ("+TOSTRING(cc)+"/"+TOSTRING(CELL_BLOCKSIZE)+") DEEP: " + TOSTRING(deep);
1423  MovableText *mt = new MovableText(labelName, labelCaption);
1425  mt->setFontName("CyberbitEnglish");
1426  mt->setAdditionalHeight(1);
1427  mt->setCharacterHeight(0.3);
1428  mt->setColor(ColourValue::White);
1429  mo_node->attachObject(mt);
1430 #endif
1431 
1432  mo_node->setVisible(true);
1433  mo_node->setPosition(Vector3(x+CELL_SIZE/(float)2.0, groundheight, z+CELL_SIZE/(float)2.0));
1434 
1435  out_nodes.push_back(mo_node);
1436  }
1437  }
1438  }
1439 }
1440 
1441 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)
1442 {
1443  Entity *ent = App::GetGfxScene()->GetSceneManager()->createEntity(meshname);
1444  ent->setMaterialName("tracks/debug/collision/mesh");
1445 
1446  if (!gm)
1447  {
1448  gm = getGroundModelByString("concrete");
1449  }
1450 
1451  // Analyze the mesh
1452  size_t vertex_count,index_count;
1453  Vector3* vertices;
1454  unsigned* indices;
1455 
1456  getMeshInformation(ent->getMesh().get(),vertex_count,vertices,index_count,indices, pos, q, scale);
1457 
1458  // Generate collision triangles
1459  int collision_tri_start = (int)m_collision_tris.size();
1460  for (int i=0; i<(int)index_count/3; i++)
1461  {
1462  int triID = addCollisionTri(vertices[indices[i*3]], vertices[indices[i*3+1]], vertices[indices[i*3+2]], gm);
1463  if (collTris)
1464  collTris->push_back(triID);
1465  }
1466 
1467  // Submit the mesh record
1468  collision_mesh_t rec;
1469  rec.mesh_name = meshname;
1470  rec.source_name = srcname;
1471  rec.position = pos;
1472  rec.orientation = q;
1473  rec.scale = scale;
1474  rec.ground_model = gm;
1475  rec.num_verts = vertex_count;
1476  rec.num_indices = index_count;
1477  rec.collision_tri_start = collision_tri_start;
1478  rec.collision_tri_count = (int)m_collision_tris.size() - collision_tri_start;
1479  rec.bounding_box = ent->getMesh()->getBounds();
1480  m_collision_meshes.push_back(rec);
1481 
1482  // Clean up
1483  delete[] vertices;
1484  delete[] indices;
1485  App::GetGfxScene()->GetSceneManager()->destroyEntity(ent);
1486 }
1487 
1488 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)
1489 {
1490  // Submit the mesh record
1491  collision_mesh_t rec;
1492  rec.mesh_name = meshname;
1493  rec.source_name = srcname;
1494  rec.position = pos;
1495  rec.ground_model = gm;
1496  rec.collision_tri_start = ctri_start;
1497  rec.collision_tri_count = ctri_count;
1498  rec.bounding_box = bounding_box;
1499  m_collision_meshes.push_back(rec);
1500 }
1501 
1502 void Collisions::getMeshInformation(Mesh* mesh,size_t &vertex_count,Ogre::Vector3* &vertices,
1503  size_t &index_count, unsigned* &indices, const Ogre::Vector3 &position,
1504  const Ogre::Quaternion &orient, const Ogre::Vector3 &scale)
1505 {
1506  vertex_count = index_count = 0;
1507 
1508  bool added_shared = false;
1509  size_t current_offset = vertex_count;
1510  size_t shared_offset = vertex_count;
1511  size_t next_offset = vertex_count;
1512  size_t index_offset = index_count;
1513  //size_t prev_vert = vertex_count;
1514  //size_t prev_ind = index_count;
1515 
1516  // Calculate how many vertices and indices we're going to need
1517  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1518  {
1519  SubMesh* submesh = mesh->getSubMesh(i);
1520 
1521  // We only need to add the shared vertices once
1522  if (submesh->useSharedVertices)
1523  {
1524  if (!added_shared)
1525  {
1526  VertexData* vertex_data = mesh->sharedVertexData;
1527  vertex_count += vertex_data->vertexCount;
1528  added_shared = true;
1529  }
1530  } else
1531  {
1532  VertexData* vertex_data = submesh->vertexData;
1533  vertex_count += vertex_data->vertexCount;
1534  }
1535 
1536  // Add the indices
1537  Ogre::IndexData* index_data = submesh->indexData;
1538  index_count += index_data->indexCount;
1539  }
1540 
1541  // Allocate space for the vertices and indices
1542  vertices = new Vector3[vertex_count];
1543  indices = new unsigned[index_count];
1544 
1545  added_shared = false;
1546 
1547  // Run through the sub-meshes again, adding the data into the arrays
1548  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1549  {
1550  SubMesh* submesh = mesh->getSubMesh(i);
1551 
1552  Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
1553  if ((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
1554  {
1555  if (submesh->useSharedVertices)
1556  {
1557  added_shared = true;
1558  shared_offset = current_offset;
1559  }
1560 
1561  const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
1562  Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
1563  unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1564  Ogre::Real* pReal;
1565 
1566  for (size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
1567  {
1568  posElem->baseVertexPointerToElement(vertex, &pReal);
1569 
1570  Vector3 pt;
1571 
1572  pt.x = (*pReal++);
1573  pt.y = (*pReal++);
1574  pt.z = (*pReal++);
1575 
1576  pt = (orient * (pt * scale)) + position;
1577 
1578  vertices[current_offset + j].x = pt.x;
1579  vertices[current_offset + j].y = pt.y;
1580  vertices[current_offset + j].z = pt.z;
1581  }
1582  vbuf->unlock();
1583  next_offset += vertex_data->vertexCount;
1584  }
1585 
1586  Ogre::IndexData* index_data = submesh->indexData;
1587 
1588  size_t numTris = index_data->indexCount / 3;
1589  unsigned short* pShort = 0;
1590  unsigned int* pInt = 0;
1591  Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
1592 
1593  bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
1594 
1595  if (use32bitindexes)
1596  pInt = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1597  else
1598  pShort = static_cast<unsigned short*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1599 
1600  for (size_t k = 0; k < numTris; ++k)
1601  {
1602  size_t offset = (submesh->useSharedVertices)?shared_offset:current_offset;
1603 
1604  unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
1605  indices[index_offset + 0] = vindex + (unsigned int)offset;
1606  vindex = use32bitindexes? *pInt++ : *pShort++;
1607  indices[index_offset + 1] = vindex + (unsigned int)offset;
1608  vindex = use32bitindexes? *pInt++ : *pShort++;
1609  indices[index_offset + 2] = vindex + (unsigned int)offset;
1610 
1611  index_offset += 3;
1612  }
1613  ibuf->unlock();
1614  current_offset = next_offset;
1615  }
1616 }
1617 
1619 {
1620 }
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:722
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:50
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:1261
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:268
RoR::ground_model_t::strength
float strength
ground strength
Definition: SimData.h:711
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:42
RoR::collision_box_t::reverb_preset_name
std::string reverb_preset_name
name of the reverb preset that applies to the inside of the collision box
Definition: SimData.h:698
RoR::TRUCK
@ TRUCK
its a truck (or other land vehicle)
Definition: SimData.h:85
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:297
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:300
RoR::ground_model_t::va
float va
adhesion velocity
Definition: SimData.h:705
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:267
ErrorUtils::ShowError
static int ShowError(const std::string &title, const std::string &message)
shows a simple error message box
Definition: ErrorUtils.cpp:46
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::collision_box_t::virt
bool virt
Definition: SimData.h:679
RoR::collision_box_t::enabled
bool enabled
Definition: SimData.h:683
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:709
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:274
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:686
RoR::Collisions::groundCollision
bool groundCollision(node_t *node, float dt)
Definition: Collisions.cpp:1245
RoR::Collisions::clearEventCache
void clearEventCache()
Definition: Collisions.h:209
RoR::Collisions::findPotentialEventBoxes
void findPotentialEventBoxes(Actor *actor, CollisionBoxPtrVec &out_boxes)
Definition: Collisions.cpp:1121
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:685
RoR::collision_box_t::hi
Ogre::Vector3 hi
absolute collision box
Definition: SimData.h:687
RoR::Collisions::getPosition
Ogre::Vector3 getPosition(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1166
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:700
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:1488
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:1441
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:799
approx_exp
float approx_exp(const float x)
Definition: ApproxMath.h:68
RoR::ground_model_t::alpha
float alpha
steady-steady
Definition: SimData.h:710
RoR::collision_box_t::selfrotated
bool selfrotated
Definition: SimData.h:681
RoR::Collisions::hashtable_height
std::array< float, HASH_SIZE > hashtable_height
Definition: Collisions.h:142
Language.h
RoR::collision_box_t
Definition: SimData.h:677
RoR::collision_box_t::unrot
Ogre::Quaternion unrot
rotation
Definition: SimData.h:690
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:707
ActorManager.h
Actor.h
RoR::collision_box_t::center
Ogre::Vector3 center
center of rotation
Definition: SimData.h:688
RoR::App::GetScriptEngine
ScriptEngine * GetScriptEngine()
Definition: Application.cpp:295
RoR::Landusemap::getGroundModelAt
ground_model_t * getGroundModelAt(int x, int z)
Definition: Landusemap.cpp:57
RoR::GfxScene::GetSceneManager
Ogre::SceneManager * GetSceneManager()
Definition: GfxScene.h:83
RoR::ground_model_t::vs
float vs
stribeck velocity (m/s)
Definition: SimData.h:709
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::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:510
RoR::Collisions::loadGroundModelsConfigFile
int loadGroundModelsConfigFile(Ogre::String filename)
Definition: Collisions.cpp:150
RoR::collision_box_t::event_filter
CollisionEventFilter event_filter
Definition: SimData.h:684
RoR::collision_mesh_t::collision_tri_count
int collision_tri_count
Definition: Collisions.h:74
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, const Ogre::String &reverb_preset_name, 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
TOSTRING
#define TOSTRING(x)
Definition: Application.h:56
RoR::collision_box_t::rehi
Ogre::Vector3 rehi
relative collision box
Definition: SimData.h:695
RoR::Collisions::intersectsTris
std::pair< bool, Ogre::Real > intersectsTris(Ogre::Ray ray)
Definition: Collisions.cpp:634
RoR::MovableText::setFontName
void setFontName(const std::string &fontName)
Definition: MovableText.cpp:73
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:38
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::Terrain::getHeightAt
float getHeightAt(float x, float z)
Definition: Terrain.cpp:505
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:691
RoR::Collisions::getBox
collision_box_t * getBox(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1190
RoR::Collisions::envokeScriptCallback
void envokeScriptCallback(collision_box_t *cbox, node_t *node=0)
Definition: Collisions.cpp:608
RoR::collision_box_t::relo
Ogre::Vector3 relo
relative collision box
Definition: SimData.h:694
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:462
RoR::node_t::pos
NodeNum_t pos
This node's index in Actor::ar_nodes array.
Definition: SimData.h:277
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:680
RoR::Collisions::addCollisionTri
int addCollisionTri(Ogre::Vector3 p1, Ogre::Vector3 p2, Ogre::Vector3 p3, ground_model_t *gm)
Definition: Collisions.cpp:557
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:299
RoR::node_t
Physics: A vertex in the softbody structure.
Definition: SimData.h:259
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:296
RoR::collision_box_t::camforced
bool camforced
Definition: SimData.h:682
RoR::ground_model_t::name
char name[256]
Definition: SimData.h:727
RoR::node_t::friction_coef
Ogre::Real friction_coef
Definition: SimData.h:273
RoR::AIRPLANE
@ AIRPLANE
its an airplane
Definition: SimData.h:86
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:696
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:704
RoR::ground_model_t::t2
float t2
hydrodynamic friction (s/m)
Definition: SimData.h:708
RoR::node_t::nd_last_collision_slip
Ogre::Vector3 nd_last_collision_slip
Physics state; last collision slip vector.
Definition: SimData.h:298
ApproxMath.h
RoR::ground_model_t::ms
float ms
static friction coefficient
Definition: SimData.h:706
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:692
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:959
RoR::node_t::volume_coef
Ogre::Real volume_coef
Definition: SimData.h:275
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:1502
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:1347
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:719
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:402
RoR::collision_mesh_t::num_verts
int num_verts
Definition: Collisions.h:75
_L
#define _L
Definition: ErrorUtils.cpp:35
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:689
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:713
RoR::collision_box_t::selfunrot
Ogre::Quaternion selfunrot
self rotation
Definition: SimData.h:693
RoR::Collisions::permitEvent
bool permitEvent(Actor *actor, CollisionEventFilter filter)
Definition: Collisions.cpp:939
RoR::Collisions::getDirection
Ogre::Quaternion getDirection(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1178
RoR::ground_model_t
Surface friction properties.
Definition: SimData.h:703
RoR::ground_model_t::drag_anisotropy
float drag_anisotropy
Upwards/Downwards drag anisotropy.
Definition: SimData.h:723
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:1202
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:697
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:714
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:1618
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
RoR::node_t::mass
Ogre::Real mass
Definition: SimData.h:271
RoR::BOAT
@ BOAT
its a boat
Definition: SimData.h:87
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:343
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::Collisions::intersectsTerrain
std::pair< bool, Ogre::Real > intersectsTerrain(Ogre::Ray ray)
Checks whether a Ray intersects the terrain.
Definition: Collisions.cpp:677
RoR::App::GetGfxScene
GfxScene * GetGfxScene()
Definition: Application.cpp:292
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:43
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:269
RoR::Collisions::~Collisions
~Collisions()
Definition: Collisions.cpp:140