aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs')
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs1192
1 files changed, 1192 insertions, 0 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
new file mode 100644
index 0000000..82a8803
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -0,0 +1,1192 @@
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 */
27using System;
28using System.Reflection;
29using System.Collections.Generic;
30using System.Xml;
31using log4net;
32using OMV = OpenMetaverse;
33using OpenSim.Framework;
34using OpenSim.Region.Physics.Manager;
35using OpenSim.Region.Physics.ConvexDecompositionDotNet;
36
37namespace OpenSim.Region.Physics.BulletSPlugin
38{
39 [Serializable]
40public sealed class BSPrim : PhysicsActor
41{
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 private static readonly string LogHeader = "[BULLETS PRIM]";
44
45 private IMesh _mesh;
46 private PrimitiveBaseShape _pbs;
47 private ShapeData.PhysicsShapeType _shapeType;
48 private ulong _hullKey;
49 private List<ConvexResult> _hulls;
50
51 private BSScene _scene;
52 private String _avName;
53 private uint _localID = 0;
54
55 private OMV.Vector3 _size;
56 private OMV.Vector3 _scale;
57 private bool _stopped;
58 private bool _grabbed;
59 private bool _isSelected;
60 private bool _isVolumeDetect;
61 private OMV.Vector3 _position;
62 private float _mass;
63 private float _density;
64 private OMV.Vector3 _force;
65 private OMV.Vector3 _velocity;
66 private OMV.Vector3 _torque;
67 private float _collisionScore;
68 private OMV.Vector3 _acceleration;
69 private OMV.Quaternion _orientation;
70 private int _physicsActorType;
71 private bool _isPhysical;
72 private bool _flying;
73 private float _friction;
74 private bool _setAlwaysRun;
75 private bool _throttleUpdates;
76 private bool _isColliding;
77 private bool _collidingGround;
78 private bool _collidingObj;
79 private bool _floatOnWater;
80 private OMV.Vector3 _rotationalVelocity;
81 private bool _kinematic;
82 private float _buoyancy;
83 private OMV.Vector3 _angularVelocity;
84
85 private List<BSPrim> _childrenPrims;
86 private BSPrim _parentPrim;
87
88 private int _subscribedEventsMs = 0;
89 private int _lastCollisionTime = 0;
90 long _collidingStep;
91 long _collidingGroundStep;
92
93 private BSDynamics _vehicle;
94
95 private OMV.Vector3 _PIDTarget;
96 private bool _usePID;
97 private float _PIDTau;
98 private bool _useHoverPID;
99 private float _PIDHoverHeight;
100 private PIDHoverType _PIDHoverType;
101 private float _PIDHoverTao;
102
103 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
104 OMV.Quaternion rotation, IMesh mesh, PrimitiveBaseShape pbs, bool pisPhysical)
105 {
106 // m_log.DebugFormat("{0}: BSPrim creation of {1}, id={2}", LogHeader, primName, localID);
107 _localID = localID;
108 _avName = primName;
109 _scene = parent_scene;
110 _position = pos;
111 _size = size;
112 _scale = new OMV.Vector3(1f, 1f, 1f); // the scale will be set by CreateGeom depending on object type
113 _orientation = rotation;
114 _buoyancy = 1f;
115 _velocity = OMV.Vector3.Zero;
116 _angularVelocity = OMV.Vector3.Zero;
117 _mesh = mesh;
118 _hullKey = 0;
119 _pbs = pbs;
120 _isPhysical = pisPhysical;
121 _isVolumeDetect = false;
122 _subscribedEventsMs = 0;
123 _friction = _scene.DefaultFriction; // TODO: compute based on object material
124 _density = _scene.DefaultDensity; // TODO: compute based on object material
125 _parentPrim = null; // not a child or a parent
126 _vehicle = new BSDynamics(this); // add vehicleness
127 _childrenPrims = new List<BSPrim>();
128 if (_isPhysical)
129 _mass = CalculateMass();
130 else
131 _mass = 0f;
132 // do the actual object creation at taint time
133 _scene.TaintedObject(delegate()
134 {
135 CreateGeom();
136 CreateObject();
137 });
138 }
139
140 // called when this prim is being destroyed and we should free all the resources
141 public void Destroy()
142 {
143 // m_log.DebugFormat("{0}: Destroy", LogHeader);
144 // Undo any vehicle properties
145 _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE);
146 _scene.RemoveVehiclePrim(this); // just to make sure
147 _scene.TaintedObject(delegate()
148 {
149 BulletSimAPI.DestroyObject(_scene.WorldID, _localID);
150 });
151 }
152
153 public override bool Stopped {
154 get { return _stopped; }
155 }
156 public override OMV.Vector3 Size {
157 get { return _size; }
158 set {
159 _size = value;
160 _scene.TaintedObject(delegate()
161 {
162 if (_isPhysical) _mass = CalculateMass(); // changing size changes the mass
163 BulletSimAPI.SetObjectScaleMass(_scene.WorldID, _localID, _scale, _mass, _isPhysical);
164 RecreateGeomAndObject();
165 });
166 }
167 }
168 public override PrimitiveBaseShape Shape {
169 set {
170 _pbs = value;
171 _scene.TaintedObject(delegate()
172 {
173 if (_isPhysical) _mass = CalculateMass(); // changing the shape changes the mass
174 RecreateGeomAndObject();
175 });
176 }
177 }
178 public override uint LocalID {
179 set { _localID = value; }
180 get { return _localID; }
181 }
182 public override bool Grabbed {
183 set { _grabbed = value;
184 }
185 }
186 public override bool Selected {
187 set {
188 _isSelected = value;
189 _scene.TaintedObject(delegate()
190 {
191 SetObjectDynamic();
192 });
193 }
194 }
195 public override void CrossingFailure() { return; }
196
197 // link me to the specified parent
198 public override void link(PhysicsActor obj) {
199 BSPrim parent = (BSPrim)obj;
200 // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID);
201 // TODO: decide if this parent checking needs to happen at taint time
202 if (_parentPrim == null)
203 {
204 if (parent != null)
205 {
206 // I don't have a parent so I am joining a linkset
207 parent.AddChildToLinkset(this);
208 }
209 }
210 else
211 {
212 // I already have a parent, is parenting changing?
213 if (parent != _parentPrim)
214 {
215 if (parent == null)
216 {
217 // we are being removed from a linkset
218 _parentPrim.RemoveChildFromLinkset(this);
219 }
220 else
221 {
222 // asking to reparent a prim should not happen
223 m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader);
224 }
225 }
226 }
227 return;
228 }
229
230 // delink me from my linkset
231 public override void delink() {
232 // TODO: decide if this parent checking needs to happen at taint time
233 // Race condition here: if link() and delink() in same simulation tick, the delink will not happen
234 // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID);
235 if (_parentPrim != null)
236 {
237 _parentPrim.RemoveChildFromLinkset(this);
238 }
239 return;
240 }
241
242 public void AddChildToLinkset(BSPrim pchild)
243 {
244 BSPrim child = pchild;
245 _scene.TaintedObject(delegate()
246 {
247 if (!_childrenPrims.Contains(child))
248 {
249 _childrenPrims.Add(child);
250 child.ParentPrim = this; // the child has gained a parent
251 RecreateGeomAndObject(); // rebuild my shape with the new child added
252 }
253 });
254 return;
255 }
256
257 public void RemoveChildFromLinkset(BSPrim pchild)
258 {
259 BSPrim child = pchild;
260 _scene.TaintedObject(delegate()
261 {
262 if (_childrenPrims.Contains(child))
263 {
264 _childrenPrims.Remove(child);
265 child.ParentPrim = null; // the child has lost its parent
266 RecreateGeomAndObject(); // rebuild my shape with the child removed
267 }
268 else
269 {
270 m_log.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset");
271 }
272 });
273 return;
274 }
275
276 public BSPrim ParentPrim
277 {
278 set { _parentPrim = value; }
279 }
280
281 public ulong HullKey
282 {
283 get { return _hullKey; }
284 }
285
286 // return true if we are the root of a linkset (there are children to manage)
287 public bool IsRootOfLinkset
288 {
289 get { return (_parentPrim == null && _childrenPrims.Count != 0); }
290 }
291
292 public override void LockAngularMotion(OMV.Vector3 axis) { return; }
293
294 public override OMV.Vector3 Position {
295 get {
296 // don't do the following GetObjectPosition because this function is called a zillion times
297 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
298 return _position;
299 }
300 set {
301 _position = value;
302 _scene.TaintedObject(delegate()
303 {
304 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
305 // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position);
306 });
307 }
308 }
309 public override float Mass {
310 get { return _mass; }
311 }
312 public override OMV.Vector3 Force {
313 get { return _force; }
314 set {
315 _force = value;
316 _scene.TaintedObject(delegate()
317 {
318 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
319 });
320 }
321 }
322
323 public override int VehicleType {
324 get {
325 return (int)_vehicle.Type; // if we are a vehicle, return that type
326 }
327 set {
328 Vehicle type = (Vehicle)value;
329 _vehicle.ProcessTypeChange(type);
330 _scene.TaintedObject(delegate()
331 {
332 if (type == Vehicle.TYPE_NONE)
333 {
334 _scene.RemoveVehiclePrim(this);
335 }
336 else
337 {
338 // make it so the scene will call us each tick to do vehicle things
339 _scene.AddVehiclePrim(this);
340 }
341 return;
342 });
343 }
344 }
345 public override void VehicleFloatParam(int param, float value)
346 {
347 _vehicle.ProcessFloatVehicleParam((Vehicle)param, value);
348 }
349 public override void VehicleVectorParam(int param, OMV.Vector3 value)
350 {
351 _vehicle.ProcessVectorVehicleParam((Vehicle)param, value);
352 }
353 public override void VehicleRotationParam(int param, OMV.Quaternion rotation)
354 {
355 _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation);
356 }
357 public override void VehicleFlags(int param, bool remove)
358 {
359 _vehicle.ProcessVehicleFlags(param, remove);
360 }
361 // Called each simulation step to advance vehicle characteristics
362 public void StepVehicle(float timeStep)
363 {
364 _vehicle.Step(timeStep, _scene);
365 }
366
367 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
368 public override void SetVolumeDetect(int param) {
369 bool newValue = (param != 0);
370 if (_isVolumeDetect != newValue)
371 {
372 _isVolumeDetect = newValue;
373 _scene.TaintedObject(delegate()
374 {
375 SetObjectDynamic();
376 });
377 }
378 return;
379 }
380
381 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
382 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
383 public override OMV.Vector3 Velocity {
384 get { return _velocity; }
385 set { _velocity = value;
386 _scene.TaintedObject(delegate()
387 {
388 BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity);
389 });
390 }
391 }
392 public OMV.Vector3 AngularVelocity
393 {
394 get { return _angularVelocity; }
395 set
396 {
397 _angularVelocity = value;
398 _scene.TaintedObject(delegate()
399 {
400 BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _angularVelocity);
401 });
402 }
403 }
404 public override OMV.Vector3 Torque {
405 get { return _torque; }
406 set { _torque = value;
407 }
408 }
409 public override float CollisionScore {
410 get { return _collisionScore; }
411 set { _collisionScore = value;
412 }
413 }
414 public override OMV.Vector3 Acceleration {
415 get { return _acceleration; }
416 }
417 public override OMV.Quaternion Orientation {
418 get { return _orientation; }
419 set {
420 _orientation = value;
421 _scene.TaintedObject(delegate()
422 {
423 // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID);
424 BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation);
425 // m_log.DebugFormat("{0}: set orientation: {1}", LogHeader, _orientation);
426 });
427 }
428 }
429 public override int PhysicsActorType {
430 get { return _physicsActorType; }
431 set { _physicsActorType = value;
432 }
433 }
434 public override bool IsPhysical {
435 get { return _isPhysical; }
436 set {
437 _isPhysical = value;
438 _scene.TaintedObject(delegate()
439 {
440 SetObjectDynamic();
441 });
442 }
443 }
444
445 // An object is static (does not move) if selected or not physical
446 private bool IsStatic
447 {
448 get { return _isSelected || !IsPhysical; }
449 }
450
451 // An object is solid if it's not phantom and if it's not doing VolumeDetect
452 private bool IsSolid
453 {
454 get { return !IsPhantom && !_isVolumeDetect; }
455 }
456
457 // make gravity work if the object is physical and not selected
458 // no locking here because only called when it is safe
459 private void SetObjectDynamic()
460 {
461 // non-physical things work best with a mass of zero
462 _mass = IsStatic ? 0f : CalculateMass();
463 BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass);
464 // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}, mass={4}", LogHeader, _localID, IsStatic, IsSolid, _mass);
465 }
466
467 // prims don't fly
468 public override bool Flying {
469 get { return _flying; }
470 set { _flying = value; }
471 }
472 public override bool SetAlwaysRun {
473 get { return _setAlwaysRun; }
474 set { _setAlwaysRun = value; }
475 }
476 public override bool ThrottleUpdates {
477 get { return _throttleUpdates; }
478 set { _throttleUpdates = value; }
479 }
480 public override bool IsColliding {
481 get { return (_collidingStep == _scene.SimulationStep); }
482 set { _isColliding = value; }
483 }
484 public override bool CollidingGround {
485 get { return (_collidingGroundStep == _scene.SimulationStep); }
486 set { _collidingGround = value; }
487 }
488 public override bool CollidingObj {
489 get { return _collidingObj; }
490 set { _collidingObj = value; }
491 }
492 public bool IsPhantom {
493 get {
494 // SceneObjectPart removes phantom objects from the physics scene
495 // so, although we could implement touching and such, we never
496 // are invoked as a phantom object
497 return false;
498 }
499 }
500 public override bool FloatOnWater {
501 set { _floatOnWater = value; }
502 }
503 public override OMV.Vector3 RotationalVelocity {
504 get { return _rotationalVelocity; }
505 set { _rotationalVelocity = value;
506 // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity);
507 }
508 }
509 public override bool Kinematic {
510 get { return _kinematic; }
511 set { _kinematic = value;
512 // m_log.DebugFormat("{0}: Kinematic={1}", LogHeader, _kinematic);
513 }
514 }
515 public override float Buoyancy {
516 get { return _buoyancy; }
517 set { _buoyancy = value;
518 _scene.TaintedObject(delegate()
519 {
520 BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy);
521 });
522 }
523 }
524
525 // Used for MoveTo
526 public override OMV.Vector3 PIDTarget {
527 set { _PIDTarget = value; }
528 }
529 public override bool PIDActive {
530 set { _usePID = value; }
531 }
532 public override float PIDTau {
533 set { _PIDTau = value; }
534 }
535
536 // Used for llSetHoverHeight and maybe vehicle height
537 // Hover Height will override MoveTo target's Z
538 public override bool PIDHoverActive {
539 set { _useHoverPID = value; }
540 }
541 public override float PIDHoverHeight {
542 set { _PIDHoverHeight = value; }
543 }
544 public override PIDHoverType PIDHoverType {
545 set { _PIDHoverType = value; }
546 }
547 public override float PIDHoverTau {
548 set { _PIDHoverTao = value; }
549 }
550
551 // For RotLookAt
552 public override OMV.Quaternion APIDTarget { set { return; } }
553 public override bool APIDActive { set { return; } }
554 public override float APIDStrength { set { return; } }
555 public override float APIDDamping { set { return; } }
556
557 public override void AddForce(OMV.Vector3 force, bool pushforce) {
558 if (force.IsFinite())
559 {
560 _force.X += force.X;
561 _force.Y += force.Y;
562 _force.Z += force.Z;
563 }
564 else
565 {
566 m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader);
567 }
568 _scene.TaintedObject(delegate()
569 {
570 BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force);
571 });
572 }
573
574 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
575 // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce);
576 }
577 public override void SetMomentum(OMV.Vector3 momentum) {
578 }
579 public override void SubscribeEvents(int ms) {
580 _subscribedEventsMs = ms;
581 _lastCollisionTime = Util.EnvironmentTickCount() - _subscribedEventsMs; // make first collision happen
582 }
583 public override void UnSubscribeEvents() {
584 _subscribedEventsMs = 0;
585 }
586 public override bool SubscribedEvents() {
587 return (_subscribedEventsMs > 0);
588 }
589
590 #region Mass Calculation
591
592 private float CalculateMass()
593 {
594 float volume = _size.X * _size.Y * _size.Z; // default
595 float tmp;
596
597 float returnMass = 0;
598 float hollowAmount = (float)_pbs.ProfileHollow * 2.0e-5f;
599 float hollowVolume = hollowAmount * hollowAmount;
600
601 switch (_pbs.ProfileShape)
602 {
603 case ProfileShape.Square:
604 // default box
605
606 if (_pbs.PathCurve == (byte)Extrusion.Straight)
607 {
608 if (hollowAmount > 0.0)
609 {
610 switch (_pbs.HollowShape)
611 {
612 case HollowShape.Square:
613 case HollowShape.Same:
614 break;
615
616 case HollowShape.Circle:
617
618 hollowVolume *= 0.78539816339f;
619 break;
620
621 case HollowShape.Triangle:
622
623 hollowVolume *= (0.5f * .5f);
624 break;
625
626 default:
627 hollowVolume = 0;
628 break;
629 }
630 volume *= (1.0f - hollowVolume);
631 }
632 }
633
634 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
635 {
636 //a tube
637
638 volume *= 0.78539816339e-2f * (float)(200 - _pbs.PathScaleX);
639 tmp= 1.0f -2.0e-2f * (float)(200 - _pbs.PathScaleY);
640 volume -= volume*tmp*tmp;
641
642 if (hollowAmount > 0.0)
643 {
644 hollowVolume *= hollowAmount;
645
646 switch (_pbs.HollowShape)
647 {
648 case HollowShape.Square:
649 case HollowShape.Same:
650 break;
651
652 case HollowShape.Circle:
653 hollowVolume *= 0.78539816339f;;
654 break;
655
656 case HollowShape.Triangle:
657 hollowVolume *= 0.5f * 0.5f;
658 break;
659 default:
660 hollowVolume = 0;
661 break;
662 }
663 volume *= (1.0f - hollowVolume);
664 }
665 }
666
667 break;
668
669 case ProfileShape.Circle:
670
671 if (_pbs.PathCurve == (byte)Extrusion.Straight)
672 {
673 volume *= 0.78539816339f; // elipse base
674
675 if (hollowAmount > 0.0)
676 {
677 switch (_pbs.HollowShape)
678 {
679 case HollowShape.Same:
680 case HollowShape.Circle:
681 break;
682
683 case HollowShape.Square:
684 hollowVolume *= 0.5f * 2.5984480504799f;
685 break;
686
687 case HollowShape.Triangle:
688 hollowVolume *= .5f * 1.27323954473516f;
689 break;
690
691 default:
692 hollowVolume = 0;
693 break;
694 }
695 volume *= (1.0f - hollowVolume);
696 }
697 }
698
699 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
700 {
701 volume *= 0.61685027506808491367715568749226e-2f * (float)(200 - _pbs.PathScaleX);
702 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
703 volume *= (1.0f - tmp * tmp);
704
705 if (hollowAmount > 0.0)
706 {
707
708 // calculate the hollow volume by it's shape compared to the prim shape
709 hollowVolume *= hollowAmount;
710
711 switch (_pbs.HollowShape)
712 {
713 case HollowShape.Same:
714 case HollowShape.Circle:
715 break;
716
717 case HollowShape.Square:
718 hollowVolume *= 0.5f * 2.5984480504799f;
719 break;
720
721 case HollowShape.Triangle:
722 hollowVolume *= .5f * 1.27323954473516f;
723 break;
724
725 default:
726 hollowVolume = 0;
727 break;
728 }
729 volume *= (1.0f - hollowVolume);
730 }
731 }
732 break;
733
734 case ProfileShape.HalfCircle:
735 if (_pbs.PathCurve == (byte)Extrusion.Curve1)
736 {
737 volume *= 0.52359877559829887307710723054658f;
738 }
739 break;
740
741 case ProfileShape.EquilateralTriangle:
742
743 if (_pbs.PathCurve == (byte)Extrusion.Straight)
744 {
745 volume *= 0.32475953f;
746
747 if (hollowAmount > 0.0)
748 {
749
750 // calculate the hollow volume by it's shape compared to the prim shape
751 switch (_pbs.HollowShape)
752 {
753 case HollowShape.Same:
754 case HollowShape.Triangle:
755 hollowVolume *= .25f;
756 break;
757
758 case HollowShape.Square:
759 hollowVolume *= 0.499849f * 3.07920140172638f;
760 break;
761
762 case HollowShape.Circle:
763 // Hollow shape is a perfect cyllinder in respect to the cube's scale
764 // Cyllinder hollow volume calculation
765
766 hollowVolume *= 0.1963495f * 3.07920140172638f;
767 break;
768
769 default:
770 hollowVolume = 0;
771 break;
772 }
773 volume *= (1.0f - hollowVolume);
774 }
775 }
776 else if (_pbs.PathCurve == (byte)Extrusion.Curve1)
777 {
778 volume *= 0.32475953f;
779 volume *= 0.01f * (float)(200 - _pbs.PathScaleX);
780 tmp = 1.0f - .02f * (float)(200 - _pbs.PathScaleY);
781 volume *= (1.0f - tmp * tmp);
782
783 if (hollowAmount > 0.0)
784 {
785
786 hollowVolume *= hollowAmount;
787
788 switch (_pbs.HollowShape)
789 {
790 case HollowShape.Same:
791 case HollowShape.Triangle:
792 hollowVolume *= .25f;
793 break;
794
795 case HollowShape.Square:
796 hollowVolume *= 0.499849f * 3.07920140172638f;
797 break;
798
799 case HollowShape.Circle:
800
801 hollowVolume *= 0.1963495f * 3.07920140172638f;
802 break;
803
804 default:
805 hollowVolume = 0;
806 break;
807 }
808 volume *= (1.0f - hollowVolume);
809 }
810 }
811 break;
812
813 default:
814 break;
815 }
816
817
818
819 float taperX1;
820 float taperY1;
821 float taperX;
822 float taperY;
823 float pathBegin;
824 float pathEnd;
825 float profileBegin;
826 float profileEnd;
827
828 if (_pbs.PathCurve == (byte)Extrusion.Straight || _pbs.PathCurve == (byte)Extrusion.Flexible)
829 {
830 taperX1 = _pbs.PathScaleX * 0.01f;
831 if (taperX1 > 1.0f)
832 taperX1 = 2.0f - taperX1;
833 taperX = 1.0f - taperX1;
834
835 taperY1 = _pbs.PathScaleY * 0.01f;
836 if (taperY1 > 1.0f)
837 taperY1 = 2.0f - taperY1;
838 taperY = 1.0f - taperY1;
839 }
840 else
841 {
842 taperX = _pbs.PathTaperX * 0.01f;
843 if (taperX < 0.0f)
844 taperX = -taperX;
845 taperX1 = 1.0f - taperX;
846
847 taperY = _pbs.PathTaperY * 0.01f;
848 if (taperY < 0.0f)
849 taperY = -taperY;
850 taperY1 = 1.0f - taperY;
851
852 }
853
854
855 volume *= (taperX1 * taperY1 + 0.5f * (taperX1 * taperY + taperX * taperY1) + 0.3333333333f * taperX * taperY);
856
857 pathBegin = (float)_pbs.PathBegin * 2.0e-5f;
858 pathEnd = 1.0f - (float)_pbs.PathEnd * 2.0e-5f;
859 volume *= (pathEnd - pathBegin);
860
861 // this is crude aproximation
862 profileBegin = (float)_pbs.ProfileBegin * 2.0e-5f;
863 profileEnd = 1.0f - (float)_pbs.ProfileEnd * 2.0e-5f;
864 volume *= (profileEnd - profileBegin);
865
866 returnMass = _density * volume;
867
868 if (returnMass <= 0)
869 returnMass = 0.0001f;//ckrinke: Mass must be greater then zero.
870
871 if (IsRootOfLinkset)
872 {
873 foreach (BSPrim prim in _childrenPrims)
874 {
875 returnMass += prim.CalculateMass();
876 }
877 }
878
879 if (returnMass > _scene.maximumMassObject)
880 returnMass = _scene.maximumMassObject;
881 return returnMass;
882 }// end CalculateMass
883 #endregion Mass Calculation
884
885 // Create the geometry information in Bullet for later use
886 // No locking here because this is done when we know physics is not simulating
887 private void CreateGeom()
888 {
889 if (_mesh == null)
890 {
891 // the mesher thought this was too simple to mesh. Use a native Bullet collision shape.
892 if (_pbs.ProfileShape == ProfileShape.HalfCircle && _pbs.PathCurve == (byte)Extrusion.Curve1)
893 {
894 if (_size.X == _size.Y && _size.Y == _size.Z && _size.X == _size.Z)
895 {
896 // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to sphere of size {1}", LogHeader, _size);
897 _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE;
898 // Bullet native objects are scaled by the Bullet engine so pass the size in
899 _scale = _size;
900 }
901 }
902 else
903 {
904 // m_log.DebugFormat("{0}: CreateGeom: mesh null. Defaulting to box of size {1}", LogHeader, _size);
905 _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX;
906 _scale = _size;
907 }
908 }
909 else
910 {
911 if (_hullKey != 0)
912 {
913 // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey);
914 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
915 _hullKey = 0;
916 _hulls.Clear();
917 }
918
919 int[] indices = _mesh.getIndexListAsInt();
920 List<OMV.Vector3> vertices = _mesh.getVertexList();
921
922 //format conversion from IMesh format to DecompDesc format
923 List<int> convIndices = new List<int>();
924 List<float3> convVertices = new List<float3>();
925 for (int ii = 0; ii < indices.GetLength(0); ii++)
926 {
927 convIndices.Add(indices[ii]);
928 }
929 foreach (OMV.Vector3 vv in vertices)
930 {
931 convVertices.Add(new float3(vv.X, vv.Y, vv.Z));
932 }
933
934 // setup and do convex hull conversion
935 _hulls = new List<ConvexResult>();
936 DecompDesc dcomp = new DecompDesc();
937 dcomp.mIndices = convIndices;
938 dcomp.mVertices = convVertices;
939 ConvexBuilder convexBuilder = new ConvexBuilder(HullReturn);
940 // create the hull into the _hulls variable
941 convexBuilder.process(dcomp);
942
943 // Convert the vertices and indices for passing to unmanaged
944 // The hull information is passed as a large floating point array.
945 // The format is:
946 // convHulls[0] = number of hulls
947 // convHulls[1] = number of vertices in first hull
948 // convHulls[2] = hull centroid X coordinate
949 // convHulls[3] = hull centroid Y coordinate
950 // convHulls[4] = hull centroid Z coordinate
951 // convHulls[5] = first hull vertex X
952 // convHulls[6] = first hull vertex Y
953 // convHulls[7] = first hull vertex Z
954 // convHulls[8] = second hull vertex X
955 // ...
956 // convHulls[n] = number of vertices in second hull
957 // convHulls[n+1] = second hull centroid X coordinate
958 // ...
959 //
960 // TODO: is is very inefficient. Someday change the convex hull generator to return
961 // data structures that do not need to be converted in order to pass to Bullet.
962 // And maybe put the values directly into pinned memory rather than marshaling.
963 int hullCount = _hulls.Count;
964 int totalVertices = 1; // include one for the count of the hulls
965 foreach (ConvexResult cr in _hulls)
966 {
967 totalVertices += 4; // add four for the vertex count and centroid
968 totalVertices += cr.HullIndices.Count * 3; // we pass just triangles
969 }
970 float[] convHulls = new float[totalVertices];
971
972 convHulls[0] = (float)hullCount;
973 int jj = 1;
974 foreach (ConvexResult cr in _hulls)
975 {
976 // copy vertices for index access
977 float3[] verts = new float3[cr.HullVertices.Count];
978 int kk = 0;
979 foreach (float3 ff in cr.HullVertices)
980 {
981 verts[kk++] = ff;
982 }
983
984 // add to the array one hull's worth of data
985 convHulls[jj++] = cr.HullIndices.Count;
986 convHulls[jj++] = 0f; // centroid x,y,z
987 convHulls[jj++] = 0f;
988 convHulls[jj++] = 0f;
989 foreach (int ind in cr.HullIndices)
990 {
991 convHulls[jj++] = verts[ind].x;
992 convHulls[jj++] = verts[ind].y;
993 convHulls[jj++] = verts[ind].z;
994 }
995 }
996
997 // create the hull definition in Bullet
998 _hullKey = (ulong)_pbs.GetHashCode();
999 // m_log.DebugFormat("{0}: CreateGeom: calling CreateHull. lid= {1}, key={2}, hulls={3}", LogHeader, _localID, _hullKey, hullCount);
1000 BulletSimAPI.CreateHull(_scene.WorldID, _hullKey, hullCount, convHulls);
1001 _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL;
1002 // meshes are already scaled by the meshmerizer
1003 _scale = new OMV.Vector3(1f, 1f, 1f);
1004 }
1005 return;
1006 }
1007
1008 private void HullReturn(ConvexResult result)
1009 {
1010 _hulls.Add(result);
1011 return;
1012 }
1013
1014 // Create an object in Bullet
1015 // No locking here because this is done when the physics engine is not simulating
1016 private void CreateObject()
1017 {
1018 if (IsRootOfLinkset)
1019 {
1020 // Create a linkset around this object
1021 /*
1022 * NOTE: the original way of creating a linkset was to create a compound hull in the
1023 * root which consisted of the hulls of all the children. This didn't work well because
1024 * OpenSimulator needs updates and collisions for all the children and the physics
1025 * engine didn't create events for the children when the root hull was moved.
1026 * This code creates the compound hull.
1027 // If I am the root prim of a linkset, replace my physical shape with all the
1028 // pieces of the children.
1029 // All of the children should have called CreateGeom so they have a hull
1030 // in the physics engine already. Here we pull together all of those hulls
1031 // into one shape.
1032 int totalPrimsInLinkset = _childrenPrims.Count + 1;
1033 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, totalPrimsInLinkset);
1034 ShapeData[] shapes = new ShapeData[totalPrimsInLinkset];
1035 FillShapeInfo(out shapes[0]);
1036 int ii = 1;
1037 foreach (BSPrim prim in _childrenPrims)
1038 {
1039 // m_log.DebugFormat("{0}: CreateLinkset: adding prim {1}", LogHeader, prim.LocalID);
1040 prim.FillShapeInfo(out shapes[ii]);
1041 ii++;
1042 }
1043 BulletSimAPI.CreateLinkset(_scene.WorldID, totalPrimsInLinkset, shapes);
1044 */
1045 // Create the linkset by putting constraints between the objects of the set so they cannot move
1046 // relative to each other.
1047 // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1);
1048
1049 // remove any constraints that might be in place
1050 foreach (BSPrim prim in _childrenPrims)
1051 {
1052 BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID);
1053 }
1054 // create constraints between the root prim and each of the children
1055 foreach (BSPrim prim in _childrenPrims)
1056 {
1057 // this is a constraint that allows no freedom of movement between the two objects
1058 // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818
1059 BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, OMV.Vector3.Zero, OMV.Vector3.Zero,
1060 OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero, OMV.Vector3.Zero);
1061 }
1062 }
1063 else
1064 {
1065 // simple object
1066 // m_log.DebugFormat("{0}: CreateObject. ID={1}", LogHeader, LocalID);
1067 ShapeData shape;
1068 FillShapeInfo(out shape);
1069 BulletSimAPI.CreateObject(_scene.WorldID, shape);
1070 }
1071 }
1072
1073 // Copy prim's info into the BulletSim shape description structure
1074 public void FillShapeInfo(out ShapeData shape)
1075 {
1076 shape.ID = _localID;
1077 shape.Type = _shapeType;
1078 shape.Position = _position;
1079 shape.Rotation = _orientation;
1080 shape.Velocity = _velocity;
1081 shape.Scale = _scale;
1082 shape.Mass = _isPhysical ? _mass : 0f;
1083 shape.Buoyancy = _buoyancy;
1084 shape.MeshKey = _hullKey;
1085 shape.Collidable = (!IsPhantom) ? ShapeData.numericTrue : ShapeData.numericFalse;
1086 shape.Friction = _friction;
1087 shape.Static = _isPhysical ? ShapeData.numericFalse : ShapeData.numericTrue;
1088 }
1089
1090 // Rebuild the geometry and object.
1091 // This is called when the shape changes so we need to recreate the mesh/hull.
1092 // No locking here because this is done when the physics engine is not simulating
1093 private void RecreateGeomAndObject()
1094 {
1095 if (_hullKey != 0)
1096 {
1097 // if a hull already exists, delete the old one
1098 BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey);
1099 _hullKey = 0;
1100 }
1101 // If this object is complex or we are the root of a linkset, build a mesh.
1102 // The root of a linkset must be a mesh so we can create the linked compound object.
1103 if (_scene.NeedsMeshing(_pbs) || IsRootOfLinkset )
1104 {
1105 // m_log.DebugFormat("{0}: RecreateGeomAndObject: creating mesh", LogHeader);
1106 _mesh = _scene.mesher.CreateMesh(_avName, _pbs, _size, _scene.meshLOD, _isPhysical);
1107 }
1108 else
1109 {
1110 // it's a BulletSim native shape.
1111 _mesh = null;
1112 }
1113 CreateGeom(); // create the geometry for this prim
1114 CreateObject();
1115 return;
1116 }
1117
1118 // The physics engine says that properties have updated. Update same and inform
1119 // the world that things have changed.
1120 // TODO: do we really need to check for changed? Maybe just copy values and call RequestPhysicsterseUpdate()
1121 private int UpPropPosition = 1 << 0;
1122 private int UpPropRotation = 1 << 1;
1123 private int UpPropVelocity = 1 << 2;
1124 private int UpPropAcceleration = 1 << 3;
1125 private int UpPropAngularVel = 1 << 4;
1126
1127 public void UpdateProperties(EntityProperties entprop)
1128 {
1129 int changed = 0;
1130 // assign to the local variables so the normal set action does not happen
1131 if (_position != entprop.Position)
1132 {
1133 _position = entprop.Position;
1134 // m_log.DebugFormat("{0}: UpdateProperties: position = {1}", LogHeader, _position);
1135 changed |= UpPropPosition;
1136 }
1137 if (_orientation != entprop.Rotation)
1138 {
1139 _orientation = entprop.Rotation;
1140 // m_log.DebugFormat("{0}: UpdateProperties: rotation = {1}", LogHeader, _orientation);
1141 changed |= UpPropRotation;
1142 }
1143 if (_velocity != entprop.Velocity)
1144 {
1145 _velocity = entprop.Velocity;
1146 // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity);
1147 changed |= UpPropVelocity;
1148 }
1149 if (_acceleration != entprop.Acceleration)
1150 {
1151 _acceleration = entprop.Acceleration;
1152 // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration);
1153 changed |= UpPropAcceleration;
1154 }
1155 if (_rotationalVelocity != entprop.AngularVelocity)
1156 {
1157 _rotationalVelocity = entprop.AngularVelocity;
1158 // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity);
1159 changed |= UpPropAngularVel;
1160 }
1161 if (changed != 0)
1162 {
1163 // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation);
1164 base.RequestPhysicsterseUpdate();
1165 }
1166 }
1167
1168 // I've collided with something
1169 public void Collide(uint collidingWith, ActorTypes type, OMV.Vector3 contactPoint, OMV.Vector3 contactNormal, float pentrationDepth)
1170 {
1171 // m_log.DebugFormat("{0}: Collide: ms={1}, id={2}, with={3}", LogHeader, _subscribedEventsMs, LocalID, collidingWith);
1172 // The following makes IsColliding() and IsCollidingGround() work
1173 _collidingStep = _scene.SimulationStep;
1174 if (collidingWith == BSScene.TERRAIN_ID || collidingWith == BSScene.GROUNDPLANE_ID)
1175 {
1176 _collidingGroundStep = _scene.SimulationStep;
1177 }
1178
1179 if (_subscribedEventsMs == 0) return; // nothing in the object is waiting for collision events
1180 // throttle the collisions to the number of milliseconds specified in the subscription
1181 int nowTime = Util.EnvironmentTickCount();
1182 if (nowTime < (_lastCollisionTime + _subscribedEventsMs)) return;
1183 _lastCollisionTime = nowTime;
1184
1185 // create the event for the collision
1186 Dictionary<uint, ContactPoint> contactPoints = new Dictionary<uint, ContactPoint>();
1187 contactPoints.Add(collidingWith, new ContactPoint(contactPoint, contactNormal, pentrationDepth));
1188 CollisionEventUpdate args = new CollisionEventUpdate(LocalID, (int)type, 1, contactPoints);
1189 base.SendCollisionUpdate(args);
1190 }
1191}
1192}