OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
BSPrim.cs
Go to the documentation of this file.
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 
28 using System;
29 using System.Reflection;
30 using System.Collections.Generic;
31 using System.Xml;
32 using log4net;
33 using OMV = OpenMetaverse;
34 using OpenSim.Framework;
35 using OpenSim.Region.PhysicsModules.SharedBase;
36 using OpenSim.Region.PhysicsModules.ConvexDecompositionDotNet;
37 
38 namespace OpenSim.Region.PhysicsModule.BulletS
39 {
40 
41  [Serializable]
42 public class BSPrim : BSPhysObject
43 {
44  protected static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
45  private static readonly string LogHeader = "[BULLETS PRIM]";
46 
47  // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48  private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
49 
50  private bool _grabbed;
51  private bool _isSelected;
52  private bool _isVolumeDetect;
53 
54  private float _mass; // the mass of this object
55  private OMV.Vector3 _acceleration;
56  private int _physicsActorType;
57  private bool _isPhysical;
58  private bool _flying;
59  private bool _setAlwaysRun;
60  private bool _throttleUpdates;
61  private bool _floatOnWater;
62  private OMV.Vector3 _rotationalVelocity;
63  private bool _kinematic;
64  private float _buoyancy;
65 
66  private int CrossingFailures { get; set; }
67 
68  // Keep a handle to the vehicle actor so it is easy to set parameters on same.
69  public const string VehicleActorName = "BasicVehicle";
70 
71  // Parameters for the hover actor
72  public const string HoverActorName = "BSPrim.HoverActor";
73  // Parameters for the axis lock actor
74  public const String LockedAxisActorName = "BSPrim.LockedAxis";
75  // Parameters for the move to target actor
76  public const string MoveToTargetActorName = "BSPrim.MoveToTargetActor";
77  // Parameters for the setForce and setTorque actors
78  public const string SetForceActorName = "BSPrim.SetForceActor";
79  public const string SetTorqueActorName = "BSPrim.SetTorqueActor";
80 
81  public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
82  OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
83  : base(parent_scene, localID, primName, "BSPrim")
84  {
85  // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
86  _physicsActorType = (int)ActorTypes.Prim;
87  RawPosition = pos;
88  _size = size;
89  Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
90  RawOrientation = rotation;
91  _buoyancy = 0f;
92  RawVelocity = OMV.Vector3.Zero;
93  _rotationalVelocity = OMV.Vector3.Zero;
94  BaseShape = pbs;
95  _isPhysical = pisPhysical;
96  _isVolumeDetect = false;
97 
98  _mass = CalculateMass();
99 
100  DetailLog("{0},BSPrim.constructor,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(pbs));
101  // DetailLog("{0},BSPrim.constructor,call", LocalID);
102  // do the actual object creation at taint time
103  PhysScene.TaintedObject(LocalID, "BSPrim.create", delegate()
104  {
105  // Make sure the object is being created with some sanity.
106  ExtremeSanityCheck(true /* inTaintTime */);
107 
108  CreateGeomAndObject(true);
109 
110  CurrentCollisionFlags = PhysScene.PE.GetCollisionFlags(PhysBody);
111 
112  IsInitialized = true;
113  });
114  }
115 
116  // called when this prim is being destroyed and we should free all the resources
117  public override void Destroy()
118  {
119  // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
120  IsInitialized = false;
121 
122  base.Destroy();
123 
124  // Undo any vehicle properties
125  this.VehicleType = (int)Vehicle.TYPE_NONE;
126 
127  PhysScene.TaintedObject(LocalID, "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  PhysScene.Shapes.DereferenceBody(PhysBody, null);
132  PhysBody.Clear();
133  PhysShape.Dereference(PhysScene);
134  PhysShape = new BSShapeNull();
135  });
136  }
137 
138  // No one uses this property.
139  public override bool Stopped {
140  get { return false; }
141  }
142 
143  public override bool IsIncomplete {
144  get {
145  return ShapeRebuildScheduled;
146  }
147  }
148 
149  // 'true' if this object's shape is in need of a rebuild and a rebuild has been queued.
150  // The prim is still available but its underlying shape will change soon.
151  // This is protected by a 'lock(this)'.
152  public bool ShapeRebuildScheduled { get; protected set; }
153 
154  public override OMV.Vector3 Size {
155  get { return _size; }
156  set {
157  // We presume the scale and size are the same. If scale must be changed for
158  // the physical shape, that is done when the geometry is built.
159  _size = value;
160  Scale = _size;
161  ForceBodyShapeRebuild(false);
162  }
163  }
164 
165  public override PrimitiveBaseShape Shape {
166  set {
167  BaseShape = value;
168  DetailLog("{0},BSPrim.changeShape,pbs={1}", LocalID, BSScene.PrimitiveBaseShapeToString(BaseShape));
169  PrimAssetState = PrimAssetCondition.Unknown;
170  ForceBodyShapeRebuild(false);
171  }
172  }
173  // Cause the body and shape of the prim to be rebuilt if necessary.
174  // If there are no changes required, this is quick and does not make changes to the prim.
175  // If rebuilding is necessary (like changing from static to physical), that will happen.
176  // The 'ShapeRebuildScheduled' tells any checker that the body/shape may change shortly.
177  // The return parameter is not used by anyone.
178  public override bool ForceBodyShapeRebuild(bool inTaintTime)
179  {
180  if (inTaintTime)
181  {
182  // If called in taint time, do the operation immediately
183  _mass = CalculateMass(); // changing the shape changes the mass
184  CreateGeomAndObject(true);
185  }
186  else
187  {
188  lock (this)
189  {
190  // If a rebuild is not already in the queue
191  if (!ShapeRebuildScheduled)
192  {
193  // Remember that a rebuild is queued -- this is used to flag an incomplete object
194  ShapeRebuildScheduled = true;
195  PhysScene.TaintedObject(LocalID, "BSPrim.ForceBodyShapeRebuild", delegate()
196  {
197  _mass = CalculateMass(); // changing the shape changes the mass
198  CreateGeomAndObject(true);
199  ShapeRebuildScheduled = false;
200  });
201  }
202  }
203  }
204  return true;
205  }
206  public override bool Grabbed {
207  set { _grabbed = value;
208  }
209  }
210  public override bool Selected {
211  set
212  {
213  if (value != _isSelected)
214  {
215  _isSelected = value;
216  PhysScene.TaintedObject(LocalID, "BSPrim.setSelected", delegate()
217  {
218  DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
219  SetObjectDynamic(false);
220  });
221  }
222  }
223  }
224  public override bool IsSelected
225  {
226  get { return _isSelected; }
227  }
228 
229  public override void CrossingFailure()
230  {
231  CrossingFailures++;
232  if (CrossingFailures > BSParam.CrossingFailuresBeforeOutOfBounds)
233  {
234  base.RaiseOutOfBounds(RawPosition);
235  }
236  else if (CrossingFailures == BSParam.CrossingFailuresBeforeOutOfBounds)
237  {
238  m_log.WarnFormat("{0} Too many crossing failures for {1}", LogHeader, Name);
239  }
240  return;
241  }
242 
243  // link me to the specified parent
244  public override void link(PhysicsActor obj) {
245  }
246 
247  // delink me from my linkset
248  public override void delink() {
249  }
250 
251  // Set motion values to zero.
252  // Do it to the properties so the values get set in the physics engine.
253  // Push the setting of the values to the viewer.
254  // Called at taint time!
255  public override void ZeroMotion(bool inTaintTime)
256  {
257  RawVelocity = OMV.Vector3.Zero;
258  _acceleration = OMV.Vector3.Zero;
259  _rotationalVelocity = OMV.Vector3.Zero;
260 
261  // Zero some other properties in the physics engine
262  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
263  {
264  if (PhysBody.HasPhysicalBody)
265  PhysScene.PE.ClearAllForces(PhysBody);
266  });
267  }
268  public override void ZeroAngularMotion(bool inTaintTime)
269  {
270  _rotationalVelocity = OMV.Vector3.Zero;
271  // Zero some other properties in the physics engine
272  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ZeroMotion", delegate()
273  {
274  // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
275  if (PhysBody.HasPhysicalBody)
276  {
277  PhysScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
278  PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
279  }
280  });
281  }
282 
283  public override void LockAngularMotion(byte axislocks)
284  {
285  DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axislocks);
286 
287  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
288  if ((axislocks & 0x02) != 0)
289  {
290  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
291  }
292  if ((axislocks & 0x04) != 0)
293  {
294  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
295  }
296  if ((axislocks & 0x08) != 0)
297  {
298  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z, 0f, 0f);
299  }
300 
301  InitializeAxisActor();
302 
303  return;
304  }
305 
306  public override OMV.Vector3 Position {
307  get {
308  // don't do the GetObjectPosition for root elements because this function is called a zillion times.
309  // RawPosition = ForcePosition;
310  return RawPosition;
311  }
312  set {
313  // If the position must be forced into the physics engine, use ForcePosition.
314  // All positions are given in world positions.
315  if (RawPosition == value)
316  {
317  DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
318  return;
319  }
320  RawPosition = value;
321  PositionSanityCheck(false);
322 
323  PhysScene.TaintedObject(LocalID, "BSPrim.setPosition", delegate()
324  {
325  DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, RawPosition, RawOrientation);
326  ForcePosition = RawPosition;
327  });
328  }
329  }
330 
331  // NOTE: overloaded by BSPrimDisplaced to handle offset for center-of-gravity.
332  public override OMV.Vector3 ForcePosition {
333  get {
334  RawPosition = PhysScene.PE.GetPosition(PhysBody);
335  return RawPosition;
336  }
337  set {
338  RawPosition = value;
339  if (PhysBody.HasPhysicalBody)
340  {
341  PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
342  ActivateIfPhysical(false);
343  }
344  }
345  }
346 
347  // Check that the current position is sane and, if not, modify the position to make it so.
348  // Check for being below terrain and being out of bounds.
349  // Returns 'true' of the position was made sane by some action.
350  private bool PositionSanityCheck(bool inTaintTime)
351  {
352  bool ret = false;
353 
354  // We don't care where non-physical items are placed
355  if (!IsPhysicallyActive)
356  return ret;
357 
358  if (!PhysScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
359  {
360  // The physical object is out of the known/simulated area.
361  // Upper levels of code will handle the transition to other areas so, for
362  // the time, we just ignore the position.
363  return ret;
364  }
365 
366  float terrainHeight = PhysScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
367  OMV.Vector3 upForce = OMV.Vector3.Zero;
368  float approxSize = Math.Max(Size.X, Math.Max(Size.Y, Size.Z));
369  if ((RawPosition.Z + approxSize / 2f) < terrainHeight)
370  {
371  DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, RawPosition, terrainHeight);
372  float targetHeight = terrainHeight + (Size.Z / 2f);
373  // If the object is below ground it just has to be moved up because pushing will
374  // not get it through the terrain
375  RawPosition = new OMV.Vector3(RawPosition.X, RawPosition.Y, targetHeight);
376  if (inTaintTime)
377  {
378  ForcePosition = RawPosition;
379  }
380  // If we are throwing the object around, zero its other forces
381  ZeroMotion(inTaintTime);
382  ret = true;
383  }
384 
385  if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
386  {
387  float waterHeight = PhysScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
388  // TODO: a floating motor so object will bob in the water
389  if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
390  {
391  // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
392  upForce.Z = (waterHeight - RawPosition.Z) * 1f;
393 
394  // Apply upforce and overcome gravity.
395  OMV.Vector3 correctionForce = upForce - PhysScene.DefaultGravity;
396  DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, RawPosition, upForce, correctionForce);
397  AddForce(inTaintTime, correctionForce);
398  ret = true;
399  }
400  }
401 
402  return ret;
403  }
404 
405  // Occasionally things will fly off and really get lost.
406  // Find the wanderers and bring them back.
407  // Return 'true' if some parameter need some sanity.
408  private bool ExtremeSanityCheck(bool inTaintTime)
409  {
410  bool ret = false;
411 
412  int wayOverThere = -1000;
413  int wayOutThere = 10000;
414  // There have been instances of objects getting thrown way out of bounds and crashing
415  // the border crossing code.
416  if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
417  || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
418  || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
419  {
420  RawPosition = new OMV.Vector3(10, 10, 50);
421  ZeroMotion(inTaintTime);
422  ret = true;
423  }
424  if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
425  {
426  RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
427  ret = true;
428  }
429  if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
430  {
431  _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
432  ret = true;
433  }
434 
435  return ret;
436  }
437 
438  // Return the effective mass of the object.
439  // The definition of this call is to return the mass of the prim.
440  // If the simulator cares about the mass of the linkset, it will sum it itself.
441  public override float Mass
442  {
443  get { return _mass; }
444  }
445  // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
446  public virtual float TotalMass
447  {
448  get { return _mass; }
449  }
450  // used when we only want this prim's mass and not the linkset thing
451  public override float RawMass {
452  get { return _mass; }
453  }
454  // Set the physical mass to the passed mass.
455  // Note that this does not change _mass!
456  public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
457  {
458  if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
459  {
460  if (IsStatic)
461  {
462  PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
463  Inertia = OMV.Vector3.Zero;
464  PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
465  PhysScene.PE.UpdateInertiaTensor(PhysBody);
466  }
467  else
468  {
469  if (inWorld)
470  {
471  // Changing interesting properties doesn't change proxy and collision cache
472  // information. The Bullet solution is to re-add the object to the world
473  // after parameters are changed.
474  PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
475  }
476 
477  // The computation of mass props requires gravity to be set on the object.
478  Gravity = ComputeGravity(Buoyancy);
479  PhysScene.PE.SetGravity(PhysBody, Gravity);
480 
481  // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
482  // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
483 
484  Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
485  PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
486  PhysScene.PE.UpdateInertiaTensor(PhysBody);
487 
488  DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
489  LocalID, physMass, Inertia, Gravity, inWorld);
490 
491  if (inWorld)
492  {
493  AddObjectToPhysicalWorld();
494  }
495  }
496  }
497  }
498 
499  // Return what gravity should be set to this very moment
500  public OMV.Vector3 ComputeGravity(float buoyancy)
501  {
502  OMV.Vector3 ret = PhysScene.DefaultGravity;
503 
504  if (!IsStatic)
505  {
506  ret *= (1f - buoyancy);
507  ret *= GravModifier;
508  }
509 
510  return ret;
511  }
512 
513  // Is this used?
514  public override OMV.Vector3 CenterOfMass
515  {
516  get { return RawPosition; }
517  }
518 
519  // Is this used?
520  public override OMV.Vector3 GeometricCenter
521  {
522  get { return RawPosition; }
523  }
524 
525  public override OMV.Vector3 Force {
526  get { return RawForce; }
527  set {
528  RawForce = value;
529  EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
530  {
531  return new BSActorSetForce(PhysScene, this, SetForceActorName);
532  });
533 
534  // Call update so actor Refresh() is called to start things off
535  PhysScene.TaintedObject(LocalID, "BSPrim.setForce", delegate()
536  {
537  UpdatePhysicalParameters();
538  });
539  }
540  }
541 
542  // Find and return a handle to the current vehicle actor.
543  // Return 'null' if there is no vehicle actor.
544  public BSDynamics GetVehicleActor(bool createIfNone)
545  {
546  BSDynamics ret = null;
547  BSActor actor;
548  if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
549  {
550  ret = actor as BSDynamics;
551  }
552  else
553  {
554  if (createIfNone)
555  {
556  ret = new BSDynamics(PhysScene, this, VehicleActorName);
557  PhysicalActors.Add(ret.ActorName, ret);
558  }
559  }
560  return ret;
561  }
562 
563  public override int VehicleType {
564  get {
565  int ret = (int)Vehicle.TYPE_NONE;
566  BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
567  if (vehicleActor != null)
568  ret = (int)vehicleActor.Type;
569  return ret;
570  }
571  set {
572  Vehicle type = (Vehicle)value;
573 
574  PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
575  {
576  // Some vehicle scripts change vehicle type on the fly as an easy way to
577  // change all the parameters. Like a plane changing to CAR when on the
578  // ground. In this case, don't want to zero motion.
579  // ZeroMotion(true /* inTaintTime */);
580  if (type == Vehicle.TYPE_NONE)
581  {
582  // Vehicle type is 'none' so get rid of any actor that may have been allocated.
583  BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
584  if (vehicleActor != null)
585  {
586  PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
587  }
588  }
589  else
590  {
591  // Vehicle type is not 'none' so create an actor and set it running.
592  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
593  if (vehicleActor != null)
594  {
595  vehicleActor.ProcessTypeChange(type);
596  ActivateIfPhysical(false);
597  }
598  }
599  });
600  }
601  }
602  public override void VehicleFloatParam(int param, float value)
603  {
604  PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
605  {
606  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
607  if (vehicleActor != null)
608  {
609  vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
610  ActivateIfPhysical(false);
611  }
612  });
613  }
614  public override void VehicleVectorParam(int param, OMV.Vector3 value)
615  {
616  PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
617  {
618  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
619  if (vehicleActor != null)
620  {
621  vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
622  ActivateIfPhysical(false);
623  }
624  });
625  }
626  public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
627  {
628  PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
629  {
630  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
631  if (vehicleActor != null)
632  {
633  vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
634  ActivateIfPhysical(false);
635  }
636  });
637  }
638  public override void VehicleFlags(int param, bool remove)
639  {
640  PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
641  {
642  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
643  if (vehicleActor != null)
644  {
645  vehicleActor.ProcessVehicleFlags(param, remove);
646  }
647  });
648  }
649 
650  public override void SetVehicle(object pvdata)
651  {
652  PhysScene.TaintedObject(LocalID, "BSPrim.SetVehicle", delegate ()
653  {
654  BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
655  if (vehicleActor != null && (pvdata is VehicleData) )
656  {
657  VehicleData vdata = (VehicleData)pvdata;
658  // vehicleActor.ProcessSetVehicle((VehicleData)vdata);
659 
660  vehicleActor.ProcessTypeChange(vdata.m_type);
661  vehicleActor.ProcessVehicleFlags(-1, false);
662  vehicleActor.ProcessVehicleFlags((int)vdata.m_flags, false);
663 
664  // Linear properties
665  vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_DIRECTION, vdata.m_linearMotorDirection);
666  vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_FRICTION_TIMESCALE, vdata.m_linearFrictionTimescale);
667  vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE, vdata.m_linearMotorDecayTimescale);
668  vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_MOTOR_TIMESCALE, vdata.m_linearMotorTimescale);
669  vehicleActor.ProcessVectorVehicleParam(Vehicle.LINEAR_MOTOR_OFFSET, vdata.m_linearMotorOffset);
670 
671  //Angular properties
672  vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_MOTOR_DIRECTION, vdata.m_angularMotorDirection);
673  vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_TIMESCALE, vdata.m_angularMotorTimescale);
674  vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE, vdata.m_angularMotorDecayTimescale);
675  vehicleActor.ProcessVectorVehicleParam(Vehicle.ANGULAR_FRICTION_TIMESCALE, vdata.m_angularFrictionTimescale);
676 
677  //Deflection properties
678  vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_EFFICIENCY, vdata.m_angularDeflectionEfficiency);
679  vehicleActor.ProcessFloatVehicleParam(Vehicle.ANGULAR_DEFLECTION_TIMESCALE, vdata.m_angularDeflectionTimescale);
680  vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_EFFICIENCY, vdata.m_linearDeflectionEfficiency);
681  vehicleActor.ProcessFloatVehicleParam(Vehicle.LINEAR_DEFLECTION_TIMESCALE, vdata.m_linearDeflectionTimescale);
682 
683  //Banking properties
684  vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_EFFICIENCY, vdata.m_bankingEfficiency);
685  vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_MIX, vdata.m_bankingMix);
686  vehicleActor.ProcessFloatVehicleParam(Vehicle.BANKING_TIMESCALE, vdata.m_bankingTimescale);
687 
688  //Hover and Buoyancy properties
689  vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_HEIGHT, vdata.m_VhoverHeight);
690  vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_EFFICIENCY, vdata.m_VhoverEfficiency);
691  vehicleActor.ProcessFloatVehicleParam(Vehicle.HOVER_TIMESCALE, vdata.m_VhoverTimescale);
692  vehicleActor.ProcessFloatVehicleParam(Vehicle.BUOYANCY, vdata.m_VehicleBuoyancy);
693 
694  //Attractor properties
695  vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_EFFICIENCY, vdata.m_verticalAttractionEfficiency);
696  vehicleActor.ProcessFloatVehicleParam(Vehicle.VERTICAL_ATTRACTION_TIMESCALE, vdata.m_verticalAttractionTimescale);
697 
698  vehicleActor.ProcessRotationVehicleParam(Vehicle.REFERENCE_FRAME, vdata.m_referenceFrame);
699  }
700  });
701  }
702 
703  // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
704  public override void SetVolumeDetect(int param) {
705  bool newValue = (param != 0);
706  if (_isVolumeDetect != newValue)
707  {
708  _isVolumeDetect = newValue;
709  PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
710  {
711  // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
712  SetObjectDynamic(true);
713  });
714  }
715  return;
716  }
717  public override bool IsVolumeDetect
718  {
719  get { return _isVolumeDetect; }
720  }
721  public override void SetMaterial(int material)
722  {
723  base.SetMaterial(material);
724  PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
725  {
726  UpdatePhysicalParameters();
727  });
728  }
729  public override float Friction
730  {
731  get { return base.Friction; }
732  set
733  {
734  if (base.Friction != value)
735  {
736  base.Friction = value;
737  PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
738  {
739  UpdatePhysicalParameters();
740  });
741  }
742  }
743  }
744  public override float Restitution
745  {
746  get { return base.Restitution; }
747  set
748  {
749  if (base.Restitution != value)
750  {
751  base.Restitution = value;
752  PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
753  {
754  UpdatePhysicalParameters();
755  });
756  }
757  }
758  }
759  // The simulator/viewer keep density as 100kg/m3.
760  // Remember to use BSParam.DensityScaleFactor to create the physical density.
761  public override float Density
762  {
763  get { return base.Density; }
764  set
765  {
766  if (base.Density != value)
767  {
768  base.Density = value;
769  PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
770  {
771  UpdatePhysicalParameters();
772  });
773  }
774  }
775  }
776  public override float GravModifier
777  {
778  get { return base.GravModifier; }
779  set
780  {
781  if (base.GravModifier != value)
782  {
783  base.GravModifier = value;
784  PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
785  {
786  UpdatePhysicalParameters();
787  });
788  }
789  }
790  }
791  public override OMV.Vector3 Velocity {
792  get { return RawVelocity; }
793  set {
794  RawVelocity = value;
795  PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
796  {
797  // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
798  ForceVelocity = RawVelocity;
799  });
800  }
801  }
802  public override OMV.Vector3 ForceVelocity {
803  get { return RawVelocity; }
804  set {
805  PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
806 
807  RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
808  if (PhysBody.HasPhysicalBody)
809  {
810  DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
811  PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
812  ActivateIfPhysical(false);
813  }
814  }
815  }
816  public override OMV.Vector3 Torque {
817  get { return RawTorque; }
818  set {
819  RawTorque = value;
820  EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
821  {
822  return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
823  });
824  DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
825 
826  // Call update so actor Refresh() is called to start things off
827  PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
828  {
829  UpdatePhysicalParameters();
830  });
831  }
832  }
833  public override OMV.Vector3 Acceleration {
834  get { return _acceleration; }
835  set { _acceleration = value; }
836  }
837 
838  public override OMV.Quaternion Orientation {
839  get {
840  return RawOrientation;
841  }
842  set {
843  if (RawOrientation == value)
844  return;
845  RawOrientation = value;
846 
847  PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
848  {
849  ForceOrientation = RawOrientation;
850  });
851  }
852  }
853  // Go directly to Bullet to get/set the value.
854  public override OMV.Quaternion ForceOrientation
855  {
856  get
857  {
858  RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
859  return RawOrientation;
860  }
861  set
862  {
863  RawOrientation = value;
864  if (PhysBody.HasPhysicalBody)
865  PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
866  }
867  }
868  public override int PhysicsActorType {
869  get { return _physicsActorType; }
870  set { _physicsActorType = value; }
871  }
872  public override bool IsPhysical {
873  get { return _isPhysical; }
874  set {
875  if (_isPhysical != value)
876  {
877  _isPhysical = value;
878  PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
879  {
880  DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
881  SetObjectDynamic(true);
882  // whether phys-to-static or static-to-phys, the object is not moving.
883  ZeroMotion(true);
884 
885  });
886  }
887  }
888  }
889 
890  // An object is static (does not move) if selected or not physical
891  public override bool IsStatic
892  {
893  get { return _isSelected || !IsPhysical; }
894  }
895 
896  // An object is solid if it's not phantom and if it's not doing VolumeDetect
897  public override bool IsSolid
898  {
899  get { return !IsPhantom && !_isVolumeDetect; }
900  }
901 
902  // The object is moving and is actively being dynamic in the physical world
903  public override bool IsPhysicallyActive
904  {
905  get { return !_isSelected && IsPhysical; }
906  }
907 
908  // Make gravity work if the object is physical and not selected
909  // Called at taint-time!!
910  private void SetObjectDynamic(bool forceRebuild)
911  {
912  // Recreate the physical object if necessary
913  CreateGeomAndObject(forceRebuild);
914  }
915 
916  // Convert the simulator's physical properties into settings on BulletSim objects.
917  // There are four flags we're interested in:
918  // IsStatic: Object does not move, otherwise the object has mass and moves
919  // isSolid: other objects bounce off of this object
920  // isVolumeDetect: other objects pass through but can generate collisions
921  // collisionEvents: whether this object returns collision events
922  // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
923  public virtual void UpdatePhysicalParameters()
924  {
925  if (!PhysBody.HasPhysicalBody)
926  {
927  // This would only happen if updates are called for during initialization when the body is not set up yet.
928  // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
929  return;
930  }
931 
932  // Mangling all the physical properties requires the object not be in the physical world.
933  // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
934  PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
935 
936  // Set up the object physicalness (does gravity and collisions move this object)
937  MakeDynamic(IsStatic);
938 
939  // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
940  PhysicalActors.Refresh();
941 
942  // Arrange for collision events if the simulator wants them
943  EnableCollisions(SubscribedEvents());
944 
945  // Make solid or not (do things bounce off or pass through this object).
946  MakeSolid(IsSolid);
947 
948  AddObjectToPhysicalWorld();
949 
950  // Rebuild its shape
951  PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
952 
953  DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
954  LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
955  CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
956  }
957 
958  // "Making dynamic" means changing to and from static.
959  // When static, gravity does not effect the object and it is fixed in space.
960  // When dynamic, the object can fall and be pushed by others.
961  // This is independent of its 'solidness' which controls what passes through
962  // this object and what interacts with it.
963  protected virtual void MakeDynamic(bool makeStatic)
964  {
965  if (makeStatic)
966  {
967  // Become a Bullet 'static' object type
968  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
969  // Stop all movement
970  ZeroMotion(true);
971 
972  // Set various physical properties so other object interact properly
973  PhysScene.PE.SetFriction(PhysBody, Friction);
974  PhysScene.PE.SetRestitution(PhysBody, Restitution);
975  PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
976 
977  // Mass is zero which disables a bunch of physics stuff in Bullet
978  UpdatePhysicalMassProperties(0f, false);
979  // Set collision detection parameters
980  if (BSParam.CcdMotionThreshold > 0f)
981  {
982  PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
983  PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
984  }
985 
986  // The activation state is 'disabled' so Bullet will not try to act on it.
987  // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
988  // Start it out sleeping and physical actions could wake it up.
989  PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
990 
991  // This collides like a static object
992  PhysBody.collisionType = CollisionType.Static;
993  }
994  else
995  {
996  // Not a Bullet static object
997  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
998 
999  // Set various physical properties so other object interact properly
1000  PhysScene.PE.SetFriction(PhysBody, Friction);
1001  PhysScene.PE.SetRestitution(PhysBody, Restitution);
1002  // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
1003 
1004  // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
1005  // Since this can be called multiple times, only zero forces when becoming physical
1006  // PhysicsScene.PE.ClearAllForces(BSBody);
1007 
1008  // For good measure, make sure the transform is set through to the motion state
1009  ForcePosition = RawPosition;
1010  ForceVelocity = RawVelocity;
1011  ForceRotationalVelocity = _rotationalVelocity;
1012 
1013  // A dynamic object has mass
1014  UpdatePhysicalMassProperties(RawMass, false);
1015 
1016  // Set collision detection parameters
1017  if (BSParam.CcdMotionThreshold > 0f)
1018  {
1019  PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
1020  PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
1021  }
1022 
1023  // Various values for simulation limits
1024  PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
1025  PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
1026  PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
1027  PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
1028 
1029  // This collides like an object.
1030  PhysBody.collisionType = CollisionType.Dynamic;
1031 
1032  // Force activation of the object so Bullet will act on it.
1033  // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
1034  PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
1035  }
1036  }
1037 
1038  // "Making solid" means that other object will not pass through this object.
1039  // To make transparent, we create a Bullet ghost object.
1040  // Note: This expects to be called from the UpdatePhysicalParameters() routine as
1041  // the functions after this one set up the state of a possibly newly created collision body.
1042  private void MakeSolid(bool makeSolid)
1043  {
1044  CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
1045  if (makeSolid)
1046  {
1047  // Verify the previous code created the correct shape for this type of thing.
1048  if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
1049  {
1050  m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
1051  }
1052  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1053  }
1054  else
1055  {
1056  if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1057  {
1058  m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1059  }
1060  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1061 
1062  // Change collision info from a static object to a ghosty collision object
1063  PhysBody.collisionType = CollisionType.VolumeDetect;
1064  }
1065  }
1066 
1067  // Turn on or off the flag controlling whether collision events are returned to the simulator.
1068  private void EnableCollisions(bool wantsCollisionEvents)
1069  {
1070  if (wantsCollisionEvents)
1071  {
1072  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1073  }
1074  else
1075  {
1076  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1077  }
1078  }
1079 
1080  // Add me to the physical world.
1081  // Object MUST NOT already be in the world.
1082  // This routine exists because some assorted properties get mangled by adding to the world.
1083  internal void AddObjectToPhysicalWorld()
1084  {
1085  if (PhysBody.HasPhysicalBody)
1086  {
1087  PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1088  }
1089  else
1090  {
1091  m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1092  DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1093  }
1094  }
1095 
1096  // prims don't fly
1097  public override bool Flying {
1098  get { return _flying; }
1099  set {
1100  _flying = value;
1101  }
1102  }
1103  public override bool SetAlwaysRun {
1104  get { return _setAlwaysRun; }
1105  set { _setAlwaysRun = value; }
1106  }
1107  public override bool ThrottleUpdates {
1108  get { return _throttleUpdates; }
1109  set { _throttleUpdates = value; }
1110  }
1111  public bool IsPhantom {
1112  get {
1113  // SceneObjectPart removes phantom objects from the physics scene
1114  // so, although we could implement touching and such, we never
1115  // are invoked as a phantom object
1116  return false;
1117  }
1118  }
1119  public override bool FloatOnWater {
1120  set {
1121  _floatOnWater = value;
1122  PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1123  {
1124  if (_floatOnWater)
1125  CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1126  else
1127  CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1128  });
1129  }
1130  }
1131  public override OMV.Vector3 RotationalVelocity {
1132  get {
1133  return _rotationalVelocity;
1134  }
1135  set {
1136  _rotationalVelocity = value;
1137  Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1138  // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1139  PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1140  {
1141  ForceRotationalVelocity = _rotationalVelocity;
1142  });
1143  }
1144  }
1145  public override OMV.Vector3 ForceRotationalVelocity {
1146  get {
1147  return _rotationalVelocity;
1148  }
1149  set {
1150  _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1151  if (PhysBody.HasPhysicalBody)
1152  {
1153  DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1154  PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1155  // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1156  ActivateIfPhysical(false);
1157  }
1158  }
1159  }
1160  public override bool Kinematic {
1161  get { return _kinematic; }
1162  set { _kinematic = value;
1163  // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1164  }
1165  }
1166  public override float Buoyancy {
1167  get { return _buoyancy; }
1168  set {
1169  _buoyancy = value;
1170  PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1171  {
1172  ForceBuoyancy = _buoyancy;
1173  });
1174  }
1175  }
1176  public override float ForceBuoyancy {
1177  get { return _buoyancy; }
1178  set {
1179  _buoyancy = value;
1180  // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1181  // Force the recalculation of the various inertia,etc variables in the object
1182  UpdatePhysicalMassProperties(RawMass, true);
1183  DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1184  ActivateIfPhysical(false);
1185  }
1186  }
1187 
1188  public override bool PIDActive
1189  {
1190  get
1191  {
1192  return MoveToTargetActive;
1193  }
1194 
1195  set
1196  {
1197  MoveToTargetActive = value;
1198 
1199  EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1200  {
1201  return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1202  });
1203 
1204  // Call update so actor Refresh() is called to start things off
1205  PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1206  {
1207  UpdatePhysicalParameters();
1208  });
1209  }
1210  }
1211 
1212  public override OMV.Vector3 PIDTarget
1213  {
1214  set
1215  {
1216  base.PIDTarget = value;
1217  BSActor actor;
1218  if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1219  {
1220  // if the actor exists, tell it to refresh its values.
1221  actor.Refresh();
1222  }
1223 
1224  }
1225  }
1226  // Used for llSetHoverHeight and maybe vehicle height
1227  // Hover Height will override MoveTo target's Z
1228  public override bool PIDHoverActive {
1229  get
1230  {
1231  return base.HoverActive;
1232  }
1233  set {
1234  base.HoverActive = value;
1235  EnableActor(HoverActive, HoverActorName, delegate()
1236  {
1237  return new BSActorHover(PhysScene, this, HoverActorName);
1238  });
1239 
1240  // Call update so actor Refresh() is called to start things off
1241  PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1242  {
1243  UpdatePhysicalParameters();
1244  });
1245  }
1246  }
1247 
1248  public override void AddForce(OMV.Vector3 force, bool pushforce) {
1249  // Per documentation, max force is limited.
1250  OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1251 
1252  // Push forces seem to be scaled differently (follow pattern in ubODE)
1253  if (!pushforce) {
1254  // Since this force is being applied in only one step, make this a force per second.
1255  addForce /= PhysScene.LastTimeStep;
1256  }
1257 
1258  AddForce(false /* inTaintTime */, addForce);
1259  }
1260 
1261  // Applying a force just adds this to the total force on the object.
1262  // This added force will only last the next simulation tick.
1263  public override void AddForce(bool inTaintTime, OMV.Vector3 force) {
1264  // for an object, doesn't matter if force is a pushforce or not
1265  if (IsPhysicallyActive)
1266  {
1267  if (force.IsFinite())
1268  {
1269  // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1270 
1271  OMV.Vector3 addForce = force;
1272  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1273  {
1274  // Bullet adds this central force to the total force for this tick.
1275  // Deep down in Bullet:
1276  // linearVelocity += totalForce / mass * timeStep;
1277  DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1278  if (PhysBody.HasPhysicalBody)
1279  {
1280  PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1281  ActivateIfPhysical(false);
1282  }
1283  });
1284  }
1285  else
1286  {
1287  m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1288  return;
1289  }
1290  }
1291  }
1292 
1293  public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1294  // for an object, doesn't matter if force is a pushforce or not
1295  if (!IsPhysicallyActive)
1296  {
1297  if (impulse.IsFinite())
1298  {
1299  OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1300  // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1301 
1302  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1303  {
1304  // Bullet adds this impulse immediately to the velocity
1305  DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1306  if (PhysBody.HasPhysicalBody)
1307  {
1308  PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1309  ActivateIfPhysical(false);
1310  }
1311  });
1312  }
1313  else
1314  {
1315  m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1316  return;
1317  }
1318  }
1319  }
1320 
1321  // BSPhysObject.AddAngularForce()
1322  public override void AddAngularForce(bool inTaintTime, OMV.Vector3 force)
1323  {
1324  if (force.IsFinite())
1325  {
1326  OMV.Vector3 angForce = force;
1327  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1328  {
1329  if (PhysBody.HasPhysicalBody)
1330  {
1331  DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1332  PhysScene.PE.ApplyTorque(PhysBody, angForce);
1333  ActivateIfPhysical(false);
1334  }
1335  });
1336  }
1337  else
1338  {
1339  m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1340  return;
1341  }
1342  }
1343 
1344  // A torque impulse.
1345  // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1346  // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1347  // Computed as: angularVelocity += impulse * inertia;
1348  public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1349  {
1350  OMV.Vector3 applyImpulse = impulse;
1351  PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1352  {
1353  if (PhysBody.HasPhysicalBody)
1354  {
1355  PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1356  ActivateIfPhysical(false);
1357  }
1358  });
1359  }
1360 
1361  public override void SetMomentum(OMV.Vector3 momentum) {
1362  // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1363  }
1364  #region Mass Calculation
1365 
1366  private float CalculateMass()
1367  {
1368  float volume = _size.X * _size.Y * _size.Z; // default
1369  float tmp;
1370 
1371  float returnMass = 0;
1372  float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1373  float hollowVolume = hollowAmount * hollowAmount;
1374 
1375  switch (BaseShape.ProfileShape)
1376  {
1377  case ProfileShape.Square:
1378  // default box
1379 
1380  if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1381  {
1382  if (hollowAmount > 0.0)
1383  {
1384  switch (BaseShape.HollowShape)
1385  {
1386  case HollowShape.Square:
1387  case HollowShape.Same:
1388  break;
1389 
1390  case HollowShape.Circle:
1391 
1392  hollowVolume *= 0.78539816339f;
1393  break;
1394 
1395  case HollowShape.Triangle:
1396 
1397  hollowVolume *= (0.5f * .5f);
1398  break;
1399 
1400  default:
1401  hollowVolume = 0;
1402  break;
1403  }
1404  volume *= (1.0f - hollowVolume);
1405  }
1406  }
1407 
1408  else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1409  {
1410  //a tube
1411 
1412  volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1413  tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1414  volume -= volume*tmp*tmp;
1415 
1416  if (hollowAmount > 0.0)
1417  {
1418  hollowVolume *= hollowAmount;
1419 
1420  switch (BaseShape.HollowShape)
1421  {
1422  case HollowShape.Square:
1423  case HollowShape.Same:
1424  break;
1425 
1426  case HollowShape.Circle:
1427  hollowVolume *= 0.78539816339f;;
1428  break;
1429 
1430  case HollowShape.Triangle:
1431  hollowVolume *= 0.5f * 0.5f;
1432  break;
1433  default:
1434  hollowVolume = 0;
1435  break;
1436  }
1437  volume *= (1.0f - hollowVolume);
1438  }
1439  }
1440 
1441  break;
1442 
1443  case ProfileShape.Circle:
1444 
1445  if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1446  {
1447  volume *= 0.78539816339f; // elipse base
1448 
1449  if (hollowAmount > 0.0)
1450  {
1451  switch (BaseShape.HollowShape)
1452  {
1453  case HollowShape.Same:
1454  case HollowShape.Circle:
1455  break;
1456 
1457  case HollowShape.Square:
1458  hollowVolume *= 0.5f * 2.5984480504799f;
1459  break;
1460 
1461  case HollowShape.Triangle:
1462  hollowVolume *= .5f * 1.27323954473516f;
1463  break;
1464 
1465  default:
1466  hollowVolume = 0;
1467  break;
1468  }
1469  volume *= (1.0f - hollowVolume);
1470  }
1471  }
1472 
1473  else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1474  {
1475  volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1476  tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1477  volume *= (1.0f - tmp * tmp);
1478 
1479  if (hollowAmount > 0.0)
1480  {
1481 
1482  // calculate the hollow volume by it's shape compared to the prim shape
1483  hollowVolume *= hollowAmount;
1484 
1485  switch (BaseShape.HollowShape)
1486  {
1487  case HollowShape.Same:
1488  case HollowShape.Circle:
1489  break;
1490 
1491  case HollowShape.Square:
1492  hollowVolume *= 0.5f * 2.5984480504799f;
1493  break;
1494 
1495  case HollowShape.Triangle:
1496  hollowVolume *= .5f * 1.27323954473516f;
1497  break;
1498 
1499  default:
1500  hollowVolume = 0;
1501  break;
1502  }
1503  volume *= (1.0f - hollowVolume);
1504  }
1505  }
1506  break;
1507 
1508  case ProfileShape.HalfCircle:
1509  if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1510  {
1511  volume *= 0.52359877559829887307710723054658f;
1512  }
1513  break;
1514 
1515  case ProfileShape.EquilateralTriangle:
1516 
1517  if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1518  {
1519  volume *= 0.32475953f;
1520 
1521  if (hollowAmount > 0.0)
1522  {
1523 
1524  // calculate the hollow volume by it's shape compared to the prim shape
1525  switch (BaseShape.HollowShape)
1526  {
1527  case HollowShape.Same:
1528  case HollowShape.Triangle:
1529  hollowVolume *= .25f;
1530  break;
1531 
1532  case HollowShape.Square:
1533  hollowVolume *= 0.499849f * 3.07920140172638f;
1534  break;
1535 
1536  case HollowShape.Circle:
1537  // Hollow shape is a perfect cyllinder in respect to the cube's scale
1538  // Cyllinder hollow volume calculation
1539 
1540  hollowVolume *= 0.1963495f * 3.07920140172638f;
1541  break;
1542 
1543  default:
1544  hollowVolume = 0;
1545  break;
1546  }
1547  volume *= (1.0f - hollowVolume);
1548  }
1549  }
1550  else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1551  {
1552  volume *= 0.32475953f;
1553  volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1554  tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1555  volume *= (1.0f - tmp * tmp);
1556 
1557  if (hollowAmount > 0.0)
1558  {
1559 
1560  hollowVolume *= hollowAmount;
1561 
1562  switch (BaseShape.HollowShape)
1563  {
1564  case HollowShape.Same:
1565  case HollowShape.Triangle:
1566  hollowVolume *= .25f;
1567  break;
1568 
1569  case HollowShape.Square:
1570  hollowVolume *= 0.499849f * 3.07920140172638f;
1571  break;
1572 
1573  case HollowShape.Circle:
1574 
1575  hollowVolume *= 0.1963495f * 3.07920140172638f;
1576  break;
1577 
1578  default:
1579  hollowVolume = 0;
1580  break;
1581  }
1582  volume *= (1.0f - hollowVolume);
1583  }
1584  }
1585  break;
1586 
1587  default:
1588  break;
1589  }
1590 
1591 
1592 
1593  float taperX1;
1594  float taperY1;
1595  float taperX;
1596  float taperY;
1597  float pathBegin;
1598  float pathEnd;
1599  float profileBegin;
1600  float profileEnd;
1601 
1602  if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1603  {
1604  taperX1 = BaseShape.PathScaleX * 0.01f;
1605  if (taperX1 > 1.0f)
1606  taperX1 = 2.0f - taperX1;
1607  taperX = 1.0f - taperX1;
1608 
1609  taperY1 = BaseShape.PathScaleY * 0.01f;
1610  if (taperY1 > 1.0f)
1611  taperY1 = 2.0f - taperY1;
1612  taperY = 1.0f - taperY1;
1613  }
1614  else
1615  {
1616  taperX = BaseShape.PathTaperX * 0.01f;
1617  if (taperX < 0.0f)
1618  taperX = -taperX;
1619  taperX1 = 1.0f - taperX;
1620 
1621  taperY = BaseShape.PathTaperY * 0.01f;
1622  if (taperY < 0.0f)
1623  taperY = -taperY;
1624  taperY1 = 1.0f - taperY;
1625 
1626  }
1627 
1628 
1629  volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1630 
1631  pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1632  pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1633  volume *= (pathEnd - pathBegin);
1634 
1635  // this is crude aproximation
1636  profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1637  profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1638  volume *= (profileEnd - profileBegin);
1639 
1640  returnMass = Density * BSParam.DensityScaleFactor * volume;
1641 
1642  returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1643  // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1644  DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1645  LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1646 
1647  return returnMass;
1648  }// end CalculateMass
1649  #endregion Mass Calculation
1650 
1651  // Rebuild the geometry and object.
1652  // This is called when the shape changes so we need to recreate the mesh/hull.
1653  // Called at taint-time!!!
1654  public void CreateGeomAndObject(bool forceRebuild)
1655  {
1656  // Create the correct physical representation for this type of object.
1657  // Updates base.PhysBody and base.PhysShape with the new information.
1658  // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1659  PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1660  {
1661  // Called if the current prim body is about to be destroyed.
1662  // Remove all the physical dependencies on the old body.
1663  // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1664  // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1665  RemoveDependencies();
1666  });
1667 
1668  // Make sure the properties are set on the new object
1669  UpdatePhysicalParameters();
1670  return;
1671  }
1672 
1673  // Called at taint-time
1674  protected virtual void RemoveDependencies()
1675  {
1676  PhysicalActors.RemoveDependencies();
1677  }
1678 
1679  #region Extension
1680  public override object Extension(string pFunct, params object[] pParams)
1681  {
1682  DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1683  object ret = null;
1684  switch (pFunct)
1685  {
1686  case ExtendedPhysics.PhysFunctAxisLockLimits:
1687  ret = SetAxisLockLimitsExtension(pParams);
1688  break;
1689  default:
1690  ret = base.Extension(pFunct, pParams);
1691  break;
1692  }
1693  return ret;
1694  }
1695 
1696  private void InitializeAxisActor()
1697  {
1698  EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1699  LockedAxisActorName, delegate()
1700  {
1701  return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1702  });
1703 
1704  // Update parameters so the new actor's Refresh() action is called at the right time.
1705  PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1706  {
1707  UpdatePhysicalParameters();
1708  });
1709  }
1710 
1711  // Passed an array of an array of parameters, set the axis locking.
1712  // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1713  // followed by another int and floats, etc.
1714  private object SetAxisLockLimitsExtension(object[] pParams)
1715  {
1716  DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1717  object ret = null;
1718  try
1719  {
1720  if (pParams.GetLength(0) > 1)
1721  {
1722  int index = 2;
1723  while (index < pParams.GetLength(0))
1724  {
1725  var funct = pParams[index];
1726  DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1727  if (funct is Int32 || funct is Int64)
1728  {
1729  switch ((int)funct)
1730  {
1731  // Those that take no parameters
1732  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1733  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1734  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1735  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1736  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1737  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1738  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1739  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1740  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1741  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1742  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1743  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1744  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1745  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1746  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1747  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1748  case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1749  ApplyAxisLimits((int)funct, 0f, 0f);
1750  index += 1;
1751  break;
1752  // Those that take two parameters (the limits)
1753  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1754  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1755  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1756  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1757  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1758  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1759  ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1760  index += 3;
1761  break;
1762  default:
1763  m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1764  index += 1;
1765  break;
1766  }
1767  }
1768  }
1769  InitializeAxisActor();
1770  ret = (object)index;
1771  }
1772  }
1773  catch (Exception e)
1774  {
1775  m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1776  ret = null;
1777  }
1778  return ret; // not implemented yet
1779  }
1780 
1781  // Set the locking parameters.
1782  // If an axis is locked, the limits for the axis are set to zero,
1783  // If the axis is being constrained, the high and low value are passed and set.
1784  // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1785  protected void ApplyAxisLimits(int funct, float low, float high)
1786  {
1787  DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1788  float linearMax = 23000f;
1789  float angularMax = (float)Math.PI;
1790 
1791  switch (funct)
1792  {
1793  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1794  this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1795  this.LockedLinearAxisLow = OMV.Vector3.Zero;
1796  this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1797  break;
1798  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1799  this.LockedLinearAxis.X = LockedAxis;
1800  this.LockedLinearAxisLow.X = 0f;
1801  this.LockedLinearAxisHigh.X = 0f;
1802  break;
1803  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1804  this.LockedLinearAxis.X = LockedAxis;
1805  this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1806  this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1807  break;
1808  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1809  this.LockedLinearAxis.Y = LockedAxis;
1810  this.LockedLinearAxisLow.Y = 0f;
1811  this.LockedLinearAxisHigh.Y = 0f;
1812  break;
1813  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1814  this.LockedLinearAxis.Y = LockedAxis;
1815  this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1816  this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1817  break;
1818  case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1819  this.LockedLinearAxis.Z = LockedAxis;
1820  this.LockedLinearAxisLow.Z = 0f;
1821  this.LockedLinearAxisHigh.Z = 0f;
1822  break;
1823  case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1824  this.LockedLinearAxis.Z = LockedAxis;
1825  this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1826  this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1827  break;
1828  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1829  this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1830  this.LockedAngularAxisLow = OMV.Vector3.Zero;
1831  this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1832  break;
1833  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1834  this.LockedAngularAxis.X = LockedAxis;
1835  this.LockedAngularAxisLow.X = 0;
1836  this.LockedAngularAxisHigh.X = 0;
1837  break;
1838  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1839  this.LockedAngularAxis.X = LockedAxis;
1840  this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1841  this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1842  break;
1843  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1844  this.LockedAngularAxis.Y = LockedAxis;
1845  this.LockedAngularAxisLow.Y = 0;
1846  this.LockedAngularAxisHigh.Y = 0;
1847  break;
1848  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1849  this.LockedAngularAxis.Y = LockedAxis;
1850  this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1851  this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1852  break;
1853  case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1854  this.LockedAngularAxis.Z = LockedAxis;
1855  this.LockedAngularAxisLow.Z = 0;
1856  this.LockedAngularAxisHigh.Z = 0;
1857  break;
1858  case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1859  this.LockedAngularAxis.Z = LockedAxis;
1860  this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1861  this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1862  break;
1863  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1864  this.LockedLinearAxis = LockedAxisFree;
1865  this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1866  this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1867  break;
1868  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1869  this.LockedLinearAxis.X = FreeAxis;
1870  this.LockedLinearAxisLow.X = -linearMax;
1871  this.LockedLinearAxisHigh.X = linearMax;
1872  break;
1873  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1874  this.LockedLinearAxis.Y = FreeAxis;
1875  this.LockedLinearAxisLow.Y = -linearMax;
1876  this.LockedLinearAxisHigh.Y = linearMax;
1877  break;
1878  case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1879  this.LockedLinearAxis.Z = FreeAxis;
1880  this.LockedLinearAxisLow.Z = -linearMax;
1881  this.LockedLinearAxisHigh.Z = linearMax;
1882  break;
1883  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1884  this.LockedAngularAxis = LockedAxisFree;
1885  this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1886  this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1887  break;
1888  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1889  this.LockedAngularAxis.X = FreeAxis;
1890  this.LockedAngularAxisLow.X = -angularMax;
1891  this.LockedAngularAxisHigh.X = angularMax;
1892  break;
1893  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1894  this.LockedAngularAxis.Y = FreeAxis;
1895  this.LockedAngularAxisLow.Y = -angularMax;
1896  this.LockedAngularAxisHigh.Y = angularMax;
1897  break;
1898  case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1899  this.LockedAngularAxis.Z = FreeAxis;
1900  this.LockedAngularAxisLow.Z = -angularMax;
1901  this.LockedAngularAxisHigh.Z = angularMax;
1902  break;
1903  case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1904  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1905  ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1906  break;
1907  default:
1908  break;
1909  }
1910  return;
1911  }
1912  #endregion // Extension
1913 
1914  // The physics engine says that properties have updated. Update same and inform
1915  // the world that things have changed.
1916  // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1917  // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1918  public override void UpdateProperties(EntityProperties entprop)
1919  {
1920  // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1921  TriggerPreUpdatePropertyAction(ref entprop);
1922 
1923  // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1924 
1925  // Assign directly to the local variables so the normal set actions do not happen
1926  RawPosition = entprop.Position;
1927  RawOrientation = entprop.Rotation;
1928  // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1929  // very sensitive to velocity changes.
1930  if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1931  RawVelocity = entprop.Velocity;
1932  _acceleration = entprop.Acceleration;
1933  _rotationalVelocity = entprop.RotationalVelocity;
1934 
1935  // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1936 
1937  // The sanity check can change the velocity and/or position.
1938  if (PositionSanityCheck(true /* inTaintTime */ ))
1939  {
1940  entprop.Position = RawPosition;
1941  entprop.Velocity = RawVelocity;
1942  entprop.RotationalVelocity = _rotationalVelocity;
1943  entprop.Acceleration = _acceleration;
1944  }
1945 
1946  OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1947  DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1948 
1949  // remember the current and last set values
1950  LastEntityProperties = CurrentEntityProperties;
1951  CurrentEntityProperties = entprop;
1952 
1953  PhysScene.PostUpdate(this);
1954  }
1955 }
1956 }
OpenMetaverse OMV
override void LockAngularMotion(byte axislocks)
Definition: BSPrim.cs:283
override void ZeroAngularMotion(bool inTaintTime)
Definition: BSPrim.cs:268
override void VehicleVectorParam(int param, OMV.Vector3 value)
Definition: BSPrim.cs:614
void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
Definition: BSPrim.cs:1348
static string PrimitiveBaseShapeToString(PrimitiveBaseShape pbs)
Definition: BSScene.cs:1001
delegate void SetAlwaysRun(IClientAPI remoteClient, bool SetAlwaysRun)
Each physical object can have 'actors' who are pushing the object around. This can be used for hover...
Definition: BSActors.cs:118
override void ZeroMotion(bool inTaintTime)
Definition: BSPrim.cs:255
override void SetVolumeDetect(int param)
Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more ...
Definition: BSPrim.cs:704
override void UpdateProperties(EntityProperties entprop)
Definition: BSPrim.cs:1918
BSDynamics GetVehicleActor(bool createIfNone)
Definition: BSPrim.cs:544
override void VehicleFlags(int param, bool remove)
Definition: BSPrim.cs:638
override void VehicleFloatParam(int param, float value)
Definition: BSPrim.cs:602
virtual void MakeDynamic(bool makeStatic)
Definition: BSPrim.cs:963
void CreateGeomAndObject(bool forceRebuild)
Definition: BSPrim.cs:1654
OMV.Vector3 ComputeGravity(float buoyancy)
Definition: BSPrim.cs:500
BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
Definition: BSPrim.cs:81
OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion rotation
Definition: ICM_Api.cs:32
override void SetMomentum(OMV.Vector3 momentum)
Definition: BSPrim.cs:1361
void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime)
Definition: BSPrim.cs:1293
override void AddAngularForce(bool inTaintTime, OMV.Vector3 force)
Definition: BSPrim.cs:1322
override void VehicleRotationParam(int param, OMV.Quaternion rotation)
Definition: BSPrim.cs:626
void ApplyAxisLimits(int funct, float low, float high)
Definition: BSPrim.cs:1785
override object Extension(string pFunct, params object[] pParams)
Definition: BSPrim.cs:1680
override void AddForce(OMV.Vector3 force, bool pushforce)
Definition: BSPrim.cs:1248
override void SetVehicle(object pvdata)
Definition: BSPrim.cs:650
override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
Definition: BSPrim.cs:456
override void link(PhysicsActor obj)
Definition: BSPrim.cs:244
override void SetMaterial(int material)
Definition: BSPrim.cs:721
override void AddForce(bool inTaintTime, OMV.Vector3 force)
Definition: BSPrim.cs:1263
override bool ForceBodyShapeRebuild(bool inTaintTime)
Definition: BSPrim.cs:178