aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs1467
1 files changed, 1467 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
new file mode 100644
index 0000000..a889c24
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSNPlugin/BSPrim.cs
@@ -0,0 +1,1467 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Collections.Generic;
31using System.Xml;
32using log4net;
33using OMV = OpenMetaverse;
34using OpenSim.Framework;
35using OpenSim.Region.Physics.Manager;
36using OpenSim.Region.Physics.ConvexDecompositionDotNet;
37
38namespace OpenSim.Region.Physics.BulletSNPlugin
39{
40
41 [Serializable]
42public sealed class BSPrim : BSPhysObject
43{
44 private 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 private OMV.Vector3 _position;
54 private float _mass; // the mass of this object
55 private float _density;
56 private OMV.Vector3 _force;
57 private OMV.Vector3 _velocity;
58 private OMV.Vector3 _torque;
59 private float _collisionScore;
60 private OMV.Vector3 _acceleration;
61 private OMV.Quaternion _orientation;
62 private int _physicsActorType;
63 private bool _isPhysical;
64 private bool _flying;
65 private float _friction;
66 private float _restitution;
67 private bool _setAlwaysRun;
68 private bool _throttleUpdates;
69 private bool _isColliding;
70 private bool _collidingGround;
71 private bool _collidingObj;
72 private bool _floatOnWater;
73 private OMV.Vector3 _rotationalVelocity;
74 private bool _kinematic;
75 private float _buoyancy;
76
77 private BSDynamics _vehicle;
78
79 private OMV.Vector3 _PIDTarget;
80 private bool _usePID;
81 private float _PIDTau;
82 private bool _useHoverPID;
83 private float _PIDHoverHeight;
84 private PIDHoverType _PIDHoverType;
85 private float _PIDHoverTao;
86
87 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
88 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
89 : base(parent_scene, localID, primName, "BSPrim")
90 {
91 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
92 _physicsActorType = (int)ActorTypes.Prim;
93 _position = pos;
94 _size = size;
95 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
96 _orientation = rotation;
97 _buoyancy = 1f;
98 _velocity = OMV.Vector3.Zero;
99 _rotationalVelocity = OMV.Vector3.Zero;
100 BaseShape = pbs;
101 _isPhysical = pisPhysical;
102 _isVolumeDetect = false;
103
104 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
105 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
106 _density = PhysicsScene.Params.defaultDensity;
107 _friction = PhysicsScene.Params.defaultFriction;
108 _restitution = PhysicsScene.Params.defaultRestitution;
109
110 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
111
112 _mass = CalculateMass();
113
114 // No body or shape yet
115 PhysBody = new BulletBody(LocalID);
116 PhysShape = new BulletShape();
117
118 DetailLog("{0},BSPrim.constructor,call", LocalID);
119 // do the actual object creation at taint time
120 PhysicsScene.TaintedObject("BSPrim.create", delegate()
121 {
122 CreateGeomAndObject(true);
123
124 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr);
125 });
126 }
127
128 // called when this prim is being destroyed and we should free all the resources
129 public override void Destroy()
130 {
131 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
132 base.Destroy();
133
134 // Undo any links between me and any other object
135 BSPhysObject parentBefore = Linkset.LinksetRoot;
136 int childrenBefore = Linkset.NumberOfChildren;
137
138 Linkset = Linkset.RemoveMeFromLinkset(this);
139
140 DetailLog("{0},BSPrim.Destroy,call,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}",
141 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
142
143 // Undo any vehicle properties
144 this.VehicleType = (int)Vehicle.TYPE_NONE;
145
146 PhysicsScene.TaintedObject("BSPrim.destroy", delegate()
147 {
148 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
149 // If there are physical body and shape, release my use of same.
150 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
151 PhysBody.Clear();
152 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
153 PhysShape.Clear();
154 });
155 }
156
157 // No one uses this property.
158 public override bool Stopped {
159 get { return false; }
160 }
161 public override OMV.Vector3 Size {
162 get { return _size; }
163 set {
164 // We presume the scale and size are the same. If scale must be changed for
165 // the physical shape, that is done when the geometry is built.
166 _size = value;
167 Scale = _size;
168 ForceBodyShapeRebuild(false);
169 }
170 }
171
172 public override PrimitiveBaseShape Shape {
173 set {
174 BaseShape = value;
175 ForceBodyShapeRebuild(false);
176 }
177 }
178 // Whatever the linkset wants is what I want.
179 public override BSPhysicsShapeType PreferredPhysicalShape
180 { get { return Linkset.PreferredPhysicalShape(this); } }
181
182 public override bool ForceBodyShapeRebuild(bool inTaintTime)
183 {
184 LastAssetBuildFailed = false;
185 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ForceBodyShapeRebuild", delegate()
186 {
187 _mass = CalculateMass(); // changing the shape changes the mass
188 CreateGeomAndObject(true);
189 });
190 return true;
191 }
192 public override bool Grabbed {
193 set { _grabbed = value;
194 }
195 }
196 public override bool Selected {
197 set
198 {
199 if (value != _isSelected)
200 {
201 _isSelected = value;
202 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
203 {
204 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
205 SetObjectDynamic(false);
206 });
207 }
208 }
209 }
210 public override void CrossingFailure() { return; }
211
212 // link me to the specified parent
213 public override void link(PhysicsActor obj) {
214 BSPrim parent = obj as BSPrim;
215 if (parent != null)
216 {
217 BSPhysObject parentBefore = Linkset.LinksetRoot;
218 int childrenBefore = Linkset.NumberOfChildren;
219
220 Linkset = parent.Linkset.AddMeToLinkset(this);
221
222 DetailLog("{0},BSPrim.link,call,parentBefore={1}, childrenBefore=={2}, parentAfter={3}, childrenAfter={4}",
223 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
224 }
225 return;
226 }
227
228 // delink me from my linkset
229 public override void delink() {
230 // TODO: decide if this parent checking needs to happen at taint time
231 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
232
233 BSPhysObject parentBefore = Linkset.LinksetRoot;
234 int childrenBefore = Linkset.NumberOfChildren;
235
236 Linkset = Linkset.RemoveMeFromLinkset(this);
237
238 DetailLog("{0},BSPrim.delink,parentBefore={1},childrenBefore={2},parentAfter={3},childrenAfter={4}, ",
239 LocalID, parentBefore.LocalID, childrenBefore, Linkset.LinksetRoot.LocalID, Linkset.NumberOfChildren);
240 return;
241 }
242
243 // Set motion values to zero.
244 // Do it to the properties so the values get set in the physics engine.
245 // Push the setting of the values to the viewer.
246 // Called at taint time!
247 public override void ZeroMotion(bool inTaintTime)
248 {
249 _velocity = OMV.Vector3.Zero;
250 _acceleration = OMV.Vector3.Zero;
251 _rotationalVelocity = OMV.Vector3.Zero;
252
253 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 {
256 if (PhysBody.HasPhysicalBody)
257 BulletSimAPI.ClearAllForces2(PhysBody.ptr);
258 });
259 }
260 public override void ZeroAngularMotion(bool inTaintTime)
261 {
262 _rotationalVelocity = OMV.Vector3.Zero;
263 // Zero some other properties in the physics engine
264 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
265 {
266 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
267 if (PhysBody.HasPhysicalBody)
268 {
269 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
270 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
271 }
272 });
273 }
274
275 public override void LockAngularMotion(OMV.Vector3 axis)
276 {
277 DetailLog("{0},BSPrim.LockAngularMotion,call,axis={1}", LocalID, axis);
278 return;
279 }
280
281 public override OMV.Vector3 RawPosition
282 {
283 get { return _position; }
284 set { _position = value; }
285 }
286 public override OMV.Vector3 Position {
287 get {
288 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
289 * and does not fetch this position info for children. Thus this is commented out.
290 // child prims move around based on their parent. Need to get the latest location
291 if (!Linkset.IsRoot(this))
292 _position = Linkset.PositionGet(this);
293 */
294
295 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
296 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
297 return _position;
298 }
299 set {
300 // If the position must be forced into the physics engine, use ForcePosition.
301 // All positions are given in world positions.
302 if (_position == value)
303 {
304 DetailLog("{0},BSPrim.setPosition,taint,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
305 return;
306 }
307 _position = value;
308 PositionSanityCheck(false);
309
310 // A linkset might need to know if a component information changed.
311 Linkset.UpdateProperties(this, false);
312
313 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
314 {
315 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
316 ForcePosition = _position;
317 });
318 }
319 }
320 public override OMV.Vector3 ForcePosition {
321 get {
322 _position = BulletSimAPI.GetPosition2(PhysBody.ptr);
323 return _position;
324 }
325 set {
326 _position = value;
327 if (PhysBody.HasPhysicalBody)
328 {
329 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
330 ActivateIfPhysical(false);
331 }
332 }
333 }
334
335 // Check that the current position is sane and, if not, modify the position to make it so.
336 // Check for being below terrain and being out of bounds.
337 // Returns 'true' of the position was made sane by some action.
338 private bool PositionSanityCheck(bool inTaintTime)
339 {
340 bool ret = false;
341
342 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
343 {
344 // The physical object is out of the known/simulated area.
345 // Upper levels of code will handle the transition to other areas so, for
346 // the time, we just ignore the position.
347 return ret;
348 }
349
350 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
351 OMV.Vector3 upForce = OMV.Vector3.Zero;
352 if (RawPosition.Z < terrainHeight)
353 {
354 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
355 float targetHeight = terrainHeight + (Size.Z / 2f);
356 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
357 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
358 ret = true;
359 }
360
361 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
362 {
363 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
364 // TODO: a floating motor so object will bob in the water
365 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
366 {
367 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
368 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
369 ret = true;
370 }
371 }
372
373 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
374 // TODO: This should be intergrated with a geneal physics action mechanism.
375 // TODO: This should be moderated with PID'ness.
376 if (ret)
377 {
378 // Apply upforce and overcome gravity.
379 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
380 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
381 AddForce(correctionForce, false, inTaintTime);
382 }
383 return ret;
384 }
385
386 // Return the effective mass of the object.
387 // If there are multiple items in the linkset, add them together for the root
388 public override float Mass
389 {
390 get
391 {
392 return Linkset.LinksetMass;
393 // return _mass;
394 }
395 }
396
397 // used when we only want this prim's mass and not the linkset thing
398 public override float RawMass {
399 get { return _mass; }
400 }
401 // Set the physical mass to the passed mass.
402 // Note that this does not change _mass!
403 public override void UpdatePhysicalMassProperties(float physMass)
404 {
405 if (IsStatic)
406 {
407 Inertia = OMV.Vector3.Zero;
408 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
409 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
410 }
411 else
412 {
413 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass);
414 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia);
415 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
416 // center of mass is at the zero of the object
417 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation);
418 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia);
419 }
420 }
421
422 // Is this used?
423 public override OMV.Vector3 CenterOfMass
424 {
425 get { return Linkset.CenterOfMass; }
426 }
427
428 // Is this used?
429 public override OMV.Vector3 GeometricCenter
430 {
431 get { return Linkset.GeometricCenter; }
432 }
433
434 public override OMV.Vector3 Force {
435 get { return _force; }
436 set {
437 _force = value;
438 if (_force != OMV.Vector3.Zero)
439 {
440 // If the force is non-zero, it must be reapplied each tick because
441 // Bullet clears the forces applied last frame.
442 RegisterPreStepAction("BSPrim.setForce", LocalID,
443 delegate(float timeStep)
444 {
445 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
446 if (PhysBody.HasPhysicalBody)
447 {
448 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, _force);
449 ActivateIfPhysical(false);
450 }
451 }
452 );
453 }
454 else
455 {
456 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
457 }
458 }
459 }
460
461 public override int VehicleType {
462 get {
463 return (int)_vehicle.Type; // if we are a vehicle, return that type
464 }
465 set {
466 Vehicle type = (Vehicle)value;
467
468 PhysicsScene.TaintedObject("setVehicleType", delegate()
469 {
470 // Done at taint time so we're sure the physics engine is not using the variables
471 // Vehicle code changes the parameters for this vehicle type.
472 _vehicle.ProcessTypeChange(type);
473 ActivateIfPhysical(false);
474
475 // If an active vehicle, register the vehicle code to be called before each step
476 if (_vehicle.Type == Vehicle.TYPE_NONE)
477 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
478 else
479 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
480 });
481 }
482 }
483 public override void VehicleFloatParam(int param, float value)
484 {
485 PhysicsScene.TaintedObject("BSPrim.VehicleFloatParam", delegate()
486 {
487 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
488 ActivateIfPhysical(false);
489 });
490 }
491 public override void VehicleVectorParam(int param, OMV.Vector3 value)
492 {
493 PhysicsScene.TaintedObject("BSPrim.VehicleVectorParam", delegate()
494 {
495 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
496 ActivateIfPhysical(false);
497 });
498 }
499 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
500 {
501 PhysicsScene.TaintedObject("BSPrim.VehicleRotationParam", delegate()
502 {
503 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
504 ActivateIfPhysical(false);
505 });
506 }
507 public override void VehicleFlags(int param, bool remove)
508 {
509 PhysicsScene.TaintedObject("BSPrim.VehicleFlags", delegate()
510 {
511 _vehicle.ProcessVehicleFlags(param, remove);
512 });
513 }
514
515 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
516 public override void SetVolumeDetect(int param) {
517 bool newValue = (param != 0);
518 if (_isVolumeDetect != newValue)
519 {
520 _isVolumeDetect = newValue;
521 PhysicsScene.TaintedObject("BSPrim.SetVolumeDetect", delegate()
522 {
523 // DetailLog("{0},setVolumeDetect,taint,volDetect={1}", LocalID, _isVolumeDetect);
524 SetObjectDynamic(true);
525 });
526 }
527 return;
528 }
529 public override OMV.Vector3 Velocity {
530 get { return _velocity; }
531 set {
532 _velocity = value;
533 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
534 {
535 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
536 ForceVelocity = _velocity;
537 });
538 }
539 }
540 public override OMV.Vector3 ForceVelocity {
541 get { return _velocity; }
542 set {
543 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
544
545 _velocity = value;
546 if (PhysBody.HasPhysicalBody)
547 {
548 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity);
549 ActivateIfPhysical(false);
550 }
551 }
552 }
553 public override OMV.Vector3 Torque {
554 get { return _torque; }
555 set {
556 _torque = value;
557 if (_torque != OMV.Vector3.Zero)
558 {
559 // If the torque is non-zero, it must be reapplied each tick because
560 // Bullet clears the forces applied last frame.
561 RegisterPreStepAction("BSPrim.setTorque", LocalID,
562 delegate(float timeStep)
563 {
564 if (PhysBody.HasPhysicalBody)
565 AddAngularForce(_torque, false, true);
566 }
567 );
568 }
569 else
570 {
571 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
572 }
573 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
574 }
575 }
576 public override float CollisionScore {
577 get { return _collisionScore; }
578 set { _collisionScore = value;
579 }
580 }
581 public override OMV.Vector3 Acceleration {
582 get { return _acceleration; }
583 set { _acceleration = value; }
584 }
585 public override OMV.Quaternion RawOrientation
586 {
587 get { return _orientation; }
588 set { _orientation = value; }
589 }
590 public override OMV.Quaternion Orientation {
591 get {
592 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
593 * and does not fetch this position info for children. Thus this is commented out.
594 // Children move around because tied to parent. Get a fresh value.
595 if (!Linkset.IsRoot(this))
596 {
597 _orientation = Linkset.OrientationGet(this);
598 }
599 */
600 return _orientation;
601 }
602 set {
603 if (_orientation == value)
604 return;
605 _orientation = value;
606
607 // A linkset might need to know if a component information changed.
608 Linkset.UpdateProperties(this, false);
609
610 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
611 {
612 if (PhysBody.HasPhysicalBody)
613 {
614 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr);
615 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
616 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
617 }
618 });
619 }
620 }
621 // Go directly to Bullet to get/set the value.
622 public override OMV.Quaternion ForceOrientation
623 {
624 get
625 {
626 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr);
627 return _orientation;
628 }
629 set
630 {
631 _orientation = value;
632 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
633 }
634 }
635 public override int PhysicsActorType {
636 get { return _physicsActorType; }
637 set { _physicsActorType = value; }
638 }
639 public override bool IsPhysical {
640 get { return _isPhysical; }
641 set {
642 if (_isPhysical != value)
643 {
644 _isPhysical = value;
645 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
646 {
647 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
648 SetObjectDynamic(true);
649 // whether phys-to-static or static-to-phys, the object is not moving.
650 ZeroMotion(true);
651 });
652 }
653 }
654 }
655
656 // An object is static (does not move) if selected or not physical
657 public override bool IsStatic
658 {
659 get { return _isSelected || !IsPhysical; }
660 }
661
662 // An object is solid if it's not phantom and if it's not doing VolumeDetect
663 public override bool IsSolid
664 {
665 get { return !IsPhantom && !_isVolumeDetect; }
666 }
667
668 // Make gravity work if the object is physical and not selected
669 // Called at taint-time!!
670 private void SetObjectDynamic(bool forceRebuild)
671 {
672 // Recreate the physical object if necessary
673 CreateGeomAndObject(forceRebuild);
674 }
675
676 // Convert the simulator's physical properties into settings on BulletSim objects.
677 // There are four flags we're interested in:
678 // IsStatic: Object does not move, otherwise the object has mass and moves
679 // isSolid: other objects bounce off of this object
680 // isVolumeDetect: other objects pass through but can generate collisions
681 // collisionEvents: whether this object returns collision events
682 private void UpdatePhysicalParameters()
683 {
684 // DetailLog("{0},BSPrim.UpdatePhysicalParameters,entry,body={1},shape={2}", LocalID, BSBody, BSShape);
685
686 // Mangling all the physical properties requires the object not be in the physical world.
687 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
688 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr);
689
690 // Set up the object physicalness (does gravity and collisions move this object)
691 MakeDynamic(IsStatic);
692
693 // Update vehicle specific parameters (after MakeDynamic() so can change physical parameters)
694 _vehicle.Refresh();
695
696 // Arrange for collision events if the simulator wants them
697 EnableCollisions(SubscribedEvents());
698
699 // Make solid or not (do things bounce off or pass through this object).
700 MakeSolid(IsSolid);
701
702 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr, _position, _orientation);
703
704 // Rebuild its shape
705 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr);
706
707 // Collision filter can be set only when the object is in the world
708 PhysBody.ApplyCollisionMask();
709
710 // Recompute any linkset parameters.
711 // When going from non-physical to physical, this re-enables the constraints that
712 // had been automatically disabled when the mass was set to zero.
713 // For compound based linksets, this enables and disables interactions of the children.
714 Linkset.Refresh(this);
715
716 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}",
717 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape);
718 }
719
720 // "Making dynamic" means changing to and from static.
721 // When static, gravity does not effect the object and it is fixed in space.
722 // When dynamic, the object can fall and be pushed by others.
723 // This is independent of its 'solidness' which controls what passes through
724 // this object and what interacts with it.
725 private void MakeDynamic(bool makeStatic)
726 {
727 if (makeStatic)
728 {
729 // Become a Bullet 'static' object type
730 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
731 // Stop all movement
732 ZeroMotion(true);
733
734 // Set various physical properties so other object interact properly
735 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
736 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
737 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
738
739 // Mass is zero which disables a bunch of physics stuff in Bullet
740 UpdatePhysicalMassProperties(0f);
741 // Set collision detection parameters
742 if (BSParam.CcdMotionThreshold > 0f)
743 {
744 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
745 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
746 }
747
748 // The activation state is 'disabled' so Bullet will not try to act on it.
749 // BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION);
750 // Start it out sleeping and physical actions could wake it up.
751 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ISLAND_SLEEPING);
752
753 // This collides like a static object
754 PhysBody.collisionType = CollisionType.Static;
755
756 // There can be special things needed for implementing linksets
757 Linkset.MakeStatic(this);
758 }
759 else
760 {
761 // Not a Bullet static object
762 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
763
764 // Set various physical properties so other object interact properly
765 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
766 BulletSimAPI.SetFriction2(PhysBody.ptr, matAttrib.friction);
767 BulletSimAPI.SetRestitution2(PhysBody.ptr, matAttrib.restitution);
768
769 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
770 // Since this can be called multiple times, only zero forces when becoming physical
771 // BulletSimAPI.ClearAllForces2(BSBody.ptr);
772
773 // For good measure, make sure the transform is set through to the motion state
774 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation);
775
776 // Center of mass is at the center of the object
777 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation);
778
779 // A dynamic object has mass
780 UpdatePhysicalMassProperties(RawMass);
781
782 // Set collision detection parameters
783 if (BSParam.CcdMotionThreshold > 0f)
784 {
785 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, BSParam.CcdMotionThreshold);
786 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, BSParam.CcdSweptSphereRadius);
787 }
788
789 // Various values for simulation limits
790 BulletSimAPI.SetDamping2(PhysBody.ptr, BSParam.LinearDamping, BSParam.AngularDamping);
791 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, BSParam.DeactivationTime);
792 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
793 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, BSParam.ContactProcessingThreshold);
794
795 // This collides like an object.
796 PhysBody.collisionType = CollisionType.Dynamic;
797
798 // Force activation of the object so Bullet will act on it.
799 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
800 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG);
801
802 // There might be special things needed for implementing linksets.
803 Linkset.MakeDynamic(this);
804 }
805 }
806
807 // "Making solid" means that other object will not pass through this object.
808 // To make transparent, we create a Bullet ghost object.
809 // Note: This expects to be called from the UpdatePhysicalParameters() routine as
810 // the functions after this one set up the state of a possibly newly created collision body.
811 private void MakeSolid(bool makeSolid)
812 {
813 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr);
814 if (makeSolid)
815 {
816 // Verify the previous code created the correct shape for this type of thing.
817 if ((bodyType & CollisionObjectTypes.CO_RIGID_BODY) == 0)
818 {
819 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
820 }
821 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
822 }
823 else
824 {
825 if ((bodyType & CollisionObjectTypes.CO_GHOST_OBJECT) == 0)
826 {
827 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
828 }
829 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE);
830
831 // Change collision info from a static object to a ghosty collision object
832 PhysBody.collisionType = CollisionType.VolumeDetect;
833 }
834 }
835
836 // Enable physical actions. Bullet will keep sleeping non-moving physical objects so
837 // they need waking up when parameters are changed.
838 // Called in taint-time!!
839 private void ActivateIfPhysical(bool forceIt)
840 {
841 if (IsPhysical && PhysBody.HasPhysicalBody)
842 BulletSimAPI.Activate2(PhysBody.ptr, forceIt);
843 }
844
845 // Turn on or off the flag controlling whether collision events are returned to the simulator.
846 private void EnableCollisions(bool wantsCollisionEvents)
847 {
848 if (wantsCollisionEvents)
849 {
850 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
851 }
852 else
853 {
854 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
855 }
856 }
857
858 // prims don't fly
859 public override bool Flying {
860 get { return _flying; }
861 set {
862 _flying = value;
863 }
864 }
865 public override bool SetAlwaysRun {
866 get { return _setAlwaysRun; }
867 set { _setAlwaysRun = value; }
868 }
869 public override bool ThrottleUpdates {
870 get { return _throttleUpdates; }
871 set { _throttleUpdates = value; }
872 }
873 public override bool IsColliding {
874 get { return (CollidingStep == PhysicsScene.SimulationStep); }
875 set { _isColliding = value; }
876 }
877 public override bool CollidingGround {
878 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
879 set { _collidingGround = value; }
880 }
881 public override bool CollidingObj {
882 get { return _collidingObj; }
883 set { _collidingObj = value; }
884 }
885 public bool IsPhantom {
886 get {
887 // SceneObjectPart removes phantom objects from the physics scene
888 // so, although we could implement touching and such, we never
889 // are invoked as a phantom object
890 return false;
891 }
892 }
893 public override bool FloatOnWater {
894 set {
895 _floatOnWater = value;
896 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
897 {
898 if (_floatOnWater)
899 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
900 else
901 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER);
902 });
903 }
904 }
905 public override OMV.Vector3 RotationalVelocity {
906 get {
907 return _rotationalVelocity;
908 }
909 set {
910 _rotationalVelocity = value;
911 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
912 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
913 {
914 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
915 ForceRotationalVelocity = _rotationalVelocity;
916 });
917 }
918 }
919 public override OMV.Vector3 ForceRotationalVelocity {
920 get {
921 return _rotationalVelocity;
922 }
923 set {
924 _rotationalVelocity = value;
925 if (PhysBody.HasPhysicalBody)
926 {
927 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity);
928 ActivateIfPhysical(false);
929 }
930 }
931 }
932 public override bool Kinematic {
933 get { return _kinematic; }
934 set { _kinematic = value;
935 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
936 }
937 }
938 public override float Buoyancy {
939 get { return _buoyancy; }
940 set {
941 _buoyancy = value;
942 PhysicsScene.TaintedObject("BSPrim.setBuoyancy", delegate()
943 {
944 ForceBuoyancy = _buoyancy;
945 });
946 }
947 }
948 public override float ForceBuoyancy {
949 get { return _buoyancy; }
950 set {
951 _buoyancy = value;
952 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
953 // Buoyancy is faked by changing the gravity applied to the object
954 if (PhysBody.HasPhysicalBody)
955 {
956 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
957 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav));
958 ActivateIfPhysical(false);
959 }
960 }
961 }
962
963 // Used for MoveTo
964 public override OMV.Vector3 PIDTarget {
965 set { _PIDTarget = value; }
966 }
967 public override bool PIDActive {
968 set { _usePID = value; }
969 }
970 public override float PIDTau {
971 set { _PIDTau = value; }
972 }
973
974 // Used for llSetHoverHeight and maybe vehicle height
975 // Hover Height will override MoveTo target's Z
976 public override bool PIDHoverActive {
977 set { _useHoverPID = value; }
978 }
979 public override float PIDHoverHeight {
980 set { _PIDHoverHeight = value; }
981 }
982 public override PIDHoverType PIDHoverType {
983 set { _PIDHoverType = value; }
984 }
985 public override float PIDHoverTau {
986 set { _PIDHoverTao = value; }
987 }
988
989 // For RotLookAt
990 public override OMV.Quaternion APIDTarget { set { return; } }
991 public override bool APIDActive { set { return; } }
992 public override float APIDStrength { set { return; } }
993 public override float APIDDamping { set { return; } }
994
995 public override void AddForce(OMV.Vector3 force, bool pushforce) {
996 AddForce(force, pushforce, false);
997 }
998 // Applying a force just adds this to the total force on the object.
999 // This added force will only last the next simulation tick.
1000 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
1001 // for an object, doesn't matter if force is a pushforce or not
1002 if (force.IsFinite())
1003 {
1004 OMV.Vector3 addForce = force;
1005 DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1006 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1007 {
1008 // Bullet adds this central force to the total force for this tick
1009 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1010 if (PhysBody.HasPhysicalBody)
1011 {
1012 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, addForce);
1013 ActivateIfPhysical(false);
1014 }
1015 });
1016 }
1017 else
1018 {
1019 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1020 return;
1021 }
1022 }
1023
1024 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
1025 AddAngularForce(force, pushforce, false);
1026 }
1027 public void AddAngularForce(OMV.Vector3 force, bool pushforce, bool inTaintTime)
1028 {
1029 if (force.IsFinite())
1030 {
1031 OMV.Vector3 angForce = force;
1032 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
1033 {
1034 if (PhysBody.HasPhysicalBody)
1035 {
1036 BulletSimAPI.ApplyTorque2(PhysBody.ptr, angForce);
1037 ActivateIfPhysical(false);
1038 }
1039 });
1040 }
1041 else
1042 {
1043 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
1044 return;
1045 }
1046 }
1047
1048 // A torque impulse.
1049 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1050 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1051 // Computed as: angularVelocity += impulse * inertia;
1052 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1053 {
1054 OMV.Vector3 applyImpulse = impulse;
1055 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1056 {
1057 if (PhysBody.HasPhysicalBody)
1058 {
1059 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse);
1060 ActivateIfPhysical(false);
1061 }
1062 });
1063 }
1064
1065 public override void SetMomentum(OMV.Vector3 momentum) {
1066 // DetailLog("{0},BSPrim.SetMomentum,call,mom={1}", LocalID, momentum);
1067 }
1068 #region Mass Calculation
1069
1070 private float CalculateMass()
1071 {
1072 float volume = _size.X * _size.Y * _size.Z; // default
1073 float tmp;
1074
1075 float returnMass = 0;
1076 float hollowAmount = (float)BaseShape.ProfileHollow * 2.0e-5f;
1077 float hollowVolume = hollowAmount * hollowAmount;
1078
1079 switch (BaseShape.ProfileShape)
1080 {
1081 case ProfileShape.Square:
1082 // default box
1083
1084 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1085 {
1086 if (hollowAmount > 0.0)
1087 {
1088 switch (BaseShape.HollowShape)
1089 {
1090 case HollowShape.Square:
1091 case HollowShape.Same:
1092 break;
1093
1094 case HollowShape.Circle:
1095
1096 hollowVolume *= 0.78539816339f;
1097 break;
1098
1099 case HollowShape.Triangle:
1100
1101 hollowVolume *= (0.5f * .5f);
1102 break;
1103
1104 default:
1105 hollowVolume = 0;
1106 break;
1107 }
1108 volume *= (1.0f - hollowVolume);
1109 }
1110 }
1111
1112 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1113 {
1114 //a tube
1115
1116 volume *= 0.78539816339e-2f * (float)(200 - BaseShape.PathScaleX);
1117 tmp= 1.0f -2.0e-2f * (float)(200 - BaseShape.PathScaleY);
1118 volume -= volume*tmp*tmp;
1119
1120 if (hollowAmount > 0.0)
1121 {
1122 hollowVolume *= hollowAmount;
1123
1124 switch (BaseShape.HollowShape)
1125 {
1126 case HollowShape.Square:
1127 case HollowShape.Same:
1128 break;
1129
1130 case HollowShape.Circle:
1131 hollowVolume *= 0.78539816339f;;
1132 break;
1133
1134 case HollowShape.Triangle:
1135 hollowVolume *= 0.5f * 0.5f;
1136 break;
1137 default:
1138 hollowVolume = 0;
1139 break;
1140 }
1141 volume *= (1.0f - hollowVolume);
1142 }
1143 }
1144
1145 break;
1146
1147 case ProfileShape.Circle:
1148
1149 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1150 {
1151 volume *= 0.78539816339f; // elipse base
1152
1153 if (hollowAmount > 0.0)
1154 {
1155 switch (BaseShape.HollowShape)
1156 {
1157 case HollowShape.Same:
1158 case HollowShape.Circle:
1159 break;
1160
1161 case HollowShape.Square:
1162 hollowVolume *= 0.5f * 2.5984480504799f;
1163 break;
1164
1165 case HollowShape.Triangle:
1166 hollowVolume *= .5f * 1.27323954473516f;
1167 break;
1168
1169 default:
1170 hollowVolume = 0;
1171 break;
1172 }
1173 volume *= (1.0f - hollowVolume);
1174 }
1175 }
1176
1177 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1178 {
1179 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - BaseShape.PathScaleX);
1180 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1181 volume *= (1.0f - tmp * tmp);
1182
1183 if (hollowAmount > 0.0)
1184 {
1185
1186 // calculate the hollow volume by it's shape compared to the prim shape
1187 hollowVolume *= hollowAmount;
1188
1189 switch (BaseShape.HollowShape)
1190 {
1191 case HollowShape.Same:
1192 case HollowShape.Circle:
1193 break;
1194
1195 case HollowShape.Square:
1196 hollowVolume *= 0.5f * 2.5984480504799f;
1197 break;
1198
1199 case HollowShape.Triangle:
1200 hollowVolume *= .5f * 1.27323954473516f;
1201 break;
1202
1203 default:
1204 hollowVolume = 0;
1205 break;
1206 }
1207 volume *= (1.0f - hollowVolume);
1208 }
1209 }
1210 break;
1211
1212 case ProfileShape.HalfCircle:
1213 if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1214 {
1215 volume *= 0.52359877559829887307710723054658f;
1216 }
1217 break;
1218
1219 case ProfileShape.EquilateralTriangle:
1220
1221 if (BaseShape.PathCurve == (byte)Extrusion.Straight)
1222 {
1223 volume *= 0.32475953f;
1224
1225 if (hollowAmount > 0.0)
1226 {
1227
1228 // calculate the hollow volume by it's shape compared to the prim shape
1229 switch (BaseShape.HollowShape)
1230 {
1231 case HollowShape.Same:
1232 case HollowShape.Triangle:
1233 hollowVolume *= .25f;
1234 break;
1235
1236 case HollowShape.Square:
1237 hollowVolume *= 0.499849f * 3.07920140172638f;
1238 break;
1239
1240 case HollowShape.Circle:
1241 // Hollow shape is a perfect cyllinder in respect to the cube's scale
1242 // Cyllinder hollow volume calculation
1243
1244 hollowVolume *= 0.1963495f * 3.07920140172638f;
1245 break;
1246
1247 default:
1248 hollowVolume = 0;
1249 break;
1250 }
1251 volume *= (1.0f - hollowVolume);
1252 }
1253 }
1254 else if (BaseShape.PathCurve == (byte)Extrusion.Curve1)
1255 {
1256 volume *= 0.32475953f;
1257 volume *= 0.01f * (float)(200 - BaseShape.PathScaleX);
1258 tmp = 1.0f - .02f * (float)(200 - BaseShape.PathScaleY);
1259 volume *= (1.0f - tmp * tmp);
1260
1261 if (hollowAmount > 0.0)
1262 {
1263
1264 hollowVolume *= hollowAmount;
1265
1266 switch (BaseShape.HollowShape)
1267 {
1268 case HollowShape.Same:
1269 case HollowShape.Triangle:
1270 hollowVolume *= .25f;
1271 break;
1272
1273 case HollowShape.Square:
1274 hollowVolume *= 0.499849f * 3.07920140172638f;
1275 break;
1276
1277 case HollowShape.Circle:
1278
1279 hollowVolume *= 0.1963495f * 3.07920140172638f;
1280 break;
1281
1282 default:
1283 hollowVolume = 0;
1284 break;
1285 }
1286 volume *= (1.0f - hollowVolume);
1287 }
1288 }
1289 break;
1290
1291 default:
1292 break;
1293 }
1294
1295
1296
1297 float taperX1;
1298 float taperY1;
1299 float taperX;
1300 float taperY;
1301 float pathBegin;
1302 float pathEnd;
1303 float profileBegin;
1304 float profileEnd;
1305
1306 if (BaseShape.PathCurve == (byte)Extrusion.Straight || BaseShape.PathCurve == (byte)Extrusion.Flexible)
1307 {
1308 taperX1 = BaseShape.PathScaleX * 0.01f;
1309 if (taperX1 > 1.0f)
1310 taperX1 = 2.0f - taperX1;
1311 taperX = 1.0f - taperX1;
1312
1313 taperY1 = BaseShape.PathScaleY * 0.01f;
1314 if (taperY1 > 1.0f)
1315 taperY1 = 2.0f - taperY1;
1316 taperY = 1.0f - taperY1;
1317 }
1318 else
1319 {
1320 taperX = BaseShape.PathTaperX * 0.01f;
1321 if (taperX < 0.0f)
1322 taperX = -taperX;
1323 taperX1 = 1.0f - taperX;
1324
1325 taperY = BaseShape.PathTaperY * 0.01f;
1326 if (taperY < 0.0f)
1327 taperY = -taperY;
1328 taperY1 = 1.0f - taperY;
1329
1330 }
1331
1332
1333 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
1334
1335 pathBegin = (float)BaseShape.PathBegin * 2.0e-5f;
1336 pathEnd = 1.0f - (float)BaseShape.PathEnd * 2.0e-5f;
1337 volume *= (pathEnd - pathBegin);
1338
1339 // this is crude aproximation
1340 profileBegin = (float)BaseShape.ProfileBegin * 2.0e-5f;
1341 profileEnd = 1.0f - (float)BaseShape.ProfileEnd * 2.0e-5f;
1342 volume *= (profileEnd - profileBegin);
1343
1344 returnMass = _density * volume;
1345
1346 /* Comment out code that computes the mass of the linkset. That is done in the Linkset class.
1347 if (IsRootOfLinkset)
1348 {
1349 foreach (BSPrim prim in _childrenPrims)
1350 {
1351 returnMass += prim.CalculateMass();
1352 }
1353 }
1354 */
1355
1356 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1357
1358 return returnMass;
1359 }// end CalculateMass
1360 #endregion Mass Calculation
1361
1362 // Rebuild the geometry and object.
1363 // This is called when the shape changes so we need to recreate the mesh/hull.
1364 // Called at taint-time!!!
1365 public void CreateGeomAndObject(bool forceRebuild)
1366 {
1367 // If this prim is part of a linkset, we must remove and restore the physical
1368 // links if the body is rebuilt.
1369 bool needToRestoreLinkset = false;
1370 bool needToRestoreVehicle = false;
1371
1372 // Create the correct physical representation for this type of object.
1373 // Updates PhysBody and PhysShape with the new information.
1374 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1375 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1376 {
1377 // Called if the current prim body is about to be destroyed.
1378 // Remove all the physical dependencies on the old body.
1379 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1380 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1381 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1382 });
1383
1384 if (needToRestoreLinkset)
1385 {
1386 // If physical body dependencies were removed, restore them
1387 Linkset.RestoreBodyDependencies(this);
1388 }
1389 if (needToRestoreVehicle)
1390 {
1391 // If physical body dependencies were removed, restore them
1392 _vehicle.RestoreBodyDependencies(this);
1393 }
1394
1395 // Make sure the properties are set on the new object
1396 UpdatePhysicalParameters();
1397 return;
1398 }
1399
1400 // The physics engine says that properties have updated. Update same and inform
1401 // the world that things have changed.
1402 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1403 enum UpdatedProperties {
1404 Position = 1 << 0,
1405 Rotation = 1 << 1,
1406 Velocity = 1 << 2,
1407 Acceleration = 1 << 3,
1408 RotationalVel = 1 << 4
1409 }
1410
1411 const float ROTATION_TOLERANCE = 0.01f;
1412 const float VELOCITY_TOLERANCE = 0.001f;
1413 const float POSITION_TOLERANCE = 0.05f;
1414 const float ACCELERATION_TOLERANCE = 0.01f;
1415 const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f;
1416
1417 public override void UpdateProperties(EntityProperties entprop)
1418 {
1419 // Updates only for individual prims and for the root object of a linkset.
1420 if (Linkset.IsRoot(this))
1421 {
1422 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1423 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1424 if (_vehicle.IsActive)
1425 {
1426 entprop.RotationalVelocity = OMV.Vector3.Zero;
1427 }
1428
1429 // Assign directly to the local variables so the normal set action does not happen
1430 _position = entprop.Position;
1431 _orientation = entprop.Rotation;
1432 _velocity = entprop.Velocity;
1433 _acceleration = entprop.Acceleration;
1434 _rotationalVelocity = entprop.RotationalVelocity;
1435
1436 // The sanity check can change the velocity and/or position.
1437 if (IsPhysical && PositionSanityCheck(true))
1438 {
1439 entprop.Position = _position;
1440 entprop.Velocity = _velocity;
1441 }
1442
1443 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1444 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1445 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1446
1447 // remember the current and last set values
1448 LastEntityProperties = CurrentEntityProperties;
1449 CurrentEntityProperties = entprop;
1450
1451 base.RequestPhysicsterseUpdate();
1452 }
1453 /*
1454 else
1455 {
1456 // For debugging, report the movement of children
1457 DetailLog("{0},BSPrim.UpdateProperties,child,pos={1},orient={2},vel={3},accel={4},rotVel={5}",
1458 LocalID, entprop.Position, entprop.Rotation, entprop.Velocity,
1459 entprop.Acceleration, entprop.RotationalVelocity);
1460 }
1461 */
1462
1463 // The linkset implimentation might want to know about this.
1464 Linkset.UpdateProperties(this, true);
1465 }
1466}
1467}