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  return b && b->ar_driveable == TRUCK;
916  case EVENT_AIRPLANE:
917  return b && b->ar_driveable == AIRPLANE;
918  case EVENT_BOAT:
919  return b && b->ar_driveable == BOAT;
920  case EVENT_DELETE:
921  return !b;
922  default:
923  return false;
924  }
925 }
926 
927 bool Collisions::nodeCollision(node_t *node, float dt)
928 {
929  // find the correct cell
930  int refx = (int)(node->AbsPosition.x / CELL_SIZE);
931  int refz = (int)(node->AbsPosition.z / CELL_SIZE);
932  int hash = hash_find(refx, refz);
933  unsigned int cell_id = (refx << 16) + refz;
934 
935  if (node->AbsPosition.y > hashtable_height[hash])
936  return false;
937 
938  collision_tri_t *minctri = 0;
939  float minctridist = 100.0;
940  Vector3 minctripoint;
941 
942  bool contacted = false;
943  bool isScriptCallbackEnvoked = false;
944 
945  size_t num_elements = hashtable[hash].size();
946  for (size_t k=0; k < num_elements; k++)
947  {
948  if (hashtable[hash][k].cell_id != cell_id)
949  {
950  continue;
951  }
952  else if (hashtable[hash][k].IsCollisionBox())
953  {
954  collision_box_t *cbox = &m_collision_boxes[hashtable[hash][k].element_index];
955 
956  if (!cbox->enabled)
957  continue;
958 
959  if (node->AbsPosition > cbox->lo && node->AbsPosition < cbox->hi)
960  {
961  if (cbox->refined || cbox->selfrotated)
962  {
963  // we may have a collision, do a change of repere
964  Vector3 Pos = node->AbsPosition-cbox->center;
965  if (cbox->refined)
966  {
967  Pos = cbox->unrot * Pos;
968  }
969  if (cbox->selfrotated)
970  {
971  Pos = Pos - cbox->selfcenter;
972  Pos = cbox->selfunrot * Pos;
973  Pos = Pos + cbox->selfcenter;
974  }
975  // now test with the inner box
976  if (Pos > cbox->relo && Pos < cbox->rehi)
977  {
978  if (cbox->camforced && !forcecam)
979  {
980  forcecam = true;
981  forcecampos = cbox->campos;
982  }
983  if (!cbox->virt)
984  {
985  // collision, process as usual
986  // we have a collision
987  contacted = true;
988  // determine which side collided
989  float t = cbox->rehi.z - Pos.z;
990  float min = Pos.z - cbox->relo.z;
991  Vector3 normal = Vector3(0, 0, -1);
992  if (t < min) { min = t; normal = Vector3(0,0,1);}; //north
993  t = Pos.x - cbox->relo.x;
994  if (t < min) { min = t; normal = Vector3(-1,0,0);}; //west
995  t = cbox->rehi.x - Pos.x;
996  if (t < min) { min = t; normal = Vector3(1,0,0);}; //east
997  t = Pos.y - cbox->relo.y;
998  if (t < min) { min = t; normal = Vector3(0,-1,0);}; //down
999  t = cbox->rehi.y - Pos.y;
1000  if (t < min) { min = t; normal = Vector3(0,1,0);}; //up
1001 
1002  // resume repere for the normal
1003  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1004  if (cbox->refined) normal = cbox->rot * normal;
1005 
1006  // collision boxes are always out of concrete as it seems
1007  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1009  }
1010  }
1011  } else
1012  {
1013  if (cbox->camforced && !forcecam)
1014  {
1015  forcecam = true;
1016  forcecampos = cbox->campos;
1017  }
1018  if (!cbox->virt)
1019  {
1020  // we have a collision
1021  contacted=true;
1022  // determine which side collided
1023  float t = cbox->hi.z - node->AbsPosition.z;
1024  float min = node->AbsPosition.z - cbox->lo.z;
1025  Vector3 normal = Vector3(0, 0, -1);
1026  if (t < min) {min = t; normal = Vector3(0,0,1);}; //north
1027  t = node->AbsPosition.x - cbox->lo.x;
1028  if (t < min) {min = t; normal = Vector3(-1,0,0);}; //west
1029  t = cbox->hi.x - node->AbsPosition.x;
1030  if (t < min) {min = t; normal = Vector3(1,0,0);}; //east
1031  t = node->AbsPosition.y - cbox->lo.y;
1032  if (t < min) {min = t; normal = Vector3(0,-1,0);}; //down
1033  t = cbox->hi.y - node->AbsPosition.y;
1034  if (t < min) {min = t; normal = Vector3(0,1,0);}; //up
1035 
1036  // resume repere for the normal
1037  if (cbox->selfrotated) normal = cbox->selfrot * normal;
1038  if (cbox->refined) normal = cbox->rot * normal;
1039 
1040  // collision boxes are always out of concrete as it seems
1041  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, defaultgm);
1043  }
1044  }
1045  }
1046  }
1047  else
1048  {
1049  // tri collision
1050  const int ctri_index = hashtable[hash][k].element_index - hash_coll_element_t::ELEMENT_TRI_BASE_INDEX;
1051  collision_tri_t *ctri = &m_collision_tris[ctri_index];
1052  if (!ctri->enabled)
1053  continue;
1054  if (node->AbsPosition.y > ctri->aab.getMaximum().y || node->AbsPosition.y < ctri->aab.getMinimum().y ||
1055  node->AbsPosition.x > ctri->aab.getMaximum().x || node->AbsPosition.x < ctri->aab.getMinimum().x ||
1056  node->AbsPosition.z > ctri->aab.getMaximum().z || node->AbsPosition.z < ctri->aab.getMinimum().z)
1057  continue;
1058  // check if this tri is minimal
1059  // transform
1060  Vector3 point = ctri->forward * (node->AbsPosition - ctri->a);
1061  // test if within tri collision volume (potential cause of bug!)
1062  if (point.x >= 0 && point.y >= 0 && (point.x + point.y) <= 1.0 && point.z < 0 && point.z > -0.1)
1063  {
1064  if (-point.z < minctridist)
1065  {
1066  minctri = ctri;
1067  minctridist = -point.z;
1068  minctripoint = point;
1069  }
1070  }
1071  }
1072  }
1073 
1074  // process minctri collision
1075  if (minctri)
1076  {
1077  // we have a contact
1078  contacted=true;
1079  // we need the normal
1080  // resume repere for the normal
1081  Vector3 normal = minctri->reverse * Vector3::UNIT_Z;
1082  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, minctri->gm);
1083  node->nd_last_collision_gm = minctri->gm;
1084  }
1085 
1086  return contacted;
1087 }
1088 
1090 {
1091  // Find collision cells occupied by the actor (remember 'Y' is 'up').
1092  // Remember there's a dedicated bounding box `ar_evboxes_bounding_box`.
1093  // ----------------------------------------------------------------------
1094 
1095  const AxisAlignedBox aabb = actor->ar_evboxes_bounding_box;
1096  const int cell_lo_x = (int)(aabb.getMinimum().x / (float)CELL_SIZE);
1097  const int cell_lo_z = (int)(aabb.getMinimum().z / (float)CELL_SIZE);
1098  const int cell_hi_x = (int)(aabb.getMaximum().x / (float)CELL_SIZE);
1099  const int cell_hi_z = (int)(aabb.getMaximum().z / (float)CELL_SIZE);
1100 
1101  // Loop the collision cells
1102  for (int refx = cell_lo_x; refx <= cell_hi_x; refx++)
1103  {
1104  for (int refz = cell_lo_z; refz <= cell_hi_z; refz++)
1105  {
1106  // Find current cell
1107  const int hash = this->hash_find(refx, refz);
1108  const unsigned int cell_id = (refx << 16) + refz;
1109 
1110  // Find eligible event boxes in the cell
1111  for (size_t k = 0; k < hashtable[hash].size(); k++)
1112  {
1113  if (hashtable[hash][k].cell_id != cell_id)
1114  {
1115  continue;
1116  }
1117  else if (hashtable[hash][k].IsCollisionBox())
1118  {
1119  collision_box_t* cbox = &m_collision_boxes[hashtable[hash][k].element_index];
1120 
1121  if (!cbox->enabled)
1122  continue;
1123 
1124  if (cbox->eventsourcenum != -1 && this->permitEvent(actor, cbox->event_filter))
1125  {
1126  out_boxes.push_back(cbox);
1127  }
1128  }
1129  }
1130  }
1131  }
1132 }
1133 
1134 Vector3 Collisions::getPosition(const Ogre::String &inst, const Ogre::String &box)
1135 {
1136  for (int i=0; i<free_eventsource; i++)
1137  {
1138  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1139  {
1141  }
1142  }
1143  return Vector3::ZERO;
1144 }
1145 
1146 Quaternion Collisions::getDirection(const Ogre::String &inst, const Ogre::String &box)
1147 {
1148  for (int i=0; i<free_eventsource; i++)
1149  {
1150  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1151  {
1153  }
1154  }
1155  return Quaternion::ZERO;
1156 }
1157 
1158 collision_box_t *Collisions::getBox(const Ogre::String &inst, const Ogre::String &box)
1159 {
1160  for (int i=0; i<free_eventsource; i++)
1161  {
1162  if (inst == eventsources[i].es_instance_name && box == eventsources[i].es_box_name)
1163  {
1165  }
1166  }
1167  return NULL;
1168 }
1169 
1170 bool Collisions::isInside(Ogre::Vector3 pos, const Ogre::String &inst, const Ogre::String &box, float border)
1171 {
1172  collision_box_t *cbox = getBox(inst, box);
1173 
1174  return isInside(pos, cbox, border);
1175 }
1176 
1177 bool Collisions::isInside(Ogre::Vector3 pos, collision_box_t *cbox, float border)
1178 {
1179  if (!cbox) return false;
1180 
1181  if (pos + border > cbox->lo
1182  && pos - border < cbox->hi)
1183  {
1184  if (cbox->refined || cbox->selfrotated)
1185  {
1186  // we may have a collision, do a change of repere
1187  Vector3 rpos = pos - cbox->center;
1188  if (cbox->refined)
1189  {
1190  rpos = cbox->unrot * rpos;
1191  }
1192  if (cbox->selfrotated)
1193  {
1194  rpos = rpos - cbox->selfcenter;
1195  rpos = cbox->selfunrot * rpos;
1196  rpos = rpos + cbox->selfcenter;
1197  }
1198 
1199  // now test with the inner box
1200  if (rpos > cbox->relo
1201  && rpos < cbox->rehi)
1202  {
1203  return true;
1204  }
1205  } else
1206  {
1207  return true;
1208  }
1209  }
1210  return false;
1211 }
1212 
1214 {
1215  Real v = App::GetGameContext()->GetTerrain()->GetHeightAt(node->AbsPosition.x, node->AbsPosition.z);
1216  if (v > node->AbsPosition.y)
1217  {
1218  ground_model_t* ogm = landuse ? landuse->getGroundModelAt(node->AbsPosition.x, node->AbsPosition.z) : nullptr;
1219  // when landuse fails or we don't have it, use the default value
1220  if (!ogm) ogm = defaultgroundgm;
1221  Ogre::Vector3 normal = App::GetGameContext()->GetTerrain()->GetNormalAt(node->AbsPosition.x, v, node->AbsPosition.z);
1222  node->Forces += primitiveCollision(node, node->Velocity, node->mass, normal, dt, ogm, v - node->AbsPosition.y);
1223  node->nd_last_collision_gm = ogm;
1224  return true;
1225  }
1226  return false;
1227 }
1228 
1229 Vector3 RoR::primitiveCollision(node_t *node, Ogre::Vector3 velocity, float mass, Ogre::Vector3 normal, float dt, ground_model_t* gm, float penetration)
1230 {
1231  Vector3 force = Vector3::ZERO;
1232  float Vnormal = velocity.dotProduct(normal);
1233  float Fnormal = node->Forces.dotProduct(normal);
1234 
1235  // if we are inside the fluid (solid ground is below us)
1236  if (gm->solid_ground_level != 0.0f && penetration >= 0)
1237  {
1238  float Vsquared = velocity.squaredLength();
1239  // First of all calculate power law fluid viscosity
1240  float m = gm->flow_consistency_index * approx_pow(Vsquared, (gm->flow_behavior_index - 1.0f) * 0.5f);
1241 
1242  // Then calculate drag based on above. We'are using a simplified Stokes' drag.
1243  // Per node fluid drag surface coefficient set by node property applies here
1244  Vector3 Fdrag = velocity * (-m * node->surface_coef);
1245 
1246  // If we have anisotropic drag
1247  if (gm->drag_anisotropy < 1.0f && Vnormal > 0)
1248  {
1249  float da_factor;
1250  if (Vsquared > gm->va * gm->va)
1251  da_factor = 1.0;
1252  else
1253  da_factor = Vsquared / (gm->va * gm->va);
1254  Fdrag += (Vnormal * m * (1.0f - gm->drag_anisotropy) * da_factor) * normal;
1255  }
1256  force += Fdrag;
1257 
1258  // Now calculate upwards force based on a simplified boyancy equation;
1259  // If the fluid is pseudoplastic then boyancy is constrained to only "stopping" a node from going downwards
1260  // Buoyancy per node volume coefficient set by node property applies here
1261  float Fboyancy = gm->fluid_density * penetration * (-DEFAULT_GRAVITY) * node->volume_coef;
1262  if (gm->flow_behavior_index < 1.0f && Vnormal >= 0.0f)
1263  {
1264  if (Fnormal < 0 && Fboyancy>-Fnormal)
1265  {
1266  Fboyancy = -Fnormal;
1267  }
1268  }
1269  force += Fboyancy * normal;
1270  }
1271 
1272  // if we are inside or touching the solid ground
1273  if (penetration >= gm->solid_ground_level)
1274  {
1275  // steady force
1276  float Freaction = -Fnormal;
1277  // impact force
1278  if (Vnormal < 0)
1279  {
1280  float penetration_depth = gm->solid_ground_level - penetration;
1281  Freaction -= (0.8f * Vnormal + 0.2f * penetration_depth / dt) * mass / dt; // Newton's second law
1282  }
1283  if (Freaction > 0)
1284  {
1285  Vector3 slipf = node->Forces - Fnormal * normal;
1286  Vector3 slip = velocity - Vnormal * normal;
1287  float slipv = slip.normalise();
1288  // If the velocity that we slip is lower than adhesion velocity and
1289  // we have a downforce and the slip forces are lower than static friction
1290  // forces then it's time to go into static friction physics mode.
1291  // This code is a direct translation of textbook static friction physics
1292  float Greaction = Freaction * gm->strength * node->friction_coef; //General moderated reaction
1293  float msGreaction = gm->ms * Greaction;
1294  if (slipv < gm->va && Greaction > 0.0f && slipf.squaredLength() <= msGreaction * msGreaction)
1295  {
1296  // Static friction model (with a little smoothing to help the integrator deal with it)
1297  float ff = -msGreaction * (1.0f - approx_exp(-slipv / gm->va));
1298  force += Freaction * normal + ff * slip - slipf;
1299  } else
1300  {
1301  // Stribek model. It also comes directly from textbooks.
1302  float g = gm->mc + (gm->ms - gm->mc) * approx_exp(-approx_pow(slipv / gm->vs, gm->alpha));
1303  float ff = -(g + std::min(gm->t2 * slipv, 5.0f)) * Greaction;
1304  force += Freaction * normal + ff * slip;
1305  }
1306  node->nd_avg_collision_slip = node->nd_avg_collision_slip * 0.995 + slipv * 0.005f;
1307  node->nd_last_collision_slip = slipv * slip;
1308  node->nd_last_collision_force = std::min(-Freaction, 0.0f) * normal;
1309  }
1310  }
1311 
1312  return force;
1313 }
1314 
1315 void Collisions::createCollisionDebugVisualization(Ogre::SceneNode* root_node, Ogre::AxisAlignedBox const& area_limit, std::vector<Ogre::SceneNode*>& out_nodes)
1316 {
1317  LOG("COLL: Creating collision debug visualization ...");
1318 
1319 
1320 
1321  for (int x=0; x<(int)(m_terrain_size.x); x+=(int)CELL_SIZE)
1322  {
1323  for (int z=0; z<(int)(m_terrain_size.z); z+=(int)CELL_SIZE)
1324  {
1325 
1326  if (!area_limit.contains(Ogre::Vector3(x, 0.f, z)))
1327  continue;
1328 
1329  int cellx = (int)(x/(float)CELL_SIZE);
1330  int cellz = (int)(z/(float)CELL_SIZE);
1331  const int hash = hash_find(cellx, cellz);
1332 
1333  bool used = std::find_if(hashtable[hash].begin(), hashtable[hash].end(), [&](hash_coll_element_t const &c) {
1334  return c.cell_id == (cellx << 16) + cellz;
1335  }) != hashtable[hash].end();
1336 
1337  if (used)
1338  {
1339  float groundheight = -9999;
1340  float x2 = x+CELL_SIZE;
1341  float z2 = z+CELL_SIZE;
1342 
1343  // find a good ground height for all corners of the cell ...
1344  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x, z));
1345  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x2, z));
1346  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x, z2));
1347  groundheight = std::max(groundheight, App::GetGameContext()->GetTerrain()->GetHeightAt(x2, z2));
1348  groundheight += 0.1; // 10 cm hover
1349 
1350  float percentd = static_cast<float>(hashtable[hash].size()) / static_cast<float>(CELL_BLOCKSIZE);
1351  if (percentd > 1) percentd = 1;
1352 
1353  // see `RoR::GUI::CollisionsDebug::GenerateCellDebugMaterials()`
1354  String matName = "mat-coll-dbg-"+TOSTRING((int)(percentd*100));
1355  String cell_name="("+TOSTRING(cellx)+","+ TOSTRING(cellz)+")";
1356 
1357  ManualObject *mo = App::GetGfxScene()->GetSceneManager()->createManualObject("collisionDebugVisualization"+cell_name);
1358  SceneNode *mo_node = root_node->createChildSceneNode("collisionDebugVisualization_node"+cell_name);
1359 
1360  mo->begin(matName, Ogre::RenderOperation::OT_TRIANGLE_LIST);
1361 
1362  // 1st tri
1363  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1364  mo->textureCoord(0,0);
1365 
1366  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1367  mo->textureCoord(1,1);
1368 
1369  mo->position(CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1370  mo->textureCoord(1,0);
1371 
1372  // 2nd tri
1373  mo->position(-CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1374  mo->textureCoord(0,1);
1375 
1376  mo->position(CELL_SIZE/(float)2.0, 0, CELL_SIZE/(float)2.0);
1377  mo->textureCoord(1,1);
1378 
1379  mo->position(-CELL_SIZE/(float)2.0, 0, -CELL_SIZE/(float)2.0);
1380  mo->textureCoord(0,0);
1381 
1382  mo->end();
1383  mo->setBoundingBox(AxisAlignedBox(0, 0, 0, CELL_SIZE, 1, CELL_SIZE));
1384  mo->setRenderingDistance(200.f);
1385  mo_node->attachObject(mo);
1386 
1387 #if 0
1388  // setup the label
1389  String labelName = "label_"+cell_name;
1390  String labelCaption = cell_name+" "+TOSTRING(percent*100,2) + "% usage ("+TOSTRING(cc)+"/"+TOSTRING(CELL_BLOCKSIZE)+") DEEP: " + TOSTRING(deep);
1391  MovableText *mt = new MovableText(labelName, labelCaption);
1393  mt->setFontName("CyberbitEnglish");
1394  mt->setAdditionalHeight(1);
1395  mt->setCharacterHeight(0.3);
1396  mt->setColor(ColourValue::White);
1397  mo_node->attachObject(mt);
1398 #endif
1399 
1400  mo_node->setVisible(true);
1401  mo_node->setPosition(Vector3(x+CELL_SIZE/(float)2.0, groundheight, z+CELL_SIZE/(float)2.0));
1402 
1403  out_nodes.push_back(mo_node);
1404  }
1405  }
1406  }
1407 }
1408 
1409 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)
1410 {
1411  Entity *ent = App::GetGfxScene()->GetSceneManager()->createEntity(meshname);
1412  ent->setMaterialName("tracks/debug/collision/mesh");
1413 
1414  if (!gm)
1415  {
1416  gm = getGroundModelByString("concrete");
1417  }
1418 
1419  // Analyze the mesh
1420  size_t vertex_count,index_count;
1421  Vector3* vertices;
1422  unsigned* indices;
1423 
1424  getMeshInformation(ent->getMesh().getPointer(),vertex_count,vertices,index_count,indices, pos, q, scale);
1425 
1426  // Generate collision triangles
1427  int collision_tri_start = (int)m_collision_tris.size();
1428  for (int i=0; i<(int)index_count/3; i++)
1429  {
1430  int triID = addCollisionTri(vertices[indices[i*3]], vertices[indices[i*3+1]], vertices[indices[i*3+2]], gm);
1431  if (collTris)
1432  collTris->push_back(triID);
1433  }
1434 
1435  // Submit the mesh record
1436  collision_mesh_t rec;
1437  rec.mesh_name = meshname;
1438  rec.source_name = srcname;
1439  rec.position = pos;
1440  rec.orientation = q;
1441  rec.scale = scale;
1442  rec.ground_model = gm;
1443  rec.num_verts = vertex_count;
1444  rec.num_indices = index_count;
1445  rec.collision_tri_start = collision_tri_start;
1446  rec.collision_tri_count = (int)m_collision_tris.size() - collision_tri_start;
1447  rec.bounding_box = ent->getMesh()->getBounds();
1448  m_collision_meshes.push_back(rec);
1449 
1450  // Clean up
1451  delete[] vertices;
1452  delete[] indices;
1453  App::GetGfxScene()->GetSceneManager()->destroyEntity(ent);
1454 }
1455 
1456 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)
1457 {
1458  // Submit the mesh record
1459  collision_mesh_t rec;
1460  rec.mesh_name = meshname;
1461  rec.source_name = srcname;
1462  rec.position = pos;
1463  rec.ground_model = gm;
1464  rec.collision_tri_start = ctri_start;
1465  rec.collision_tri_count = ctri_count;
1466  rec.bounding_box = bounding_box;
1467  m_collision_meshes.push_back(rec);
1468 }
1469 
1470 void Collisions::getMeshInformation(Mesh* mesh,size_t &vertex_count,Ogre::Vector3* &vertices,
1471  size_t &index_count, unsigned* &indices, const Ogre::Vector3 &position,
1472  const Ogre::Quaternion &orient, const Ogre::Vector3 &scale)
1473 {
1474  vertex_count = index_count = 0;
1475 
1476  bool added_shared = false;
1477  size_t current_offset = vertex_count;
1478  size_t shared_offset = vertex_count;
1479  size_t next_offset = vertex_count;
1480  size_t index_offset = index_count;
1481  //size_t prev_vert = vertex_count;
1482  //size_t prev_ind = index_count;
1483 
1484  // Calculate how many vertices and indices we're going to need
1485  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1486  {
1487  SubMesh* submesh = mesh->getSubMesh(i);
1488 
1489  // We only need to add the shared vertices once
1490  if (submesh->useSharedVertices)
1491  {
1492  if (!added_shared)
1493  {
1494  VertexData* vertex_data = mesh->sharedVertexData;
1495  vertex_count += vertex_data->vertexCount;
1496  added_shared = true;
1497  }
1498  } else
1499  {
1500  VertexData* vertex_data = submesh->vertexData;
1501  vertex_count += vertex_data->vertexCount;
1502  }
1503 
1504  // Add the indices
1505  Ogre::IndexData* index_data = submesh->indexData;
1506  index_count += index_data->indexCount;
1507  }
1508 
1509  // Allocate space for the vertices and indices
1510  vertices = new Vector3[vertex_count];
1511  indices = new unsigned[index_count];
1512 
1513  added_shared = false;
1514 
1515  // Run through the sub-meshes again, adding the data into the arrays
1516  for (int i = 0;i < mesh->getNumSubMeshes();i++)
1517  {
1518  SubMesh* submesh = mesh->getSubMesh(i);
1519 
1520  Ogre::VertexData* vertex_data = submesh->useSharedVertices ? mesh->sharedVertexData : submesh->vertexData;
1521  if ((!submesh->useSharedVertices)||(submesh->useSharedVertices && !added_shared))
1522  {
1523  if (submesh->useSharedVertices)
1524  {
1525  added_shared = true;
1526  shared_offset = current_offset;
1527  }
1528 
1529  const Ogre::VertexElement* posElem = vertex_data->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION);
1530  Ogre::HardwareVertexBufferSharedPtr vbuf = vertex_data->vertexBufferBinding->getBuffer(posElem->getSource());
1531  unsigned char* vertex = static_cast<unsigned char*>(vbuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1532  Ogre::Real* pReal;
1533 
1534  for (size_t j = 0; j < vertex_data->vertexCount; ++j, vertex += vbuf->getVertexSize())
1535  {
1536  posElem->baseVertexPointerToElement(vertex, &pReal);
1537 
1538  Vector3 pt;
1539 
1540  pt.x = (*pReal++);
1541  pt.y = (*pReal++);
1542  pt.z = (*pReal++);
1543 
1544  pt = (orient * (pt * scale)) + position;
1545 
1546  vertices[current_offset + j].x = pt.x;
1547  vertices[current_offset + j].y = pt.y;
1548  vertices[current_offset + j].z = pt.z;
1549  }
1550  vbuf->unlock();
1551  next_offset += vertex_data->vertexCount;
1552  }
1553 
1554  Ogre::IndexData* index_data = submesh->indexData;
1555 
1556  size_t numTris = index_data->indexCount / 3;
1557  unsigned short* pShort = 0;
1558  unsigned int* pInt = 0;
1559  Ogre::HardwareIndexBufferSharedPtr ibuf = index_data->indexBuffer;
1560 
1561  bool use32bitindexes = (ibuf->getType() == Ogre::HardwareIndexBuffer::IT_32BIT);
1562 
1563  if (use32bitindexes)
1564  pInt = static_cast<unsigned int*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1565  else
1566  pShort = static_cast<unsigned short*>(ibuf->lock(Ogre::HardwareBuffer::HBL_READ_ONLY));
1567 
1568  for (size_t k = 0; k < numTris; ++k)
1569  {
1570  size_t offset = (submesh->useSharedVertices)?shared_offset:current_offset;
1571 
1572  unsigned int vindex = use32bitindexes? *pInt++ : *pShort++;
1573  indices[index_offset + 0] = vindex + (unsigned int)offset;
1574  vindex = use32bitindexes? *pInt++ : *pShort++;
1575  indices[index_offset + 1] = vindex + (unsigned int)offset;
1576  vindex = use32bitindexes? *pInt++ : *pShort++;
1577  indices[index_offset + 2] = vindex + (unsigned int)offset;
1578 
1579  index_offset += 3;
1580  }
1581  ibuf->unlock();
1582  current_offset = next_offset;
1583  }
1584 }
1585 
1587 {
1588 }
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:760
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 Former name: Beam (that's why scrip...
Definition: Actor.h:47
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:1229
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:306
RoR::ground_model_t::strength
float strength
ground strength
Definition: SimData.h:749
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:104
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:334
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:337
RoR::ground_model_t::va
float va
adhesion velocity
Definition: SimData.h:743
RoR::collision_tri_t::reverse
Ogre::Matrix3 reverse
Definition: Collisions.h:57
RoR::EVENT_AIRPLANE
@ EVENT_AIRPLANE
Definition: SimData.h:51
RoR::node_t::AbsPosition
Ogre::Vector3 AbsPosition
absolute position in the world (shaky)
Definition: SimData.h:305
RoR::collision_tri_t
Definition: Collisions.h:50
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:718
RoR::collision_box_t::enabled
bool enabled
Definition: SimData.h:722
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
Definition: SimData.h:45
RoR::node_t::surface_coef
Ogre::Real surface_coef
Definition: SimData.h:312
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:725
RoR::Collisions::groundCollision
bool groundCollision(node_t *node, float dt)
Definition: Collisions.cpp:1213
RoR::Collisions::clearEventCache
void clearEventCache()
Definition: Collisions.h:201
RoR::Collisions::findPotentialEventBoxes
void findPotentialEventBoxes(Actor *actor, CollisionBoxPtrVec &out_boxes)
Definition: Collisions.cpp:1089
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:724
RoR::collision_box_t::hi
Ogre::Vector3 hi
absolute collision box
Definition: SimData.h:726
RoR::Collisions::getPosition
Ogre::Vector3 getPosition(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1134
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
Definition: SimData.h:52
RoR::CollisionBoxPtrVec
std::vector< collision_box_t * > CollisionBoxPtrVec
Definition: SimData.h:738
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
Definition: SimData.h:49
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:1456
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:1409
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:748
RoR::collision_box_t::selfrotated
bool selfrotated
Definition: SimData.h:720
RoR::Collisions::hashtable_height
std::array< float, HASH_SIZE > hashtable_height
Definition: Collisions.h:142
Language.h
RoR::collision_box_t
Definition: SimData.h:716
RoR::collision_box_t::unrot
Ogre::Quaternion unrot
rotation
Definition: SimData.h:729
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
Definition: SimData.h:50
RoR::Collisions::removeCollisionTri
void removeCollisionTri(int number)
Definition: Collisions.cpp:356
RoR::ground_model_t::mc
float mc
sliding friction coefficient
Definition: SimData.h:745
ActorManager.h
Actor.h
RoR::collision_box_t::center
Ogre::Vector3 center
center of rotation
Definition: SimData.h:727
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:747
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:525
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:530
RoR::Collisions::loadGroundModelsConfigFile
int loadGroundModelsConfigFile(Ogre::String filename)
Definition: Collisions.cpp:150
RoR::collision_box_t::event_filter
CollisionEventFilter event_filter
Definition: SimData.h:723
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:734
RoR::EVENT_DELETE
@ EVENT_DELETE
Definition: SimData.h:53
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:730
RoR::Collisions::getBox
collision_box_t * getBox(const Ogre::String &inst, const Ogre::String &box)
Definition: Collisions.cpp:1158
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:733
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:315
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:719
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:336
RoR::node_t
Physics: A vertex in the softbody structure.
Definition: SimData.h:297
RoR::App::GetGameContext
GameContext * GetGameContext()
Definition: Application.cpp:280
RoR::collision_box_t::camforced
bool camforced
Definition: SimData.h:721
RoR::ground_model_t::name
char name[256]
Definition: SimData.h:765
RoR::node_t::friction_coef
Ogre::Real friction_coef
Definition: SimData.h:311
RoR::AIRPLANE
@ AIRPLANE
its an airplane
Definition: SimData.h:105
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:735
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:746
RoR::node_t::nd_last_collision_slip
Ogre::Vector3 nd_last_collision_slip
Physics state; last collision slip vector.
Definition: SimData.h:335
ApproxMath.h
RoR::ground_model_t::ms
float ms
static friction coefficient
Definition: SimData.h:744
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:731
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:927
RoR::node_t::volume_coef
Ogre::Real volume_coef
Definition: SimData.h:313
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:1470
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:1315
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:757
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:369
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:728
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:751
RoR::collision_box_t::selfunrot
Ogre::Quaternion selfunrot
self rotation
Definition: SimData.h:732
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:1146
RoR::ground_model_t
Surface friction properties.
Definition: SimData.h:741
RoR::ground_model_t::drag_anisotropy
float drag_anisotropy
Upwards/Downwards drag anisotropy.
Definition: SimData.h:761
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:1170
RoR::EVENT_ALL
@ EVENT_ALL
Definition: SimData.h:48
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:736
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:752
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:1586
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:309
RoR::BOAT
@ BOAT
its a boat
Definition: SimData.h:106
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:299
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:307
RoR::Collisions::~Collisions
~Collisions()
Definition: Collisions.cpp:140