opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 int wayOverThere = -1000;
380 int wayOutThere = 10000;
381 // There have been instances of objects getting thrown way out of bounds and crashing
382 // the border crossing code.
383 if ( RawPosition.X < wayOverThere || RawPosition.X > wayOutThere
384 || RawPosition.Y < wayOverThere || RawPosition.X > wayOutThere
385 || RawPosition.Z < wayOverThere || RawPosition.X > wayOutThere)
386 {
387 RawPosition = new OMV.Vector3(10, 10, 50);
388 ZeroMotion(inTaintTime);
389 ret = true;
390 }
391 if (RawVelocity.LengthSquared() > BSParam.MaxLinearVelocitySquared)
392 {
393 RawVelocity = Util.ClampV(RawVelocity, BSParam.MaxLinearVelocity);
394 ret = true;
395 }
396 if (_rotationalVelocity.LengthSquared() > BSParam.MaxAngularVelocitySquared)
397 {
398 _rotationalVelocity = Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
399 ret = true;
400 }
401  
402 return ret;
403 }
404  
405 // Return the effective mass of the object.
406 // The definition of this call is to return the mass of the prim.
407 // If the simulator cares about the mass of the linkset, it will sum it itself.
408 public override float Mass
409 {
410 get { return _mass; }
411 }
412 // TotalMass returns the mass of the large object the prim may be in (overridden by linkset code)
413 public virtual float TotalMass
414 {
415 get { return _mass; }
416 }
417 // used when we only want this prim's mass and not the linkset thing
418 public override float RawMass {
419 get { return _mass; }
420 }
421 // Set the physical mass to the passed mass.
422 // Note that this does not change _mass!
423 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
424 {
425 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
426 {
427 if (IsStatic)
428 {
429 PhysScene.PE.SetGravity(PhysBody, PhysScene.DefaultGravity);
430 Inertia = OMV.Vector3.Zero;
431 PhysScene.PE.SetMassProps(PhysBody, 0f, Inertia);
432 PhysScene.PE.UpdateInertiaTensor(PhysBody);
433 }
434 else
435 {
436 if (inWorld)
437 {
438 // Changing interesting properties doesn't change proxy and collision cache
439 // information. The Bullet solution is to re-add the object to the world
440 // after parameters are changed.
441 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
442 }
443  
444 // The computation of mass props requires gravity to be set on the object.
445 Gravity = ComputeGravity(Buoyancy);
446 PhysScene.PE.SetGravity(PhysBody, Gravity);
447  
448 // OMV.Vector3 currentScale = PhysScene.PE.GetLocalScaling(PhysShape.physShapeInfo); // DEBUG DEBUG
449 // DetailLog("{0},BSPrim.UpdateMassProperties,currentScale{1},shape={2}", LocalID, currentScale, PhysShape.physShapeInfo); // DEBUG DEBUG
450  
451 Inertia = PhysScene.PE.CalculateLocalInertia(PhysShape.physShapeInfo, physMass);
452 PhysScene.PE.SetMassProps(PhysBody, physMass, Inertia);
453 PhysScene.PE.UpdateInertiaTensor(PhysBody);
454  
455 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}",
456 LocalID, physMass, Inertia, Gravity, inWorld);
457  
458 if (inWorld)
459 {
460 AddObjectToPhysicalWorld();
461 }
462 }
463 }
464 }
465  
466 // Return what gravity should be set to this very moment
467 public OMV.Vector3 ComputeGravity(float buoyancy)
468 {
469 OMV.Vector3 ret = PhysScene.DefaultGravity;
470  
471 if (!IsStatic)
472 {
473 ret *= (1f - buoyancy);
474 ret *= GravModifier;
475 }
476  
477 return ret;
478 }
479  
480 // Is this used?
481 public override OMV.Vector3 CenterOfMass
482 {
483 get { return RawPosition; }
484 }
485  
486 // Is this used?
487 public override OMV.Vector3 GeometricCenter
488 {
489 get { return RawPosition; }
490 }
491  
492 public override OMV.Vector3 Force {
493 get { return RawForce; }
494 set {
495 RawForce = value;
496 EnableActor(RawForce != OMV.Vector3.Zero, SetForceActorName, delegate()
497 {
498 return new BSActorSetForce(PhysScene, this, SetForceActorName);
499 });
500 }
501 }
502  
503 // Find and return a handle to the current vehicle actor.
504 // Return 'null' if there is no vehicle actor.
505 public BSDynamics GetVehicleActor(bool createIfNone)
506 {
507 BSDynamics ret = null;
508 BSActor actor;
509 if (PhysicalActors.TryGetActor(VehicleActorName, out actor))
510 {
511 ret = actor as BSDynamics;
512 }
513 else
514 {
515 if (createIfNone)
516 {
517 ret = new BSDynamics(PhysScene, this, VehicleActorName);
518 PhysicalActors.Add(ret.ActorName, ret);
519 }
520 }
521 return ret;
522 }
523  
524 public override int VehicleType {
525 get {
526 int ret = (int)Vehicle.TYPE_NONE;
527 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
528 if (vehicleActor != null)
529 ret = (int)vehicleActor.Type;
530 return ret;
531 }
532 set {
533 Vehicle type = (Vehicle)value;
534  
535 PhysScene.TaintedObject(LocalID, "setVehicleType", delegate()
536 {
537 // Some vehicle scripts change vehicle type on the fly as an easy way to
538 // change all the parameters. Like a plane changing to CAR when on the
539 // ground. In this case, don't want to zero motion.
540 // ZeroMotion(true /* inTaintTime */);
541 if (type == Vehicle.TYPE_NONE)
542 {
543 // Vehicle type is 'none' so get rid of any actor that may have been allocated.
544 BSDynamics vehicleActor = GetVehicleActor(false /* createIfNone */);
545 if (vehicleActor != null)
546 {
547 PhysicalActors.RemoveAndRelease(vehicleActor.ActorName);
548 }
549 }
550 else
551 {
552 // Vehicle type is not 'none' so create an actor and set it running.
553 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
554 if (vehicleActor != null)
555 {
556 vehicleActor.ProcessTypeChange(type);
557 ActivateIfPhysical(false);
558 }
559 }
560 });
561 }
562 }
563 public override void VehicleFloatParam(int param, float value)
564 {
565 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFloatParam", delegate()
566 {
567 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
568 if (vehicleActor != null)
569 {
570 vehicleActor.ProcessFloatVehicleParam((Vehicle)param, value);
571 ActivateIfPhysical(false);
572 }
573 });
574 }
575 public override void VehicleVectorParam(int param, OMV.Vector3 value)
576 {
577 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleVectorParam", delegate()
578 {
579 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
580 if (vehicleActor != null)
581 {
582 vehicleActor.ProcessVectorVehicleParam((Vehicle)param, value);
583 ActivateIfPhysical(false);
584 }
585 });
586 }
587 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
588 {
589 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleRotationParam", delegate()
590 {
591 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
592 if (vehicleActor != null)
593 {
594 vehicleActor.ProcessRotationVehicleParam((Vehicle)param, rotation);
595 ActivateIfPhysical(false);
596 }
597 });
598 }
599 public override void VehicleFlags(int param, bool remove)
600 {
601 PhysScene.TaintedObject(LocalID, "BSPrim.VehicleFlags", delegate()
602 {
603 BSDynamics vehicleActor = GetVehicleActor(true /* createIfNone */);
604 if (vehicleActor != null)
605 {
606 vehicleActor.ProcessVehicleFlags(param, remove);
607 }
608 });
609 }
610  
611 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
612 public override void SetVolumeDetect(int param) {
613 bool newValue = (param != 0);
614 if (_isVolumeDetect != newValue)
615 {
616 _isVolumeDetect = newValue;
617 PhysScene.TaintedObject(LocalID, "BSPrim.SetVolumeDetect", delegate()
618 {
619 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
620 SetObjectDynamic(true);
621 });
622 }
623 return;
624 }
625 public override bool IsVolumeDetect
626 {
627 get { return _isVolumeDetect; }
628 }
629 public override void SetMaterial(int material)
630 {
631 base.SetMaterial(material);
632 PhysScene.TaintedObject(LocalID, "BSPrim.SetMaterial", delegate()
633 {
634 UpdatePhysicalParameters();
635 });
636 }
637 public override float Friction
638 {
639 get { return base.Friction; }
640 set
641 {
642 if (base.Friction != value)
643 {
644 base.Friction = value;
645 PhysScene.TaintedObject(LocalID, "BSPrim.setFriction", delegate()
646 {
647 UpdatePhysicalParameters();
648 });
649 }
650 }
651 }
652 public override float Restitution
653 {
654 get { return base.Restitution; }
655 set
656 {
657 if (base.Restitution != value)
658 {
659 base.Restitution = value;
660 PhysScene.TaintedObject(LocalID, "BSPrim.setRestitution", delegate()
661 {
662 UpdatePhysicalParameters();
663 });
664 }
665 }
666 }
667 // The simulator/viewer keep density as 100kg/m3.
668 // Remember to use BSParam.DensityScaleFactor to create the physical density.
669 public override float Density
670 {
671 get { return base.Density; }
672 set
673 {
674 if (base.Density != value)
675 {
676 base.Density = value;
677 PhysScene.TaintedObject(LocalID, "BSPrim.setDensity", delegate()
678 {
679 UpdatePhysicalParameters();
680 });
681 }
682 }
683 }
684 public override float GravModifier
685 {
686 get { return base.GravModifier; }
687 set
688 {
689 if (base.GravModifier != value)
690 {
691 base.GravModifier = value;
692 PhysScene.TaintedObject(LocalID, "BSPrim.setGravityModifier", delegate()
693 {
694 UpdatePhysicalParameters();
695 });
696 }
697 }
698 }
699 public override OMV.Vector3 Velocity {
700 get { return RawVelocity; }
701 set {
702 RawVelocity = value;
703 PhysScene.TaintedObject(LocalID, "BSPrim.setVelocity", delegate()
704 {
705 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, RawVelocity);
706 ForceVelocity = RawVelocity;
707 });
708 }
709 }
710 public override OMV.Vector3 ForceVelocity {
711 get { return RawVelocity; }
712 set {
713 PhysScene.AssertInTaintTime("BSPrim.ForceVelocity");
714  
715 RawVelocity = Util.ClampV(value, BSParam.MaxLinearVelocity);
716 if (PhysBody.HasPhysicalBody)
717 {
718 DetailLog("{0},BSPrim.ForceVelocity,taint,vel={1}", LocalID, RawVelocity);
719 PhysScene.PE.SetLinearVelocity(PhysBody, RawVelocity);
720 ActivateIfPhysical(false);
721 }
722 }
723 }
724 public override OMV.Vector3 Torque {
725 get { return RawTorque; }
726 set {
727 RawTorque = value;
728 EnableActor(RawTorque != OMV.Vector3.Zero, SetTorqueActorName, delegate()
729 {
730 return new BSActorSetTorque(PhysScene, this, SetTorqueActorName);
731 });
732 DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, RawTorque);
733 }
734 }
735 public override OMV.Vector3 Acceleration {
736 get { return _acceleration; }
737 set { _acceleration = value; }
738 }
739  
740 public override OMV.Quaternion Orientation {
741 get {
742 return RawOrientation;
743 }
744 set {
745 if (RawOrientation == value)
746 return;
747 RawOrientation = value;
748  
749 PhysScene.TaintedObject(LocalID, "BSPrim.setOrientation", delegate()
750 {
751 ForceOrientation = RawOrientation;
752 });
753 }
754 }
755 // Go directly to Bullet to get/set the value.
756 public override OMV.Quaternion ForceOrientation
757 {
758 get
759 {
760 RawOrientation = PhysScene.PE.GetOrientation(PhysBody);
761 return RawOrientation;
762 }
763 set
764 {
765 RawOrientation = value;
766 if (PhysBody.HasPhysicalBody)
767 PhysScene.PE.SetTranslation(PhysBody, RawPosition, RawOrientation);
768 }
769 }
770 public override int PhysicsActorType {
771 get { return _physicsActorType; }
772 set { _physicsActorType = value; }
773 }
774 public override bool IsPhysical {
775 get { return _isPhysical; }
776 set {
777 if (_isPhysical != value)
778 {
779 _isPhysical = value;
780 PhysScene.TaintedObject(LocalID, "BSPrim.setIsPhysical", delegate()
781 {
782 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
783 SetObjectDynamic(true);
784 // whether phys-to-static or static-to-phys, the object is not moving.
785 ZeroMotion(true);
786  
787 });
788 }
789 }
790 }
791  
792 // An object is static (does not move) if selected or not physical
793 public override bool IsStatic
794 {
795 get { return _isSelected || !IsPhysical; }
796 }
797  
798 // An object is solid if it's not phantom and if it's not doing VolumeDetect
799 public override bool IsSolid
800 {
801 get { return !IsPhantom && !_isVolumeDetect; }
802 }
803  
804 // The object is moving and is actively being dynamic in the physical world
805 public override bool IsPhysicallyActive
806 {
807 get { return !_isSelected && IsPhysical; }
808 }
809  
810 // Make gravity work if the object is physical and not selected
811 // Called at taint-time!!
812 private void SetObjectDynamic(bool forceRebuild)
813 {
814 // Recreate the physical object if necessary
815 CreateGeomAndObject(forceRebuild);
816 }
817  
818 // Convert the simulator's physical properties into settings on BulletSim objects.
819 // There are four flags we're interested in:
820 // IsStatic: Object does not move, otherwise the object has mass and moves
821 // isSolid: other objects bounce off of this object
822 // isVolumeDetect: other objects pass through but can generate collisions
823 // collisionEvents: whether this object returns collision events
824 // NOTE: overloaded by BSPrimLinkable to also update linkset physical parameters.
825 public virtual void UpdatePhysicalParameters()
826 {
827 if (!PhysBody.HasPhysicalBody)
828 {
829 // This would only happen if updates are called for during initialization when the body is not set up yet.
830 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,taint,calledWithNoPhysBody", LocalID);
831 return;
832 }
833  
834 // Mangling all the physical properties requires the object not be in the physical world.
835 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
836 PhysScene.PE.RemoveObjectFromWorld(PhysScene.World, PhysBody);
837  
838 // Set up the object physicalness (does gravity and collisions move this object)
839 MakeDynamic(IsStatic);
840  
841 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
842 PhysicalActors.Refresh();
843  
844 // Arrange for collision events if the simulator wants them
845 EnableCollisions(SubscribedEvents());
846  
847 // Make solid or not (do things bounce off or pass through this object).
848 MakeSolid(IsSolid);
849  
850 AddObjectToPhysicalWorld();
851  
852 // Rebuild its shape
853 PhysScene.PE.UpdateSingleAabb(PhysScene.World, PhysBody);
854  
855 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
856 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(),
857 CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
858 }
859  
860 // "Making dynamic" means changing to and from static.
861 // When static, gravity does not effect the object and it is fixed in space.
862 // When dynamic, the object can fall and be pushed by others.
863 // This is independent of its 'solidness' which controls what passes through
864 // this object and what interacts with it.
865 protected virtual void MakeDynamic(bool makeStatic)
866 {
867 if (makeStatic)
868 {
869 // Become a Bullet 'static' object type
870 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
871 // Stop all movement
872 ZeroMotion(true);
873  
874 // Set various physical properties so other object interact properly
875 PhysScene.PE.SetFriction(PhysBody, Friction);
876 PhysScene.PE.SetRestitution(PhysBody, Restitution);
877 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
878  
879 // Mass is zero which disables a bunch of physics stuff in Bullet
880 UpdatePhysicalMassProperties(0f, false);
881 // Set collision detection parameters
882 if (BSParam.CcdMotionThreshold > 0f)
883 {
884 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
885 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
886 }
887  
888 // The activation state is 'disabled' so Bullet will not try to act on it.
889 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
890 // Start it out sleeping and physical actions could wake it up.
891 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
892  
893 // This collides like a static object
894 PhysBody.collisionType = CollisionType.Static;
895 }
896 else
897 {
898 // Not a Bullet static object
899 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
900  
901 // Set various physical properties so other object interact properly
902 PhysScene.PE.SetFriction(PhysBody, Friction);
903 PhysScene.PE.SetRestitution(PhysBody, Restitution);
904 // DetailLog("{0},BSPrim.MakeDynamic,frict={1},rest={2}", LocalID, Friction, Restitution);
905  
906 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
907 // Since this can be called multiple times, only zero forces when becoming physical
908 // PhysicsScene.PE.ClearAllForces(BSBody);
909  
910 // For good measure, make sure the transform is set through to the motion state
911 ForcePosition = RawPosition;
912 ForceVelocity = RawVelocity;
913 ForceRotationalVelocity = _rotationalVelocity;
914  
915 // A dynamic object has mass
916 UpdatePhysicalMassProperties(RawMass, false);
917  
918 // Set collision detection parameters
919 if (BSParam.CcdMotionThreshold > 0f)
920 {
921 PhysScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
922 PhysScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
923 }
924  
925 // Various values for simulation limits
926 PhysScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
927 PhysScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
928 PhysScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
929 PhysScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
930  
931 // This collides like an object.
932 PhysBody.collisionType = CollisionType.Dynamic;
933  
934 // Force activation of the object so Bullet will act on it.
935 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
936 PhysScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
937 }
938 }
939  
940 // "Making solid" means that other object will not pass through this object.
941 // To make transparent, we create a Bullet ghost object.
942 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
943 // the functions after this one set up the state of a possibly newly created collision body.
944 private void MakeSolid(bool makeSolid)
945 {
946 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysScene.PE.GetBodyType(PhysBody);
947 if (makeSolid)
948 {
949 // Verify the previous code created the correct shape for this type of thing.
950 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
951 {
952 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
953 }
954 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
955 }
956 else
957 {
958 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
959 {
960 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
961 }
962 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
963  
964 // Change collision info from a static object to a ghosty collision object
965 PhysBody.collisionType = CollisionType.VolumeDetect;
966 }
967 }
968  
969 // Turn on or off the flag controlling whether collision events are returned to the simulator.
970 private void EnableCollisions(bool wantsCollisionEvents)
971 {
972 if (wantsCollisionEvents)
973 {
974 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
975 }
976 else
977 {
978 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
979 }
980 }
981  
982 // Add me to the physical world.
983 // Object MUST NOT already be in the world.
984 // This routine exists because some assorted properties get mangled by adding to the world.
985 internal void AddObjectToPhysicalWorld()
986 {
987 if (PhysBody.HasPhysicalBody)
988 {
989 PhysScene.PE.AddObjectToWorld(PhysScene.World, PhysBody);
990 }
991 else
992 {
993 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
994 DetailLog("{0},BSPrim.AddObjectToPhysicalWorld,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
995 }
996 }
997  
998 // prims don't fly
999 public override bool Flying {
1000 get { return _flying; }
1001 set {
1002 _flying = value;
1003 }
1004 }
1005 public override bool SetAlwaysRun {
1006 get { return _setAlwaysRun; }
1007 set { _setAlwaysRun = value; }
1008 }
1009 public override bool ThrottleUpdates {
1010 get { return _throttleUpdates; }
1011 set { _throttleUpdates = value; }
1012 }
1013 public bool IsPhantom {
1014 get {
1015 // SceneObjectPart removes phantom objects from the physics scene
1016 // so, although we could implement touching and such, we never
1017 // are invoked as a phantom object
1018 return false;
1019 }
1020 }
1021 public override bool FloatOnWater {
1022 set {
1023 _floatOnWater = value;
1024 PhysScene.TaintedObject(LocalID, "BSPrim.setFloatOnWater", delegate()
1025 {
1026 if (_floatOnWater)
1027 CurrentCollisionFlags = PhysScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1028 else
1029 CurrentCollisionFlags = PhysScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
1030 });
1031 }
1032 }
1033 public override OMV.Vector3 RotationalVelocity {
1034 get {
1035 return _rotationalVelocity;
1036 }
1037 set {
1038 _rotationalVelocity = value;
1039 Util.ClampV(_rotationalVelocity, BSParam.MaxAngularVelocity);
1040 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
1041 PhysScene.TaintedObject(LocalID, "BSPrim.setRotationalVelocity", delegate()
1042 {
1043 ForceRotationalVelocity = _rotationalVelocity;
1044 });
1045 }
1046 }
1047 public override OMV.Vector3 ForceRotationalVelocity {
1048 get {
1049 return _rotationalVelocity;
1050 }
1051 set {
1052 _rotationalVelocity = Util.ClampV(value, BSParam.MaxAngularVelocity);
1053 if (PhysBody.HasPhysicalBody)
1054 {
1055 DetailLog("{0},BSPrim.ForceRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
1056 PhysScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
1057 // PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
1058 ActivateIfPhysical(false);
1059 }
1060 }
1061 }
1062 public override bool Kinematic {
1063 get { return _kinematic; }
1064 set { _kinematic = value;
1065 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
1066 }
1067 }
1068 public override float Buoyancy {
1069 get { return _buoyancy; }
1070 set {
1071 _buoyancy = value;
1072 PhysScene.TaintedObject(LocalID, "BSPrim.setBuoyancy", delegate()
1073 {
1074 ForceBuoyancy = _buoyancy;
1075 });
1076 }
1077 }
1078 public override float ForceBuoyancy {
1079 get { return _buoyancy; }
1080 set {
1081 _buoyancy = value;
1082 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
1083 // Force the recalculation of the various inertia,etc variables in the object
1084 UpdatePhysicalMassProperties(RawMass, true);
1085 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2},grav={3}", LocalID, _buoyancy, RawMass, Gravity);
1086 ActivateIfPhysical(false);
1087 }
1088 }
1089  
1090 public override bool PIDActive {
1091 set {
1092 base.MoveToTargetActive = value;
1093 EnableActor(MoveToTargetActive, MoveToTargetActorName, delegate()
1094 {
1095 return new BSActorMoveToTarget(PhysScene, this, MoveToTargetActorName);
1096 });
1097 }
1098 }
1099  
1100 public override OMV.Vector3 PIDTarget
1101 {
1102 set
1103 {
1104 base.PIDTarget = value;
1105 BSActor actor;
1106 if (PhysicalActors.TryGetActor(MoveToTargetActorName, out actor))
1107 {
1108 // if the actor exists, tell it to refresh its values.
1109 actor.Refresh();
1110 }
1111  
1112 }
1113 }
1114 // Used for llSetHoverHeight and maybe vehicle height
1115 // Hover Height will override MoveTo target's Z
1116 public override bool PIDHoverActive {
1117 set {
1118 base.HoverActive = value;
1119 EnableActor(HoverActive, HoverActorName, delegate()
1120 {
1121 return new BSActorHover(PhysScene, this, HoverActorName);
1122 });
1123 }
1124 }
1125  
1126 public override void AddForce(OMV.Vector3 force, bool pushforce) {
1127 // Per documentation, max force is limited.
1128 OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
1129  
1130 // Since this force is being applied in only one step, make this a force per second.
1131 addForce /= PhysScene.LastTimeStep;
1132 AddForce(addForce, pushforce, false /* inTaintTime */);
1133 }
1134  
1135 // Applying a force just adds this to the total force on the object.
1136 // This added force will only last the next simulation tick.
1137 public override void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1138 // for an object, doesn't matter if force is a pushforce or not
1139 if (IsPhysicallyActive)
1140 {
1141 if (force.IsFinite())
1142 {
1143 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1144  
1145 OMV.Vector3 addForce = force;
1146 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddForce", delegate()
1147 {
1148 // Bullet adds this central force to the total force for this tick.
1149 // Deep down in Bullet:
1150 // linearVelocity += totalForce / mass * timeStep;
1151 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1152 if (PhysBody.HasPhysicalBody)
1153 {
1154 PhysScene.PE.ApplyCentralForce(PhysBody, addForce);
1155 ActivateIfPhysical(false);
1156 }
1157 });
1158 }
1159 else
1160 {
1161 m_log.WarnFormat("{0}: AddForce: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1162 return;
1163 }
1164 }
1165 }
1166  
1167 public void AddForceImpulse(OMV.Vector3 impulse, bool pushforce, bool inTaintTime) {
1168 // for an object, doesn't matter if force is a pushforce or not
1169 if (!IsPhysicallyActive)
1170 {
1171 if (impulse.IsFinite())
1172 {
1173 OMV.Vector3 addImpulse = Util.ClampV(impulse, BSParam.MaxAddForceMagnitude);
1174 // DetailLog("{0},BSPrim.addForceImpulse,call,impulse={1}", LocalID, impulse);
1175  
1176 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddImpulse", delegate()
1177 {
1178 // Bullet adds this impulse immediately to the velocity
1179 DetailLog("{0},BSPrim.addForceImpulse,taint,impulseforce={1}", LocalID, addImpulse);
1180 if (PhysBody.HasPhysicalBody)
1181 {
1182 PhysScene.PE.ApplyCentralImpulse(PhysBody, addImpulse);
1183 ActivateIfPhysical(false);
1184 }
1185 });
1186 }
1187 else
1188 {
1189 m_log.WarnFormat("{0}: AddForceImpulse: Got a NaN impulse applied to a prim. LocalID={1}", LogHeader, LocalID);
1190 return;
1191 }
1192 }
1193 }
1194  
1195 // BSPhysObject.AddAngularForce()
1196 public override void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1197 {
1198 if (force.IsFinite())
1199 {
1200 OMV.Vector3 angForce = force;
1201 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.AddAngularForce", delegate()
1202 {
1203 if (PhysBody.HasPhysicalBody)
1204 {
1205 DetailLog("{0},BSPrim.AddAngularForce,taint,angForce={1}", LocalID, angForce);
1206 PhysScene.PE.ApplyTorque(PhysBody, angForce);
1207 ActivateIfPhysical(false);
1208 }
1209 });
1210 }
1211 else
1212 {
1213 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1214 return;
1215 }
1216 }
1217  
1218 // A torque impulse.
1219 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1220 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1221 // Computed as: angularVelocity += impulse * inertia;
1222 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1223 {
1224 OMV.Vector3 applyImpulse = impulse;
1225 PhysScene.TaintedObject(inTaintTime, LocalID, "BSPrim.ApplyTorqueImpulse", delegate()
1226 {
1227 if (PhysBody.HasPhysicalBody)
1228 {
1229 PhysScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1230 ActivateIfPhysical(false);
1231 }
1232 });
1233 }
1234  
1235 public override void SetMomentum(OMV.Vector3 momentum) {
1236 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1237 }
1238 #region Mass Calculation
1239  
1240 private float CalculateMass()
1241 {
1242 float volume = _size.X * _size.Y * _size.Z; // default
1243 float tmp;
1244  
1245 float returnMass = 0;
1246 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1247 float hollowVolume = hollowAmount * hollowAmount;
1248  
1249 switch (BaseShape.ProfileShape)
1250 {
1251 case ProfileShape.Square:
1252 // default box
1253  
1254 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1255 {
1256 if (hollowAmount > 0.0)
1257 {
1258 switch (BaseShape.HollowShape)
1259 {
1260 case HollowShape.Square:
1261 case HollowShape.Same:
1262 break;
1263  
1264 case HollowShape.Circle:
1265  
1266 hollowVolume *= 0.78539816339f;
1267 break;
1268  
1269 case HollowShape.Triangle:
1270  
1271 hollowVolume *= (0.5f * .5f);
1272 break;
1273  
1274 default:
1275 hollowVolume = 0;
1276 break;
1277 }
1278 volume *= (1.0f - hollowVolume);
1279 }
1280 }
1281  
1282 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1283 {
1284 //a tube
1285  
1286 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1287 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1288 volume -= volume*tmp*tmp;
1289  
1290 if (hollowAmount > 0.0)
1291 {
1292 hollowVolume *= hollowAmount;
1293  
1294 switch (BaseShape.HollowShape)
1295 {
1296 case HollowShape.Square:
1297 case HollowShape.Same:
1298 break;
1299  
1300 case HollowShape.Circle:
1301 hollowVolume *= 0.78539816339f;;
1302 break;
1303  
1304 case HollowShape.Triangle:
1305 hollowVolume *= 0.5f * 0.5f;
1306 break;
1307 default:
1308 hollowVolume = 0;
1309 break;
1310 }
1311 volume *= (1.0f - hollowVolume);
1312 }
1313 }
1314  
1315 break;
1316  
1317 case ProfileShape.Circle:
1318  
1319 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1320 {
1321 volume *= 0.78539816339f; // elipse base
1322  
1323 if (hollowAmount > 0.0)
1324 {
1325 switch (BaseShape.HollowShape)
1326 {
1327 case HollowShape.Same:
1328 case HollowShape.Circle:
1329 break;
1330  
1331 case HollowShape.Square:
1332 hollowVolume *= 0.5f * 2.5984480504799f;
1333 break;
1334  
1335 case HollowShape.Triangle:
1336 hollowVolume *= .5f * 1.27323954473516f;
1337 break;
1338  
1339 default:
1340 hollowVolume = 0;
1341 break;
1342 }
1343 volume *= (1.0f - hollowVolume);
1344 }
1345 }
1346  
1347 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1348 {
1349 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1350 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1351 volume *= (1.0f - tmp * tmp);
1352  
1353 if (hollowAmount > 0.0)
1354 {
1355  
1356 // calculate the hollow volume by it's shape compared to the prim shape
1357 hollowVolume *= hollowAmount;
1358  
1359 switch (BaseShape.HollowShape)
1360 {
1361 case HollowShape.Same:
1362 case HollowShape.Circle:
1363 break;
1364  
1365 case HollowShape.Square:
1366 hollowVolume *= 0.5f * 2.5984480504799f;
1367 break;
1368  
1369 case HollowShape.Triangle:
1370 hollowVolume *= .5f * 1.27323954473516f;
1371 break;
1372  
1373 default:
1374 hollowVolume = 0;
1375 break;
1376 }
1377 volume *= (1.0f - hollowVolume);
1378 }
1379 }
1380 break;
1381  
1382 case ProfileShape.HalfCircle:
1383 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1384 {
1385 volume *= 0.52359877559829887307710723054658f;
1386 }
1387 break;
1388  
1389 case ProfileShape.EquilateralTriangle:
1390  
1391 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1392 {
1393 volume *= 0.32475953f;
1394  
1395 if (hollowAmount > 0.0)
1396 {
1397  
1398 // calculate the hollow volume by it's shape compared to the prim shape
1399 switch (BaseShape.HollowShape)
1400 {
1401 case HollowShape.Same:
1402 case HollowShape.Triangle:
1403 hollowVolume *= .25f;
1404 break;
1405  
1406 case HollowShape.Square:
1407 hollowVolume *= 0.499849f * 3.07920140172638f;
1408 break;
1409  
1410 case HollowShape.Circle:
1411 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1412 // Cyllinder hollow volume calculation
1413  
1414 hollowVolume *= 0.1963495f * 3.07920140172638f;
1415 break;
1416  
1417 default:
1418 hollowVolume = 0;
1419 break;
1420 }
1421 volume *= (1.0f - hollowVolume);
1422 }
1423 }
1424 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1425 {
1426 volume *= 0.32475953f;
1427 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1428 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1429 volume *= (1.0f - tmp * tmp);
1430  
1431 if (hollowAmount > 0.0)
1432 {
1433  
1434 hollowVolume *= hollowAmount;
1435  
1436 switch (BaseShape.HollowShape)
1437 {
1438 case HollowShape.Same:
1439 case HollowShape.Triangle:
1440 hollowVolume *= .25f;
1441 break;
1442  
1443 case HollowShape.Square:
1444 hollowVolume *= 0.499849f * 3.07920140172638f;
1445 break;
1446  
1447 case HollowShape.Circle:
1448  
1449 hollowVolume *= 0.1963495f * 3.07920140172638f;
1450 break;
1451  
1452 default:
1453 hollowVolume = 0;
1454 break;
1455 }
1456 volume *= (1.0f - hollowVolume);
1457 }
1458 }
1459 break;
1460  
1461 default:
1462 break;
1463 }
1464  
1465  
1466  
1467 float taperX1;
1468 float taperY1;
1469 float taperX;
1470 float taperY;
1471 float pathBegin;
1472 float pathEnd;
1473 float profileBegin;
1474 float profileEnd;
1475  
1476 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1477 {
1478 taperX1 = BaseShape.PathScaleX * 0.01f;
1479 if (taperX1 > 1.0f)
1480 taperX1 = 2.0f - taperX1;
1481 taperX = 1.0f - taperX1;
1482  
1483 taperY1 = BaseShape.PathScaleY * 0.01f;
1484 if (taperY1 > 1.0f)
1485 taperY1 = 2.0f - taperY1;
1486 taperY = 1.0f - taperY1;
1487 }
1488 else
1489 {
1490 taperX = BaseShape.PathTaperX * 0.01f;
1491 if (taperX < 0.0f)
1492 taperX = -taperX;
1493 taperX1 = 1.0f - taperX;
1494  
1495 taperY = BaseShape.PathTaperY * 0.01f;
1496 if (taperY < 0.0f)
1497 taperY = -taperY;
1498 taperY1 = 1.0f - taperY;
1499  
1500 }
1501  
1502  
1503 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1504  
1505 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1506 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1507 volume *= (pathEnd - pathBegin);
1508  
1509 // this is crude aproximation
1510 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1511 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1512 volume *= (profileEnd - profileBegin);
1513  
1514 returnMass = Density * BSParam.DensityScaleFactor * volume;
1515  
1516 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1517 // DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3}", LocalID, Density, volume, returnMass);
1518 DetailLog("{0},BSPrim.CalculateMass,den={1},vol={2},mass={3},pathB={4},pathE={5},profB={6},profE={7},siz={8}",
1519 LocalID, Density, volume, returnMass, pathBegin, pathEnd, profileBegin, profileEnd, _size);
1520  
1521 return returnMass;
1522 }// end CalculateMass
1523 #endregion Mass Calculation
1524  
1525 // Rebuild the geometry and object.
1526 // This is called when the shape changes so we need to recreate the mesh/hull.
1527 // Called at taint-time!!!
1528 public void CreateGeomAndObject(bool forceRebuild)
1529 {
1530 // Create the correct physical representation for this type of object.
1531 // Updates base.PhysBody and base.PhysShape with the new information.
1532 // Ignore 'forceRebuild'. 'GetBodyAndShape' makes the right choices and changes of necessary.
1533 PhysScene.Shapes.GetBodyAndShape(false /*forceRebuild */, PhysScene.World, this, delegate(BulletBody pBody, BulletShape pShape)
1534 {
1535 // Called if the current prim body is about to be destroyed.
1536 // Remove all the physical dependencies on the old body.
1537 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1538 // Note: this virtual function is overloaded by BSPrimLinkable to remove linkset constraints.
1539 RemoveDependencies();
1540 });
1541  
1542 // Make sure the properties are set on the new object
1543 UpdatePhysicalParameters();
1544 return;
1545 }
1546  
1547 // Called at taint-time
1548 protected virtual void RemoveDependencies()
1549 {
1550 PhysicalActors.RemoveDependencies();
1551 }
1552  
1553 #region Extension
1554 public override object Extension(string pFunct, params object[] pParams)
1555 {
1556 DetailLog("{0} BSPrim.Extension,op={1}", LocalID, pFunct);
1557 object ret = null;
1558 switch (pFunct)
1559 {
1560 default:
1561 ret = base.Extension(pFunct, pParams);
1562 break;
1563 }
1564 return ret;
1565 }
1566 #endregion // Extension
1567  
1568 // The physics engine says that properties have updated. Update same and inform
1569 // the world that things have changed.
1570 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimLinkable which modifies updates from root and children prims.
1571 // NOTE: BSPrim.UpdateProperties is overloaded by BSPrimDisplaced which handles mapping physical position to simulator position.
1572 public override void UpdateProperties(EntityProperties entprop)
1573 {
1574 // Let anyone (like the actors) modify the updated properties before they are pushed into the object and the simulator.
1575 TriggerPreUpdatePropertyAction(ref entprop);
1576  
1577 // DetailLog("{0},BSPrim.UpdateProperties,entry,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1578  
1579 // Assign directly to the local variables so the normal set actions do not happen
1580 RawPosition = entprop.Position;
1581 RawOrientation = entprop.Rotation;
1582 // DEBUG DEBUG DEBUG -- smooth velocity changes a bit. The simulator seems to be
1583 // very sensitive to velocity changes.
1584 if (entprop.Velocity == OMV.Vector3.Zero || !entprop.Velocity.ApproxEquals(RawVelocity, BSParam.UpdateVelocityChangeThreshold))
1585 RawVelocity = entprop.Velocity;
1586 _acceleration = entprop.Acceleration;
1587 _rotationalVelocity = entprop.RotationalVelocity;
1588  
1589 // DetailLog("{0},BSPrim.UpdateProperties,afterAssign,entprop={1}", LocalID, entprop); // DEBUG DEBUG
1590  
1591 // The sanity check can change the velocity and/or position.
1592 if (PositionSanityCheck(true /* inTaintTime */ ))
1593 {
1594 entprop.Position = RawPosition;
1595 entprop.Velocity = RawVelocity;
1596 entprop.RotationalVelocity = _rotationalVelocity;
1597 entprop.Acceleration = _acceleration;
1598 }
1599  
1600 OMV.Vector3 direction = OMV.Vector3.UnitX * RawOrientation; // DEBUG DEBUG DEBUG
1601 DetailLog("{0},BSPrim.UpdateProperties,call,entProp={1},dir={2}", LocalID, entprop, direction);
1602  
1603 // remember the current and last set values
1604 LastEntityProperties = CurrentEntityProperties;
1605 CurrentEntityProperties = entprop;
1606  
1607 PhysScene.PostUpdate(this);
1608 }
1609 }
1610 }