BSPrim.cs 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192
  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 copyrightD
  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 OpenSimulator 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. using System;
  28. using System.Reflection;
  29. using System.Collections.Generic;
  30. using System.Xml;
  31. using log4net;
  32. using OMV = OpenMetaverse;
  33. using OpenSim.Framework;
  34. using OpenSim.Region.Physics.Manager;
  35. using OpenSim.Region.Physics.ConvexDecompositionDotNet;
  36. namespace OpenSim.Region.Physics.BulletSPlugin
  37. {
  38. [Serializable]
  39. public sealed class BSPrim : PhysicsActor
  40. {
  41. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  42. private static readonly string LogHeader = "[BULLETS PRIM]";
  43. private IMesh _mesh;
  44. private PrimitiveBaseShape _pbs;
  45. private ShapeData.PhysicsShapeType _shapeType;
  46. private ulong _hullKey;
  47. private List<ConvexResult> _hulls;
  48. private BSScene _scene;
  49. private String _avName;
  50. private uint _localID = 0;
  51. private OMV.Vector3 _size;
  52. private OMV.Vector3 _scale;
  53. private bool _stopped;
  54. private bool _grabbed;
  55. private bool _isSelected;
  56. private bool _isVolumeDetect;
  57. private OMV.Vector3 _position;
  58. private float _mass;
  59. private float _density;
  60. private OMV.Vector3 _force;
  61. private OMV.Vector3 _velocity;
  62. private OMV.Vector3 _torque;
  63. private float _collisionScore;
  64. private OMV.Vector3 _acceleration;
  65. private OMV.Quaternion _orientation;
  66. private int _physicsActorType;
  67. private bool _isPhysical;
  68. private bool _flying;
  69. private float _friction;
  70. private bool _setAlwaysRun;
  71. private bool _throttleUpdates;
  72. private bool _isColliding;
  73. private bool _collidingGround;
  74. private bool _collidingObj;
  75. private bool _floatOnWater;
  76. private OMV.Vector3 _rotationalVelocity;
  77. private bool _kinematic;
  78. private float _buoyancy;
  79. private OMV.Vector3 _angularVelocity;
  80. private List<BSPrim> _childrenPrims;
  81. private BSPrim _parentPrim;
  82. private int _subscribedEventsMs = 0;
  83. private int _lastCollisionTime = 0;
  84. long _collidingStep;
  85. long _collidingGroundStep;
  86. private BSDynamics _vehicle;
  87. private OMV.Vector3 _PIDTarget;
  88. private bool _usePID;
  89. private float _PIDTau;
  90. private bool _useHoverPID;
  91. private float _PIDHoverHeight;
  92. private PIDHoverType _PIDHoverType;
  93. private float _PIDHoverTao;
  94. public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
  95. OMV.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical)
  96. {
  97. // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
  98. _localID = localID;
  99. _avName = primName;
  100. _scene = parent_scene;
  101. _position = pos;
  102. _size = size;
  103. _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
  104. _orientation = rotation;
  105. _buoyancy = 1f;
  106. _velocity = OMV.Vector3.Zero;
  107. _angularVelocity = OMV.Vector3.Zero;
  108. _mesh = mesh;
  109. _hullKey = 0;
  110. _pbs = pbs;
  111. _isPhysical = pisPhysical;
  112. _isVolumeDetect = false;
  113. _subscribedEventsMs = 0;
  114. _friction = _scene.DefaultFriction; // TODO: compute based on object material
  115. _density = _scene.DefaultDensity; // TODO: compute based on object material
  116. _parentPrim = null; // not a child or a parent
  117. _vehicle = new BSDynamics(this); // add vehicleness
  118. _childrenPrims = new List<BSPrim>();
  119. if (_isPhysical)
  120. _mass = CalculateMass();
  121. else
  122. _mass = 0f;
  123. // do the actual object creation at taint time
  124. _scene.TaintedObject(delegate()
  125. {
  126. CreateGeom();
  127. CreateObject();
  128. });
  129. }
  130. // called when this prim is being destroyed and we should free all the resources
  131. public void Destroy()
  132. {
  133. // m_log.DebugFormat("{0}: Destroy", LogHeader);
  134. // Undo any vehicle properties
  135. _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
  136. _scene.RemoveVehiclePrim(this); // just to make sure
  137. _scene.TaintedObject(delegate()
  138. {
  139. BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
  140. });
  141. }
  142. public override bool Stopped {
  143. get { return _stopped; }
  144. }
  145. public override OMV.Vector3 Size {
  146. get { return _size; }
  147. set {
  148. _size = value;
  149. _scene.TaintedObject(delegate()
  150. {
  151. if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
  152. BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
  153. RecreateGeomAndObject();
  154. });
  155. }
  156. }
  157. public override PrimitiveBaseShape Shape {
  158. set {
  159. _pbs = value;
  160. _scene.TaintedObject(delegate()
  161. {
  162. if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
  163. RecreateGeomAndObject();
  164. });
  165. }
  166. }
  167. public override uint LocalID {
  168. set { _localID = value; }
  169. get { return _localID; }
  170. }
  171. public override bool Grabbed {
  172. set { _grabbed = value;
  173. }
  174. }
  175. public override bool Selected {
  176. set {
  177. _isSelected = value;
  178. _scene.TaintedObject(delegate()
  179. {
  180. SetObjectDynamic();
  181. });
  182. }
  183. }
  184. public override void CrossingFailure() { return; }
  185. // link me to the specified parent
  186. public override void link(PhysicsActor obj) {
  187. BSPrim parent = (BSPrim)obj;
  188. // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
  189. // TODO: decide if this parent checking needs to happen at taint time
  190. if (_parentPrim == null)
  191. {
  192. if (parent != null)
  193. {
  194. // I don't have a parent so I am joining a linkset
  195. parent.AddChildToLinkset(this);
  196. }
  197. }
  198. else
  199. {
  200. // I already have a parent, is parenting changing?
  201. if (parent != _parentPrim)
  202. {
  203. if (parent == null)
  204. {
  205. // we are being removed from a linkset
  206. _parentPrim.RemoveChildFromLinkset(this);
  207. }
  208. else
  209. {
  210. // asking to reparent a prim should not happen
  211. m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
  212. }
  213. }
  214. }
  215. return;
  216. }
  217. // delink me from my linkset
  218. public override void delink() {
  219. // TODO: decide if this parent checking needs to happen at taint time
  220. // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
  221. // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
  222. if (_parentPrim != null)
  223. {
  224. _parentPrim.RemoveChildFromLinkset(this);
  225. }
  226. return;
  227. }
  228. public void AddChildToLinkset(BSPrim pchild)
  229. {
  230. BSPrim child = pchild;
  231. _scene.TaintedObject(delegate()
  232. {
  233. if (!_childrenPrims.Contains(child))
  234. {
  235. _childrenPrims.Add(child);
  236. child.ParentPrim = this; // the child has gained a parent
  237. RecreateGeomAndObject(); // rebuild my shape with the new child added
  238. }
  239. });
  240. return;
  241. }
  242. public void RemoveChildFromLinkset(BSPrim pchild)
  243. {
  244. BSPrim child = pchild;
  245. _scene.TaintedObject(delegate()
  246. {
  247. if (_childrenPrims.Contains(child))
  248. {
  249. _childrenPrims.Remove(child);
  250. child.ParentPrim = null; // the child has lost its parent
  251. RecreateGeomAndObject(); // rebuild my shape with the child removed
  252. }
  253. else
  254. {
  255. m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
  256. }
  257. });
  258. return;
  259. }
  260. public BSPrim ParentPrim
  261. {
  262. set { _parentPrim = value; }
  263. }
  264. public ulong HullKey
  265. {
  266. get { return _hullKey; }
  267. }
  268. // return true if we are the root of a linkset (there are children to manage)
  269. public bool IsRootOfLinkset
  270. {
  271. get { return (_parentPrim == null && _childrenPrims.Count != 0); }
  272. }
  273. public override void LockAngularMotion(OMV.Vector3 axis) { return; }
  274. public override OMV.Vector3 Position {
  275. get {
  276. // don't do the following GetObjectPosition because this function is called a zillion times
  277. // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
  278. return _position;
  279. }
  280. set {
  281. _position = value;
  282. _scene.TaintedObject(delegate()
  283. {
  284. BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
  285. // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
  286. });
  287. }
  288. }
  289. public override float Mass {
  290. get { return _mass; }
  291. }
  292. public override OMV.Vector3 Force {
  293. get { return _force; }
  294. set {
  295. _force = value;
  296. _scene.TaintedObject(delegate()
  297. {
  298. BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
  299. });
  300. }
  301. }
  302. public override int VehicleType {
  303. get {
  304. return (int)_vehicle.Type; // if we are a vehicle, return that type
  305. }
  306. set {
  307. Vehicle type = (Vehicle)value;
  308. _vehicle.ProcessTypeChange(type);
  309. _scene.TaintedObject(delegate()
  310. {
  311. if (type == Vehicle.TYPE_NONE)
  312. {
  313. _scene.RemoveVehiclePrim(this);
  314. }
  315. else
  316. {
  317. // make it so the scene will call us each tick to do vehicle things
  318. _scene.AddVehiclePrim(this);
  319. }
  320. return;
  321. });
  322. }
  323. }
  324. public override void VehicleFloatParam(int param, float value)
  325. {
  326. _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
  327. }
  328. public override void VehicleVectorParam(int param, OMV.Vector3 value)
  329. {
  330. _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
  331. }
  332. public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
  333. {
  334. _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
  335. }
  336. public override void VehicleFlags(int param, bool remove)
  337. {
  338. _vehicle.ProcessVehicleFlags(param, remove);
  339. }
  340. // Called each simulation step to advance vehicle characteristics
  341. public void StepVehicle(float timeStep)
  342. {
  343. _vehicle.Step(timeStep, _scene);
  344. }
  345. // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
  346. public override void SetVolumeDetect(int param) {
  347. bool newValue = (param != 0);
  348. if (_isVolumeDetect != newValue)
  349. {
  350. _isVolumeDetect = newValue;
  351. _scene.TaintedObject(delegate()
  352. {
  353. SetObjectDynamic();
  354. });
  355. }
  356. return;
  357. }
  358. public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
  359. public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
  360. public override OMV.Vector3 Velocity {
  361. get { return _velocity; }
  362. set { _velocity = value;
  363. _scene.TaintedObject(delegate()
  364. {
  365. BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
  366. });
  367. }
  368. }
  369. public OMV.Vector3 AngularVelocity
  370. {
  371. get { return _angularVelocity; }
  372. set
  373. {
  374. _angularVelocity = value;
  375. _scene.TaintedObject(delegate()
  376. {
  377. BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _angularVelocity);
  378. });
  379. }
  380. }
  381. public override OMV.Vector3 Torque {
  382. get { return _torque; }
  383. set { _torque = value;
  384. }
  385. }
  386. public override float CollisionScore {
  387. get { return _collisionScore; }
  388. set { _collisionScore = value;
  389. }
  390. }
  391. public override OMV.Vector3 Acceleration {
  392. get { return _acceleration; }
  393. }
  394. public override OMV.Quaternion Orientation {
  395. get { return _orientation; }
  396. set {
  397. _orientation = value;
  398. _scene.TaintedObject(delegate()
  399. {
  400. // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
  401. BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
  402. // m_log.DebugFormat("{0}: set orientation: {1}", LogHeader, _orientation);
  403. });
  404. }
  405. }
  406. public override int PhysicsActorType {
  407. get { return _physicsActorType; }
  408. set { _physicsActorType = value;
  409. }
  410. }
  411. public override bool IsPhysical {
  412. get { return _isPhysical; }
  413. set {
  414. _isPhysical = value;
  415. _scene.TaintedObject(delegate()
  416. {
  417. SetObjectDynamic();
  418. });
  419. }
  420. }
  421. // An object is static (does not move) if selected or not physical
  422. private bool IsStatic
  423. {
  424. get { return _isSelected || !IsPhysical; }
  425. }
  426. // An object is solid if it's not phantom and if it's not doing VolumeDetect
  427. private bool IsSolid
  428. {
  429. get { return !IsPhantom && !_isVolumeDetect; }
  430. }
  431. // make gravity work if the object is physical and not selected
  432. // no locking here because only called when it is safe
  433. private void SetObjectDynamic()
  434. {
  435. // non-physical things work best with a mass of zero
  436. _mass = IsStatic ? 0f : CalculateMass();
  437. BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
  438. // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass);
  439. }
  440. // prims don't fly
  441. public override bool Flying {
  442. get { return _flying; }
  443. set { _flying = value; }
  444. }
  445. public override bool SetAlwaysRun {
  446. get { return _setAlwaysRun; }
  447. set { _setAlwaysRun = value; }
  448. }
  449. public override bool ThrottleUpdates {
  450. get { return _throttleUpdates; }
  451. set { _throttleUpdates = value; }
  452. }
  453. public override bool IsColliding {
  454. get { return (_collidingStep == _scene.SimulationStep); }
  455. set { _isColliding = value; }
  456. }
  457. public override bool CollidingGround {
  458. get { return (_collidingGroundStep == _scene.SimulationStep); }
  459. set { _collidingGround = value; }
  460. }
  461. public override bool CollidingObj {
  462. get { return _collidingObj; }
  463. set { _collidingObj = value; }
  464. }
  465. public bool IsPhantom {
  466. get {
  467. // SceneObjectPart removes phantom objects from the physics scene
  468. // so, although we could implement touching and such, we never
  469. // are invoked as a phantom object
  470. return false;
  471. }
  472. }
  473. public override bool FloatOnWater {
  474. set { _floatOnWater = value; }
  475. }
  476. public override OMV.Vector3 RotationalVelocity {
  477. get { return _rotationalVelocity; }
  478. set { _rotationalVelocity = value;
  479. // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
  480. }
  481. }
  482. public override bool Kinematic {
  483. get { return _kinematic; }
  484. set { _kinematic = value;
  485. // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
  486. }
  487. }
  488. public override float Buoyancy {
  489. get { return _buoyancy; }
  490. set { _buoyancy = value;
  491. _scene.TaintedObject(delegate()
  492. {
  493. BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
  494. });
  495. }
  496. }
  497. // Used for MoveTo
  498. public override OMV.Vector3 PIDTarget {
  499. set { _PIDTarget = value; }
  500. }
  501. public override bool PIDActive {
  502. set { _usePID = value; }
  503. }
  504. public override float PIDTau {
  505. set { _PIDTau = value; }
  506. }
  507. // Used for llSetHoverHeight and maybe vehicle height
  508. // Hover Height will override MoveTo target's Z
  509. public override bool PIDHoverActive {
  510. set { _useHoverPID = value; }
  511. }
  512. public override float PIDHoverHeight {
  513. set { _PIDHoverHeight = value; }
  514. }
  515. public override PIDHoverType PIDHoverType {
  516. set { _PIDHoverType = value; }
  517. }
  518. public override float PIDHoverTau {
  519. set { _PIDHoverTao = value; }
  520. }
  521. // For RotLookAt
  522. public override OMV.Quaternion APIDTarget { set { return; } }
  523. public override bool APIDActive { set { return; } }
  524. public override float APIDStrength { set { return; } }
  525. public override float APIDDamping { set { return; } }
  526. public override void AddForce(OMV.Vector3 force, bool pushforce) {
  527. if (force.IsFinite())
  528. {
  529. _force.X += force.X;
  530. _force.Y += force.Y;
  531. _force.Z += force.Z;
  532. }
  533. else
  534. {
  535. m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
  536. }
  537. _scene.TaintedObject(delegate()
  538. {
  539. BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
  540. });
  541. }
  542. public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
  543. // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
  544. }
  545. public override void SetMomentum(OMV.Vector3 momentum) {
  546. }
  547. public override void SubscribeEvents(int ms) {
  548. _subscribedEventsMs = ms;
  549. _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
  550. }
  551. public override void UnSubscribeEvents() {
  552. _subscribedEventsMs = 0;
  553. }
  554. public override bool SubscribedEvents() {
  555. return (_subscribedEventsMs > 0);
  556. }
  557. #region Mass Calculation
  558. private float CalculateMass()
  559. {
  560. float volume = _size.X * _size.Y * _size.Z; // default
  561. float tmp;
  562. float returnMass = 0;
  563. float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
  564. float hollowVolume = hollowAmount * hollowAmount;
  565. switch (_pbs.ProfileShape)
  566. {
  567. case ProfileShape.Square:
  568. // default box
  569. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  570. {
  571. if (hollowAmount > 0.0)
  572. {
  573. switch (_pbs.HollowShape)
  574. {
  575. case HollowShape.Square:
  576. case HollowShape.Same:
  577. break;
  578. case HollowShape.Circle:
  579. hollowVolume *= 0.78539816339f;
  580. break;
  581. case HollowShape.Triangle:
  582. hollowVolume *= (0.5f * .5f);
  583. break;
  584. default:
  585. hollowVolume = 0;
  586. break;
  587. }
  588. volume *= (1.0f - hollowVolume);
  589. }
  590. }
  591. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  592. {
  593. //a tube
  594. volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
  595. tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
  596. volume -= volume*tmp*tmp;
  597. if (hollowAmount > 0.0)
  598. {
  599. hollowVolume *= hollowAmount;
  600. switch (_pbs.HollowShape)
  601. {
  602. case HollowShape.Square:
  603. case HollowShape.Same:
  604. break;
  605. case HollowShape.Circle:
  606. hollowVolume *= 0.78539816339f;;
  607. break;
  608. case HollowShape.Triangle:
  609. hollowVolume *= 0.5f * 0.5f;
  610. break;
  611. default:
  612. hollowVolume = 0;
  613. break;
  614. }
  615. volume *= (1.0f - hollowVolume);
  616. }
  617. }
  618. break;
  619. case ProfileShape.Circle:
  620. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  621. {
  622. volume *= 0.78539816339f; // elipse base
  623. if (hollowAmount > 0.0)
  624. {
  625. switch (_pbs.HollowShape)
  626. {
  627. case HollowShape.Same:
  628. case HollowShape.Circle:
  629. break;
  630. case HollowShape.Square:
  631. hollowVolume *= 0.5f * 2.5984480504799f;
  632. break;
  633. case HollowShape.Triangle:
  634. hollowVolume *= .5f * 1.27323954473516f;
  635. break;
  636. default:
  637. hollowVolume = 0;
  638. break;
  639. }
  640. volume *= (1.0f - hollowVolume);
  641. }
  642. }
  643. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  644. {
  645. volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
  646. tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
  647. volume *= (1.0f - tmp * tmp);
  648. if (hollowAmount > 0.0)
  649. {
  650. // calculate the hollow volume by it's shape compared to the prim shape
  651. hollowVolume *= hollowAmount;
  652. switch (_pbs.HollowShape)
  653. {
  654. case HollowShape.Same:
  655. case HollowShape.Circle:
  656. break;
  657. case HollowShape.Square:
  658. hollowVolume *= 0.5f * 2.5984480504799f;
  659. break;
  660. case HollowShape.Triangle:
  661. hollowVolume *= .5f * 1.27323954473516f;
  662. break;
  663. default:
  664. hollowVolume = 0;
  665. break;
  666. }
  667. volume *= (1.0f - hollowVolume);
  668. }
  669. }
  670. break;
  671. case ProfileShape.HalfCircle:
  672. if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  673. {
  674. volume *= 0.52359877559829887307710723054658f;
  675. }
  676. break;
  677. case ProfileShape.EquilateralTriangle:
  678. if (_pbs.PathCurve == (byte)Extrusion.Straight)
  679. {
  680. volume *= 0.32475953f;
  681. if (hollowAmount > 0.0)
  682. {
  683. // calculate the hollow volume by it's shape compared to the prim shape
  684. switch (_pbs.HollowShape)
  685. {
  686. case HollowShape.Same:
  687. case HollowShape.Triangle:
  688. hollowVolume *= .25f;
  689. break;
  690. case HollowShape.Square:
  691. hollowVolume *= 0.499849f * 3.07920140172638f;
  692. break;
  693. case HollowShape.Circle:
  694. // Hollow shape is a perfect cyllinder in respect to the cube's scale
  695. // Cyllinder hollow volume calculation
  696. hollowVolume *= 0.1963495f * 3.07920140172638f;
  697. break;
  698. default:
  699. hollowVolume = 0;
  700. break;
  701. }
  702. volume *= (1.0f - hollowVolume);
  703. }
  704. }
  705. else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
  706. {
  707. volume *= 0.32475953f;
  708. volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
  709. tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
  710. volume *= (1.0f - tmp * tmp);
  711. if (hollowAmount > 0.0)
  712. {
  713. hollowVolume *= hollowAmount;
  714. switch (_pbs.HollowShape)
  715. {
  716. case HollowShape.Same:
  717. case HollowShape.Triangle:
  718. hollowVolume *= .25f;
  719. break;
  720. case HollowShape.Square:
  721. hollowVolume *= 0.499849f * 3.07920140172638f;
  722. break;
  723. case HollowShape.Circle:
  724. hollowVolume *= 0.1963495f * 3.07920140172638f;
  725. break;
  726. default:
  727. hollowVolume = 0;
  728. break;
  729. }
  730. volume *= (1.0f - hollowVolume);
  731. }
  732. }
  733. break;
  734. default:
  735. break;
  736. }
  737. float taperX1;
  738. float taperY1;
  739. float taperX;
  740. float taperY;
  741. float pathBegin;
  742. float pathEnd;
  743. float profileBegin;
  744. float profileEnd;
  745. if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
  746. {
  747. taperX1 = _pbs.PathScaleX * 0.01f;
  748. if (taperX1 > 1.0f)
  749. taperX1 = 2.0f - taperX1;
  750. taperX = 1.0f - taperX1;
  751. taperY1 = _pbs.PathScaleY * 0.01f;
  752. if (taperY1 > 1.0f)
  753. taperY1 = 2.0f - taperY1;
  754. taperY = 1.0f - taperY1;
  755. }
  756. else
  757. {
  758. taperX = _pbs.PathTaperX * 0.01f;
  759. if (taperX < 0.0f)
  760. taperX = -taperX;
  761. taperX1 = 1.0f - taperX;
  762. taperY = _pbs.PathTaperY * 0.01f;
  763. if (taperY < 0.0f)
  764. taperY = -taperY;
  765. taperY1 = 1.0f - taperY;
  766. }
  767. volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
  768. pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
  769. pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
  770. volume *= (pathEnd - pathBegin);
  771. // this is crude aproximation
  772. profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
  773. profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
  774. volume *= (profileEnd - profileBegin);
  775. returnMass = _density * volume;
  776. if (returnMass <= 0)
  777. returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
  778. if (IsRootOfLinkset)
  779. {
  780. foreach (BSPrim prim in _childrenPrims)
  781. {
  782. returnMass += prim.CalculateMass();
  783. }
  784. }
  785. if (returnMass > _scene.maximumMassObject)
  786. returnMass = _scene.maximumMassObject;
  787. return returnMass;
  788. }// end CalculateMass
  789. #endregion Mass Calculation
  790. // Create the geometry information in Bullet for later use
  791. // No locking here because this is done when we know physics is not simulating
  792. private void CreateGeom()
  793. {
  794. if (_mesh == null)
  795. {
  796. // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
  797. if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
  798. {
  799. if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
  800. {
  801. // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to sphere of size {1}", LogHeader, _size);
  802. _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
  803. // Bullet native objects are scaled by the Bullet engine so pass the size in
  804. _scale = _size;
  805. }
  806. }
  807. else
  808. {
  809. // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box of size {1}", LogHeader, _size);
  810. _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
  811. _scale = _size;
  812. }
  813. }
  814. else
  815. {
  816. if (_hullKey != 0)
  817. {
  818. // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
  819. BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
  820. _hullKey = 0;
  821. _hulls.Clear();
  822. }
  823. int[] indices = _mesh.getIndexListAsInt();
  824. List<OMV.Vector3> vertices = _mesh.getVertexList();
  825. //format conversion from IMesh format to DecompDesc format
  826. List<int> convIndices = new List<int>();
  827. List<float3> convVertices = new List<float3>();
  828. for (int ii = 0; ii < indices.GetLength(0); ii++)
  829. {
  830. convIndices.Add(indices[ii]);
  831. }
  832. foreach (OMV.Vector3 vv in vertices)
  833. {
  834. convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
  835. }
  836. // setup and do convex hull conversion
  837. _hulls = new List<ConvexResult>();
  838. DecompDesc dcomp = new DecompDesc();
  839. dcomp.mIndices = convIndices;
  840. dcomp.mVertices = convVertices;
  841. ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
  842. // create the hull into the _hulls variable
  843. convexBuilder.process(dcomp);
  844. // Convert the vertices and indices for passing to unmanaged
  845. // The hull information is passed as a large floating point array.
  846. // The format is:
  847. // convHulls[0] = number of hulls
  848. // convHulls[1] = number of vertices in first hull
  849. // convHulls[2] = hull centroid X coordinate
  850. // convHulls[3] = hull centroid Y coordinate
  851. // convHulls[4] = hull centroid Z coordinate
  852. // convHulls[5] = first hull vertex X
  853. // convHulls[6] = first hull vertex Y
  854. // convHulls[7] = first hull vertex Z
  855. // convHulls[8] = second hull vertex X
  856. // ...
  857. // convHulls[n] = number of vertices in second hull
  858. // convHulls[n+1] = second hull centroid X coordinate
  859. // ...
  860. //
  861. // TODO: is is very inefficient. Someday change the convex hull generator to return
  862. // data structures that do not need to be converted in order to pass to Bullet.
  863. // And maybe put the values directly into pinned memory rather than marshaling.
  864. int hullCount = _hulls.Count;
  865. int totalVertices = 1; // include one for the count of the hulls
  866. foreach (ConvexResult cr in _hulls)
  867. {
  868. totalVertices += 4; // add four for the vertex count and centroid
  869. totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
  870. }
  871. float[] convHulls = new float[totalVertices];
  872. convHulls[0] = (float)hullCount;
  873. int jj = 1;
  874. foreach (ConvexResult cr in _hulls)
  875. {
  876. // copy vertices for index access
  877. float3[] verts = new float3[cr.HullVertices.Count];
  878. int kk = 0;
  879. foreach (float3 ff in cr.HullVertices)
  880. {
  881. verts[kk++] = ff;
  882. }
  883. // add to the array one hull's worth of data
  884. convHulls[jj++] = cr.HullIndices.Count;
  885. convHulls[jj++] = 0f; // centroid x,y,z
  886. convHulls[jj++] = 0f;
  887. convHulls[jj++] = 0f;
  888. foreach (int ind in cr.HullIndices)
  889. {
  890. convHulls[jj++] = verts[ind].x;
  891. convHulls[jj++] = verts[ind].y;
  892. convHulls[jj++] = verts[ind].z;
  893. }
  894. }
  895. // create the hull definition in Bullet
  896. _hullKey = (ulong)_pbs.GetHashCode();
  897. // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid= {1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
  898. BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
  899. _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
  900. // meshes are already scaled by the meshmerizer
  901. _scale = new OMV.Vector3(1f, 1f, 1f);
  902. }
  903. return;
  904. }
  905. private void HullReturn(ConvexResult result)
  906. {
  907. _hulls.Add(result);
  908. return;
  909. }
  910. // Create an object in Bullet
  911. // No locking here because this is done when the physics engine is not simulating
  912. private void CreateObject()
  913. {
  914. if (IsRootOfLinkset)
  915. {
  916. // Create a linkset around this object
  917. /*
  918. * NOTE: the original way of creating a linkset was to create a compound hull in the
  919. * root which consisted of the hulls of all the children. This didn't work well because
  920. * OpenSimulator needs updates and collisions for all the children and the physics
  921. * engine didn't create events for the children when the root hull was moved.
  922. * This code creates the compound hull.
  923. // If I am the root prim of a linkset, replace my physical shape with all the
  924. // pieces of the children.
  925. // All of the children should have called CreateGeom so they have a hull
  926. // in the physics engine already. Here we pull together all of those hulls
  927. // into one shape.
  928. int totalPrimsInLinkset = _childrenPrims.Count + 1;
  929. // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
  930. ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
  931. FillShapeInfo(out shapes[0]);
  932. int ii = 1;
  933. foreach (BSPrim prim in _childrenPrims)
  934. {
  935. // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
  936. prim.FillShapeInfo(out shapes[ii]);
  937. ii++;
  938. }
  939. BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
  940. */
  941. // Create the linkset by putting constraints between the objects of the set so they cannot move
  942. // relative to each other.
  943. // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
  944. // remove any constraints that might be in place
  945. foreach (BSPrim prim in _childrenPrims)
  946. {
  947. BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
  948. }
  949. // create constraints between the root prim and each of the children
  950. foreach (BSPrim prim in _childrenPrims)
  951. {
  952. // this is a constraint that allows no freedom of movement between the two objects
  953. // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
  954. BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, OMV.Vector3.Zero, OMV.Vector3.Zero,
  955. OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero);
  956. }
  957. }
  958. else
  959. {
  960. // simple object
  961. // m_log.DebugFormat("{0}: CreateObject. ID={1}", LogHeader, LocalID);
  962. ShapeData shape;
  963. FillShapeInfo(out shape);
  964. BulletSimAPI.CreateObject(_scene.WorldID, shape);
  965. }
  966. }
  967. // Copy prim's info into the BulletSim shape description structure
  968. public void FillShapeInfo(out ShapeData shape)
  969. {
  970. shape.ID = _localID;
  971. shape.Type = _shapeType;
  972. shape.Position = _position;
  973. shape.Rotation = _orientation;
  974. shape.Velocity = _velocity;
  975. shape.Scale = _scale;
  976. shape.Mass = _isPhysical ? _mass : 0f;
  977. shape.Buoyancy = _buoyancy;
  978. shape.MeshKey = _hullKey;
  979. shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
  980. shape.Friction = _friction;
  981. shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
  982. }
  983. // Rebuild the geometry and object.
  984. // This is called when the shape changes so we need to recreate the mesh/hull.
  985. // No locking here because this is done when the physics engine is not simulating
  986. private void RecreateGeomAndObject()
  987. {
  988. if (_hullKey != 0)
  989. {
  990. // if a hull already exists, delete the old one
  991. BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
  992. _hullKey = 0;
  993. }
  994. // If this object is complex or we are the root of a linkset, build a mesh.
  995. // The root of a linkset must be a mesh so we can create the linked compound object.
  996. if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset )
  997. {
  998. // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader);
  999. _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.meshLOD, _isPhysical);
  1000. }
  1001. else
  1002. {
  1003. // it's a BulletSim native shape.
  1004. _mesh = null;
  1005. }
  1006. CreateGeom(); // create the geometry for this prim
  1007. CreateObject();
  1008. return;
  1009. }
  1010. // The physics engine says that properties have updated. Update same and inform
  1011. // the world that things have changed.
  1012. // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
  1013. private int UpPropPosition = 1 << 0;
  1014. private int UpPropRotation = 1 << 1;
  1015. private int UpPropVelocity = 1 << 2;
  1016. private int UpPropAcceleration = 1 << 3;
  1017. private int UpPropAngularVel = 1 << 4;
  1018. public void UpdateProperties(EntityProperties entprop)
  1019. {
  1020. int changed = 0;
  1021. // assign to the local variables so the normal set action does not happen
  1022. if (_position != entprop.Position)
  1023. {
  1024. _position = entprop.Position;
  1025. // m_log.DebugFormat("{0}: UpdateProperties: position = {1}", LogHeader, _position);
  1026. changed |= UpPropPosition;
  1027. }
  1028. if (_orientation != entprop.Rotation)
  1029. {
  1030. _orientation = entprop.Rotation;
  1031. // m_log.DebugFormat("{0}: UpdateProperties: rotation = {1}", LogHeader, _orientation);
  1032. changed |= UpPropRotation;
  1033. }
  1034. if (_velocity != entprop.Velocity)
  1035. {
  1036. _velocity = entprop.Velocity;
  1037. // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
  1038. changed |= UpPropVelocity;
  1039. }
  1040. if (_acceleration != entprop.Acceleration)
  1041. {
  1042. _acceleration = entprop.Acceleration;
  1043. // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
  1044. changed |= UpPropAcceleration;
  1045. }
  1046. if (_rotationalVelocity != entprop.AngularVelocity)
  1047. {
  1048. _rotationalVelocity = entprop.AngularVelocity;
  1049. // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
  1050. changed |= UpPropAngularVel;
  1051. }
  1052. if (changed != 0)
  1053. {
  1054. // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
  1055. base.RequestPhysicsterseUpdate();
  1056. }
  1057. }
  1058. // I've collided with something
  1059. public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
  1060. {
  1061. // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
  1062. // The following makes IsColliding() and IsCollidingGround() work
  1063. _collidingStep = _scene.SimulationStep;
  1064. if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
  1065. {
  1066. _collidingGroundStep = _scene.SimulationStep;
  1067. }
  1068. if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
  1069. // throttle the collisions to the number of milliseconds specified in the subscription
  1070. int nowTime = Util.EnvironmentTickCount();
  1071. if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
  1072. _lastCollisionTime = nowTime;
  1073. // create the event for the collision
  1074. Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
  1075. contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
  1076. CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
  1077. base.SendCollisionUpdate(args);
  1078. }
  1079. }
  1080. }