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