OdePlugin.cs 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. *
  27. */
  28. using System;
  29. using System.Collections.Generic;
  30. using System.Runtime.InteropServices;
  31. using Axiom.Math;
  32. using Ode.NET;
  33. using OpenSim.Framework;
  34. using OpenSim.Framework.Console;
  35. using OpenSim.Region.Physics.Manager;
  36. //using OpenSim.Region.Physics.OdePlugin.Meshing;
  37. namespace OpenSim.Region.Physics.OdePlugin
  38. {
  39. /// <summary>
  40. /// ODE plugin
  41. /// </summary>
  42. public class OdePlugin : IPhysicsPlugin
  43. {
  44. private OdeScene _mScene;
  45. public OdePlugin()
  46. {
  47. }
  48. public bool Init()
  49. {
  50. return true;
  51. }
  52. public PhysicsScene GetScene()
  53. {
  54. if (_mScene == null)
  55. {
  56. _mScene = new OdeScene();
  57. }
  58. return (_mScene);
  59. }
  60. public string GetName()
  61. {
  62. return ("OpenDynamicsEngine");
  63. }
  64. public void Dispose()
  65. {
  66. }
  67. }
  68. public class OdeScene : PhysicsScene
  69. {
  70. // TODO: this should be hard-coded in some common place
  71. private const uint m_regionWidth = 256;
  72. private const uint m_regionHeight = 256;
  73. private static float ODE_STEPSIZE = 0.004f;
  74. private static bool RENDER_FLAG = false;
  75. private static float metersInSpace = 29.9f;
  76. private IntPtr contactgroup;
  77. private IntPtr LandGeom = (IntPtr) 0;
  78. private double[] _heightmap;
  79. private GCHandle gchHeightMap; // rex
  80. private d.NearCallback nearCallback;
  81. public d.TriCallback triCallback;
  82. public d.TriArrayCallback triArrayCallback;
  83. private List<OdeCharacter> _characters = new List<OdeCharacter>();
  84. private List<OdePrim> _prims = new List<OdePrim>();
  85. private List<OdePrim> _activeprims = new List<OdePrim>();
  86. private List<OdePrim> _taintedPrim = new List<OdePrim>();
  87. public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
  88. public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
  89. private d.ContactGeom[] contacts = new d.ContactGeom[30];
  90. private d.Contact contact;
  91. private d.Contact TerrainContact;
  92. private d.Contact AvatarMovementprimContact;
  93. private d.Contact AvatarMovementTerrainContact;
  94. private int m_physicsiterations = 10;
  95. private float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
  96. private PhysicsActor PANull = new NullPhysicsActor();
  97. private float step_time = 0.0f;
  98. public IntPtr world;
  99. public IntPtr space;
  100. // split static geometry collision handling into spaces of 30 meters
  101. public IntPtr[,] staticPrimspace = new IntPtr[(int) (300/metersInSpace),(int) (300/metersInSpace)];
  102. public static Object OdeLock = new Object();
  103. public IMesher mesher;
  104. public OdeScene()
  105. {
  106. nearCallback = near;
  107. triCallback = TriCallback;
  108. triArrayCallback = TriArrayCallback;
  109. /*
  110. contact.surface.mode |= d.ContactFlags.Approx1 | d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP;
  111. contact.surface.mu = 10.0f;
  112. contact.surface.bounce = 0.9f;
  113. contact.surface.soft_erp = 0.005f;
  114. contact.surface.soft_cfm = 0.00003f;
  115. */
  116. contact.surface.mu = 250.0f;
  117. contact.surface.bounce = 0.2f;
  118. TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  119. TerrainContact.surface.mu = 550.0f;
  120. TerrainContact.surface.bounce = 0.1f;
  121. TerrainContact.surface.soft_erp = 0.1025f;
  122. AvatarMovementprimContact.surface.mu = 150.0f;
  123. AvatarMovementprimContact.surface.bounce = 0.1f;
  124. AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  125. AvatarMovementTerrainContact.surface.mu = 150.0f;
  126. AvatarMovementTerrainContact.surface.bounce = 0.1f;
  127. AvatarMovementTerrainContact.surface.soft_erp = 0.1025f;
  128. lock (OdeLock)
  129. {
  130. world = d.WorldCreate();
  131. space = d.HashSpaceCreate(IntPtr.Zero);
  132. d.HashSpaceSetLevels(space, -4, 128);
  133. contactgroup = d.JointGroupCreate(0);
  134. //contactgroup
  135. d.WorldSetGravity(world, 0.0f, 0.0f, -10.0f);
  136. d.WorldSetAutoDisableFlag(world, false);
  137. d.WorldSetContactSurfaceLayer(world, 0.001f);
  138. d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
  139. d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
  140. }
  141. _heightmap = new double[514*514];
  142. gchHeightMap = GCHandle.Alloc(_heightmap, GCHandleType.Pinned); // rex
  143. for (int i = 0; i < staticPrimspace.GetLength(0); i++)
  144. {
  145. for (int j = 0; j < staticPrimspace.GetLength(1); j++)
  146. {
  147. staticPrimspace[i, j] = IntPtr.Zero;
  148. }
  149. }
  150. }
  151. public override void Initialise(IMesher meshmerizer)
  152. {
  153. mesher = meshmerizer;
  154. }
  155. public string whichspaceamIin(PhysicsVector pos)
  156. {
  157. return calculateSpaceForGeom(pos).ToString();
  158. }
  159. private void near(IntPtr space, IntPtr g1, IntPtr g2)
  160. {
  161. // no lock here! It's invoked from within Simulate(), which is thread-locked
  162. if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
  163. {
  164. // Separating static prim geometry spaces.
  165. // We'll be calling near recursivly if one
  166. // of them is a space to find all of the
  167. // contact points in the space
  168. d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
  169. //Colliding a space or a geom with a space or a geom.
  170. //Collide all geoms in each space..
  171. //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
  172. //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
  173. }
  174. else
  175. {
  176. // Colliding Geom To Geom
  177. // This portion of the function 'was' blatantly ripped off from BoxStack.cs
  178. IntPtr b1 = d.GeomGetBody(g1);
  179. IntPtr b2 = d.GeomGetBody(g2);
  180. if (g1 == g2)
  181. return; // Can't collide with yourself
  182. if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
  183. return;
  184. d.GeomClassID id = d.GeomGetClass(g1);
  185. String name1 = null;
  186. String name2 = null;
  187. if (!geom_name_map.TryGetValue(g1, out name1))
  188. {
  189. name1 = "null";
  190. }
  191. if (!geom_name_map.TryGetValue(g2, out name2))
  192. {
  193. name2 = "null";
  194. }
  195. if (id == d.GeomClassID.TriMeshClass)
  196. {
  197. // MainLog.Instance.Verbose("near: A collision was detected between {1} and {2}", 0, name1, name2);
  198. //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2);
  199. }
  200. int count = 0;
  201. try
  202. {
  203. count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
  204. }
  205. catch (SEHException)
  206. {
  207. MainLog.Instance.Error("PHYSICS",
  208. "The Operating system shut down ODE because of corrupt memory. This could be a result of really irregular terrain. If this repeats continuously, restart using Basic Physics and terrain fill your terrain. Restarting the sim.");
  209. base.TriggerPhysicsBasedRestart();
  210. }
  211. for (int i = 0; i < count; i++)
  212. {
  213. IntPtr joint;
  214. // If we're colliding with terrain, use 'TerrainContact' instead of contact.
  215. // allows us to have different settings
  216. PhysicsActor p1;
  217. PhysicsActor p2;
  218. if (!actor_name_map.TryGetValue(g1, out p1))
  219. {
  220. p1 = PANull;
  221. }
  222. if (!actor_name_map.TryGetValue(g2, out p2))
  223. {
  224. p2 = PANull;
  225. }
  226. // We only need to test p2 for 'jump crouch purposes'
  227. p2.IsColliding = true;
  228. switch (p1.PhysicsActorType)
  229. {
  230. case (int) ActorTypes.Agent:
  231. p2.CollidingObj = true;
  232. break;
  233. case (int) ActorTypes.Prim:
  234. if (p2.Velocity.X > 0 || p2.Velocity.Y > 0 || p2.Velocity.Z > 0)
  235. p2.CollidingObj = true;
  236. break;
  237. case (int) ActorTypes.Unknown:
  238. p2.CollidingGround = true;
  239. break;
  240. case (int)ActorTypes.PrimVolume: // rex, added primvolume
  241. if (Util.UnixTimeSinceEpoch() > p2.NextPrimVolumeTime)
  242. {
  243. p2.NextPrimVolumeTime = Util.UnixTimeSinceEpoch() + 1;
  244. p1.SendCollisionUpdate(new CollisionEventUpdate(p2.m_localID,0,true,null));
  245. }
  246. return;
  247. default:
  248. p2.CollidingGround = true;
  249. break;
  250. }
  251. // we don't want prim or avatar to explode
  252. #region InterPenetration Handling - Unintended physics explosions
  253. if (contacts[i].depth >= 0.08f)
  254. {
  255. if (contacts[i].depth >= 1.00f)
  256. {
  257. //MainLog.Instance.Debug("PHYSICS",contacts[i].depth.ToString());
  258. }
  259. // If you interpenetrate a prim with an agent
  260. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  261. p1.PhysicsActorType == (int) ActorTypes.Prim) ||
  262. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  263. p2.PhysicsActorType == (int) ActorTypes.Prim))
  264. {
  265. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  266. {
  267. //p2.CollidingObj = true;
  268. //contacts[i].depth = 0.003f;
  269. //p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
  270. //OdeCharacter character = (OdeCharacter) p2;
  271. //character.SetPidStatus(true);
  272. //contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p1.Size.X / 2), contacts[i].pos.Y + (p1.Size.Y / 2), contacts[i].pos.Z + (p1.Size.Z / 2));
  273. }
  274. else
  275. {
  276. //contacts[i].depth = 0.0000000f;
  277. }
  278. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  279. {
  280. //p1.CollidingObj = true;
  281. //contacts[i].depth = 0.003f;
  282. //p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
  283. //contacts[i].pos = new d.Vector3(contacts[i].pos.X + (p2.Size.X / 2), contacts[i].pos.Y + (p2.Size.Y / 2), contacts[i].pos.Z + (p2.Size.Z / 2));
  284. //OdeCharacter character = (OdeCharacter)p1;
  285. //character.SetPidStatus(true);
  286. }
  287. else
  288. {
  289. //contacts[i].depth = 0.0000000f;
  290. }
  291. }
  292. // If you interpenetrate a prim with another prim
  293. if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
  294. {
  295. // Don't collide, one or both prim will explode.
  296. contacts[i].depth = 0f;
  297. }
  298. if (contacts[i].depth >= 1.00f)
  299. {
  300. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  301. p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
  302. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  303. p2.PhysicsActorType == (int) ActorTypes.Unknown))
  304. {
  305. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  306. {
  307. OdeCharacter character = (OdeCharacter) p2;
  308. //p2.CollidingObj = true;
  309. contacts[i].depth = 0.003f;
  310. p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 0.5f);
  311. contacts[i].pos =
  312. new d.Vector3(contacts[i].pos.X + (p1.Size.X/2),
  313. contacts[i].pos.Y + (p1.Size.Y/2),
  314. contacts[i].pos.Z + (p1.Size.Z/2));
  315. character.SetPidStatus(true);
  316. }
  317. else
  318. {
  319. }
  320. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  321. {
  322. OdeCharacter character = (OdeCharacter)p1;
  323. //p2.CollidingObj = true;
  324. contacts[i].depth = 0.003f;
  325. p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 0.5f);
  326. contacts[i].pos =
  327. new d.Vector3(contacts[i].pos.X + (p1.Size.X/2),
  328. contacts[i].pos.Y + (p1.Size.Y/2),
  329. contacts[i].pos.Z + (p1.Size.Z/2));
  330. character.SetPidStatus(true);
  331. }
  332. else
  333. {
  334. //contacts[i].depth = 0.0000000f;
  335. }
  336. }
  337. }
  338. }
  339. #endregion
  340. if (contacts[i].depth >= 0f)
  341. {
  342. if (name1 == "Terrain" || name2 == "Terrain")
  343. {
  344. if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
  345. (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
  346. {
  347. AvatarMovementTerrainContact.geom = contacts[i];
  348. joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
  349. }
  350. else
  351. {
  352. TerrainContact.geom = contacts[i];
  353. joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
  354. }
  355. }
  356. else
  357. {
  358. if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
  359. (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
  360. {
  361. AvatarMovementprimContact.geom = contacts[i];
  362. joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
  363. }
  364. else
  365. {
  366. contact.geom = contacts[i];
  367. joint = d.JointCreateContact(world, contactgroup, ref contact);
  368. }
  369. }
  370. d.JointAttach(joint, b1, b2);
  371. }
  372. if (count > 3)
  373. {
  374. p2.ThrottleUpdates = true;
  375. }
  376. //System.Console.WriteLine(count.ToString());
  377. //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2);
  378. }
  379. }
  380. }
  381. private void collision_optimized(float timeStep)
  382. {
  383. foreach (OdeCharacter chr in _characters)
  384. {
  385. chr.IsColliding = false;
  386. chr.CollidingGround = false;
  387. chr.CollidingObj = false;
  388. d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
  389. }
  390. // If the sim is running slow this frame,
  391. // don't process collision for prim!
  392. if (timeStep < (m_SkipFramesAtms/3))
  393. {
  394. foreach (OdePrim chr in _activeprims)
  395. {
  396. // This if may not need to be there.. it might be skipped anyway.
  397. if (d.BodyIsEnabled(chr.Body))
  398. {
  399. d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
  400. //foreach (OdePrim ch2 in _prims)
  401. /// should be a separate space -- lots of avatars will be N**2 slow
  402. //{
  403. //if (ch2.IsPhysical && d.BodyIsEnabled(ch2.Body))
  404. //{
  405. // Only test prim that are 0.03 meters away in one direction.
  406. // This should be Optimized!
  407. //if ((Math.Abs(ch2.Position.X - chr.Position.X) < 0.03) || (Math.Abs(ch2.Position.Y - chr.Position.Y) < 0.03) || (Math.Abs(ch2.Position.X - chr.Position.X) < 0.03))
  408. //{
  409. //d.SpaceCollide2(chr.prim_geom, ch2.prim_geom, IntPtr.Zero, nearCallback);
  410. //}
  411. //}
  412. //}
  413. }
  414. }
  415. }
  416. else
  417. {
  418. // Everything is going slow, so we're skipping object to object collisions
  419. // At least collide test against the ground.
  420. foreach (OdePrim chr in _activeprims)
  421. {
  422. // This if may not need to be there.. it might be skipped anyway.
  423. if (d.BodyIsEnabled(chr.Body))
  424. {
  425. d.SpaceCollide2(LandGeom, chr.prim_geom, IntPtr.Zero, nearCallback);
  426. }
  427. }
  428. }
  429. }
  430. public override PhysicsActor AddAvatar(string avName, PhysicsVector position, uint localID) // rex, localid
  431. {
  432. PhysicsVector pos = new PhysicsVector();
  433. pos.X = position.X;
  434. pos.Y = position.Y;
  435. pos.Z = position.Z;
  436. OdeCharacter newAv = new OdeCharacter(avName, this, pos, localID); // rex, localid
  437. _characters.Add(newAv);
  438. return newAv;
  439. }
  440. public override void RemoveAvatar(PhysicsActor actor)
  441. {
  442. lock (OdeLock)
  443. {
  444. ((OdeCharacter) actor).Destroy();
  445. _characters.Remove((OdeCharacter) actor);
  446. }
  447. }
  448. public override void RemovePrim(PhysicsActor prim)
  449. {
  450. if (prim is OdePrim)
  451. {
  452. lock (OdeLock)
  453. {
  454. OdePrim p = (OdePrim) prim;
  455. p.setPrimForRemoval();
  456. AddPhysicsActorTaint(prim);
  457. }
  458. }
  459. }
  460. public void RemovePrimThreadLocked(OdePrim prim)
  461. {
  462. lock (OdeLock)
  463. {
  464. if (prim.IsPhysical)
  465. {
  466. prim.disableBody();
  467. }
  468. // we don't want to remove the main space
  469. if (prim.m_targetSpace != space && prim.IsPhysical == false)
  470. {
  471. // If the geometry is in the targetspace, remove it from the target space
  472. if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
  473. {
  474. if (!(prim.m_targetSpace.Equals(null)))
  475. {
  476. if (d.GeomIsSpace(prim.m_targetSpace))
  477. {
  478. d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
  479. }
  480. else
  481. {
  482. MainLog.Instance.Verbose("Physics",
  483. "Invalid Scene passed to 'removeprim from scene':" +
  484. ((OdePrim) prim).m_targetSpace.ToString());
  485. }
  486. }
  487. }
  488. //If there are no more geometries in the sub-space, we don't need it in the main space anymore
  489. if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
  490. {
  491. if (!(prim.m_targetSpace.Equals(null)))
  492. {
  493. if (d.GeomIsSpace(prim.m_targetSpace))
  494. {
  495. d.SpaceRemove(space, prim.m_targetSpace);
  496. // free up memory used by the space.
  497. d.SpaceDestroy(prim.m_targetSpace);
  498. int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
  499. resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
  500. }
  501. else
  502. {
  503. MainLog.Instance.Verbose("Physics",
  504. "Invalid Scene passed to 'removeprim from scene':" +
  505. ((OdePrim) prim).m_targetSpace.ToString());
  506. }
  507. }
  508. }
  509. }
  510. d.GeomDestroy(prim.prim_geom);
  511. _prims.Remove(prim);
  512. }
  513. }
  514. public void resetSpaceArrayItemToZero(IntPtr space)
  515. {
  516. for (int x = 0; x < staticPrimspace.GetLength(0); x++)
  517. {
  518. for (int y = 0; y < staticPrimspace.GetLength(1); y++)
  519. {
  520. if (staticPrimspace[x, y] == space)
  521. staticPrimspace[x, y] = IntPtr.Zero;
  522. }
  523. }
  524. }
  525. public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
  526. {
  527. staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
  528. }
  529. public IntPtr recalculateSpaceForGeom(IntPtr geom, PhysicsVector pos, IntPtr currentspace)
  530. {
  531. //Todo recalculate space the prim is in.
  532. // Called from setting the Position and Size of an ODEPrim so
  533. // it's already in locked space.
  534. // we don't want to remove the main space
  535. // we don't need to test physical here because this function should
  536. // never be called if the prim is physical(active)
  537. if (currentspace != space)
  538. {
  539. if (d.SpaceQuery(currentspace, geom) && currentspace != (IntPtr) 0)
  540. {
  541. if (d.GeomIsSpace(currentspace))
  542. {
  543. d.SpaceRemove(currentspace, geom);
  544. }
  545. else
  546. {
  547. MainLog.Instance.Verbose("Physics",
  548. "Invalid Scene passed to 'recalculatespace':" + currentspace.ToString() +
  549. " Geom:" + geom.ToString());
  550. }
  551. }
  552. else
  553. {
  554. IntPtr sGeomIsIn = d.GeomGetSpace(geom);
  555. if (!(sGeomIsIn.Equals(null)))
  556. {
  557. if (sGeomIsIn != (IntPtr) 0)
  558. {
  559. if (d.GeomIsSpace(currentspace))
  560. {
  561. d.SpaceRemove(sGeomIsIn, geom);
  562. }
  563. else
  564. {
  565. MainLog.Instance.Verbose("Physics",
  566. "Invalid Scene passed to 'recalculatespace':" +
  567. sGeomIsIn.ToString() + " Geom:" + geom.ToString());
  568. }
  569. }
  570. }
  571. }
  572. //If there are no more geometries in the sub-space, we don't need it in the main space anymore
  573. if (d.SpaceGetNumGeoms(currentspace) == 0)
  574. {
  575. if (currentspace != (IntPtr) 0)
  576. {
  577. if (d.GeomIsSpace(currentspace))
  578. {
  579. d.SpaceRemove(space, currentspace);
  580. // free up memory used by the space.
  581. d.SpaceDestroy(currentspace);
  582. resetSpaceArrayItemToZero(currentspace);
  583. }
  584. else
  585. {
  586. MainLog.Instance.Verbose("Physics",
  587. "Invalid Scene passed to 'recalculatespace':" +
  588. currentspace.ToString() + " Geom:" + geom.ToString());
  589. }
  590. }
  591. }
  592. }
  593. else
  594. {
  595. // this is a physical object that got disabled. ;.;
  596. if (d.SpaceQuery(currentspace, geom))
  597. {
  598. if (currentspace != (IntPtr) 0)
  599. if (d.GeomIsSpace(currentspace))
  600. {
  601. d.SpaceRemove(currentspace, geom);
  602. }
  603. else
  604. {
  605. MainLog.Instance.Verbose("Physics",
  606. "Invalid Scene passed to 'recalculatespace':" +
  607. currentspace.ToString() + " Geom:" + geom.ToString());
  608. }
  609. }
  610. else
  611. {
  612. IntPtr sGeomIsIn = d.GeomGetSpace(geom);
  613. if (!(sGeomIsIn.Equals(null)))
  614. {
  615. if (sGeomIsIn != (IntPtr) 0)
  616. {
  617. if (d.GeomIsSpace(sGeomIsIn))
  618. {
  619. d.SpaceRemove(sGeomIsIn, geom);
  620. }
  621. else
  622. {
  623. MainLog.Instance.Verbose("Physics",
  624. "Invalid Scene passed to 'recalculatespace':" +
  625. sGeomIsIn.ToString() + " Geom:" + geom.ToString());
  626. }
  627. }
  628. }
  629. }
  630. }
  631. // The routines in the Position and Size sections do the 'inserting' into the space,
  632. // so all we have to do is make sure that the space that we're putting the prim into
  633. // is in the 'main' space.
  634. int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
  635. IntPtr newspace = calculateSpaceForGeom(pos);
  636. if (newspace == IntPtr.Zero)
  637. {
  638. newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
  639. d.HashSpaceSetLevels(newspace, -4, 66);
  640. }
  641. return newspace;
  642. }
  643. public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
  644. {
  645. // creating a new space for prim and inserting it into main space.
  646. staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
  647. d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
  648. return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
  649. }
  650. public IntPtr calculateSpaceForGeom(PhysicsVector pos)
  651. {
  652. int[] xyspace = calculateSpaceArrayItemFromPos(pos);
  653. //MainLog.Instance.Verbose("Physics", "Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
  654. IntPtr locationbasedspace = staticPrimspace[xyspace[0], xyspace[1]];
  655. //locationbasedspace = space;
  656. return locationbasedspace;
  657. }
  658. public int[] calculateSpaceArrayItemFromPos(PhysicsVector pos)
  659. {
  660. int[] returnint = new int[2];
  661. returnint[0] = (int) (pos.X/metersInSpace);
  662. if (returnint[0] > ((int) (259f/metersInSpace)))
  663. returnint[0] = ((int) (259f/metersInSpace));
  664. if (returnint[0] < 0)
  665. returnint[0] = 0;
  666. returnint[1] = (int) (pos.Y/metersInSpace);
  667. if (returnint[0] > ((int) (259f/metersInSpace)))
  668. returnint[0] = ((int) (259f/metersInSpace));
  669. if (returnint[0] < 0)
  670. returnint[0] = 0;
  671. return returnint;
  672. }
  673. private PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, Quaternion rotation,
  674. IMesh mesh, PrimitiveBaseShape pbs, bool isphysical, uint localID) // rex, localid
  675. {
  676. PhysicsVector pos = new PhysicsVector();
  677. pos.X = position.X;
  678. pos.Y = position.Y;
  679. pos.Z = position.Z;
  680. PhysicsVector siz = new PhysicsVector();
  681. siz.X = size.X;
  682. siz.Y = size.Y;
  683. siz.Z = size.Z;
  684. Quaternion rot = new Quaternion();
  685. rot.w = rotation.w;
  686. rot.x = rotation.x;
  687. rot.y = rotation.y;
  688. rot.z = rotation.z;
  689. int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
  690. IntPtr targetspace = calculateSpaceForGeom(pos);
  691. if (targetspace == IntPtr.Zero)
  692. targetspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
  693. OdePrim newPrim;
  694. lock (OdeLock)
  695. {
  696. newPrim = new OdePrim(name, this, targetspace, pos, siz, rot, mesh, pbs, isphysical, localID); // rex, localid
  697. _prims.Add(newPrim);
  698. }
  699. return newPrim;
  700. }
  701. public void addActivePrim(OdePrim activatePrim)
  702. {
  703. // adds active prim.. (ones that should be iterated over in collisions_optimized
  704. _activeprims.Add(activatePrim);
  705. }
  706. public void remActivePrim(OdePrim deactivatePrim)
  707. {
  708. _activeprims.Remove(deactivatePrim);
  709. }
  710. public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
  711. {
  712. /* String name1 = null;
  713. String name2 = null;
  714. if (!geom_name_map.TryGetValue(trimesh, out name1))
  715. {
  716. name1 = "null";
  717. }
  718. if (!geom_name_map.TryGetValue(refObject, out name2))
  719. {
  720. name2 = "null";
  721. }
  722. MainLog.Instance.Verbose("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
  723. */
  724. return 1;
  725. }
  726. public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
  727. {
  728. String name1 = null;
  729. String name2 = null;
  730. if (!geom_name_map.TryGetValue(trimesh, out name1))
  731. {
  732. name1 = "null";
  733. }
  734. if (!geom_name_map.TryGetValue(refObject, out name2))
  735. {
  736. name2 = "null";
  737. }
  738. // MainLog.Instance.Verbose("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
  739. d.Vector3 v0 = new d.Vector3();
  740. d.Vector3 v1 = new d.Vector3();
  741. d.Vector3 v2 = new d.Vector3();
  742. d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
  743. // MainLog.Instance.Debug("Triangle {0} is <{1},{2},{3}>, <{4},{5},{6}>, <{7},{8},{9}>", triangleIndex, v0.X, v0.Y, v0.Z, v1.X, v1.Y, v1.Z, v2.X, v2.Y, v2.Z);
  744. return 1;
  745. }
  746. public bool needsMeshing(PrimitiveBaseShape pbs)
  747. {
  748. if (pbs.ProfileHollow != 0)
  749. return true;
  750. if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
  751. return true;
  752. return false;
  753. }
  754. public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
  755. PhysicsVector size, Quaternion rotation, uint localID) //To be removed rex, localid
  756. {
  757. return AddPrimShape(primName, pbs, position, size, rotation, false,localID);
  758. }
  759. public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
  760. PhysicsVector size, Quaternion rotation, bool isPhysical, uint localID) // rex, localid
  761. {
  762. PhysicsActor result;
  763. IMesh mesh = null;
  764. switch (pbs.ProfileShape)
  765. {
  766. case ProfileShape.Square:
  767. /// support simple box & hollow box now; later, more shapes
  768. if (needsMeshing(pbs))
  769. {
  770. mesh = mesher.CreateMesh(primName, pbs, size);
  771. }
  772. break;
  773. }
  774. result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical, localID); // rex, localid
  775. return result;
  776. }
  777. public override void AddPhysicsActorTaint(PhysicsActor prim)
  778. {
  779. if (prim is OdePrim)
  780. {
  781. OdePrim taintedprim = ((OdePrim) prim);
  782. if (!(_taintedPrim.Contains(taintedprim)))
  783. _taintedPrim.Add(taintedprim);
  784. }
  785. }
  786. public override float Simulate(float timeStep)
  787. {
  788. float fps = 0;
  789. step_time += timeStep;
  790. // If We're loaded down by something else,
  791. // or debugging with the Visual Studio project on pause
  792. // skip a few frames to catch up gracefully.
  793. // without shooting the physicsactors all over the place
  794. if (step_time >= m_SkipFramesAtms)
  795. {
  796. // Instead of trying to catch up, it'll do one physics frame only
  797. step_time = ODE_STEPSIZE;
  798. m_physicsiterations = 5;
  799. }
  800. else
  801. {
  802. m_physicsiterations = 10;
  803. }
  804. lock (OdeLock)
  805. {
  806. // Process 10 frames if the sim is running normal..
  807. // process 5 frames if the sim is running slow
  808. try
  809. {
  810. d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
  811. }
  812. catch (StackOverflowException)
  813. {
  814. MainLog.Instance.Error("PHYSICS",
  815. "The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
  816. base.TriggerPhysicsBasedRestart();
  817. }
  818. int i = 0;
  819. // Figure out the Frames Per Second we're going at.
  820. fps = (((step_time/ODE_STEPSIZE*m_physicsiterations)*2)*10);
  821. while (step_time > 0.0f)
  822. {
  823. foreach (OdeCharacter actor in _characters)
  824. {
  825. actor.Move(timeStep);
  826. actor.collidelock = true;
  827. }
  828. collision_optimized(timeStep);
  829. d.WorldQuickStep(world, ODE_STEPSIZE);
  830. d.JointGroupEmpty(contactgroup);
  831. foreach (OdeCharacter actor in _characters)
  832. {
  833. actor.collidelock = false;
  834. }
  835. step_time -= ODE_STEPSIZE;
  836. i++;
  837. }
  838. foreach (OdeCharacter actor in _characters)
  839. {
  840. actor.UpdatePositionAndVelocity();
  841. }
  842. bool processedtaints = false;
  843. foreach (OdePrim prim in _taintedPrim)
  844. {
  845. prim.ProcessTaints(timeStep);
  846. if (prim.m_taintremove)
  847. {
  848. RemovePrimThreadLocked(prim);
  849. }
  850. processedtaints = true;
  851. }
  852. if (processedtaints)
  853. _taintedPrim = new List<OdePrim>();
  854. if (timeStep < 0.2f)
  855. {
  856. foreach (OdePrim actor in _activeprims)
  857. {
  858. if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
  859. {
  860. actor.UpdatePositionAndVelocity();
  861. }
  862. }
  863. }
  864. }
  865. return fps;
  866. }
  867. public override void GetResults()
  868. {
  869. }
  870. public override bool IsThreaded
  871. {
  872. get { return (false); // for now we won't be multithreaded
  873. }
  874. }
  875. public float[] ResizeTerrain512(float[] heightMap)
  876. {
  877. float[] returnarr = new float[262144];
  878. float[,] resultarr = new float[m_regionWidth,m_regionHeight];
  879. // Filling out the array into it's multi-dimentional components
  880. for (int y = 0; y < m_regionHeight; y++)
  881. {
  882. for (int x = 0; x < m_regionWidth; x++)
  883. {
  884. resultarr[y, x] = heightMap[y*m_regionWidth + x];
  885. }
  886. }
  887. // Resize using interpolation
  888. // This particular way is quick but it only works on a multiple of the original
  889. // The idea behind this method can be described with the following diagrams
  890. // second pass and third pass happen in the same loop really.. just separated
  891. // them to show what this does.
  892. // First Pass
  893. // ResultArr:
  894. // 1,1,1,1,1,1
  895. // 1,1,1,1,1,1
  896. // 1,1,1,1,1,1
  897. // 1,1,1,1,1,1
  898. // 1,1,1,1,1,1
  899. // 1,1,1,1,1,1
  900. // Second Pass
  901. // ResultArr2:
  902. // 1,,1,,1,,1,,1,,1,
  903. // ,,,,,,,,,,
  904. // 1,,1,,1,,1,,1,,1,
  905. // ,,,,,,,,,,
  906. // 1,,1,,1,,1,,1,,1,
  907. // ,,,,,,,,,,
  908. // 1,,1,,1,,1,,1,,1,
  909. // ,,,,,,,,,,
  910. // 1,,1,,1,,1,,1,,1,
  911. // ,,,,,,,,,,
  912. // 1,,1,,1,,1,,1,,1,
  913. // Third pass fills in the blanks
  914. // ResultArr2:
  915. // 1,1,1,1,1,1,1,1,1,1,1,1
  916. // 1,1,1,1,1,1,1,1,1,1,1,1
  917. // 1,1,1,1,1,1,1,1,1,1,1,1
  918. // 1,1,1,1,1,1,1,1,1,1,1,1
  919. // 1,1,1,1,1,1,1,1,1,1,1,1
  920. // 1,1,1,1,1,1,1,1,1,1,1,1
  921. // 1,1,1,1,1,1,1,1,1,1,1,1
  922. // 1,1,1,1,1,1,1,1,1,1,1,1
  923. // 1,1,1,1,1,1,1,1,1,1,1,1
  924. // 1,1,1,1,1,1,1,1,1,1,1,1
  925. // 1,1,1,1,1,1,1,1,1,1,1,1
  926. // X,Y = .
  927. // X+1,y = ^
  928. // X,Y+1 = *
  929. // X+1,Y+1 = #
  930. // Filling in like this;
  931. // .*
  932. // ^#
  933. // 1st .
  934. // 2nd *
  935. // 3rd ^
  936. // 4th #
  937. // on single loop.
  938. float[,] resultarr2 = new float[512,512];
  939. for (int y = 0; y < m_regionHeight; y++)
  940. {
  941. for (int x = 0; x < m_regionWidth; x++)
  942. {
  943. resultarr2[y*2, x*2] = resultarr[y, x];
  944. if (y < m_regionHeight)
  945. {
  946. if (y + 1 < m_regionHeight)
  947. {
  948. if (x + 1 < m_regionWidth)
  949. {
  950. resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
  951. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  952. }
  953. else
  954. {
  955. resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
  956. }
  957. }
  958. else
  959. {
  960. resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
  961. }
  962. }
  963. if (x < m_regionWidth)
  964. {
  965. if (x + 1 < m_regionWidth)
  966. {
  967. if (y + 1 < m_regionHeight)
  968. {
  969. resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
  970. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  971. }
  972. else
  973. {
  974. resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
  975. }
  976. }
  977. else
  978. {
  979. resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
  980. }
  981. }
  982. if (x < m_regionWidth && y < m_regionHeight)
  983. {
  984. if ((x + 1 < m_regionWidth) && (y + 1 < m_regionHeight))
  985. {
  986. resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
  987. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  988. }
  989. else
  990. {
  991. resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
  992. }
  993. }
  994. }
  995. }
  996. //Flatten out the array
  997. int i = 0;
  998. for (int y = 0; y < 512; y++)
  999. {
  1000. for (int x = 0; x < 512; x++)
  1001. {
  1002. if (resultarr2[y, x] <= 0)
  1003. returnarr[i] = 0.0000001f;
  1004. else
  1005. returnarr[i] = resultarr2[y, x];
  1006. i++;
  1007. }
  1008. }
  1009. return returnarr;
  1010. }
  1011. public override void SetTerrain(float[] heightMap)
  1012. {
  1013. // this._heightmap[i] = (double)heightMap[i];
  1014. // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...)
  1015. // also, creating a buffer zone of one extra sample all around
  1016. const uint heightmapWidth = m_regionWidth + 2;
  1017. const uint heightmapHeight = m_regionHeight + 2;
  1018. const uint heightmapWidthSamples = 2*m_regionWidth + 2;
  1019. const uint heightmapHeightSamples = 2*m_regionHeight + 2;
  1020. const float scale = 1.0f;
  1021. const float offset = 0.0f;
  1022. const float thickness = 2.0f;
  1023. const int wrap = 0;
  1024. //Double resolution
  1025. heightMap = ResizeTerrain512(heightMap);
  1026. for (int x = 0; x < heightmapWidthSamples; x++)
  1027. {
  1028. for (int y = 0; y < heightmapHeightSamples; y++)
  1029. {
  1030. int xx = Util.Clip(x - 1, 0, 511);
  1031. int yy = Util.Clip(y - 1, 0, 511);
  1032. double val = (double) heightMap[yy*512 + xx];
  1033. _heightmap[x*heightmapHeightSamples + y] = val;
  1034. }
  1035. }
  1036. lock (OdeLock)
  1037. {
  1038. if (!(LandGeom == (IntPtr) 0))
  1039. {
  1040. d.SpaceRemove(space, LandGeom);
  1041. }
  1042. IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
  1043. d.GeomHeightfieldDataBuildDouble(HeightmapData, _heightmap, 0, heightmapWidth, heightmapHeight,
  1044. (int) heightmapWidthSamples, (int) heightmapHeightSamples, scale,
  1045. offset, thickness, wrap);
  1046. d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
  1047. LandGeom = d.CreateHeightfield(space, HeightmapData, 1);
  1048. geom_name_map[LandGeom] = "Terrain";
  1049. d.Matrix3 R = new d.Matrix3();
  1050. Quaternion q1 = Quaternion.FromAngleAxis(1.5707f, new Vector3(1, 0, 0));
  1051. Quaternion q2 = Quaternion.FromAngleAxis(1.5707f, new Vector3(0, 1, 0));
  1052. //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
  1053. q1 = q1*q2;
  1054. //q1 = q1 * q3;
  1055. Vector3 v3 = new Vector3();
  1056. float angle = 0;
  1057. q1.ToAngleAxis(ref angle, ref v3);
  1058. d.RFromAxisAndAngle(out R, v3.x, v3.y, v3.z, angle);
  1059. d.GeomSetRotation(LandGeom, ref R);
  1060. d.GeomSetPosition(LandGeom, 128, 128, 0);
  1061. }
  1062. }
  1063. public override void DeleteTerrain()
  1064. {
  1065. }
  1066. }
  1067. }