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