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