clockwerk-opensim-stable – Blame information for rev 1

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