BSPrim.cs 55 KB

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