BSPrim.cs 53 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379
  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. // Uncomment this it enable code to do all shape an body memory management
  28. // in the C# code.
  29. using System;
  30. using System.Reflection;
  31. using System.Collections.Generic;
  32. using System.Xml;
  33. using log4net;
  34. using OMV = OpenMetaverse;
  35. using OpenSim.Framework;
  36. using OpenSim.Region.Physics.Manager;
  37. using OpenSim.Region.Physics.ConvexDecompositionDotNet;
  38. namespace OpenSim.Region.Physics.BulletSPlugin
  39. {
  40. [Serializable]
  41. public sealed class BSPrim : BSPhysObject
  42. {
  43. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  44. private static readonly string LogHeader = "[BULLETS PRIM]";
  45. // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
  46. // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
  47. private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
  48. // private OMV.Vector3 _scale; // the multiplier for each mesh dimension for the mesh as created by the meshmerizer
  49. private bool _grabbed;
  50. private bool _isSelected;
  51. private bool _isVolumeDetect;
  52. private OMV.Vector3 _position;
  53. private float _mass; // the mass of this object
  54. private float _density;
  55. private OMV.Vector3 _force;
  56. private OMV.Vector3 _velocity;
  57. private OMV.Vector3 _torque;
  58. private float _collisionScore;
  59. private OMV.Vector3 _acceleration;
  60. private OMV.Quaternion _orientation;
  61. private int _physicsActorType;
  62. private bool _isPhysical;
  63. private bool _flying;
  64. private float _friction;
  65. private float _restitution;
  66. private bool _setAlwaysRun;
  67. private bool _throttleUpdates;
  68. private bool _isColliding;
  69. private bool _collidingGround;
  70. private bool _collidingObj;
  71. private bool _floatOnWater;
  72. private OMV.Vector3 _rotationalVelocity;
  73. private bool _kinematic;
  74. private float _buoyancy;
  75. private BSDynamics _vehicle;
  76. private OMV.Vector3 _PIDTarget;
  77. private bool _usePID;
  78. private float _PIDTau;
  79. private bool _useHoverPID;
  80. private float _PIDHoverHeight;
  81. private PIDHoverType _PIDHoverType;
  82. private float _PIDHoverTao;
  83. public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
  84. OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
  85. {
  86. // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
  87. base.BaseInitialize(parent_scene, localID, primName, "BSPrim");
  88. _physicsActorType = (int)ActorTypes.Prim;
  89. _position = pos;
  90. _size = size;
  91. Scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
  92. _orientation = rotation;
  93. _buoyancy = 1f;
  94. _velocity = OMV.Vector3.Zero;
  95. _rotationalVelocity = OMV.Vector3.Zero;
  96. BaseShape = pbs;
  97. _isPhysical = pisPhysical;
  98. _isVolumeDetect = false;
  99. _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material
  100. _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material
  101. _restitution = PhysicsScene.Params.defaultRestitution;
  102. _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
  103. _mass = CalculateMass();
  104. // No body or shape yet
  105. BSBody = new BulletBody(LocalID, IntPtr.Zero);
  106. BSShape = new BulletShape(IntPtr.Zero);
  107. DetailLog("{0},BSPrim.constructor,call", LocalID);
  108. // do the actual object creation at taint time
  109. PhysicsScene.TaintedObject("BSPrim.create", delegate()
  110. {
  111. CreateGeomAndObject(true);
  112. CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(BSBody.ptr);
  113. });
  114. }
  115. // called when this prim is being destroyed and we should free all the resources
  116. public override void Destroy()
  117. {
  118. // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
  119. // Undo any links between me and any other object
  120. BSPhysObject parentBefore = Linkset.LinksetRoot;
  121. int childrenBefore = Linkset.NumberOfChildren;
  122. Linkset = Linkset.RemoveMeFromLinkset(this);
  123. DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
  124. LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
  125. // Undo any vehicle properties
  126. this.VehicleType = (int)Vehicle.TYPE_NONE;
  127. PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
  128. {
  129. DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
  130. // If there are physical body and shape, release my use of same.
  131. PhysicsScene.Shapes.DereferenceBody(BSBody, true, null);
  132. PhysicsScene.Shapes.DereferenceShape(BSShape, true, null);
  133. });
  134. }
  135. // No one uses this property.
  136. public override bool Stopped {
  137. get { return false; }
  138. }
  139. public override OMV.Vector3 Size {
  140. get { return _size; }
  141. set {
  142. _size = value;
  143. ForceBodyShapeRebuild(false);
  144. }
  145. }
  146. // Scale is what we set in the physics engine. It is different than 'size' in that
  147. // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
  148. public override OMV.Vector3 Scale { get; set; }
  149. public override PrimitiveBaseShape Shape {
  150. set {
  151. BaseShape = value;
  152. ForceBodyShapeRebuild(false);
  153. }
  154. }
  155. public override bool ForceBodyShapeRebuild(bool inTaintTime)
  156. {
  157. LastAssetBuildFailed = false;
  158. BSScene.TaintCallback rebuildOperation = delegate()
  159. {
  160. _mass = CalculateMass(); // changing the shape changes the mass
  161. CreateGeomAndObject(true);
  162. };
  163. if (inTaintTime)
  164. rebuildOperation();
  165. else
  166. PhysicsScene.TaintedObject("BSPrim.ForceBodyShapeRebuild", rebuildOperation);
  167. return true;
  168. }
  169. public override bool Grabbed {
  170. set { _grabbed = value;
  171. }
  172. }
  173. public override bool Selected {
  174. set {
  175. _isSelected = value;
  176. PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
  177. {
  178. DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
  179. SetObjectDynamic(false);
  180. });
  181. }
  182. }
  183. public override void CrossingFailure() { return; }
  184. // link me to the specified parent
  185. public override void link(PhysicsActor obj) {
  186. BSPrim parent = obj as BSPrim;
  187. if (parent != null)
  188. {
  189. BSPhysObject parentBefore = Linkset.LinksetRoot;
  190. int childrenBefore = Linkset.NumberOfChildren;
  191. Linkset = parent.Linkset.AddMeToLinkset(this);
  192. DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
  193. LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
  194. }
  195. return;
  196. }
  197. // delink me from my linkset
  198. public override void delink() {
  199. // TODO: decide if this parent checking needs to happen at taint time
  200. // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
  201. BSPhysObject parentBefore = Linkset.LinksetRoot;
  202. int childrenBefore = Linkset.NumberOfChildren;
  203. Linkset = Linkset.RemoveMeFromLinkset(this);
  204. DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
  205. LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
  206. return;
  207. }
  208. // Set motion values to zero.
  209. // Do it to the properties so the values get set in the physics engine.
  210. // Push the setting of the values to the viewer.
  211. // Called at taint time!
  212. public override void ZeroMotion()
  213. {
  214. _velocity = OMV.Vector3.Zero;
  215. _acceleration = OMV.Vector3.Zero;
  216. _rotationalVelocity = OMV.Vector3.Zero;
  217. // Zero some other properties directly into the physics engine
  218. BulletSimAPI.ClearForces2(BSBody.ptr);
  219. }
  220. public override void LockAngularMotion(OMV.Vector3 axis)
  221. {
  222. DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
  223. return;
  224. }
  225. public override OMV.Vector3 Position {
  226. get {
  227. if (!Linkset.IsRoot(this))
  228. // child prims move around based on their parent. Need to get the latest location
  229. _position = BulletSimAPI.GetPosition2(BSBody.ptr);
  230. // don't do the GetObjectPosition for root elements because this function is called a zillion times
  231. // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
  232. return _position;
  233. }
  234. set {
  235. // If you must push the position into the physics engine, use ForcePosition.
  236. if (_position == value)
  237. {
  238. return;
  239. }
  240. _position = value;
  241. // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
  242. PositionSanityCheck();
  243. PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
  244. {
  245. // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
  246. BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
  247. });
  248. }
  249. }
  250. public override OMV.Vector3 ForcePosition {
  251. get {
  252. _position = BulletSimAPI.GetPosition2(BSBody.ptr);
  253. return _position;
  254. }
  255. set {
  256. _position = value;
  257. PositionSanityCheck();
  258. BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
  259. }
  260. }
  261. // Check that the current position is sane and, if not, modify the position to make it so.
  262. // Check for being below terrain and being out of bounds.
  263. // Returns 'true' of the position was made sane by some action.
  264. private bool PositionSanityCheck()
  265. {
  266. bool ret = false;
  267. // If totally below the ground, move the prim up
  268. // TODO: figure out the right solution for this... only for dynamic objects?
  269. /*
  270. float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
  271. if (Position.Z < terrainHeight)
  272. {
  273. DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
  274. _position.Z = terrainHeight + 2.0f;
  275. ret = true;
  276. }
  277. */
  278. if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
  279. {
  280. float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position);
  281. // TODO: a floating motor so object will bob in the water
  282. if (Position.Z < waterHeight)
  283. {
  284. _position.Z = waterHeight;
  285. ret = true;
  286. }
  287. }
  288. // TODO: check for out of bounds
  289. return ret;
  290. }
  291. // A version of the sanity check that also makes sure a new position value is
  292. // pushed to the physics engine. This routine would be used by anyone
  293. // who is not already pushing the value.
  294. private bool PositionSanityCheck(bool inTaintTime)
  295. {
  296. bool ret = false;
  297. if (PositionSanityCheck())
  298. {
  299. // The new position value must be pushed into the physics engine but we can't
  300. // just assign to "Position" because of potential call loops.
  301. BSScene.TaintCallback sanityOperation = delegate()
  302. {
  303. DetailLog("{0},BSPrim.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
  304. ForcePosition = _position;
  305. };
  306. if (inTaintTime)
  307. sanityOperation();
  308. else
  309. PhysicsScene.TaintedObject("BSPrim.PositionSanityCheck", sanityOperation);
  310. ret = true;
  311. }
  312. return ret;
  313. }
  314. // Return the effective mass of the object.
  315. // If there are multiple items in the linkset, add them together for the root
  316. public override float Mass
  317. {
  318. get
  319. {
  320. // return Linkset.LinksetMass;
  321. return _mass;
  322. }
  323. }
  324. // used when we only want this prim's mass and not the linkset thing
  325. public override float MassRaw { get { return _mass; } }
  326. // Is this used?
  327. public override OMV.Vector3 CenterOfMass
  328. {
  329. get { return Linkset.CenterOfMass; }
  330. }
  331. // Is this used?
  332. public override OMV.Vector3 GeometricCenter
  333. {
  334. get { return Linkset.GeometricCenter; }
  335. }
  336. public override OMV.Vector3 Force {
  337. get { return _force; }
  338. set {
  339. _force = value;
  340. PhysicsScene.TaintedObject("BSPrim.setForce", delegate()
  341. {
  342. // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force);
  343. BulletSimAPI.SetObjectForce2(BSBody.ptr, _force);
  344. });
  345. }
  346. }
  347. public override int VehicleType {
  348. get {
  349. return (int)_vehicle.Type; // if we are a vehicle, return that type
  350. }
  351. set {
  352. Vehicle type = (Vehicle)value;
  353. // Tell the scene about the vehicle so it will get processing each frame.
  354. PhysicsScene.VehicleInSceneTypeChanged(this, type);
  355. PhysicsScene.TaintedObject("setVehicleType", delegate()
  356. {
  357. // Done at taint time so we're sure the physics engine is not using the variables
  358. // Vehicle code changes the parameters for this vehicle type.
  359. _vehicle.ProcessTypeChange(type);
  360. });
  361. }
  362. }
  363. public override void VehicleFloatParam(int param, float value)
  364. {
  365. PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
  366. {
  367. _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
  368. });
  369. }
  370. public override void VehicleVectorParam(int param, OMV.Vector3 value)
  371. {
  372. PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
  373. {
  374. _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
  375. });
  376. }
  377. public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
  378. {
  379. PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
  380. {
  381. _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
  382. });
  383. }
  384. public override void VehicleFlags(int param, bool remove)
  385. {
  386. PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
  387. {
  388. _vehicle.ProcessVehicleFlags(param, remove);
  389. });
  390. }
  391. // Called each simulation step to advance vehicle characteristics.
  392. // Called from Scene when doing simulation step so we're in taint processing time.
  393. public override void StepVehicle(float timeStep)
  394. {
  395. if (IsPhysical)
  396. {
  397. _vehicle.Step(timeStep);
  398. }
  399. }
  400. // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
  401. public override void SetVolumeDetect(int param) {
  402. bool newValue = (param != 0);
  403. if (_isVolumeDetect != newValue)
  404. {
  405. _isVolumeDetect = newValue;
  406. PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
  407. {
  408. // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
  409. SetObjectDynamic(true);
  410. });
  411. }
  412. return;
  413. }
  414. public override OMV.Vector3 Velocity {
  415. get { return _velocity; }
  416. set {
  417. _velocity = value;
  418. PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
  419. {
  420. // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
  421. BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
  422. });
  423. }
  424. }
  425. public override OMV.Vector3 ForceVelocity {
  426. get { return _velocity; }
  427. set {
  428. _velocity = value;
  429. BulletSimAPI.SetLinearVelocity2(BSBody.ptr, _velocity);
  430. }
  431. }
  432. public override OMV.Vector3 Torque {
  433. get { return _torque; }
  434. set { _torque = value;
  435. // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
  436. }
  437. }
  438. public override float CollisionScore {
  439. get { return _collisionScore; }
  440. set { _collisionScore = value;
  441. }
  442. }
  443. public override OMV.Vector3 Acceleration {
  444. get { return _acceleration; }
  445. set { _acceleration = value; }
  446. }
  447. public override OMV.Quaternion Orientation {
  448. get {
  449. if (!Linkset.IsRoot(this))
  450. {
  451. // Children move around because tied to parent. Get a fresh value.
  452. _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
  453. }
  454. return _orientation;
  455. }
  456. set {
  457. if (_orientation == value)
  458. return;
  459. _orientation = value;
  460. // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint?
  461. PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
  462. {
  463. // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
  464. // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
  465. BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
  466. });
  467. }
  468. }
  469. // Go directly to Bullet to get/set the value.
  470. public override OMV.Quaternion ForceOrientation
  471. {
  472. get
  473. {
  474. _orientation = BulletSimAPI.GetOrientation2(BSBody.ptr);
  475. return _orientation;
  476. }
  477. set
  478. {
  479. _orientation = value;
  480. BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
  481. }
  482. }
  483. public override int PhysicsActorType {
  484. get { return _physicsActorType; }
  485. set { _physicsActorType = value; }
  486. }
  487. public override bool IsPhysical {
  488. get { return _isPhysical; }
  489. set {
  490. if (_isPhysical != value)
  491. {
  492. _isPhysical = value;
  493. PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
  494. {
  495. // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
  496. SetObjectDynamic(true);
  497. });
  498. }
  499. }
  500. }
  501. // An object is static (does not move) if selected or not physical
  502. public override bool IsStatic
  503. {
  504. get { return _isSelected || !IsPhysical; }
  505. }
  506. // An object is solid if it's not phantom and if it's not doing VolumeDetect
  507. public override bool IsSolid
  508. {
  509. get { return !IsPhantom && !_isVolumeDetect; }
  510. }
  511. // Make gravity work if the object is physical and not selected
  512. // Called at taint-time!!
  513. private void SetObjectDynamic(bool forceRebuild)
  514. {
  515. // Recreate the physical object if necessary
  516. CreateGeomAndObject(forceRebuild);
  517. }
  518. // Convert the simulator's physical properties into settings on BulletSim objects.
  519. // There are four flags we're interested in:
  520. // IsStatic: Object does not move, otherwise the object has mass and moves
  521. // isSolid: other objects bounce off of this object
  522. // isVolumeDetect: other objects pass through but can generate collisions
  523. // collisionEvents: whether this object returns collision events
  524. private void UpdatePhysicalParameters()
  525. {
  526. // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
  527. // Mangling all the physical properties requires the object not be in the physical world.
  528. // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
  529. BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, BSBody.ptr);
  530. // Set up the object physicalness (does gravity and collisions move this object)
  531. MakeDynamic(IsStatic);
  532. // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
  533. _vehicle.Refresh();
  534. // Arrange for collision events if the simulator wants them
  535. EnableCollisions(SubscribedEvents());
  536. // Make solid or not (do things bounce off or pass through this object).
  537. MakeSolid(IsSolid);
  538. BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, BSBody.ptr);
  539. // Rebuild its shape
  540. BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, BSBody.ptr);
  541. // Collision filter can be set only when the object is in the world
  542. if (BSBody.collisionFilter != 0 || BSBody.collisionMask != 0)
  543. {
  544. BulletSimAPI.SetCollisionFilterMask2(BSBody.ptr, (uint)BSBody.collisionFilter, (uint)BSBody.collisionMask);
  545. }
  546. // Recompute any linkset parameters.
  547. // When going from non-physical to physical, this re-enables the constraints that
  548. // had been automatically disabled when the mass was set to zero.
  549. Linkset.Refresh(this, true);
  550. DetailLog("{0},BSPrim.UpdatePhysicalParameters,exit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
  551. LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, BSBody, BSShape);
  552. }
  553. // "Making dynamic" means changing to and from static.
  554. // When static, gravity does not effect the object and it is fixed in space.
  555. // When dynamic, the object can fall and be pushed by others.
  556. // This is independent of its 'solidness' which controls what passes through
  557. // this object and what interacts with it.
  558. private void MakeDynamic(bool makeStatic)
  559. {
  560. if (makeStatic)
  561. {
  562. // Become a Bullet 'static' object type
  563. CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
  564. // Stop all movement
  565. BulletSimAPI.ClearAllForces2(BSBody.ptr);
  566. // Center of mass is at the center of the object
  567. BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.BSBody.ptr, _position, _orientation);
  568. // Mass is zero which disables a bunch of physics stuff in Bullet
  569. BulletSimAPI.SetMassProps2(BSBody.ptr, 0f, OMV.Vector3.Zero);
  570. // There is no inertia in a static object
  571. BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
  572. // Set collision detection parameters
  573. if (PhysicsScene.Params.ccdMotionThreshold > 0f)
  574. {
  575. BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
  576. BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
  577. }
  578. // There can be special things needed for implementing linksets
  579. Linkset.MakeStatic(this);
  580. // The activation state is 'disabled' so Bullet will not try to act on it.
  581. BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.DISABLE_SIMULATION);
  582. // Start it out sleeping and physical actions could wake it up.
  583. // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING);
  584. BSBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter;
  585. BSBody.collisionMask = CollisionFilterGroups.StaticObjectMask;
  586. }
  587. else
  588. {
  589. // Not a Bullet static object
  590. CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
  591. // Set various physical properties so internal dynamic properties will get computed correctly as they are set
  592. BulletSimAPI.SetFriction2(BSBody.ptr, PhysicsScene.Params.defaultFriction);
  593. BulletSimAPI.SetRestitution2(BSBody.ptr, PhysicsScene.Params.defaultRestitution);
  594. // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
  595. BulletSimAPI.ClearAllForces2(BSBody.ptr);
  596. // For good measure, make sure the transform is set through to the motion state
  597. BulletSimAPI.SetTranslation2(BSBody.ptr, _position, _orientation);
  598. // A dynamic object has mass
  599. IntPtr collisionShapePtr = BulletSimAPI.GetCollisionShape2(BSBody.ptr);
  600. OMV.Vector3 inertia = BulletSimAPI.CalculateLocalInertia2(collisionShapePtr, Mass);
  601. BulletSimAPI.SetMassProps2(BSBody.ptr, _mass, inertia);
  602. BulletSimAPI.UpdateInertiaTensor2(BSBody.ptr);
  603. // Set collision detection parameters
  604. if (PhysicsScene.Params.ccdMotionThreshold > 0f)
  605. {
  606. BulletSimAPI.SetCcdMotionThreshold2(BSBody.ptr, PhysicsScene.Params.ccdMotionThreshold);
  607. BulletSimAPI.SetCcdSweepSphereRadius2(BSBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius);
  608. }
  609. // Various values for simulation limits
  610. BulletSimAPI.SetDamping2(BSBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping);
  611. BulletSimAPI.SetDeactivationTime2(BSBody.ptr, PhysicsScene.Params.deactivationTime);
  612. BulletSimAPI.SetSleepingThresholds2(BSBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
  613. BulletSimAPI.SetContactProcessingThreshold2(BSBody.ptr, PhysicsScene.Params.contactProcessingThreshold);
  614. // There might be special things needed for implementing linksets.
  615. Linkset.MakeDynamic(this);
  616. // Force activation of the object so Bullet will act on it.
  617. // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
  618. BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG);
  619. // BulletSimAPI.Activate2(BSBody.ptr, true);
  620. BSBody.collisionFilter = CollisionFilterGroups.ObjectFilter;
  621. BSBody.collisionMask = CollisionFilterGroups.ObjectMask;
  622. }
  623. }
  624. // "Making solid" means that other object will not pass through this object.
  625. // To make transparent, we create a Bullet ghost object.
  626. // Note: This expects to be called from the UpdatePhysicalParameters() routine as
  627. // the functions after this one set up the state of a possibly newly created collision body.
  628. private void MakeSolid(bool makeSolid)
  629. {
  630. CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(BSBody.ptr);
  631. if (makeSolid)
  632. {
  633. // Verify the previous code created the correct shape for this type of thing.
  634. if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
  635. {
  636. m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
  637. }
  638. CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
  639. }
  640. else
  641. {
  642. if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
  643. {
  644. m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
  645. }
  646. CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
  647. BSBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter;
  648. BSBody.collisionMask = CollisionFilterGroups.VolumeDetectMask;
  649. }
  650. }
  651. // Turn on or off the flag controlling whether collision events are returned to the simulator.
  652. private void EnableCollisions(bool wantsCollisionEvents)
  653. {
  654. if (wantsCollisionEvents)
  655. {
  656. CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
  657. }
  658. else
  659. {
  660. CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
  661. }
  662. }
  663. // prims don't fly
  664. public override bool Flying {
  665. get { return _flying; }
  666. set {
  667. _flying = value;
  668. }
  669. }
  670. public override bool SetAlwaysRun {
  671. get { return _setAlwaysRun; }
  672. set { _setAlwaysRun = value; }
  673. }
  674. public override bool ThrottleUpdates {
  675. get { return _throttleUpdates; }
  676. set { _throttleUpdates = value; }
  677. }
  678. public override bool IsColliding {
  679. get { return (CollidingStep == PhysicsScene.SimulationStep); }
  680. set { _isColliding = value; }
  681. }
  682. public override bool CollidingGround {
  683. get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
  684. set { _collidingGround = value; }
  685. }
  686. public override bool CollidingObj {
  687. get { return _collidingObj; }
  688. set { _collidingObj = value; }
  689. }
  690. public bool IsPhantom {
  691. get {
  692. // SceneObjectPart removes phantom objects from the physics scene
  693. // so, although we could implement touching and such, we never
  694. // are invoked as a phantom object
  695. return false;
  696. }
  697. }
  698. public override bool FloatOnWater {
  699. set {
  700. _floatOnWater = value;
  701. PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
  702. {
  703. if (_floatOnWater)
  704. CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
  705. else
  706. CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(BSBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
  707. });
  708. }
  709. }
  710. public override OMV.Vector3 RotationalVelocity {
  711. get {
  712. /*
  713. OMV.Vector3 pv = OMV.Vector3.Zero;
  714. // if close to zero, report zero
  715. // This is copied from ODE but I'm not sure why it returns zero but doesn't
  716. // zero the property in the physics engine.
  717. if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
  718. return pv;
  719. */
  720. return _rotationalVelocity;
  721. }
  722. set {
  723. _rotationalVelocity = value;
  724. // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
  725. PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
  726. {
  727. // DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
  728. BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
  729. });
  730. }
  731. }
  732. public override OMV.Vector3 ForceRotationalVelocity {
  733. get {
  734. return _rotationalVelocity;
  735. }
  736. set {
  737. _rotationalVelocity = value;
  738. BulletSimAPI.SetAngularVelocity2(BSBody.ptr, _rotationalVelocity);
  739. }
  740. }
  741. public override bool Kinematic {
  742. get { return _kinematic; }
  743. set { _kinematic = value;
  744. // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
  745. }
  746. }
  747. public override float Buoyancy {
  748. get { return _buoyancy; }
  749. set {
  750. _buoyancy = value;
  751. PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
  752. {
  753. ForceBuoyancy = _buoyancy;
  754. });
  755. }
  756. }
  757. public override float ForceBuoyancy {
  758. get { return _buoyancy; }
  759. set {
  760. _buoyancy = value;
  761. // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
  762. // Buoyancy is faked by changing the gravity applied to the object
  763. float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
  764. BulletSimAPI.SetGravity2(BSBody.ptr, new OMV.Vector3(0f, 0f, grav));
  765. }
  766. }
  767. // Used for MoveTo
  768. public override OMV.Vector3 PIDTarget {
  769. set { _PIDTarget = value; }
  770. }
  771. public override bool PIDActive {
  772. set { _usePID = value; }
  773. }
  774. public override float PIDTau {
  775. set { _PIDTau = value; }
  776. }
  777. // Used for llSetHoverHeight and maybe vehicle height
  778. // Hover Height will override MoveTo target's Z
  779. public override bool PIDHoverActive {
  780. set { _useHoverPID = value; }
  781. }
  782. public override float PIDHoverHeight {
  783. set { _PIDHoverHeight = value; }
  784. }
  785. public override PIDHoverType PIDHoverType {
  786. set { _PIDHoverType = value; }
  787. }
  788. public override float PIDHoverTau {
  789. set { _PIDHoverTao = value; }
  790. }
  791. // For RotLookAt
  792. public override OMV.Quaternion APIDTarget { set { return; } }
  793. public override bool APIDActive { set { return; } }
  794. public override float APIDStrength { set { return; } }
  795. public override float APIDDamping { set { return; } }
  796. private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
  797. public override void AddForce(OMV.Vector3 force, bool pushforce) {
  798. AddForce(force, pushforce, false);
  799. }
  800. public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
  801. // for an object, doesn't matter if force is a pushforce or not
  802. if (force.IsFinite())
  803. {
  804. // _force += force;
  805. lock (m_accumulatedForces)
  806. m_accumulatedForces.Add(new OMV.Vector3(force));
  807. }
  808. else
  809. {
  810. m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
  811. return;
  812. }
  813. BSScene.TaintCallback addForceOperation = delegate()
  814. {
  815. OMV.Vector3 fSum = OMV.Vector3.Zero;
  816. lock (m_accumulatedForces)
  817. {
  818. // Sum the accumulated additional forces for one big force to apply once.
  819. foreach (OMV.Vector3 v in m_accumulatedForces)
  820. {
  821. fSum += v;
  822. }
  823. m_accumulatedForces.Clear();
  824. }
  825. // DetailLog("{0},BSPrim.AddObjectForce,taint,force={1}", LocalID, fSum);
  826. // For unknown reasons, "ApplyCentralForce" adds this force to the total force on the object.
  827. if (fSum != OMV.Vector3.Zero)
  828. BulletSimAPI.ApplyCentralForce2(BSBody.ptr, fSum);
  829. };
  830. if (inTaintTime)
  831. addForceOperation();
  832. else
  833. PhysicsScene.TaintedObject("BSPrim.AddForce", addForceOperation);
  834. }
  835. public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
  836. // DetailLog("{0},BSPrim.AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce);
  837. // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
  838. }
  839. public override void SetMomentum(OMV.Vector3 momentum) {
  840. // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
  841. }
  842. #region Mass Calculation
  843. private float CalculateMass()
  844. {
  845. float volume = _size.X * _size.Y * _size.Z; // default
  846. float tmp;
  847. float returnMass = 0;
  848. float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
  849. float hollowVolume = hollowAmount * hollowAmount;
  850. switch (BaseShape.ProfileShape)
  851. {
  852. case ProfileShape.Square:
  853. // default box
  854. if (BaseShape.PathCurve == (byte)Extrusion.Straight)
  855. {
  856. if (hollowAmount > 0.0)
  857. {
  858. switch (BaseShape.HollowShape)
  859. {
  860. case HollowShape.Square:
  861. case HollowShape.Same:
  862. break;
  863. case HollowShape.Circle:
  864. hollowVolume *= 0.78539816339f;
  865. break;
  866. case HollowShape.Triangle:
  867. hollowVolume *= (0.5f * .5f);
  868. break;
  869. default:
  870. hollowVolume = 0;
  871. break;
  872. }
  873. volume *= (1.0f - hollowVolume);
  874. }
  875. }
  876. else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
  877. {
  878. //a tube
  879. volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
  880. tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
  881. volume -= volume*tmp*tmp;
  882. if (hollowAmount > 0.0)
  883. {
  884. hollowVolume *= hollowAmount;
  885. switch (BaseShape.HollowShape)
  886. {
  887. case HollowShape.Square:
  888. case HollowShape.Same:
  889. break;
  890. case HollowShape.Circle:
  891. hollowVolume *= 0.78539816339f;;
  892. break;
  893. case HollowShape.Triangle:
  894. hollowVolume *= 0.5f * 0.5f;
  895. break;
  896. default:
  897. hollowVolume = 0;
  898. break;
  899. }
  900. volume *= (1.0f - hollowVolume);
  901. }
  902. }
  903. break;
  904. case ProfileShape.Circle:
  905. if (BaseShape.PathCurve == (byte)Extrusion.Straight)
  906. {
  907. volume *= 0.78539816339f; // elipse base
  908. if (hollowAmount > 0.0)
  909. {
  910. switch (BaseShape.HollowShape)
  911. {
  912. case HollowShape.Same:
  913. case HollowShape.Circle:
  914. break;
  915. case HollowShape.Square:
  916. hollowVolume *= 0.5f * 2.5984480504799f;
  917. break;
  918. case HollowShape.Triangle:
  919. hollowVolume *= .5f * 1.27323954473516f;
  920. break;
  921. default:
  922. hollowVolume = 0;
  923. break;
  924. }
  925. volume *= (1.0f - hollowVolume);
  926. }
  927. }
  928. else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
  929. {
  930. volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
  931. tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
  932. volume *= (1.0f - tmp * tmp);
  933. if (hollowAmount > 0.0)
  934. {
  935. // calculate the hollow volume by it's shape compared to the prim shape
  936. hollowVolume *= hollowAmount;
  937. switch (BaseShape.HollowShape)
  938. {
  939. case HollowShape.Same:
  940. case HollowShape.Circle:
  941. break;
  942. case HollowShape.Square:
  943. hollowVolume *= 0.5f * 2.5984480504799f;
  944. break;
  945. case HollowShape.Triangle:
  946. hollowVolume *= .5f * 1.27323954473516f;
  947. break;
  948. default:
  949. hollowVolume = 0;
  950. break;
  951. }
  952. volume *= (1.0f - hollowVolume);
  953. }
  954. }
  955. break;
  956. case ProfileShape.HalfCircle:
  957. if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
  958. {
  959. volume *= 0.52359877559829887307710723054658f;
  960. }
  961. break;
  962. case ProfileShape.EquilateralTriangle:
  963. if (BaseShape.PathCurve == (byte)Extrusion.Straight)
  964. {
  965. volume *= 0.32475953f;
  966. if (hollowAmount > 0.0)
  967. {
  968. // calculate the hollow volume by it's shape compared to the prim shape
  969. switch (BaseShape.HollowShape)
  970. {
  971. case HollowShape.Same:
  972. case HollowShape.Triangle:
  973. hollowVolume *= .25f;
  974. break;
  975. case HollowShape.Square:
  976. hollowVolume *= 0.499849f * 3.07920140172638f;
  977. break;
  978. case HollowShape.Circle:
  979. // Hollow shape is a perfect cyllinder in respect to the cube's scale
  980. // Cyllinder hollow volume calculation
  981. hollowVolume *= 0.1963495f * 3.07920140172638f;
  982. break;
  983. default:
  984. hollowVolume = 0;
  985. break;
  986. }
  987. volume *= (1.0f - hollowVolume);
  988. }
  989. }
  990. else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
  991. {
  992. volume *= 0.32475953f;
  993. volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
  994. tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
  995. volume *= (1.0f - tmp * tmp);
  996. if (hollowAmount > 0.0)
  997. {
  998. hollowVolume *= hollowAmount;
  999. switch (BaseShape.HollowShape)
  1000. {
  1001. case HollowShape.Same:
  1002. case HollowShape.Triangle:
  1003. hollowVolume *= .25f;
  1004. break;
  1005. case HollowShape.Square:
  1006. hollowVolume *= 0.499849f * 3.07920140172638f;
  1007. break;
  1008. case HollowShape.Circle:
  1009. hollowVolume *= 0.1963495f * 3.07920140172638f;
  1010. break;
  1011. default:
  1012. hollowVolume = 0;
  1013. break;
  1014. }
  1015. volume *= (1.0f - hollowVolume);
  1016. }
  1017. }
  1018. break;
  1019. default:
  1020. break;
  1021. }
  1022. float taperX1;
  1023. float taperY1;
  1024. float taperX;
  1025. float taperY;
  1026. float pathBegin;
  1027. float pathEnd;
  1028. float profileBegin;
  1029. float profileEnd;
  1030. if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
  1031. {
  1032. taperX1 = BaseShape.PathScaleX * 0.01f;
  1033. if (taperX1 > 1.0f)
  1034. taperX1 = 2.0f - taperX1;
  1035. taperX = 1.0f - taperX1;
  1036. taperY1 = BaseShape.PathScaleY * 0.01f;
  1037. if (taperY1 > 1.0f)
  1038. taperY1 = 2.0f - taperY1;
  1039. taperY = 1.0f - taperY1;
  1040. }
  1041. else
  1042. {
  1043. taperX = BaseShape.PathTaperX * 0.01f;
  1044. if (taperX < 0.0f)
  1045. taperX = -taperX;
  1046. taperX1 = 1.0f - taperX;
  1047. taperY = BaseShape.PathTaperY * 0.01f;
  1048. if (taperY < 0.0f)
  1049. taperY = -taperY;
  1050. taperY1 = 1.0f - taperY;
  1051. }
  1052. volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
  1053. pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
  1054. pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
  1055. volume *= (pathEnd - pathBegin);
  1056. // this is crude aproximation
  1057. profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
  1058. profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
  1059. volume *= (profileEnd - profileBegin);
  1060. returnMass = _density * volume;
  1061. /*
  1062. * This change means each object keeps its own mass and the Mass property
  1063. * will return the sum if we're part of a linkset.
  1064. if (IsRootOfLinkset)
  1065. {
  1066. foreach (BSPrim prim in _childrenPrims)
  1067. {
  1068. returnMass += prim.CalculateMass();
  1069. }
  1070. }
  1071. */
  1072. if (returnMass <= 0)
  1073. returnMass = 0.0001f;
  1074. if (returnMass > PhysicsScene.MaximumObjectMass)
  1075. returnMass = PhysicsScene.MaximumObjectMass;
  1076. return returnMass;
  1077. }// end CalculateMass
  1078. #endregion Mass Calculation
  1079. // Copy prim's info into the BulletSim shape description structure
  1080. public void FillShapeInfo(out ShapeData shape)
  1081. {
  1082. shape.ID = LocalID;
  1083. shape.Type = ShapeData.PhysicsShapeType.SHAPE_UNKNOWN;
  1084. shape.Position = _position;
  1085. shape.Rotation = _orientation;
  1086. shape.Velocity = _velocity;
  1087. shape.Size = _size;
  1088. shape.Scale = Scale;
  1089. shape.Mass = _isPhysical ? _mass : 0f;
  1090. shape.Buoyancy = _buoyancy;
  1091. shape.HullKey = 0;
  1092. shape.MeshKey = 0;
  1093. shape.Friction = _friction;
  1094. shape.Restitution = _restitution;
  1095. shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
  1096. shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
  1097. shape.Solid = IsSolid ? ShapeData.numericFalse : ShapeData.numericTrue;
  1098. }
  1099. // Rebuild the geometry and object.
  1100. // This is called when the shape changes so we need to recreate the mesh/hull.
  1101. // Called at taint-time!!!
  1102. private void CreateGeomAndObject(bool forceRebuild)
  1103. {
  1104. ShapeData shapeData;
  1105. FillShapeInfo(out shapeData);
  1106. // If this prim is part of a linkset, we must remove and restore the physical
  1107. // links if the body is rebuilt.
  1108. bool needToRestoreLinkset = false;
  1109. // Create the correct physical representation for this type of object.
  1110. // Updates BSBody and BSShape with the new information.
  1111. // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
  1112. // Returns 'true' if either the body or the shape was changed.
  1113. PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, shapeData, BaseShape,
  1114. null, delegate(BulletBody dBody)
  1115. {
  1116. // Called if the current prim body is about to be destroyed.
  1117. // Remove all the physical dependencies on the old body.
  1118. // (Maybe someday make the changing of BSShape an event handled by BSLinkset.)
  1119. needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
  1120. });
  1121. if (needToRestoreLinkset)
  1122. {
  1123. // If physical body dependencies were removed, restore them
  1124. Linkset.RestoreBodyDependencies(this);
  1125. }
  1126. // Make sure the properties are set on the new object
  1127. UpdatePhysicalParameters();
  1128. return;
  1129. }
  1130. // The physics engine says that properties have updated. Update same and inform
  1131. // the world that things have changed.
  1132. // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
  1133. enum UpdatedProperties {
  1134. Position = 1 << 0,
  1135. Rotation = 1 << 1,
  1136. Velocity = 1 << 2,
  1137. Acceleration = 1 << 3,
  1138. RotationalVel = 1 << 4
  1139. }
  1140. const float ROTATION_TOLERANCE = 0.01f;
  1141. const float VELOCITY_TOLERANCE = 0.001f;
  1142. const float POSITION_TOLERANCE = 0.05f;
  1143. const float ACCELERATION_TOLERANCE = 0.01f;
  1144. const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
  1145. public override void UpdateProperties(EntityProperties entprop)
  1146. {
  1147. /*
  1148. UpdatedProperties changed = 0;
  1149. // assign to the local variables so the normal set action does not happen
  1150. // if (_position != entprop.Position)
  1151. if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
  1152. {
  1153. _position = entprop.Position;
  1154. changed |= UpdatedProperties.Position;
  1155. }
  1156. // if (_orientation != entprop.Rotation)
  1157. if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
  1158. {
  1159. _orientation = entprop.Rotation;
  1160. changed |= UpdatedProperties.Rotation;
  1161. }
  1162. // if (_velocity != entprop.Velocity)
  1163. if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
  1164. {
  1165. _velocity = entprop.Velocity;
  1166. changed |= UpdatedProperties.Velocity;
  1167. }
  1168. // if (_acceleration != entprop.Acceleration)
  1169. if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
  1170. {
  1171. _acceleration = entprop.Acceleration;
  1172. changed |= UpdatedProperties.Acceleration;
  1173. }
  1174. // if (_rotationalVelocity != entprop.RotationalVelocity)
  1175. if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
  1176. {
  1177. _rotationalVelocity = entprop.RotationalVelocity;
  1178. changed |= UpdatedProperties.RotationalVel;
  1179. }
  1180. if (changed != 0)
  1181. {
  1182. // Only update the position of single objects and linkset roots
  1183. if (this._parentPrim == null)
  1184. {
  1185. base.RequestPhysicsterseUpdate();
  1186. }
  1187. }
  1188. */
  1189. // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
  1190. // Updates only for individual prims and for the root object of a linkset.
  1191. if (Linkset.IsRoot(this))
  1192. {
  1193. // Assign to the local variables so the normal set action does not happen
  1194. _position = entprop.Position;
  1195. _orientation = entprop.Rotation;
  1196. _velocity = entprop.Velocity;
  1197. _acceleration = entprop.Acceleration;
  1198. _rotationalVelocity = entprop.RotationalVelocity;
  1199. // remember the current and last set values
  1200. LastEntityProperties = CurrentEntityProperties;
  1201. CurrentEntityProperties = entprop;
  1202. PositionSanityCheck(true);
  1203. DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
  1204. LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity);
  1205. // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG
  1206. base.RequestPhysicsterseUpdate();
  1207. }
  1208. /*
  1209. else
  1210. {
  1211. // For debugging, report the movement of children
  1212. DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
  1213. LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
  1214. entprop.Acceleration, entprop.RotationalVelocity);
  1215. }
  1216. */
  1217. // The linkset implimentation might want to know about this.
  1218. Linkset.UpdateProperties(this);
  1219. }
  1220. }
  1221. }