aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs')
-rw-r--r--OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs1895
1 files changed, 1895 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
new file mode 100644
index 0000000..6f27ac7
--- /dev/null
+++ b/OpenSim/Region/PhysicsModules/BulletS/BSPrim.cs
@@ -0,0 +1,1895 @@
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
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.PhysicsModules.SharedBase;
36using OpenSim.Region.PhysicsModule.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.PhysicsModule.BulletS
39{
40
41 [Serializable]
42public 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(OMV.Vector3 axis)
284 {
285 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
286
287 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
288 if (axis.X != 1)
289 {
290 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X, 0f, 0f);
291 }
292 if (axis.Y != 1)
293 {
294 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y, 0f, 0f);
295 }
296 if (axis.Z != 1)
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(correctionForce, false, inTaintTime);
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 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
651 public override void SetVolumeDetect(int param) {
652 bool newValue = (param != 0);
653 if (_isVolumeDetect != newValue)
654 {
655 _isVolumeDetect = newValue;
656 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
657 {
658 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
659 SetObjectDynamic(true);
660 });
661 }
662 return;
663 }
664 public override bool IsVolumeDetect
665 {
666 get { return _isVolumeDetect; }
667 }
668 public override void SetMaterial(int material)
669 {
670 base.SetMaterial(material);
671 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
672 {
673 UpdatePhysicalParameters();
674 });
675 }
676 public override float Friction
677 {
678 get { return base.Friction; }
679 set
680 {
681 if (base.Friction != value)
682 {
683 base.Friction = value;
684 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
685 {
686 UpdatePhysicalParameters();
687 });
688 }
689 }
690 }
691 public override float Restitution
692 {
693 get { return base.Restitution; }
694 set
695 {
696 if (base.Restitution != value)
697 {
698 base.Restitution = value;
699 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
700 {
701 UpdatePhysicalParameters();
702 });
703 }
704 }
705 }
706 // The simulator/viewer keep density as 100kg/m3.
707 // Remember to use BSParam.DensityScaleFactor to create the physical density.
708 public override float Density
709 {
710 get { return base.Density; }
711 set
712 {
713 if (base.Density != value)
714 {
715 base.Density = value;
716 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
717 {
718 UpdatePhysicalParameters();
719 });
720 }
721 }
722 }
723 public override float GravModifier
724 {
725 get { return base.GravModifier; }
726 set
727 {
728 if (base.GravModifier != value)
729 {
730 base.GravModifier = value;
731 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
732 {
733 UpdatePhysicalParameters();
734 });
735 }
736 }
737 }
738 public override OMV.Vector3 Velocity {
739 get { return RawVelocity; }
740 set {
741 RawVelocity = value;
742 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
743 {
744 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
745 ForceVelocity = RawVelocity;
746 });
747 }
748 }
749 public override OMV.Vector3 ForceVelocity {
750 get { return RawVelocity; }
751 set {
752 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
753
754 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
755 if (PhysBody.HasPhysicalBody)
756 {
757 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
758 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
759 ActivateIfPhysical(false);
760 }
761 }
762 }
763 public override OMV.Vector3 Torque {
764 get { return RawTorque; }
765 set {
766 RawTorque = value;
767 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
768 {
769 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
770 });
771 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
772
773 // Call update so actor Refresh() is called to start things off
774 PhysScene.TaintedObject(LocalID, "BSPrim.setTorque", delegate()
775 {
776 UpdatePhysicalParameters();
777 });
778 }
779 }
780 public override OMV.Vector3 Acceleration {
781 get { return _acceleration; }
782 set { _acceleration = value; }
783 }
784
785 public override OMV.Quaternion Orientation {
786 get {
787 return RawOrientation;
788 }
789 set {
790 if (RawOrientation == value)
791 return;
792 RawOrientation = value;
793
794 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
795 {
796 ForceOrientation = RawOrientation;
797 });
798 }
799 }
800 // Go directly to Bullet to get/set the value.
801 public override OMV.Quaternion ForceOrientation
802 {
803 get
804 {
805 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
806 return RawOrientation;
807 }
808 set
809 {
810 RawOrientation = value;
811 if (PhysBody.HasPhysicalBody)
812 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
813 }
814 }
815 public override int PhysicsActorType {
816 get { return _physicsActorType; }
817 set { _physicsActorType = value; }
818 }
819 public override bool IsPhysical {
820 get { return _isPhysical; }
821 set {
822 if (_isPhysical != value)
823 {
824 _isPhysical = value;
825 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
826 {
827 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
828 SetObjectDynamic(true);
829 // whether phys-to-static or static-to-phys, the object is not moving.
830 ZeroMotion(true);
831
832 });
833 }
834 }
835 }
836
837 // An object is static (does not move) if selected or not physical
838 public override bool IsStatic
839 {
840 get { return _isSelected || !IsPhysical; }
841 }
842
843 // An object is solid if it's not phantom and if it's not doing VolumeDetect
844 public override bool IsSolid
845 {
846 get { return !IsPhantom && !_isVolumeDetect; }
847 }
848
849 // The object is moving and is actively being dynamic in the physical world
850 public override bool IsPhysicallyActive
851 {
852 get { return !_isSelected && IsPhysical; }
853 }
854
855 // Make gravity work if the object is physical and not selected
856 // Called at taint-time!!
857 private void SetObjectDynamic(bool forceRebuild)
858 {
859 // Recreate the physical object if necessary
860 CreateGeomAndObject(forceRebuild);
861 }
862
863 // Convert the simulator's physical properties into settings on BulletSim objects.
864 // There are four flags we're interested in:
865 // IsStatic: Object does not move, otherwise the object has mass and moves
866 // isSolid: other objects bounce off of this object
867 // isVolumeDetect: other objects pass through but can generate collisions
868 // collisionEvents: whether this object returns collision events
869 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
870 public virtual void UpdatePhysicalParameters()
871 {
872 if (!PhysBody.HasPhysicalBody)
873 {
874 // This would only happen if updates are called for during initialization when the body is not set up yet.
875 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
876 return;
877 }
878
879 // Mangling all the physical properties requires the object not be in the physical world.
880 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
881 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
882
883 // Set up the object physicalness (does gravity and collisions move this object)
884 MakeDynamic(IsStatic);
885
886 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
887 PhysicalActors.Refresh();
888
889 // Arrange for collision events if the simulator wants them
890 EnableCollisions(SubscribedEvents());
891
892 // Make solid or not (do things bounce off or pass through this object).
893 MakeSolid(IsSolid);
894
895 AddObjectToPhysicalWorld();
896
897 // Rebuild its shape
898 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
899
900 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
901 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
902 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
903 }
904
905 // "Making dynamic" means changing to and from static.
906 // When static, gravity does not effect the object and it is fixed in space.
907 // When dynamic, the object can fall and be pushed by others.
908 // This is independent of its 'solidness' which controls what passes through
909 // this object and what interacts with it.
910 protected virtual void MakeDynamic(bool makeStatic)
911 {
912 if (makeStatic)
913 {
914 // Become a Bullet 'static' object type
915 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
916 // Stop all movement
917 ZeroMotion(true);
918
919 // Set various physical properties so other object interact properly
920 PhysScene.PE.SetFriction(PhysBody, Friction);
921 PhysScene.PE.SetRestitution(PhysBody, Restitution);
922 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
923
924 // Mass is zero which disables a bunch of physics stuff in Bullet
925 UpdatePhysicalMassProperties(0f, false);
926 // Set collision detection parameters
927 if (BSParam.CcdMotionThreshold > 0f)
928 {
929 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
930 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
931 }
932
933 // The activation state is 'disabled' so Bullet will not try to act on it.
934 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
935 // Start it out sleeping and physical actions could wake it up.
936 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
937
938 // This collides like a static object
939 PhysBody.collisionType = CollisionType.Static;
940 }
941 else
942 {
943 // Not a Bullet static object
944 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
945
946 // Set various physical properties so other object interact properly
947 PhysScene.PE.SetFriction(PhysBody, Friction);
948 PhysScene.PE.SetRestitution(PhysBody, Restitution);
949 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
950
951 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
952 // Since this can be called multiple times, only zero forces when becoming physical
953 // PhysicsScene.PE.ClearAllForces(BSBody);
954
955 // For good measure, make sure the transform is set through to the motion state
956 ForcePosition = RawPosition;
957 ForceVelocity = RawVelocity;
958 ForceRotationalVelocity = _rotationalVelocity;
959
960 // A dynamic object has mass
961 UpdatePhysicalMassProperties(RawMass, false);
962
963 // Set collision detection parameters
964 if (BSParam.CcdMotionThreshold > 0f)
965 {
966 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
967 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
968 }
969
970 // Various values for simulation limits
971 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
972 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
973 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
974 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
975
976 // This collides like an object.
977 PhysBody.collisionType = CollisionType.Dynamic;
978
979 // Force activation of the object so Bullet will act on it.
980 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
981 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
982 }
983 }
984
985 // "Making solid" means that other object will not pass through this object.
986 // To make transparent, we create a Bullet ghost object.
987 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
988 // the functions after this one set up the state of a possibly newly created collision body.
989 private void MakeSolid(bool makeSolid)
990 {
991 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
992 if (makeSolid)
993 {
994 // Verify the previous code created the correct shape for this type of thing.
995 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
996 {
997 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
998 }
999 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1000 }
1001 else
1002 {
1003 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
1004 {
1005 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
1006 }
1007 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
1008
1009 // Change collision info from a static object to a ghosty collision object
1010 PhysBody.collisionType = CollisionType.VolumeDetect;
1011 }
1012 }
1013
1014 // Turn on or off the flag controlling whether collision events are returned to the simulator.
1015 private void EnableCollisions(bool wantsCollisionEvents)
1016 {
1017 if (wantsCollisionEvents)
1018 {
1019 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1020 }
1021 else
1022 {
1023 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
1024 }
1025 }
1026
1027 // Add me to the physical world.
1028 // Object MUST NOT already be in the world.
1029 // This routine exists because some assorted properties get mangled by adding to the world.
1030 internal void AddObjectToPhysicalWorld()
1031 {
1032 if (PhysBody.HasPhysicalBody)
1033 {
1034 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
1035 }
1036 else
1037 {
1038 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
1039 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
1040 }
1041 }
1042
1043 // prims don't fly
1044 public override bool Flying {
1045 get { return _flying; }
1046 set {
1047 _flying = value;
1048 }
1049 }
1050 public override bool SetAlwaysRun {
1051 get { return _setAlwaysRun; }
1052 set { _setAlwaysRun = value; }
1053 }
1054 public override bool ThrottleUpdates {
1055 get { return _throttleUpdates; }
1056 set { _throttleUpdates = value; }
1057 }
1058 public bool IsPhantom {
1059 get {
1060 // SceneObjectPart removes phantom objects from the physics scene
1061 // so, although we could implement touching and such, we never
1062 // are invoked as a phantom object
1063 return false;
1064 }
1065 }
1066 public override bool FloatOnWater {
1067 set {
1068 _floatOnWater = value;
1069 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1070 {
1071 if (_floatOnWater)
1072 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1073 else
1074 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1075 });
1076 }
1077 }
1078 public override OMV.Vector3 RotationalVelocity {
1079 get {
1080 return _rotationalVelocity;
1081 }
1082 set {
1083 _rotationalVelocity = value;
1084 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1085 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1086 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1087 {
1088 ForceRotationalVelocity = _rotationalVelocity;
1089 });
1090 }
1091 }
1092 public override OMV.Vector3 ForceRotationalVelocity {
1093 get {
1094 return _rotationalVelocity;
1095 }
1096 set {
1097 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1098 if (PhysBody.HasPhysicalBody)
1099 {
1100 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1101 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1102 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1103 ActivateIfPhysical(false);
1104 }
1105 }
1106 }
1107 public override bool Kinematic {
1108 get { return _kinematic; }
1109 set { _kinematic = value;
1110 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1111 }
1112 }
1113 public override float Buoyancy {
1114 get { return _buoyancy; }
1115 set {
1116 _buoyancy = value;
1117 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1118 {
1119 ForceBuoyancy = _buoyancy;
1120 });
1121 }
1122 }
1123 public override float ForceBuoyancy {
1124 get { return _buoyancy; }
1125 set {
1126 _buoyancy = value;
1127 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1128 // Force the recalculation of the various inertia,etc variables in the object
1129 UpdatePhysicalMassProperties(RawMass, true);
1130 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1131 ActivateIfPhysical(false);
1132 }
1133 }
1134
1135 public override bool PIDActive
1136 {
1137 get
1138 {
1139 return MoveToTargetActive;
1140 }
1141
1142 set
1143 {
1144 MoveToTargetActive = value;
1145
1146 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1147 {
1148 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1149 });
1150
1151 // Call update so actor Refresh() is called to start things off
1152 PhysScene.TaintedObject(LocalID, "BSPrim.PIDActive", delegate()
1153 {
1154 UpdatePhysicalParameters();
1155 });
1156 }
1157 }
1158
1159 public override OMV.Vector3 PIDTarget
1160 {
1161 set
1162 {
1163 base.PIDTarget = value;
1164 BSActor actor;
1165 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1166 {
1167 // if the actor exists, tell it to refresh its values.
1168 actor.Refresh();
1169 }
1170
1171 }
1172 }
1173 // Used for llSetHoverHeight and maybe vehicle height
1174 // Hover Height will override MoveTo target's Z
1175 public override bool PIDHoverActive {
1176 set {
1177 base.HoverActive = value;
1178 EnableActor(HoverActive, HoverActorName, delegate()
1179 {
1180 return new BSActorHover(PhysScene, this, HoverActorName);
1181 });
1182
1183 // Call update so actor Refresh() is called to start things off
1184 PhysScene.TaintedObject(LocalID, "BSPrim.PIDHoverActive", delegate()
1185 {
1186 UpdatePhysicalParameters();
1187 });
1188 }
1189 }
1190
1191 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1192 // Per documentation, max force is limited.
1193 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1194
1195 // Since this force is being applied in only one step, make this a force per second.
1196 addForce /= PhysScene.LastTimeStep;
1197 AddForce(addForce, pushforce, false /* inTaintTime */);
1198 }
1199
1200 // Applying a force just adds this to the total force on the object.
1201 // This added force will only last the next simulation tick.
1202 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1203 // for an object, doesn't matter if force is a pushforce or not
1204 if (IsPhysicallyActive)
1205 {
1206 if (force.IsFinite())
1207 {
1208 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1209
1210 OMV.Vector3 addForce = force;
1211 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1212 {
1213 // Bullet adds this central force to the total force for this tick.
1214 // Deep down in Bullet:
1215 // linearVelocity += totalForce / mass * timeStep;
1216 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1217 if (PhysBody.HasPhysicalBody)
1218 {
1219 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1220 ActivateIfPhysical(false);
1221 }
1222 });
1223 }
1224 else
1225 {
1226 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1227 return;
1228 }
1229 }
1230 }
1231
1232 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1233 // for an object, doesn't matter if force is a pushforce or not
1234 if (!IsPhysicallyActive)
1235 {
1236 if (impulse.IsFinite())
1237 {
1238 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1239 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1240
1241 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1242 {
1243 // Bullet adds this impulse immediately to the velocity
1244 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1245 if (PhysBody.HasPhysicalBody)
1246 {
1247 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1248 ActivateIfPhysical(false);
1249 }
1250 });
1251 }
1252 else
1253 {
1254 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1255 return;
1256 }
1257 }
1258 }
1259
1260 // BSPhysObject.AddAngularForce()
1261 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1262 {
1263 if (force.IsFinite())
1264 {
1265 OMV.Vector3 angForce = force;
1266 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1267 {
1268 if (PhysBody.HasPhysicalBody)
1269 {
1270 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1271 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1272 ActivateIfPhysical(false);
1273 }
1274 });
1275 }
1276 else
1277 {
1278 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1279 return;
1280 }
1281 }
1282
1283 // A torque impulse.
1284 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1285 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1286 // Computed as: angularVelocity += impulse * inertia;
1287 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1288 {
1289 OMV.Vector3 applyImpulse = impulse;
1290 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1291 {
1292 if (PhysBody.HasPhysicalBody)
1293 {
1294 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1295 ActivateIfPhysical(false);
1296 }
1297 });
1298 }
1299
1300 public override void SetMomentum(OMV.Vector3 momentum) {
1301 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1302 }
1303 #region Mass Calculation
1304
1305 private float CalculateMass()
1306 {
1307 float volume = _size.X * _size.Y * _size.Z; // default
1308 float tmp;
1309
1310 float returnMass = 0;
1311 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1312 float hollowVolume = hollowAmount * hollowAmount;
1313
1314 switch (BaseShape.ProfileShape)
1315 {
1316 case ProfileShape.Square:
1317 // default box
1318
1319 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1320 {
1321 if (hollowAmount > 0.0)
1322 {
1323 switch (BaseShape.HollowShape)
1324 {
1325 case HollowShape.Square:
1326 case HollowShape.Same:
1327 break;
1328
1329 case HollowShape.Circle:
1330
1331 hollowVolume *= 0.78539816339f;
1332 break;
1333
1334 case HollowShape.Triangle:
1335
1336 hollowVolume *= (0.5f * .5f);
1337 break;
1338
1339 default:
1340 hollowVolume = 0;
1341 break;
1342 }
1343 volume *= (1.0f - hollowVolume);
1344 }
1345 }
1346
1347 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1348 {
1349 //a tube
1350
1351 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1352 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1353 volume -= volume*tmp*tmp;
1354
1355 if (hollowAmount > 0.0)
1356 {
1357 hollowVolume *= hollowAmount;
1358
1359 switch (BaseShape.HollowShape)
1360 {
1361 case HollowShape.Square:
1362 case HollowShape.Same:
1363 break;
1364
1365 case HollowShape.Circle:
1366 hollowVolume *= 0.78539816339f;;
1367 break;
1368
1369 case HollowShape.Triangle:
1370 hollowVolume *= 0.5f * 0.5f;
1371 break;
1372 default:
1373 hollowVolume = 0;
1374 break;
1375 }
1376 volume *= (1.0f - hollowVolume);
1377 }
1378 }
1379
1380 break;
1381
1382 case ProfileShape.Circle:
1383
1384 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1385 {
1386 volume *= 0.78539816339f; // elipse base
1387
1388 if (hollowAmount > 0.0)
1389 {
1390 switch (BaseShape.HollowShape)
1391 {
1392 case HollowShape.Same:
1393 case HollowShape.Circle:
1394 break;
1395
1396 case HollowShape.Square:
1397 hollowVolume *= 0.5f * 2.5984480504799f;
1398 break;
1399
1400 case HollowShape.Triangle:
1401 hollowVolume *= .5f * 1.27323954473516f;
1402 break;
1403
1404 default:
1405 hollowVolume = 0;
1406 break;
1407 }
1408 volume *= (1.0f - hollowVolume);
1409 }
1410 }
1411
1412 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1413 {
1414 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1415 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1416 volume *= (1.0f - tmp * tmp);
1417
1418 if (hollowAmount > 0.0)
1419 {
1420
1421 // calculate the hollow volume by it's shape compared to the prim shape
1422 hollowVolume *= hollowAmount;
1423
1424 switch (BaseShape.HollowShape)
1425 {
1426 case HollowShape.Same:
1427 case HollowShape.Circle:
1428 break;
1429
1430 case HollowShape.Square:
1431 hollowVolume *= 0.5f * 2.5984480504799f;
1432 break;
1433
1434 case HollowShape.Triangle:
1435 hollowVolume *= .5f * 1.27323954473516f;
1436 break;
1437
1438 default:
1439 hollowVolume = 0;
1440 break;
1441 }
1442 volume *= (1.0f - hollowVolume);
1443 }
1444 }
1445 break;
1446
1447 case ProfileShape.HalfCircle:
1448 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1449 {
1450 volume *= 0.52359877559829887307710723054658f;
1451 }
1452 break;
1453
1454 case ProfileShape.EquilateralTriangle:
1455
1456 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1457 {
1458 volume *= 0.32475953f;
1459
1460 if (hollowAmount > 0.0)
1461 {
1462
1463 // calculate the hollow volume by it's shape compared to the prim shape
1464 switch (BaseShape.HollowShape)
1465 {
1466 case HollowShape.Same:
1467 case HollowShape.Triangle:
1468 hollowVolume *= .25f;
1469 break;
1470
1471 case HollowShape.Square:
1472 hollowVolume *= 0.499849f * 3.07920140172638f;
1473 break;
1474
1475 case HollowShape.Circle:
1476 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1477 // Cyllinder hollow volume calculation
1478
1479 hollowVolume *= 0.1963495f * 3.07920140172638f;
1480 break;
1481
1482 default:
1483 hollowVolume = 0;
1484 break;
1485 }
1486 volume *= (1.0f - hollowVolume);
1487 }
1488 }
1489 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1490 {
1491 volume *= 0.32475953f;
1492 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1493 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1494 volume *= (1.0f - tmp * tmp);
1495
1496 if (hollowAmount > 0.0)
1497 {
1498
1499 hollowVolume *= hollowAmount;
1500
1501 switch (BaseShape.HollowShape)
1502 {
1503 case HollowShape.Same:
1504 case HollowShape.Triangle:
1505 hollowVolume *= .25f;
1506 break;
1507
1508 case HollowShape.Square:
1509 hollowVolume *= 0.499849f * 3.07920140172638f;
1510 break;
1511
1512 case HollowShape.Circle:
1513
1514 hollowVolume *= 0.1963495f * 3.07920140172638f;
1515 break;
1516
1517 default:
1518 hollowVolume = 0;
1519 break;
1520 }
1521 volume *= (1.0f - hollowVolume);
1522 }
1523 }
1524 break;
1525
1526 default:
1527 break;
1528 }
1529
1530
1531
1532 float taperX1;
1533 float taperY1;
1534 float taperX;
1535 float taperY;
1536 float pathBegin;
1537 float pathEnd;
1538 float profileBegin;
1539 float profileEnd;
1540
1541 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1542 {
1543 taperX1 = BaseShape.PathScaleX * 0.01f;
1544 if (taperX1 > 1.0f)
1545 taperX1 = 2.0f - taperX1;
1546 taperX = 1.0f - taperX1;
1547
1548 taperY1 = BaseShape.PathScaleY * 0.01f;
1549 if (taperY1 > 1.0f)
1550 taperY1 = 2.0f - taperY1;
1551 taperY = 1.0f - taperY1;
1552 }
1553 else
1554 {
1555 taperX = BaseShape.PathTaperX * 0.01f;
1556 if (taperX < 0.0f)
1557 taperX = -taperX;
1558 taperX1 = 1.0f - taperX;
1559
1560 taperY = BaseShape.PathTaperY * 0.01f;
1561 if (taperY < 0.0f)
1562 taperY = -taperY;
1563 taperY1 = 1.0f - taperY;
1564
1565 }
1566
1567
1568 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1569
1570 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1571 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1572 volume *= (pathEnd - pathBegin);
1573
1574 // this is crude aproximation
1575 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1576 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1577 volume *= (profileEnd - profileBegin);
1578
1579 returnMass = Density * BSParam.DensityScaleFactor * volume;
1580
1581 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1582 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1583 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1584 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1585
1586 return returnMass;
1587 }// end CalculateMass
1588 #endregion Mass Calculation
1589
1590 // Rebuild the geometry and object.
1591 // This is called when the shape changes so we need to recreate the mesh/hull.
1592 // Called at taint-time!!!
1593 public void CreateGeomAndObject(bool forceRebuild)
1594 {
1595 // Create the correct physical representation for this type of object.
1596 // Updates base.PhysBody and base.PhysShape with the new information.
1597 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1598 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1599 {
1600 // Called if the current prim body is about to be destroyed.
1601 // Remove all the physical dependencies on the old body.
1602 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1603 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1604 RemoveDependencies();
1605 });
1606
1607 // Make sure the properties are set on the new object
1608 UpdatePhysicalParameters();
1609 return;
1610 }
1611
1612 // Called at taint-time
1613 protected virtual void RemoveDependencies()
1614 {
1615 PhysicalActors.RemoveDependencies();
1616 }
1617
1618 #region Extension
1619 public override object Extension(string pFunct, params object[] pParams)
1620 {
1621 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1622 object ret = null;
1623 switch (pFunct)
1624 {
1625 case ExtendedPhysics.PhysFunctAxisLockLimits:
1626 ret = SetAxisLockLimitsExtension(pParams);
1627 break;
1628 default:
1629 ret = base.Extension(pFunct, pParams);
1630 break;
1631 }
1632 return ret;
1633 }
1634
1635 private void InitializeAxisActor()
1636 {
1637 EnableActor(LockedAngularAxis != LockedAxisFree || LockedLinearAxis != LockedAxisFree,
1638 LockedAxisActorName, delegate()
1639 {
1640 return new BSActorLockAxis(PhysScene, this, LockedAxisActorName);
1641 });
1642
1643 // Update parameters so the new actor's Refresh() action is called at the right time.
1644 PhysScene.TaintedObject(LocalID, "BSPrim.LockAxis", delegate()
1645 {
1646 UpdatePhysicalParameters();
1647 });
1648 }
1649
1650 // Passed an array of an array of parameters, set the axis locking.
1651 // This expects an int (PHYS_AXIS_*) followed by none or two limit floats
1652 // followed by another int and floats, etc.
1653 private object SetAxisLockLimitsExtension(object[] pParams)
1654 {
1655 DetailLog("{0} SetAxisLockLimitsExtension. parmlen={1}", LocalID, pParams.GetLength(0));
1656 object ret = null;
1657 try
1658 {
1659 if (pParams.GetLength(0) > 1)
1660 {
1661 int index = 2;
1662 while (index < pParams.GetLength(0))
1663 {
1664 var funct = pParams[index];
1665 DetailLog("{0} SetAxisLockLimitsExtension. op={1}, index={2}", LocalID, funct, index);
1666 if (funct is Int32 || funct is Int64)
1667 {
1668 switch ((int)funct)
1669 {
1670 // Those that take no parameters
1671 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1672 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1673 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1674 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1675 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1676 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1677 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1678 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1679 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1680 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1681 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1682 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1683 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1684 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1685 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1686 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1687 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1688 ApplyAxisLimits((int)funct, 0f, 0f);
1689 index += 1;
1690 break;
1691 // Those that take two parameters (the limits)
1692 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1693 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1694 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1695 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1696 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1697 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1698 ApplyAxisLimits((int)funct, (float)pParams[index + 1], (float)pParams[index + 2]);
1699 index += 3;
1700 break;
1701 default:
1702 m_log.WarnFormat("{0} SetSxisLockLimitsExtension. Unknown op={1}", LogHeader, funct);
1703 index += 1;
1704 break;
1705 }
1706 }
1707 }
1708 InitializeAxisActor();
1709 ret = (object)index;
1710 }
1711 }
1712 catch (Exception e)
1713 {
1714 m_log.WarnFormat("{0} SetSxisLockLimitsExtension exception in object {1}: {2}", LogHeader, this.Name, e);
1715 ret = null;
1716 }
1717 return ret; // not implemented yet
1718 }
1719
1720 // Set the locking parameters.
1721 // If an axis is locked, the limits for the axis are set to zero,
1722 // If the axis is being constrained, the high and low value are passed and set.
1723 // When done here, LockedXXXAxis flags are set and LockedXXXAxixLow/High are set to the range.
1724 protected void ApplyAxisLimits(int funct, float low, float high)
1725 {
1726 DetailLog("{0} ApplyAxisLimits. op={1}, low={2}, high={3}", LocalID, funct, low, high);
1727 float linearMax = 23000f;
1728 float angularMax = (float)Math.PI;
1729
1730 switch (funct)
1731 {
1732 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR:
1733 this.LockedLinearAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1734 this.LockedLinearAxisLow = OMV.Vector3.Zero;
1735 this.LockedLinearAxisHigh = OMV.Vector3.Zero;
1736 break;
1737 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_X:
1738 this.LockedLinearAxis.X = LockedAxis;
1739 this.LockedLinearAxisLow.X = 0f;
1740 this.LockedLinearAxisHigh.X = 0f;
1741 break;
1742 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_X:
1743 this.LockedLinearAxis.X = LockedAxis;
1744 this.LockedLinearAxisLow.X = Util.Clip(low, -linearMax, linearMax);
1745 this.LockedLinearAxisHigh.X = Util.Clip(high, -linearMax, linearMax);
1746 break;
1747 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Y:
1748 this.LockedLinearAxis.Y = LockedAxis;
1749 this.LockedLinearAxisLow.Y = 0f;
1750 this.LockedLinearAxisHigh.Y = 0f;
1751 break;
1752 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Y:
1753 this.LockedLinearAxis.Y = LockedAxis;
1754 this.LockedLinearAxisLow.Y = Util.Clip(low, -linearMax, linearMax);
1755 this.LockedLinearAxisHigh.Y = Util.Clip(high, -linearMax, linearMax);
1756 break;
1757 case ExtendedPhysics.PHYS_AXIS_LOCK_LINEAR_Z:
1758 this.LockedLinearAxis.Z = LockedAxis;
1759 this.LockedLinearAxisLow.Z = 0f;
1760 this.LockedLinearAxisHigh.Z = 0f;
1761 break;
1762 case ExtendedPhysics.PHYS_AXIS_LIMIT_LINEAR_Z:
1763 this.LockedLinearAxis.Z = LockedAxis;
1764 this.LockedLinearAxisLow.Z = Util.Clip(low, -linearMax, linearMax);
1765 this.LockedLinearAxisHigh.Z = Util.Clip(high, -linearMax, linearMax);
1766 break;
1767 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR:
1768 this.LockedAngularAxis = new OMV.Vector3(LockedAxis, LockedAxis, LockedAxis);
1769 this.LockedAngularAxisLow = OMV.Vector3.Zero;
1770 this.LockedAngularAxisHigh = OMV.Vector3.Zero;
1771 break;
1772 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_X:
1773 this.LockedAngularAxis.X = LockedAxis;
1774 this.LockedAngularAxisLow.X = 0;
1775 this.LockedAngularAxisHigh.X = 0;
1776 break;
1777 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_X:
1778 this.LockedAngularAxis.X = LockedAxis;
1779 this.LockedAngularAxisLow.X = Util.Clip(low, -angularMax, angularMax);
1780 this.LockedAngularAxisHigh.X = Util.Clip(high, -angularMax, angularMax);
1781 break;
1782 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Y:
1783 this.LockedAngularAxis.Y = LockedAxis;
1784 this.LockedAngularAxisLow.Y = 0;
1785 this.LockedAngularAxisHigh.Y = 0;
1786 break;
1787 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Y:
1788 this.LockedAngularAxis.Y = LockedAxis;
1789 this.LockedAngularAxisLow.Y = Util.Clip(low, -angularMax, angularMax);
1790 this.LockedAngularAxisHigh.Y = Util.Clip(high, -angularMax, angularMax);
1791 break;
1792 case ExtendedPhysics.PHYS_AXIS_LOCK_ANGULAR_Z:
1793 this.LockedAngularAxis.Z = LockedAxis;
1794 this.LockedAngularAxisLow.Z = 0;
1795 this.LockedAngularAxisHigh.Z = 0;
1796 break;
1797 case ExtendedPhysics.PHYS_AXIS_LIMIT_ANGULAR_Z:
1798 this.LockedAngularAxis.Z = LockedAxis;
1799 this.LockedAngularAxisLow.Z = Util.Clip(low, -angularMax, angularMax);
1800 this.LockedAngularAxisHigh.Z = Util.Clip(high, -angularMax, angularMax);
1801 break;
1802 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR:
1803 this.LockedLinearAxis = LockedAxisFree;
1804 this.LockedLinearAxisLow = new OMV.Vector3(-linearMax, -linearMax, -linearMax);
1805 this.LockedLinearAxisHigh = new OMV.Vector3(linearMax, linearMax, linearMax);
1806 break;
1807 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_X:
1808 this.LockedLinearAxis.X = FreeAxis;
1809 this.LockedLinearAxisLow.X = -linearMax;
1810 this.LockedLinearAxisHigh.X = linearMax;
1811 break;
1812 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Y:
1813 this.LockedLinearAxis.Y = FreeAxis;
1814 this.LockedLinearAxisLow.Y = -linearMax;
1815 this.LockedLinearAxisHigh.Y = linearMax;
1816 break;
1817 case ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR_Z:
1818 this.LockedLinearAxis.Z = FreeAxis;
1819 this.LockedLinearAxisLow.Z = -linearMax;
1820 this.LockedLinearAxisHigh.Z = linearMax;
1821 break;
1822 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR:
1823 this.LockedAngularAxis = LockedAxisFree;
1824 this.LockedAngularAxisLow = new OMV.Vector3(-angularMax, -angularMax, -angularMax);
1825 this.LockedAngularAxisHigh = new OMV.Vector3(angularMax, angularMax, angularMax);
1826 break;
1827 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_X:
1828 this.LockedAngularAxis.X = FreeAxis;
1829 this.LockedAngularAxisLow.X = -angularMax;
1830 this.LockedAngularAxisHigh.X = angularMax;
1831 break;
1832 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Y:
1833 this.LockedAngularAxis.Y = FreeAxis;
1834 this.LockedAngularAxisLow.Y = -angularMax;
1835 this.LockedAngularAxisHigh.Y = angularMax;
1836 break;
1837 case ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR_Z:
1838 this.LockedAngularAxis.Z = FreeAxis;
1839 this.LockedAngularAxisLow.Z = -angularMax;
1840 this.LockedAngularAxisHigh.Z = angularMax;
1841 break;
1842 case ExtendedPhysics.PHYS_AXIS_UNLOCK:
1843 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_LINEAR, 0f, 0f);
1844 ApplyAxisLimits(ExtendedPhysics.PHYS_AXIS_UNLOCK_ANGULAR, 0f, 0f);
1845 break;
1846 default:
1847 break;
1848 }
1849 return;
1850 }
1851 #endregion // Extension
1852
1853 // The physics engine says that properties have updated. Update same and inform
1854 // the world that things have changed.
1855 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1856 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1857 public override void UpdateProperties(EntityProperties entprop)
1858 {
1859 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1860 TriggerPreUpdatePropertyAction(ref entprop);
1861
1862 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1863
1864 // Assign directly to the local variables so the normal set actions do not happen
1865 RawPosition = entprop.Position;
1866 RawOrientation = entprop.Rotation;
1867 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1868 // very sensitive to velocity changes.
1869 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1870 RawVelocity = entprop.Velocity;
1871 _acceleration = entprop.Acceleration;
1872 _rotationalVelocity = entprop.RotationalVelocity;
1873
1874 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1875
1876 // The sanity check can change the velocity and/or position.
1877 if (PositionSanityCheck(true /* inTaintTime */ ))
1878 {
1879 entprop.Position = RawPosition;
1880 entprop.Velocity = RawVelocity;
1881 entprop.RotationalVelocity = _rotationalVelocity;
1882 entprop.Acceleration = _acceleration;
1883 }
1884
1885 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1886 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1887
1888 // remember the current and last set values
1889 LastEntityProperties = CurrentEntityProperties;
1890 CurrentEntityProperties = entprop;
1891
1892 PhysScene.PostUpdate(this);
1893 }
1894}
1895}