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