OdePlugin.cs 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710
  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 static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  45. private CollisionLocker ode;
  46. private OdeScene _mScene;
  47. public OdePlugin()
  48. {
  49. ode = new CollisionLocker();
  50. }
  51. public bool Init()
  52. {
  53. return true;
  54. }
  55. public PhysicsScene GetScene()
  56. {
  57. if (_mScene == null)
  58. {
  59. _mScene = new OdeScene(ode);
  60. }
  61. return (_mScene);
  62. }
  63. public string GetName()
  64. {
  65. return ("OpenDynamicsEngine");
  66. }
  67. public void Dispose()
  68. {
  69. }
  70. }
  71. public class OdeScene : PhysicsScene
  72. {
  73. private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  74. CollisionLocker ode;
  75. private const uint m_regionWidth = Constants.RegionSize;
  76. private const uint m_regionHeight = Constants.RegionSize;
  77. private static float ODE_STEPSIZE = 0.020f;
  78. private static bool RENDER_FLAG = false;
  79. private static float metersInSpace = 29.9f;
  80. private int interpenetrations_before_disable = 35;
  81. private IntPtr contactgroup;
  82. private IntPtr LandGeom = (IntPtr) 0;
  83. private float[] _heightmap;
  84. private float[] _origheightmap;
  85. private d.NearCallback nearCallback;
  86. public d.TriCallback triCallback;
  87. public d.TriArrayCallback triArrayCallback;
  88. private List<OdeCharacter> _characters = new List<OdeCharacter>();
  89. private List<OdePrim> _prims = new List<OdePrim>();
  90. private List<OdePrim> _activeprims = new List<OdePrim>();
  91. private List<OdePrim> _taintedPrim = new List<OdePrim>();
  92. public Dictionary<IntPtr, String> geom_name_map = new Dictionary<IntPtr, String>();
  93. public Dictionary<IntPtr, PhysicsActor> actor_name_map = new Dictionary<IntPtr, PhysicsActor>();
  94. private d.ContactGeom[] contacts = new d.ContactGeom[30];
  95. private d.Contact contact;
  96. private d.Contact TerrainContact;
  97. private d.Contact AvatarMovementprimContact;
  98. private d.Contact AvatarMovementTerrainContact;
  99. private int m_physicsiterations = 10;
  100. private float m_SkipFramesAtms = 0.40f; // Drop frames gracefully at a 400 ms lag
  101. private PhysicsActor PANull = new NullPhysicsActor();
  102. private float step_time = 0.0f;
  103. private int ms = 0;
  104. public IntPtr world;
  105. public IntPtr space;
  106. private IntPtr tmpSpace;
  107. // split static geometry collision handling into spaces of 30 meters
  108. public IntPtr[,] staticPrimspace = new IntPtr[(int) (300/metersInSpace),(int) (300/metersInSpace)];
  109. public static Object OdeLock = new Object();
  110. public IMesher mesher;
  111. /// <summary>
  112. /// Initiailizes the scene
  113. /// Sets many properties that ODE requires to be stable
  114. /// These settings need to be tweaked 'exactly' right or weird stuff happens.
  115. /// </summary>
  116. public OdeScene(CollisionLocker dode)
  117. {
  118. ode = dode;
  119. nearCallback = near;
  120. triCallback = TriCallback;
  121. triArrayCallback = TriArrayCallback;
  122. /*
  123. contact.surface.mode |= d.ContactFlags.Approx1 | d.ContactFlags.SoftCFM | d.ContactFlags.SoftERP;
  124. contact.surface.mu = 10.0f;
  125. contact.surface.bounce = 0.9f;
  126. contact.surface.soft_erp = 0.005f;
  127. contact.surface.soft_cfm = 0.00003f;
  128. */
  129. // Centeral contact friction and bounce
  130. contact.surface.mu = 250.0f;
  131. contact.surface.bounce = 0.2f;
  132. // Terrain contact friction and Bounce
  133. // This is the *non* moving version. Use this when an avatar
  134. // isn't moving to keep it in place better
  135. TerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  136. TerrainContact.surface.mu = 255.0f;
  137. TerrainContact.surface.bounce = 0.1f;
  138. TerrainContact.surface.soft_erp = 0.1025f;
  139. // Prim contact friction and bounce
  140. // THis is the *non* moving version of friction and bounce
  141. // Use this when an avatar comes in contact with a prim
  142. // and is moving
  143. AvatarMovementprimContact.surface.mu = 75.0f;
  144. AvatarMovementprimContact.surface.bounce = 0.1f;
  145. // Terrain contact friction bounce and various error correcting calculations
  146. // Use this when an avatar is in contact with the terrain and moving.
  147. AvatarMovementTerrainContact.surface.mode |= d.ContactFlags.SoftERP;
  148. AvatarMovementTerrainContact.surface.mu = 75.0f;
  149. AvatarMovementTerrainContact.surface.bounce = 0.1f;
  150. AvatarMovementTerrainContact.surface.soft_erp = 0.1025f;
  151. lock (OdeLock)
  152. {
  153. // Creat the world and the first space
  154. world = d.WorldCreate();
  155. space = d.HashSpaceCreate(IntPtr.Zero);
  156. d.HashSpaceSetLevels(space, -4, 128);
  157. contactgroup = d.JointGroupCreate(0);
  158. //contactgroup
  159. // Set the gravity,, don't disable things automatically (we set it explicitly on some things)
  160. d.WorldSetGravity(world, 0.0f, 0.0f, -9.8f);
  161. d.WorldSetAutoDisableFlag(world, false);
  162. d.WorldSetContactSurfaceLayer(world, 0.001f);
  163. // Set how many steps we go without running collision testing
  164. // This is in addition to the step size.
  165. // Essentially Steps * m_physicsiterations
  166. d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
  167. ///d.WorldSetContactMaxCorrectingVel(world, 1000.0f);
  168. }
  169. // zero out a heightmap array float array (single dimention [flattened]))
  170. _heightmap = new float[514*514];
  171. // Zero out the prim spaces array (we split our space into smaller spaces so
  172. // we can hit test less.
  173. for (int i = 0; i < staticPrimspace.GetLength(0); i++)
  174. {
  175. for (int j = 0; j < staticPrimspace.GetLength(1); j++)
  176. {
  177. staticPrimspace[i, j] = IntPtr.Zero;
  178. }
  179. }
  180. }
  181. public void starttiming()
  182. {
  183. ms = Environment.TickCount;
  184. }
  185. public int stoptiming()
  186. {
  187. return Environment.TickCount - ms;
  188. }
  189. // Initialize the mesh plugin
  190. public override void Initialise(IMesher meshmerizer)
  191. {
  192. mesher = meshmerizer;
  193. }
  194. internal void waitForSpaceUnlock(IntPtr space)
  195. {
  196. while (d.SpaceLockQuery(space))
  197. {
  198. }
  199. }
  200. /// <summary>
  201. /// Debug space message for printing the space that a prim/avatar is in.
  202. /// </summary>
  203. /// <param name="pos"></param>
  204. /// <returns>Returns which split up space the given position is in.</returns>
  205. public string whichspaceamIin(PhysicsVector pos)
  206. {
  207. return calculateSpaceForGeom(pos).ToString();
  208. }
  209. /// <summary>
  210. /// This is our near callback. A geometry is near a body
  211. /// </summary>
  212. /// <param name="space">The space that contains the geoms. Remember, spaces are also geoms</param>
  213. /// <param name="g1">a geometry or space</param>
  214. /// <param name="g2">another geometry or space</param>
  215. private void near(IntPtr space, IntPtr g1, IntPtr g2)
  216. {
  217. // no lock here! It's invoked from within Simulate(), which is thread-locked
  218. // Test if we're collidng a geom with a space.
  219. // If so we have to drill down into the space recursively
  220. if (d.GeomIsSpace(g1) || d.GeomIsSpace(g2))
  221. {
  222. if (g1 == (IntPtr)0 || g2 == (IntPtr)0)
  223. return;
  224. // Separating static prim geometry spaces.
  225. // We'll be calling near recursivly if one
  226. // of them is a space to find all of the
  227. // contact points in the space
  228. try
  229. {
  230. d.SpaceCollide2(g1, g2, IntPtr.Zero, nearCallback);
  231. }
  232. catch (System.AccessViolationException)
  233. {
  234. m_log.Warn("[PHYSICS]: Unable to collide test a space");
  235. return;
  236. }
  237. //Colliding a space or a geom with a space or a geom. so drill down
  238. //Collide all geoms in each space..
  239. //if (d.GeomIsSpace(g1)) d.SpaceCollide(g1, IntPtr.Zero, nearCallback);
  240. //if (d.GeomIsSpace(g2)) d.SpaceCollide(g2, IntPtr.Zero, nearCallback);
  241. }
  242. else
  243. {
  244. // Colliding Geom To Geom
  245. // This portion of the function 'was' blatantly ripped off from BoxStack.cs
  246. if (g1 == (IntPtr)0 || g2 == (IntPtr)0)
  247. return;
  248. IntPtr b1 = d.GeomGetBody(g1);
  249. IntPtr b2 = d.GeomGetBody(g2);
  250. if (g1 == g2)
  251. return; // Can't collide with yourself
  252. if (b1 != IntPtr.Zero && b2 != IntPtr.Zero && d.AreConnectedExcluding(b1, b2, d.JointType.Contact))
  253. return;
  254. d.GeomClassID id = d.GeomGetClass(g1);
  255. String name1 = null;
  256. String name2 = null;
  257. if (!geom_name_map.TryGetValue(g1, out name1))
  258. {
  259. name1 = "null";
  260. }
  261. if (!geom_name_map.TryGetValue(g2, out name2))
  262. {
  263. name2 = "null";
  264. }
  265. //if (id == d.GeomClassId.TriMeshClass)
  266. //{
  267. // m_log.Info("near: A collision was detected between {1} and {2}", 0, name1, name2);
  268. //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2);
  269. //}
  270. // Figure out how many contact points we have
  271. int count = 0;
  272. try
  273. {
  274. //m_log.Warn(g1.ToString() + "|" + g2.ToString());
  275. count = d.Collide(g1, g2, contacts.GetLength(0), contacts, d.ContactGeom.SizeOf);
  276. }
  277. catch (SEHException)
  278. {
  279. m_log.Error("[PHYSICS]: 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.");
  280. ode.drelease(world);
  281. base.TriggerPhysicsBasedRestart();
  282. }
  283. catch (System.AccessViolationException)
  284. {
  285. m_log.Warn("[PHYSICS]: Unable to collide test an object");
  286. return;
  287. }
  288. PhysicsActor p1;
  289. PhysicsActor p2;
  290. for (int i = 0; i < count; i++)
  291. {
  292. //m_log.Warn("[CCOUNT]: " + count);
  293. IntPtr joint;
  294. // If we're colliding with terrain, use 'TerrainContact' instead of contact.
  295. // allows us to have different settings
  296. if (!actor_name_map.TryGetValue(g1, out p1))
  297. {
  298. p1 = PANull;
  299. }
  300. if (!actor_name_map.TryGetValue(g2, out p2))
  301. {
  302. p2 = PANull;
  303. }
  304. // We only need to test p2 for 'jump crouch purposes'
  305. p2.IsColliding = true;
  306. switch (p1.PhysicsActorType)
  307. {
  308. case (int)ActorTypes.Agent:
  309. p2.CollidingObj = true;
  310. break;
  311. case (int)ActorTypes.Prim:
  312. if (p2.Velocity.X > 0 || p2.Velocity.Y > 0 || p2.Velocity.Z > 0)
  313. p2.CollidingObj = true;
  314. break;
  315. case (int)ActorTypes.Unknown:
  316. p2.CollidingGround = true;
  317. break;
  318. default:
  319. p2.CollidingGround = true;
  320. break;
  321. }
  322. // we don't want prim or avatar to explode
  323. #region InterPenetration Handling - Unintended physics explosions
  324. if (contacts[i].depth >= 0.08f)
  325. {
  326. //This is disabled at the moment only because it needs more tweaking
  327. //It will eventually be uncommented
  328. if (contacts[i].depth >= 1.00f)
  329. {
  330. //m_log.Debug("[PHYSICS]: " +contacts[i].depth.ToString());
  331. }
  332. //If you interpenetrate a prim with an agent
  333. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  334. p1.PhysicsActorType == (int) ActorTypes.Prim) ||
  335. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  336. p2.PhysicsActorType == (int) ActorTypes.Prim))
  337. {
  338. //contacts[i].depth = contacts[i].depth * 4.15f;
  339. /*
  340. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  341. {
  342. p2.CollidingObj = true;
  343. contacts[i].depth = 0.003f;
  344. p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 2.5f);
  345. OdeCharacter character = (OdeCharacter) p2;
  346. character.SetPidStatus(true);
  347. 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));
  348. }
  349. else
  350. {
  351. //contacts[i].depth = 0.0000000f;
  352. }
  353. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  354. {
  355. p1.CollidingObj = true;
  356. contacts[i].depth = 0.003f;
  357. p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 2.5f);
  358. 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));
  359. OdeCharacter character = (OdeCharacter)p1;
  360. character.SetPidStatus(true);
  361. }
  362. else
  363. {
  364. //contacts[i].depth = 0.0000000f;
  365. }
  366. */
  367. }
  368. // If you interpenetrate a prim with another prim
  369. if (p1.PhysicsActorType == (int) ActorTypes.Prim && p2.PhysicsActorType == (int) ActorTypes.Prim)
  370. {
  371. //OdePrim op1 = (OdePrim)p1;
  372. //OdePrim op2 = (OdePrim)p2;
  373. //op1.m_collisionscore++;
  374. //op2.m_collisionscore++;
  375. //if (op1.m_collisionscore > 8000 || op2.m_collisionscore > 8000)
  376. //{
  377. //op1.m_taintdisable = true;
  378. //AddPhysicsActorTaint(p1);
  379. //op2.m_taintdisable = true;
  380. //AddPhysicsActorTaint(p2);
  381. //}
  382. //if (contacts[i].depth >= 0.25f)
  383. //{
  384. // Don't collide, one or both prim will expld.
  385. //op1.m_interpenetrationcount++;
  386. //op2.m_interpenetrationcount++;
  387. //interpenetrations_before_disable = 200;
  388. //if (op1.m_interpenetrationcount >= interpenetrations_before_disable)
  389. //{
  390. //op1.m_taintdisable = true;
  391. //AddPhysicsActorTaint(p1);
  392. //}
  393. //if (op2.m_interpenetrationcount >= interpenetrations_before_disable)
  394. //{
  395. // op2.m_taintdisable = true;
  396. //AddPhysicsActorTaint(p2);
  397. //}
  398. //contacts[i].depth = contacts[i].depth / 8f;
  399. //contacts[i].normal = new d.Vector3(0, 0, 1);
  400. //}
  401. //if (op1.m_disabled || op2.m_disabled)
  402. //{
  403. //Manually disabled objects stay disabled
  404. //contacts[i].depth = 0f;
  405. //}
  406. }
  407. if (contacts[i].depth >= 1.00f)
  408. {
  409. //m_log.Info("[P]: " + contacts[i].depth.ToString());
  410. if ((p2.PhysicsActorType == (int) ActorTypes.Agent &&
  411. p1.PhysicsActorType == (int) ActorTypes.Unknown) ||
  412. (p1.PhysicsActorType == (int) ActorTypes.Agent &&
  413. p2.PhysicsActorType == (int) ActorTypes.Unknown))
  414. {
  415. if (p2.PhysicsActorType == (int) ActorTypes.Agent)
  416. {
  417. OdeCharacter character = (OdeCharacter) p2;
  418. //p2.CollidingObj = true;
  419. contacts[i].depth = 0.00000003f;
  420. p2.Velocity = p2.Velocity + new PhysicsVector(0, 0, 0.5f);
  421. contacts[i].pos =
  422. new d.Vector3(contacts[i].pos.X + (p1.Size.X/2),
  423. contacts[i].pos.Y + (p1.Size.Y/2),
  424. contacts[i].pos.Z + (p1.Size.Z/2));
  425. character.SetPidStatus(true);
  426. }
  427. else
  428. {
  429. }
  430. if (p1.PhysicsActorType == (int) ActorTypes.Agent)
  431. {
  432. OdeCharacter character = (OdeCharacter)p1;
  433. //p2.CollidingObj = true;
  434. contacts[i].depth = 0.00000003f;
  435. p1.Velocity = p1.Velocity + new PhysicsVector(0, 0, 0.5f);
  436. contacts[i].pos =
  437. new d.Vector3(contacts[i].pos.X + (p1.Size.X/2),
  438. contacts[i].pos.Y + (p1.Size.Y/2),
  439. contacts[i].pos.Z + (p1.Size.Z/2));
  440. character.SetPidStatus(true);
  441. }
  442. else
  443. {
  444. //contacts[i].depth = 0.0000000f;
  445. }
  446. }
  447. }
  448. }
  449. #endregion
  450. if (contacts[i].depth >= 0f)
  451. {
  452. // If we're collidng against terrain
  453. if (name1 == "Terrain" || name2 == "Terrain")
  454. {
  455. // If we're moving
  456. if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
  457. (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
  458. {
  459. // Use the movement terrain contact
  460. AvatarMovementTerrainContact.geom = contacts[i];
  461. joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementTerrainContact);
  462. }
  463. else
  464. {
  465. // Use the non moving terrain contact
  466. TerrainContact.geom = contacts[i];
  467. joint = d.JointCreateContact(world, contactgroup, ref TerrainContact);
  468. }
  469. }
  470. else
  471. {
  472. // we're colliding with prim or avatar
  473. // check if we're moving
  474. if ((p2.PhysicsActorType == (int) ActorTypes.Agent) &&
  475. (Math.Abs(p2.Velocity.X) > 0.01f || Math.Abs(p2.Velocity.Y) > 0.01f))
  476. {
  477. // Use the Movement prim contact
  478. AvatarMovementprimContact.geom = contacts[i];
  479. joint = d.JointCreateContact(world, contactgroup, ref AvatarMovementprimContact);
  480. }
  481. else
  482. {
  483. // Use the non movement contact
  484. contact.geom = contacts[i];
  485. joint = d.JointCreateContact(world, contactgroup, ref contact);
  486. }
  487. }
  488. d.JointAttach(joint, b1, b2);
  489. }
  490. if (count > 3)
  491. {
  492. // If there are more then 3 contact points, it's likely
  493. // that we've got a pile of objects
  494. //
  495. // We don't want to send out hundreds of terse updates over and over again
  496. // so lets throttle them and send them again after it's somewhat sorted out.
  497. p2.ThrottleUpdates = true;
  498. }
  499. //System.Console.WriteLine(count.ToString());
  500. //System.Console.WriteLine("near: A collision was detected between {1} and {2}", 0, name1, name2);
  501. }
  502. }
  503. }
  504. private float GetTerrainHeightAtXY(float x, float y)
  505. {
  506. return (float)_origheightmap[(int)y * Constants.RegionSize + (int)x];
  507. }
  508. /// <summary>
  509. /// This is our collision testing routine in ODE
  510. /// </summary>
  511. /// <param name="timeStep"></param>
  512. private void collision_optimized(float timeStep)
  513. {
  514. foreach (OdeCharacter chr in _characters)
  515. {
  516. // Reset the collision values to false
  517. // since we don't know if we're colliding yet
  518. chr.IsColliding = false;
  519. chr.CollidingGround = false;
  520. chr.CollidingObj = false;
  521. // test the avatar's geometry for collision with the space
  522. // This will return near and the space that they are the closest to
  523. // And we'll run this again against the avatar and the space segment
  524. // This will return with a bunch of possible objects in the space segment
  525. // and we'll run it again on all of them.
  526. try
  527. {
  528. d.SpaceCollide2(space, chr.Shell, IntPtr.Zero, nearCallback);
  529. }
  530. catch (AccessViolationException)
  531. {
  532. m_log.Warn("[PHYSICS]: Unable to space collide");
  533. }
  534. //float terrainheight = GetTerrainHeightAtXY(chr.Position.X, chr.Position.Y);
  535. //if (chr.Position.Z + (chr.Velocity.Z * timeStep) < terrainheight + 10)
  536. //{
  537. //chr.Position.Z = terrainheight + 10.0f;
  538. //forcedZ = true;
  539. //}
  540. }
  541. // If the sim is running slow this frame,
  542. // don't process collision for prim!
  543. if (timeStep < (m_SkipFramesAtms/3))
  544. {
  545. foreach (OdePrim chr in _activeprims)
  546. {
  547. // This if may not need to be there.. it might be skipped anyway.
  548. if (d.BodyIsEnabled(chr.Body) && (!chr.m_disabled))
  549. {
  550. try
  551. {
  552. d.SpaceCollide2(space, chr.prim_geom, IntPtr.Zero, nearCallback);
  553. }
  554. catch (AccessViolationException)
  555. {
  556. m_log.Warn("[PHYSICS]: Unable to space collide");
  557. }
  558. //calculateSpaceForGeom(chr.Position)
  559. //foreach (OdePrim ch2 in _prims)
  560. /// should be a separate space -- lots of avatars will be N**2 slow
  561. //{
  562. //if (ch2.IsPhysical && d.BodyIsEnabled(ch2.Body))
  563. //{
  564. // Only test prim that are 0.03 meters away in one direction.
  565. // This should be Optimized!
  566. //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))
  567. //{
  568. //d.SpaceCollide2(chr.prim_geom, ch2.prim_geom, IntPtr.Zero, nearCallback);
  569. //}
  570. //}
  571. //}
  572. }
  573. try
  574. {
  575. d.SpaceCollide2(LandGeom, chr.prim_geom, IntPtr.Zero, nearCallback);
  576. }
  577. catch (AccessViolationException)
  578. {
  579. m_log.Warn("[PHYSICS]: Unable to space collide");
  580. }
  581. }
  582. }
  583. else
  584. {
  585. // Everything is going slow, so we're skipping object to object collisions
  586. // At least collide test against the ground.
  587. foreach (OdePrim chr in _activeprims)
  588. {
  589. // This if may not need to be there.. it might be skipped anyway.
  590. if (d.BodyIsEnabled(chr.Body))
  591. {
  592. // Collide test the prims with the terrain.. since if you don't do this,
  593. // next frame, all of the physical prim in the scene will awaken and explode upwards
  594. tmpSpace = calculateSpaceForGeom(chr.Position);
  595. if (tmpSpace != (IntPtr) 0 && d.GeomIsSpace(tmpSpace))
  596. d.SpaceCollide2(calculateSpaceForGeom(chr.Position), chr.prim_geom, IntPtr.Zero, nearCallback);
  597. d.SpaceCollide2(LandGeom, chr.prim_geom, IntPtr.Zero, nearCallback);
  598. }
  599. }
  600. }
  601. }
  602. public override PhysicsActor AddAvatar(string avName, PhysicsVector position, PhysicsVector size)
  603. {
  604. PhysicsVector pos = new PhysicsVector();
  605. pos.X = position.X;
  606. pos.Y = position.Y;
  607. pos.Z = position.Z;
  608. OdeCharacter newAv = new OdeCharacter(avName, this, pos, ode, size);
  609. _characters.Add(newAv);
  610. return newAv;
  611. }
  612. public override void RemoveAvatar(PhysicsActor actor)
  613. {
  614. lock (OdeLock)
  615. {
  616. ((OdeCharacter) actor).Destroy();
  617. _characters.Remove((OdeCharacter) actor);
  618. }
  619. }
  620. public override void RemovePrim(PhysicsActor prim)
  621. {
  622. if (prim is OdePrim)
  623. {
  624. lock (OdeLock)
  625. {
  626. OdePrim p = (OdePrim) prim;
  627. p.setPrimForRemoval();
  628. AddPhysicsActorTaint(prim);
  629. //RemovePrimThreadLocked(p);
  630. }
  631. }
  632. }
  633. /// <summary>
  634. /// This is called from within simulate but outside the locked portion
  635. /// We need to do our own locking here
  636. /// Essentially, we need to remove the prim from our space segment, whatever segment it's in.
  637. ///
  638. /// If there are no more prim in the segment, we need to empty (spacedestroy)the segment and reclaim memory
  639. /// that the space was using.
  640. /// </summary>
  641. /// <param name="prim"></param>
  642. public void RemovePrimThreadLocked(OdePrim prim)
  643. {
  644. lock (ode)
  645. {
  646. if (prim.prim_geom != (IntPtr)0)
  647. {
  648. while (ode.lockquery())
  649. {
  650. }
  651. ode.dlock(world);
  652. //System.Threading.Thread.Sleep(20);
  653. prim.ResetTaints();
  654. if (prim.IsPhysical)
  655. {
  656. prim.disableBody();
  657. }
  658. // we don't want to remove the main space
  659. // If the geometry is in the targetspace, remove it from the target space
  660. //m_log.Warn(prim.m_targetSpace);
  661. //if (prim.m_targetSpace != (IntPtr)0)
  662. //{
  663. if (d.SpaceQuery(prim.m_targetSpace, prim.prim_geom))
  664. {
  665. if (d.GeomIsSpace(prim.m_targetSpace))
  666. {
  667. waitForSpaceUnlock(prim.m_targetSpace);
  668. d.SpaceRemove(prim.m_targetSpace, prim.prim_geom);
  669. prim.m_targetSpace = (IntPtr) 0;
  670. }
  671. else
  672. {
  673. m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
  674. ((OdePrim)prim).m_targetSpace.ToString());
  675. }
  676. }
  677. //}
  678. //m_log.Warn(prim.prim_geom);
  679. try
  680. {
  681. if (prim.prim_geom != (IntPtr)0)
  682. {
  683. d.GeomDestroy(prim.prim_geom);
  684. prim.prim_geom = (IntPtr)0;
  685. }
  686. else
  687. {
  688. m_log.Warn("[PHYSICS]: Unable to remove prim from physics scene");
  689. }
  690. }
  691. catch (System.AccessViolationException)
  692. {
  693. m_log.Info("[PHYSICS]: Couldn't remove prim from physics scene, it was already be removed.");
  694. }
  695. _prims.Remove(prim);
  696. //If there are no more geometries in the sub-space, we don't need it in the main space anymore
  697. //if (d.SpaceGetNumGeoms(prim.m_targetSpace) == 0)
  698. //{
  699. //if (!(prim.m_targetSpace.Equals(null)))
  700. //{
  701. //if (d.GeomIsSpace(prim.m_targetSpace))
  702. //{
  703. //waitForSpaceUnlock(prim.m_targetSpace);
  704. //d.SpaceRemove(space, prim.m_targetSpace);
  705. // free up memory used by the space.
  706. //d.SpaceDestroy(prim.m_targetSpace);
  707. //int[] xyspace = calculateSpaceArrayItemFromPos(prim.Position);
  708. //resetSpaceArrayItemToZero(xyspace[0], xyspace[1]);
  709. //}
  710. //else
  711. //{
  712. //m_log.Info("[Physics]: Invalid Scene passed to 'removeprim from scene':" +
  713. //((OdePrim) prim).m_targetSpace.ToString());
  714. //}
  715. //}
  716. //}
  717. }
  718. ode.dunlock(world);
  719. }
  720. }
  721. /// <summary>
  722. /// Takes a space pointer and zeros out the array we're using to hold the spaces
  723. /// </summary>
  724. /// <param name="space"></param>
  725. public void resetSpaceArrayItemToZero(IntPtr space)
  726. {
  727. for (int x = 0; x < staticPrimspace.GetLength(0); x++)
  728. {
  729. for (int y = 0; y < staticPrimspace.GetLength(1); y++)
  730. {
  731. if (staticPrimspace[x, y] == space)
  732. staticPrimspace[x, y] = IntPtr.Zero;
  733. }
  734. }
  735. }
  736. public void resetSpaceArrayItemToZero(int arrayitemX, int arrayitemY)
  737. {
  738. staticPrimspace[arrayitemX, arrayitemY] = IntPtr.Zero;
  739. }
  740. /// <summary>
  741. /// Called when a static prim moves. Allocates a space for the prim based on it's position
  742. /// </summary>
  743. /// <param name="geom">the pointer to the geom that moved</param>
  744. /// <param name="pos">the position that the geom moved to</param>
  745. /// <param name="currentspace">a pointer to the space it was in before it was moved.</param>
  746. /// <returns>a pointer to the new space it's in</returns>
  747. public IntPtr recalculateSpaceForGeom(IntPtr geom, PhysicsVector pos, IntPtr currentspace)
  748. {
  749. // Called from setting the Position and Size of an ODEPrim so
  750. // it's already in locked space.
  751. // we don't want to remove the main space
  752. // we don't need to test physical here because this function should
  753. // never be called if the prim is physical(active)
  754. // All physical prim end up in the root space
  755. System.Threading.Thread.Sleep(20);
  756. if (currentspace != space)
  757. {
  758. if (d.SpaceQuery(currentspace, geom) && currentspace != (IntPtr) 0)
  759. {
  760. if (d.GeomIsSpace(currentspace))
  761. {
  762. waitForSpaceUnlock(currentspace);
  763. d.SpaceRemove(currentspace, geom);
  764. }
  765. else
  766. {
  767. m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" + currentspace.ToString() +
  768. " Geom:" + geom.ToString());
  769. }
  770. }
  771. else
  772. {
  773. IntPtr sGeomIsIn = d.GeomGetSpace(geom);
  774. if (!(sGeomIsIn.Equals(null)))
  775. {
  776. if (sGeomIsIn != (IntPtr) 0)
  777. {
  778. if (d.GeomIsSpace(currentspace))
  779. {
  780. waitForSpaceUnlock(sGeomIsIn);
  781. d.SpaceRemove(sGeomIsIn, geom);
  782. }
  783. else
  784. {
  785. m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
  786. sGeomIsIn.ToString() + " Geom:" + geom.ToString());
  787. }
  788. }
  789. }
  790. }
  791. //If there are no more geometries in the sub-space, we don't need it in the main space anymore
  792. if (d.SpaceGetNumGeoms(currentspace) == 0)
  793. {
  794. if (currentspace != (IntPtr) 0)
  795. {
  796. if (d.GeomIsSpace(currentspace))
  797. {
  798. waitForSpaceUnlock(currentspace);
  799. waitForSpaceUnlock(space);
  800. d.SpaceRemove(space, currentspace);
  801. // free up memory used by the space.
  802. d.SpaceDestroy(currentspace);
  803. resetSpaceArrayItemToZero(currentspace);
  804. }
  805. else
  806. {
  807. m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
  808. currentspace.ToString() + " Geom:" + geom.ToString());
  809. }
  810. }
  811. }
  812. }
  813. else
  814. {
  815. // this is a physical object that got disabled. ;.;
  816. if (currentspace != (IntPtr)0 && geom != (IntPtr)0)
  817. {
  818. if (d.SpaceQuery(currentspace, geom))
  819. {
  820. if (d.GeomIsSpace(currentspace))
  821. {
  822. waitForSpaceUnlock(currentspace);
  823. d.SpaceRemove(currentspace, geom);
  824. }
  825. else
  826. {
  827. m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
  828. currentspace.ToString() + " Geom:" + geom.ToString());
  829. }
  830. }
  831. else
  832. {
  833. IntPtr sGeomIsIn = d.GeomGetSpace(geom);
  834. if (!(sGeomIsIn.Equals(null)))
  835. {
  836. if (sGeomIsIn != (IntPtr)0)
  837. {
  838. if (d.GeomIsSpace(sGeomIsIn))
  839. {
  840. waitForSpaceUnlock(sGeomIsIn);
  841. d.SpaceRemove(sGeomIsIn, geom);
  842. }
  843. else
  844. {
  845. m_log.Info("[Physics]: Invalid Scene passed to 'recalculatespace':" +
  846. sGeomIsIn.ToString() + " Geom:" + geom.ToString());
  847. }
  848. }
  849. }
  850. }
  851. }
  852. }
  853. // The routines in the Position and Size sections do the 'inserting' into the space,
  854. // so all we have to do is make sure that the space that we're putting the prim into
  855. // is in the 'main' space.
  856. int[] iprimspaceArrItem = calculateSpaceArrayItemFromPos(pos);
  857. IntPtr newspace = calculateSpaceForGeom(pos);
  858. if (newspace == IntPtr.Zero)
  859. {
  860. newspace = createprimspace(iprimspaceArrItem[0], iprimspaceArrItem[1]);
  861. d.HashSpaceSetLevels(newspace, -4, 66);
  862. }
  863. return newspace;
  864. }
  865. /// <summary>
  866. /// Creates a new space at X Y
  867. /// </summary>
  868. /// <param name="iprimspaceArrItemX"></param>
  869. /// <param name="iprimspaceArrItemY"></param>
  870. /// <returns>A pointer to the created space</returns>
  871. public IntPtr createprimspace(int iprimspaceArrItemX, int iprimspaceArrItemY)
  872. {
  873. // creating a new space for prim and inserting it into main space.
  874. staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY] = d.HashSpaceCreate(IntPtr.Zero);
  875. waitForSpaceUnlock(space);
  876. d.SpaceAdd(space, staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY]);
  877. return staticPrimspace[iprimspaceArrItemX, iprimspaceArrItemY];
  878. }
  879. /// <summary>
  880. /// Calculates the space the prim should be in by it's position
  881. /// </summary>
  882. /// <param name="pos"></param>
  883. /// <returns>a pointer to the space. This could be a new space or reused space.</returns>
  884. public IntPtr calculateSpaceForGeom(PhysicsVector pos)
  885. {
  886. IntPtr locationbasedspace =IntPtr.Zero;
  887. int[] xyspace = calculateSpaceArrayItemFromPos(pos);
  888. //m_log.Info("[Physics]: Attempting to use arrayItem: " + xyspace[0].ToString() + "," + xyspace[1].ToString());
  889. locationbasedspace = staticPrimspace[xyspace[0], xyspace[1]];
  890. //locationbasedspace = space;
  891. return locationbasedspace;
  892. }
  893. /// <summary>
  894. /// Holds the space allocation logic
  895. /// </summary>
  896. /// <param name="pos"></param>
  897. /// <returns>an array item based on the position</returns>
  898. public int[] calculateSpaceArrayItemFromPos(PhysicsVector pos)
  899. {
  900. int[] returnint = new int[2];
  901. returnint[0] = (int) (pos.X/metersInSpace);
  902. if (returnint[0] > ((int) (259f/metersInSpace)))
  903. returnint[0] = ((int) (259f/metersInSpace));
  904. if (returnint[0] < 0)
  905. returnint[0] = 0;
  906. returnint[1] = (int) (pos.Y/metersInSpace);
  907. if (returnint[1] > ((int) (259f/metersInSpace)))
  908. returnint[1] = ((int) (259f/metersInSpace));
  909. if (returnint[1] < 0)
  910. returnint[1] = 0;
  911. return returnint;
  912. }
  913. private PhysicsActor AddPrim(String name, PhysicsVector position, PhysicsVector size, Quaternion rotation,
  914. IMesh mesh, PrimitiveBaseShape pbs, bool isphysical)
  915. {
  916. PhysicsVector pos = new PhysicsVector();
  917. pos.X = position.X;
  918. pos.Y = position.Y;
  919. pos.Z = position.Z;
  920. PhysicsVector siz = new PhysicsVector();
  921. siz.X = size.X;
  922. siz.Y = size.Y;
  923. siz.Z = size.Z;
  924. Quaternion rot = new Quaternion();
  925. rot.w = rotation.w;
  926. rot.x = rotation.x;
  927. rot.y = rotation.y;
  928. rot.z = rotation.z;
  929. OdePrim newPrim;
  930. lock (OdeLock)
  931. {
  932. newPrim = new OdePrim(name, this, pos, siz, rot, mesh, pbs, isphysical, ode);
  933. _prims.Add(newPrim);
  934. }
  935. return newPrim;
  936. }
  937. public void addActivePrim(OdePrim activatePrim)
  938. {
  939. // adds active prim.. (ones that should be iterated over in collisions_optimized
  940. _activeprims.Add(activatePrim);
  941. }
  942. public void remActivePrim(OdePrim deactivatePrim)
  943. {
  944. _activeprims.Remove(deactivatePrim);
  945. }
  946. public int TriArrayCallback(IntPtr trimesh, IntPtr refObject, int[] triangleIndex, int triCount)
  947. {
  948. /* String name1 = null;
  949. String name2 = null;
  950. if (!geom_name_map.TryGetValue(trimesh, out name1))
  951. {
  952. name1 = "null";
  953. }
  954. if (!geom_name_map.TryGetValue(refObject, out name2))
  955. {
  956. name2 = "null";
  957. }
  958. m_log.Info("TriArrayCallback: A collision was detected between {1} and {2}", 0, name1, name2);
  959. */
  960. return 1;
  961. }
  962. public int TriCallback(IntPtr trimesh, IntPtr refObject, int triangleIndex)
  963. {
  964. String name1 = null;
  965. String name2 = null;
  966. if (!geom_name_map.TryGetValue(trimesh, out name1))
  967. {
  968. name1 = "null";
  969. }
  970. if (!geom_name_map.TryGetValue(refObject, out name2))
  971. {
  972. name2 = "null";
  973. }
  974. // m_log.Info("TriCallback: A collision was detected between {1} and {2}. Index was {3}", 0, name1, name2, triangleIndex);
  975. d.Vector3 v0 = new d.Vector3();
  976. d.Vector3 v1 = new d.Vector3();
  977. d.Vector3 v2 = new d.Vector3();
  978. d.GeomTriMeshGetTriangle(trimesh, 0, ref v0, ref v1, ref v2);
  979. // m_log.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);
  980. return 1;
  981. }
  982. /// <summary>
  983. /// Routine to figure out if we need to mesh this prim with our mesher
  984. /// </summary>
  985. /// <param name="pbs"></param>
  986. /// <returns></returns>
  987. public bool needsMeshing(PrimitiveBaseShape pbs)
  988. {
  989. if (pbs.ProfileHollow != 0)
  990. return true;
  991. if ((pbs.ProfileBegin != 0) || pbs.ProfileEnd != 0)
  992. return true;
  993. if ((pbs.PathScaleX != 100) || (pbs.PathScaleY != 100))
  994. return true;
  995. if ((pbs.PathShearX != 0) || (pbs.PathShearY != 0))
  996. return true;
  997. if (pbs.ProfileShape == ProfileShape.Circle && pbs.PathCurve == (byte)Extrusion.Straight)
  998. return true;
  999. return false;
  1000. }
  1001. public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
  1002. PhysicsVector size, Quaternion rotation) //To be removed
  1003. {
  1004. return AddPrimShape(primName, pbs, position, size, rotation, false);
  1005. }
  1006. public override PhysicsActor AddPrimShape(string primName, PrimitiveBaseShape pbs, PhysicsVector position,
  1007. PhysicsVector size, Quaternion rotation, bool isPhysical)
  1008. {
  1009. PhysicsActor result;
  1010. IMesh mesh = null;
  1011. switch (pbs.ProfileShape)
  1012. {
  1013. case ProfileShape.Square:
  1014. /// support simple box & hollow box now; later, more shapes
  1015. if (needsMeshing(pbs))
  1016. {
  1017. mesh = mesher.CreateMesh(primName, pbs, size);
  1018. }
  1019. break;
  1020. }
  1021. result = AddPrim(primName, position, size, rotation, mesh, pbs, isPhysical);
  1022. return result;
  1023. }
  1024. /// <summary>
  1025. /// Called after our prim properties are set Scale, position etc.
  1026. /// We use this event queue like method to keep changes to the physical scene occuring in the threadlocked mutex
  1027. /// This assures us that we have no race conditions
  1028. /// </summary>
  1029. /// <param name="prim"></param>
  1030. public override void AddPhysicsActorTaint(PhysicsActor prim)
  1031. {
  1032. if (prim is OdePrim)
  1033. {
  1034. OdePrim taintedprim = ((OdePrim) prim);
  1035. if (!(_taintedPrim.Contains(taintedprim)))
  1036. _taintedPrim.Add(taintedprim);
  1037. }
  1038. }
  1039. /// <summary>
  1040. /// This is our main simulate loop
  1041. /// It's thread locked by a Mutex in the scene.
  1042. /// It holds Collisions, it instructs ODE to step through the physical reactions
  1043. /// It moves the objects around in memory
  1044. /// It calls the methods that report back to the object owners.. (scenepresence, SceneObjectGroup)
  1045. /// </summary>
  1046. /// <param name="timeStep"></param>
  1047. /// <returns></returns>
  1048. public override float Simulate(float timeStep)
  1049. {
  1050. float fps = 0;
  1051. step_time += timeStep;
  1052. // If We're loaded down by something else,
  1053. // or debugging with the Visual Studio project on pause
  1054. // skip a few frames to catch up gracefully.
  1055. // without shooting the physicsactors all over the place
  1056. if (step_time >= m_SkipFramesAtms)
  1057. {
  1058. // Instead of trying to catch up, it'll do 5 physics frames only
  1059. step_time = ODE_STEPSIZE;
  1060. m_physicsiterations = 5;
  1061. }
  1062. else
  1063. {
  1064. m_physicsiterations = 10;
  1065. }
  1066. lock (OdeLock)
  1067. {
  1068. // Process 10 frames if the sim is running normal..
  1069. // process 5 frames if the sim is running slow
  1070. try
  1071. {
  1072. d.WorldSetQuickStepNumIterations(world, m_physicsiterations);
  1073. }
  1074. catch (StackOverflowException)
  1075. {
  1076. m_log.Error("[PHYSICS]: The operating system wasn't able to allocate enough memory for the simulation. Restarting the sim.");
  1077. ode.drelease(world);
  1078. base.TriggerPhysicsBasedRestart();
  1079. }
  1080. int i = 0;
  1081. // Figure out the Frames Per Second we're going at.
  1082. //(step_time == 0.004f, there's 250 of those per second. Times the step time/step size
  1083. fps = (step_time/ODE_STEPSIZE) * 1000;
  1084. while (step_time > 0.0f)
  1085. {
  1086. lock (ode)
  1087. {
  1088. if (!ode.lockquery())
  1089. {
  1090. ode.dlock(world);
  1091. try
  1092. {
  1093. foreach (OdeCharacter actor in _characters)
  1094. {
  1095. actor.Move(timeStep);
  1096. }
  1097. collision_optimized(timeStep);
  1098. d.WorldQuickStep(world, ODE_STEPSIZE);
  1099. d.JointGroupEmpty(contactgroup);
  1100. ode.dunlock(world);
  1101. }
  1102. catch (Exception e)
  1103. {
  1104. m_log.Error("[PHYSICS]: " + e.Message.ToString() + e.TargetSite.ToString());
  1105. ode.dunlock(world);
  1106. }
  1107. step_time -= ODE_STEPSIZE;
  1108. i++;
  1109. }
  1110. else
  1111. {
  1112. fps = 0;
  1113. }
  1114. }
  1115. }
  1116. foreach (OdeCharacter actor in _characters)
  1117. {
  1118. actor.UpdatePositionAndVelocity();
  1119. }
  1120. if (!ode.lockquery())
  1121. {
  1122. bool processedtaints = false;
  1123. foreach (OdePrim prim in _taintedPrim)
  1124. {
  1125. if (prim.m_taintremove)
  1126. {
  1127. RemovePrimThreadLocked(prim);
  1128. }
  1129. prim.ProcessTaints(timeStep);
  1130. processedtaints = true;
  1131. prim.m_collisionscore = 0;
  1132. }
  1133. if (processedtaints)
  1134. _taintedPrim = new List<OdePrim>();
  1135. }
  1136. foreach (OdePrim prim in _activeprims)
  1137. {
  1138. prim.m_collisionscore = 0;
  1139. }
  1140. if (timeStep < 0.2f)
  1141. {
  1142. foreach (OdePrim actor in _activeprims)
  1143. {
  1144. if (actor.IsPhysical && (d.BodyIsEnabled(actor.Body) || !actor._zeroFlag))
  1145. {
  1146. actor.UpdatePositionAndVelocity();
  1147. }
  1148. }
  1149. }
  1150. }
  1151. return fps;
  1152. }
  1153. public override void GetResults()
  1154. {
  1155. }
  1156. public override bool IsThreaded
  1157. {
  1158. // for now we won't be multithreaded
  1159. get { return (false); }
  1160. }
  1161. public float[] ResizeTerrain512NearestNeighbour(float[] heightMap)
  1162. {
  1163. float[] returnarr = new float[262144];
  1164. float[,] resultarr = new float[m_regionWidth, m_regionHeight];
  1165. // Filling out the array into it's multi-dimentional components
  1166. for (int y = 0; y < m_regionHeight; y++)
  1167. {
  1168. for (int x = 0; x < m_regionWidth; x++)
  1169. {
  1170. resultarr[y, x] = heightMap[y * m_regionWidth + x];
  1171. }
  1172. }
  1173. // Resize using Nearest Neighbour
  1174. // This particular way is quick but it only works on a multiple of the original
  1175. // The idea behind this method can be described with the following diagrams
  1176. // second pass and third pass happen in the same loop really.. just separated
  1177. // them to show what this does.
  1178. // First Pass
  1179. // ResultArr:
  1180. // 1,1,1,1,1,1
  1181. // 1,1,1,1,1,1
  1182. // 1,1,1,1,1,1
  1183. // 1,1,1,1,1,1
  1184. // 1,1,1,1,1,1
  1185. // 1,1,1,1,1,1
  1186. // Second Pass
  1187. // ResultArr2:
  1188. // 1,,1,,1,,1,,1,,1,
  1189. // ,,,,,,,,,,
  1190. // 1,,1,,1,,1,,1,,1,
  1191. // ,,,,,,,,,,
  1192. // 1,,1,,1,,1,,1,,1,
  1193. // ,,,,,,,,,,
  1194. // 1,,1,,1,,1,,1,,1,
  1195. // ,,,,,,,,,,
  1196. // 1,,1,,1,,1,,1,,1,
  1197. // ,,,,,,,,,,
  1198. // 1,,1,,1,,1,,1,,1,
  1199. // Third pass fills in the blanks
  1200. // ResultArr2:
  1201. // 1,1,1,1,1,1,1,1,1,1,1,1
  1202. // 1,1,1,1,1,1,1,1,1,1,1,1
  1203. // 1,1,1,1,1,1,1,1,1,1,1,1
  1204. // 1,1,1,1,1,1,1,1,1,1,1,1
  1205. // 1,1,1,1,1,1,1,1,1,1,1,1
  1206. // 1,1,1,1,1,1,1,1,1,1,1,1
  1207. // 1,1,1,1,1,1,1,1,1,1,1,1
  1208. // 1,1,1,1,1,1,1,1,1,1,1,1
  1209. // 1,1,1,1,1,1,1,1,1,1,1,1
  1210. // 1,1,1,1,1,1,1,1,1,1,1,1
  1211. // 1,1,1,1,1,1,1,1,1,1,1,1
  1212. // X,Y = .
  1213. // X+1,y = ^
  1214. // X,Y+1 = *
  1215. // X+1,Y+1 = #
  1216. // Filling in like this;
  1217. // .*
  1218. // ^#
  1219. // 1st .
  1220. // 2nd *
  1221. // 3rd ^
  1222. // 4th #
  1223. // on single loop.
  1224. float[,] resultarr2 = new float[512, 512];
  1225. for (int y = 0; y < m_regionHeight; y++)
  1226. {
  1227. for (int x = 0; x < m_regionWidth; x++)
  1228. {
  1229. resultarr2[y * 2, x * 2] = resultarr[y, x];
  1230. if (y < m_regionHeight)
  1231. {
  1232. resultarr2[(y * 2) + 1, x * 2] = resultarr[y, x];
  1233. }
  1234. if (x < m_regionWidth)
  1235. {
  1236. resultarr2[y * 2, (x * 2) + 1] = resultarr[y, x];
  1237. }
  1238. if (x < m_regionWidth && y < m_regionHeight)
  1239. {
  1240. resultarr2[(y * 2) + 1, (x * 2) + 1] = resultarr[y, x];
  1241. }
  1242. }
  1243. }
  1244. //Flatten out the array
  1245. int i = 0;
  1246. for (int y = 0; y < 512; y++)
  1247. {
  1248. for (int x = 0; x < 512; x++)
  1249. {
  1250. if (resultarr2[y, x] <= 0)
  1251. returnarr[i] = 0.0000001f;
  1252. else
  1253. returnarr[i] = resultarr2[y, x];
  1254. i++;
  1255. }
  1256. }
  1257. return returnarr;
  1258. }
  1259. public float[] ResizeTerrain512Interpolation(float[] heightMap)
  1260. {
  1261. float[] returnarr = new float[262144];
  1262. float[,] resultarr = new float[m_regionWidth,m_regionHeight];
  1263. // Filling out the array into it's multi-dimentional components
  1264. for (int y = 0; y < m_regionHeight; y++)
  1265. {
  1266. for (int x = 0; x < m_regionWidth; x++)
  1267. {
  1268. resultarr[y, x] = heightMap[y*m_regionWidth + x];
  1269. }
  1270. }
  1271. // Resize using interpolation
  1272. // This particular way is quick but it only works on a multiple of the original
  1273. // The idea behind this method can be described with the following diagrams
  1274. // second pass and third pass happen in the same loop really.. just separated
  1275. // them to show what this does.
  1276. // First Pass
  1277. // ResultArr:
  1278. // 1,1,1,1,1,1
  1279. // 1,1,1,1,1,1
  1280. // 1,1,1,1,1,1
  1281. // 1,1,1,1,1,1
  1282. // 1,1,1,1,1,1
  1283. // 1,1,1,1,1,1
  1284. // Second Pass
  1285. // ResultArr2:
  1286. // 1,,1,,1,,1,,1,,1,
  1287. // ,,,,,,,,,,
  1288. // 1,,1,,1,,1,,1,,1,
  1289. // ,,,,,,,,,,
  1290. // 1,,1,,1,,1,,1,,1,
  1291. // ,,,,,,,,,,
  1292. // 1,,1,,1,,1,,1,,1,
  1293. // ,,,,,,,,,,
  1294. // 1,,1,,1,,1,,1,,1,
  1295. // ,,,,,,,,,,
  1296. // 1,,1,,1,,1,,1,,1,
  1297. // Third pass fills in the blanks
  1298. // ResultArr2:
  1299. // 1,1,1,1,1,1,1,1,1,1,1,1
  1300. // 1,1,1,1,1,1,1,1,1,1,1,1
  1301. // 1,1,1,1,1,1,1,1,1,1,1,1
  1302. // 1,1,1,1,1,1,1,1,1,1,1,1
  1303. // 1,1,1,1,1,1,1,1,1,1,1,1
  1304. // 1,1,1,1,1,1,1,1,1,1,1,1
  1305. // 1,1,1,1,1,1,1,1,1,1,1,1
  1306. // 1,1,1,1,1,1,1,1,1,1,1,1
  1307. // 1,1,1,1,1,1,1,1,1,1,1,1
  1308. // 1,1,1,1,1,1,1,1,1,1,1,1
  1309. // 1,1,1,1,1,1,1,1,1,1,1,1
  1310. // X,Y = .
  1311. // X+1,y = ^
  1312. // X,Y+1 = *
  1313. // X+1,Y+1 = #
  1314. // Filling in like this;
  1315. // .*
  1316. // ^#
  1317. // 1st .
  1318. // 2nd *
  1319. // 3rd ^
  1320. // 4th #
  1321. // on single loop.
  1322. float[,] resultarr2 = new float[512,512];
  1323. for (int y = 0; y < m_regionHeight; y++)
  1324. {
  1325. for (int x = 0; x < m_regionWidth; x++)
  1326. {
  1327. resultarr2[y*2, x*2] = resultarr[y, x];
  1328. if (y < m_regionHeight)
  1329. {
  1330. if (y + 1 < m_regionHeight)
  1331. {
  1332. if (x + 1 < m_regionWidth)
  1333. {
  1334. resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x] +
  1335. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  1336. }
  1337. else
  1338. {
  1339. resultarr2[(y*2) + 1, x*2] = ((resultarr[y, x] + resultarr[y + 1, x])/2);
  1340. }
  1341. }
  1342. else
  1343. {
  1344. resultarr2[(y*2) + 1, x*2] = resultarr[y, x];
  1345. }
  1346. }
  1347. if (x < m_regionWidth)
  1348. {
  1349. if (x + 1 < m_regionWidth)
  1350. {
  1351. if (y + 1 < m_regionHeight)
  1352. {
  1353. resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
  1354. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  1355. }
  1356. else
  1357. {
  1358. resultarr2[y*2, (x*2) + 1] = ((resultarr[y, x] + resultarr[y, x + 1])/2);
  1359. }
  1360. }
  1361. else
  1362. {
  1363. resultarr2[y*2, (x*2) + 1] = resultarr[y, x];
  1364. }
  1365. }
  1366. if (x < m_regionWidth && y < m_regionHeight)
  1367. {
  1368. if ((x + 1 < m_regionWidth) && (y + 1 < m_regionHeight))
  1369. {
  1370. resultarr2[(y*2) + 1, (x*2) + 1] = ((resultarr[y, x] + resultarr[y + 1, x] +
  1371. resultarr[y, x + 1] + resultarr[y + 1, x + 1])/4);
  1372. }
  1373. else
  1374. {
  1375. resultarr2[(y*2) + 1, (x*2) + 1] = resultarr[y, x];
  1376. }
  1377. }
  1378. }
  1379. }
  1380. //Flatten out the array
  1381. int i = 0;
  1382. for (int y = 0; y < 512; y++)
  1383. {
  1384. for (int x = 0; x < 512; x++)
  1385. {
  1386. if (resultarr2[y, x] <= 0)
  1387. returnarr[i] = 0.0000001f;
  1388. else
  1389. returnarr[i] = resultarr2[y, x];
  1390. i++;
  1391. }
  1392. }
  1393. return returnarr;
  1394. }
  1395. public override void SetTerrain(float[] heightMap)
  1396. {
  1397. // this._heightmap[i] = (double)heightMap[i];
  1398. // dbm (danx0r) -- heightmap x,y must be swapped for Ode (should fix ODE, but for now...)
  1399. // also, creating a buffer zone of one extra sample all around
  1400. _origheightmap = heightMap;
  1401. const uint heightmapWidth = m_regionWidth + 2;
  1402. const uint heightmapHeight = m_regionHeight + 2;
  1403. const uint heightmapWidthSamples = 2*m_regionWidth + 2;
  1404. const uint heightmapHeightSamples = 2*m_regionHeight + 2;
  1405. const float scale = 1.0f;
  1406. const float offset = 0.0f;
  1407. const float thickness = 0.2f;
  1408. const int wrap = 0;
  1409. //Double resolution
  1410. heightMap = ResizeTerrain512Interpolation(heightMap);
  1411. for (int x = 0; x < heightmapWidthSamples; x++)
  1412. {
  1413. for (int y = 0; y < heightmapHeightSamples; y++)
  1414. {
  1415. int xx = Util.Clip(x - 1, 0, 511);
  1416. int yy = Util.Clip(y - 1, 0, 511);
  1417. float val = heightMap[yy*512 + xx];
  1418. _heightmap[x*heightmapHeightSamples + y] = val;
  1419. }
  1420. }
  1421. lock (OdeLock)
  1422. {
  1423. if (!(LandGeom == (IntPtr) 0))
  1424. {
  1425. d.SpaceRemove(space, LandGeom);
  1426. }
  1427. IntPtr HeightmapData = d.GeomHeightfieldDataCreate();
  1428. d.GeomHeightfieldDataBuildSingle(HeightmapData, _heightmap, 0, heightmapWidth, heightmapHeight,
  1429. (int) heightmapWidthSamples, (int) heightmapHeightSamples, scale,
  1430. offset, thickness, wrap);
  1431. d.GeomHeightfieldDataSetBounds(HeightmapData, m_regionWidth, m_regionHeight);
  1432. LandGeom = d.CreateHeightfield(space, HeightmapData, 1);
  1433. geom_name_map[LandGeom] = "Terrain";
  1434. d.Matrix3 R = new d.Matrix3();
  1435. Quaternion q1 = Quaternion.FromAngleAxis(1.5707f, new Vector3(1, 0, 0));
  1436. Quaternion q2 = Quaternion.FromAngleAxis(1.5707f, new Vector3(0, 1, 0));
  1437. //Axiom.Math.Quaternion q3 = Axiom.Math.Quaternion.FromAngleAxis(3.14f, new Axiom.Math.Vector3(0, 0, 1));
  1438. q1 = q1*q2;
  1439. //q1 = q1 * q3;
  1440. Vector3 v3 = new Vector3();
  1441. float angle = 0;
  1442. q1.ToAngleAxis(ref angle, ref v3);
  1443. d.RFromAxisAndAngle(out R, v3.x, v3.y, v3.z, angle);
  1444. d.GeomSetRotation(LandGeom, ref R);
  1445. d.GeomSetPosition(LandGeom, 128, 128, 0);
  1446. }
  1447. }
  1448. public override void DeleteTerrain()
  1449. {
  1450. }
  1451. public override void Dispose()
  1452. {
  1453. lock (OdeLock)
  1454. {
  1455. foreach (OdePrim prm in _prims)
  1456. {
  1457. RemovePrim(prm);
  1458. }
  1459. foreach (OdeCharacter act in _characters)
  1460. {
  1461. RemoveAvatar(act);
  1462. }
  1463. d.WorldDestroy(world);
  1464. //d.CloseODE();
  1465. }
  1466. }
  1467. }
  1468. }