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