BSPrim.cs 51 KB

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