diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin')
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | 69 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | 187 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | 331 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | 137 | ||||
-rw-r--r-- | OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | 51 |
5 files changed, 533 insertions, 242 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs index dc0c008..09e1f0c 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs | |||
@@ -41,7 +41,7 @@ public class BSCharacter : PhysicsActor | |||
41 | 41 | ||
42 | private BSScene _scene; | 42 | private BSScene _scene; |
43 | private String _avName; | 43 | private String _avName; |
44 | private bool _stopped; | 44 | // private bool _stopped; |
45 | private Vector3 _size; | 45 | private Vector3 _size; |
46 | private Vector3 _scale; | 46 | private Vector3 _scale; |
47 | private PrimitiveBaseShape _pbs; | 47 | private PrimitiveBaseShape _pbs; |
@@ -134,9 +134,9 @@ public class BSCharacter : PhysicsActor | |||
134 | { | 134 | { |
135 | base.RequestPhysicsterseUpdate(); | 135 | base.RequestPhysicsterseUpdate(); |
136 | } | 136 | } |
137 | 137 | // No one calls this method so I don't know what it could possibly mean | |
138 | public override bool Stopped { | 138 | public override bool Stopped { |
139 | get { return _stopped; } | 139 | get { return false; } |
140 | } | 140 | } |
141 | public override Vector3 Size { | 141 | public override Vector3 Size { |
142 | get { return _size; } | 142 | get { return _size; } |
@@ -391,52 +391,47 @@ public class BSCharacter : PhysicsActor | |||
391 | _mass = _density * _avatarVolume; | 391 | _mass = _density * _avatarVolume; |
392 | } | 392 | } |
393 | 393 | ||
394 | // Set to 'true' if the individual changed items should be checked | ||
395 | // (someday RequestPhysicsTerseUpdate() will take a bitmap of changed properties) | ||
396 | const bool SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES = false; | ||
397 | |||
398 | // The physics engine says that properties have updated. Update same and inform | 394 | // The physics engine says that properties have updated. Update same and inform |
399 | // the world that things have changed. | 395 | // the world that things have changed. |
400 | public void UpdateProperties(EntityProperties entprop) | 396 | public void UpdateProperties(EntityProperties entprop) |
401 | { | 397 | { |
398 | /* | ||
402 | bool changed = false; | 399 | bool changed = false; |
403 | if (SHOULD_CHECK_FOR_INDIVIDUAL_CHANGES) { | 400 | // we assign to the local variables so the normal set action does not happen |
404 | // we assign to the local variables so the normal set action does not happen | 401 | if (_position != entprop.Position) { |
405 | if (_position != entprop.Position) { | ||
406 | _position = entprop.Position; | ||
407 | changed = true; | ||
408 | } | ||
409 | if (_orientation != entprop.Rotation) { | ||
410 | _orientation = entprop.Rotation; | ||
411 | changed = true; | ||
412 | } | ||
413 | if (_velocity != entprop.Velocity) { | ||
414 | _velocity = entprop.Velocity; | ||
415 | changed = true; | ||
416 | } | ||
417 | if (_acceleration != entprop.Acceleration) { | ||
418 | _acceleration = entprop.Acceleration; | ||
419 | changed = true; | ||
420 | } | ||
421 | if (_rotationalVelocity != entprop.RotationalVelocity) { | ||
422 | _rotationalVelocity = entprop.RotationalVelocity; | ||
423 | changed = true; | ||
424 | } | ||
425 | if (changed) { | ||
426 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
427 | // Avatar movement is not done by generating this event. There is code in the heartbeat | ||
428 | // loop that updates avatars. | ||
429 | // base.RequestPhysicsterseUpdate(); | ||
430 | } | ||
431 | } | ||
432 | else { | ||
433 | _position = entprop.Position; | 402 | _position = entprop.Position; |
403 | changed = true; | ||
404 | } | ||
405 | if (_orientation != entprop.Rotation) { | ||
434 | _orientation = entprop.Rotation; | 406 | _orientation = entprop.Rotation; |
407 | changed = true; | ||
408 | } | ||
409 | if (_velocity != entprop.Velocity) { | ||
435 | _velocity = entprop.Velocity; | 410 | _velocity = entprop.Velocity; |
411 | changed = true; | ||
412 | } | ||
413 | if (_acceleration != entprop.Acceleration) { | ||
436 | _acceleration = entprop.Acceleration; | 414 | _acceleration = entprop.Acceleration; |
415 | changed = true; | ||
416 | } | ||
417 | if (_rotationalVelocity != entprop.RotationalVelocity) { | ||
437 | _rotationalVelocity = entprop.RotationalVelocity; | 418 | _rotationalVelocity = entprop.RotationalVelocity; |
419 | changed = true; | ||
420 | } | ||
421 | if (changed) { | ||
422 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
423 | // Avatar movement is not done by generating this event. There is code in the heartbeat | ||
424 | // loop that updates avatars. | ||
438 | // base.RequestPhysicsterseUpdate(); | 425 | // base.RequestPhysicsterseUpdate(); |
439 | } | 426 | } |
427 | */ | ||
428 | _position = entprop.Position; | ||
429 | _orientation = entprop.Rotation; | ||
430 | _velocity = entprop.Velocity; | ||
431 | _acceleration = entprop.Acceleration; | ||
432 | _rotationalVelocity = entprop.RotationalVelocity; | ||
433 | // Avatars don't report theirr changes the usual way. Changes are checked for in the heartbeat loop. | ||
434 | // base.RequestPhysicsterseUpdate(); | ||
440 | } | 435 | } |
441 | 436 | ||
442 | // Called by the scene when a collision with this object is reported | 437 | // Called by the scene when a collision with this object is reported |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs index eb20eb3..c197e61 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs | |||
@@ -57,7 +57,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
57 | private int frcount = 0; // Used to limit dynamics debug output to | 57 | private int frcount = 0; // Used to limit dynamics debug output to |
58 | // every 100th frame | 58 | // every 100th frame |
59 | 59 | ||
60 | // private BSScene m_parentScene = null; | ||
61 | private BSPrim m_prim; // the prim this dynamic controller belongs to | 60 | private BSPrim m_prim; // the prim this dynamic controller belongs to |
62 | 61 | ||
63 | // Vehicle properties | 62 | // Vehicle properties |
@@ -131,8 +130,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
131 | m_type = Vehicle.TYPE_NONE; | 130 | m_type = Vehicle.TYPE_NONE; |
132 | } | 131 | } |
133 | 132 | ||
134 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) | 133 | internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue, float timestep) |
135 | { | 134 | { |
135 | DetailLog("{0},ProcessFloatVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); | ||
136 | switch (pParam) | 136 | switch (pParam) |
137 | { | 137 | { |
138 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: | 138 | case Vehicle.ANGULAR_DEFLECTION_EFFICIENCY: |
@@ -229,8 +229,9 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
229 | } | 229 | } |
230 | }//end ProcessFloatVehicleParam | 230 | }//end ProcessFloatVehicleParam |
231 | 231 | ||
232 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue) | 232 | internal void ProcessVectorVehicleParam(Vehicle pParam, Vector3 pValue, float timestep) |
233 | { | 233 | { |
234 | DetailLog("{0},ProcessVectorVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); | ||
234 | switch (pParam) | 235 | switch (pParam) |
235 | { | 236 | { |
236 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: | 237 | case Vehicle.ANGULAR_FRICTION_TIMESCALE: |
@@ -265,6 +266,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
265 | 266 | ||
266 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) | 267 | internal void ProcessRotationVehicleParam(Vehicle pParam, Quaternion pValue) |
267 | { | 268 | { |
269 | DetailLog("{0},ProcessRotationalVehicleParam,param={1},val={2}", m_prim.LocalID, pParam, pValue); | ||
268 | switch (pParam) | 270 | switch (pParam) |
269 | { | 271 | { |
270 | case Vehicle.REFERENCE_FRAME: | 272 | case Vehicle.REFERENCE_FRAME: |
@@ -278,6 +280,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
278 | 280 | ||
279 | internal void ProcessVehicleFlags(int pParam, bool remove) | 281 | internal void ProcessVehicleFlags(int pParam, bool remove) |
280 | { | 282 | { |
283 | DetailLog("{0},ProcessVehicleFlags,param={1},remove={2}", m_prim.LocalID, pParam, remove); | ||
281 | if (remove) | 284 | if (remove) |
282 | { | 285 | { |
283 | if (pParam == -1) | 286 | if (pParam == -1) |
@@ -434,6 +437,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
434 | 437 | ||
435 | internal void ProcessTypeChange(Vehicle pType) | 438 | internal void ProcessTypeChange(Vehicle pType) |
436 | { | 439 | { |
440 | DetailLog("{0},ProcessTypeChange,type={1}", m_prim.LocalID, pType); | ||
437 | // Set Defaults For Type | 441 | // Set Defaults For Type |
438 | m_type = pType; | 442 | m_type = pType; |
439 | switch (pType) | 443 | switch (pType) |
@@ -594,11 +598,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
594 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); | 598 | m_flags |= (VehicleFlag.LIMIT_ROLL_ONLY); |
595 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); | 599 | m_Hoverflags |= (VehicleFlag.HOVER_GLOBAL_HEIGHT); |
596 | break; | 600 | break; |
597 | |||
598 | } | 601 | } |
599 | }//end SetDefaultsForType | 602 | }//end SetDefaultsForType |
600 | 603 | ||
601 | internal void Step(float pTimestep, BSScene pParentScene) | 604 | internal void Step(float pTimestep) |
602 | { | 605 | { |
603 | if (m_type == Vehicle.TYPE_NONE) return; | 606 | if (m_type == Vehicle.TYPE_NONE) return; |
604 | 607 | ||
@@ -606,21 +609,34 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
606 | if (frcount > 100) | 609 | if (frcount > 100) |
607 | frcount = 0; | 610 | frcount = 0; |
608 | 611 | ||
609 | MoveLinear(pTimestep, pParentScene); | 612 | MoveLinear(pTimestep); |
610 | MoveAngular(pTimestep); | 613 | MoveAngular(pTimestep); |
611 | LimitRotation(pTimestep); | 614 | LimitRotation(pTimestep); |
615 | |||
616 | DetailLog("{0},Dynamics,done,pos={1},force={2},velocity={3},angvel={4}", | ||
617 | m_prim.LocalID, m_prim.Position, m_prim.Force, m_prim.Velocity, m_prim.RotationalVelocity); | ||
612 | }// end Step | 618 | }// end Step |
613 | 619 | ||
614 | private void MoveLinear(float pTimestep, BSScene _pParentScene) | 620 | private void MoveLinear(float pTimestep) |
615 | { | 621 | { |
616 | if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) // requested m_linearMotorDirection is significant | 622 | // requested m_linearMotorDirection is significant |
623 | // if (!m_linearMotorDirection.ApproxEquals(Vector3.Zero, 0.01f)) | ||
624 | if (m_linearMotorDirection.LengthSquared() > 0.0001f) | ||
617 | { | 625 | { |
626 | Vector3 origDir = m_linearMotorDirection; | ||
627 | Vector3 origVel = m_lastLinearVelocityVector; | ||
628 | |||
618 | // add drive to body | 629 | // add drive to body |
619 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); | 630 | // Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale/pTimestep); |
620 | m_lastLinearVelocityVector += (addAmount*10); // lastLinearVelocityVector is the current body velocity vector? | 631 | Vector3 addAmount = m_linearMotorDirection/(m_linearMotorTimescale); |
632 | // lastLinearVelocityVector is the current body velocity vector? | ||
633 | // RA: Not sure what the *10 is for. A correction for pTimestep? | ||
634 | // m_lastLinearVelocityVector += (addAmount*10); | ||
635 | m_lastLinearVelocityVector += addAmount; | ||
621 | 636 | ||
622 | // This will work temporarily, but we really need to compare speed on an axis | 637 | // This will work temporarily, but we really need to compare speed on an axis |
623 | // KF: Limit body velocity to applied velocity? | 638 | // KF: Limit body velocity to applied velocity? |
639 | // Limit the velocity vector to less than the last set linear motor direction | ||
624 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) | 640 | if (Math.Abs(m_lastLinearVelocityVector.X) > Math.Abs(m_linearMotorDirectionLASTSET.X)) |
625 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; | 641 | m_lastLinearVelocityVector.X = m_linearMotorDirectionLASTSET.X; |
626 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) | 642 | if (Math.Abs(m_lastLinearVelocityVector.Y) > Math.Abs(m_linearMotorDirectionLASTSET.Y)) |
@@ -630,76 +646,93 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
630 | 646 | ||
631 | // decay applied velocity | 647 | // decay applied velocity |
632 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); | 648 | Vector3 decayfraction = ((Vector3.One/(m_linearMotorDecayTimescale/pTimestep))); |
633 | //Console.WriteLine("decay: " + decayfraction); | ||
634 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; | 649 | m_linearMotorDirection -= m_linearMotorDirection * decayfraction * 0.5f; |
635 | //Console.WriteLine("actual: " + m_linearMotorDirection); | 650 | |
651 | /* | ||
652 | Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/m_linearMotorTimescale; | ||
653 | m_lastLinearVelocityVector += addAmount; | ||
654 | |||
655 | float decayfraction = (1.0f - 1.0f / m_linearMotorDecayTimescale); | ||
656 | m_linearMotorDirection *= decayfraction; | ||
657 | |||
658 | */ | ||
659 | |||
660 | DetailLog("{0},MoveLinear,nonZero,origdir={1},origvel={2},add={3},decay={4},dir={5},vel={6}", | ||
661 | m_prim.LocalID, origDir, origVel, addAmount, decayfraction, m_linearMotorDirection, m_lastLinearVelocityVector); | ||
636 | } | 662 | } |
637 | else | 663 | else |
638 | { // requested is not significant | 664 | { |
639 | // if what remains of applied is small, zero it. | 665 | // if what remains of applied is small, zero it. |
640 | if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) | 666 | // if (m_lastLinearVelocityVector.ApproxEquals(Vector3.Zero, 0.01f)) |
641 | m_lastLinearVelocityVector = Vector3.Zero; | 667 | // m_lastLinearVelocityVector = Vector3.Zero; |
668 | m_linearMotorDirection = Vector3.Zero; | ||
669 | m_lastLinearVelocityVector = Vector3.Zero; | ||
642 | } | 670 | } |
643 | 671 | ||
644 | // convert requested object velocity to world-referenced vector | 672 | // convert requested object velocity to world-referenced vector |
645 | m_dir = m_lastLinearVelocityVector; | 673 | Quaternion rotq = m_prim.Orientation; |
646 | Quaternion rot = m_prim.Orientation; | 674 | m_dir = m_lastLinearVelocityVector * rotq; |
647 | Quaternion rotq = new Quaternion(rot.X, rot.Y, rot.Z, rot.W); // rotq = rotation of object | 675 | |
648 | m_dir *= rotq; // apply obj rotation to velocity vector | 676 | // Add the various forces into m_dir which will be our new direction vector (velocity) |
649 | 677 | ||
650 | // add Gravity andBuoyancy | 678 | // add Gravity and Buoyancy |
651 | // KF: So far I have found no good method to combine a script-requested | 679 | // KF: So far I have found no good method to combine a script-requested |
652 | // .Z velocity and gravity. Therefore only 0g will used script-requested | 680 | // .Z velocity and gravity. Therefore only 0g will used script-requested |
653 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. | 681 | // .Z velocity. >0g (m_VehicleBuoyancy < 1) will used modified gravity only. |
654 | Vector3 grav = Vector3.Zero; | 682 | Vector3 grav = Vector3.Zero; |
655 | // There is some gravity, make a gravity force vector | 683 | // There is some gravity, make a gravity force vector that is applied after object velocity. |
656 | // that is applied after object velocity. | ||
657 | float objMass = m_prim.Mass; | ||
658 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; | 684 | // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; |
659 | grav.Z = _pParentScene.DefaultGravity.Z * objMass * (1f - m_VehicleBuoyancy); | 685 | grav.Z = m_prim.Scene.DefaultGravity.Z * m_prim.Mass * (1f - m_VehicleBuoyancy); |
660 | // Preserve the current Z velocity | 686 | // Preserve the current Z velocity |
661 | Vector3 vel_now = m_prim.Velocity; | 687 | Vector3 vel_now = m_prim.Velocity; |
662 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity | 688 | m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity |
663 | 689 | ||
664 | Vector3 pos = m_prim.Position; | 690 | Vector3 pos = m_prim.Position; |
691 | Vector3 posChange = pos; | ||
665 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); | 692 | // Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f); |
666 | Vector3 posChange = new Vector3(); | ||
667 | posChange.X = pos.X - m_lastPositionVector.X; | ||
668 | posChange.Y = pos.Y - m_lastPositionVector.Y; | ||
669 | posChange.Z = pos.Z - m_lastPositionVector.Z; | ||
670 | double Zchange = Math.Abs(posChange.Z); | 693 | double Zchange = Math.Abs(posChange.Z); |
671 | if (m_BlockingEndPoint != Vector3.Zero) | 694 | if (m_BlockingEndPoint != Vector3.Zero) |
672 | { | 695 | { |
696 | bool changed = false; | ||
673 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) | 697 | if (pos.X >= (m_BlockingEndPoint.X - (float)1)) |
674 | { | 698 | { |
675 | pos.X -= posChange.X + 1; | 699 | pos.X -= posChange.X + 1; |
676 | m_prim.Position = pos; | 700 | changed = true; |
677 | } | 701 | } |
678 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) | 702 | if (pos.Y >= (m_BlockingEndPoint.Y - (float)1)) |
679 | { | 703 | { |
680 | pos.Y -= posChange.Y + 1; | 704 | pos.Y -= posChange.Y + 1; |
681 | m_prim.Position = pos; | 705 | changed = true; |
682 | } | 706 | } |
683 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) | 707 | if (pos.Z >= (m_BlockingEndPoint.Z - (float)1)) |
684 | { | 708 | { |
685 | pos.Z -= posChange.Z + 1; | 709 | pos.Z -= posChange.Z + 1; |
686 | m_prim.Position = pos; | 710 | changed = true; |
687 | } | 711 | } |
688 | if (pos.X <= 0) | 712 | if (pos.X <= 0) |
689 | { | 713 | { |
690 | pos.X += posChange.X + 1; | 714 | pos.X += posChange.X + 1; |
691 | m_prim.Position = pos; | 715 | changed = true; |
692 | } | 716 | } |
693 | if (pos.Y <= 0) | 717 | if (pos.Y <= 0) |
694 | { | 718 | { |
695 | pos.Y += posChange.Y + 1; | 719 | pos.Y += posChange.Y + 1; |
720 | changed = true; | ||
721 | } | ||
722 | if (changed) | ||
723 | { | ||
696 | m_prim.Position = pos; | 724 | m_prim.Position = pos; |
725 | DetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", | ||
726 | m_prim.LocalID, m_BlockingEndPoint, posChange, pos); | ||
697 | } | 727 | } |
698 | } | 728 | } |
699 | if (pos.Z < _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y)) | 729 | |
730 | // If below the terrain, move us above the ground a little. | ||
731 | if (pos.Z < m_prim.Scene.GetTerrainHeightAtXYZ(pos)) | ||
700 | { | 732 | { |
701 | pos.Z = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + 2; | 733 | pos.Z = m_prim.Scene.GetTerrainHeightAtXYZ(pos) + 2; |
702 | m_prim.Position = pos; | 734 | m_prim.Position = pos; |
735 | DetailLog("{0},MoveLinear,terrainHeight,pos={1}", m_prim.LocalID, pos); | ||
703 | } | 736 | } |
704 | 737 | ||
705 | // Check if hovering | 738 | // Check if hovering |
@@ -708,11 +741,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
708 | // We should hover, get the target height | 741 | // We should hover, get the target height |
709 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) | 742 | if ((m_Hoverflags & VehicleFlag.HOVER_WATER_ONLY) != 0) |
710 | { | 743 | { |
711 | m_VhoverTargetHeight = _pParentScene.GetWaterLevel() + m_VhoverHeight; | 744 | m_VhoverTargetHeight = m_prim.Scene.GetWaterLevel() + m_VhoverHeight; |
712 | } | 745 | } |
713 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) | 746 | if ((m_Hoverflags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) |
714 | { | 747 | { |
715 | m_VhoverTargetHeight = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; | 748 | m_VhoverTargetHeight = m_prim.Scene.GetTerrainHeightAtXY(pos.X, pos.Y) + m_VhoverHeight; |
716 | } | 749 | } |
717 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) | 750 | if ((m_Hoverflags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) |
718 | { | 751 | { |
@@ -746,6 +779,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
746 | } | 779 | } |
747 | } | 780 | } |
748 | 781 | ||
782 | DetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", m_prim.LocalID, pos, m_dir, m_VhoverHeight, m_VhoverTargetHeight); | ||
783 | |||
749 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped | 784 | // m_VhoverEfficiency = 0f; // 0=boucy, 1=Crit.damped |
750 | // m_VhoverTimescale = 0f; // time to acheive height | 785 | // m_VhoverTimescale = 0f; // time to acheive height |
751 | // pTimestep is time since last frame,in secs | 786 | // pTimestep is time since last frame,in secs |
@@ -774,12 +809,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
774 | { | 809 | { |
775 | grav.Z = (float)(grav.Z * 1.125); | 810 | grav.Z = (float)(grav.Z * 1.125); |
776 | } | 811 | } |
777 | float terraintemp = _pParentScene.GetTerrainHeightAtXY(pos.X, pos.Y); | 812 | float terraintemp = m_prim.Scene.GetTerrainHeightAtXYZ(pos); |
778 | float postemp = (pos.Z - terraintemp); | 813 | float postemp = (pos.Z - terraintemp); |
779 | if (postemp > 2.5f) | 814 | if (postemp > 2.5f) |
780 | { | 815 | { |
781 | grav.Z = (float)(grav.Z * 1.037125); | 816 | grav.Z = (float)(grav.Z * 1.037125); |
782 | } | 817 | } |
818 | DetailLog("{0},MoveLinear,limitMotorUp,grav={1}", m_prim.LocalID, grav); | ||
783 | //End Experimental Values | 819 | //End Experimental Values |
784 | } | 820 | } |
785 | if ((m_flags & (VehicleFlag.NO_X)) != 0) | 821 | if ((m_flags & (VehicleFlag.NO_X)) != 0) |
@@ -800,32 +836,39 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
800 | // Apply velocity | 836 | // Apply velocity |
801 | m_prim.Velocity = m_dir; | 837 | m_prim.Velocity = m_dir; |
802 | // apply gravity force | 838 | // apply gravity force |
803 | m_prim.Force = grav; | 839 | // Why is this set here? The physics engine already does gravity. |
804 | 840 | // m_prim.AddForce(grav, false); | |
841 | // m_prim.Force = grav; | ||
805 | 842 | ||
806 | // apply friction | 843 | // Apply friction |
807 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); | 844 | Vector3 decayamount = Vector3.One / (m_linearFrictionTimescale / pTimestep); |
808 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; | 845 | m_lastLinearVelocityVector -= m_lastLinearVelocityVector * decayamount; |
846 | |||
847 | DetailLog("{0},MoveLinear,done,pos={1},vel={2},force={3},decay={4}", | ||
848 | m_prim.LocalID, m_lastPositionVector, m_dir, grav, decayamount); | ||
849 | |||
809 | } // end MoveLinear() | 850 | } // end MoveLinear() |
810 | 851 | ||
811 | private void MoveAngular(float pTimestep) | 852 | private void MoveAngular(float pTimestep) |
812 | { | 853 | { |
813 | /* | 854 | // m_angularMotorDirection // angular velocity requested by LSL motor |
814 | private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor | 855 | // m_angularMotorApply // application frame counter |
815 | private int m_angularMotorApply = 0; // application frame counter | 856 | // m_angularMotorVelocity // current angular motor velocity (ramps up and down) |
816 | private float m_angularMotorVelocity = 0; // current angular motor velocity (ramps up and down) | 857 | // m_angularMotorTimescale // motor angular velocity ramp up rate |
817 | private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate | 858 | // m_angularMotorDecayTimescale // motor angular velocity decay rate |
818 | private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate | 859 | // m_angularFrictionTimescale // body angular velocity decay rate |
819 | private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate | 860 | // m_lastAngularVelocity // what was last applied to body |
820 | private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body | ||
821 | */ | ||
822 | 861 | ||
823 | // Get what the body is doing, this includes 'external' influences | 862 | // Get what the body is doing, this includes 'external' influences |
824 | Vector3 angularVelocity = m_prim.RotationalVelocity; | 863 | Vector3 angularVelocity = m_prim.RotationalVelocity; |
825 | // Vector3 angularVelocity = Vector3.Zero; | ||
826 | 864 | ||
827 | if (m_angularMotorApply > 0) | 865 | if (m_angularMotorApply > 0) |
828 | { | 866 | { |
867 | // Rather than snapping the angular motor velocity from the old value to | ||
868 | // a newly set velocity, this routine steps the value from the previous | ||
869 | // value (m_angularMotorVelocity) to the requested value (m_angularMotorDirection). | ||
870 | // There are m_angularMotorApply steps. | ||
871 | Vector3 origAngularVelocity = m_angularMotorVelocity; | ||
829 | // ramp up to new value | 872 | // ramp up to new value |
830 | // current velocity += error / (time to get there / step interval) | 873 | // current velocity += error / (time to get there / step interval) |
831 | // requested speed - last motor speed | 874 | // requested speed - last motor speed |
@@ -833,23 +876,21 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
833 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); | 876 | m_angularMotorVelocity.Y += (m_angularMotorDirection.Y - m_angularMotorVelocity.Y) / (m_angularMotorTimescale / pTimestep); |
834 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); | 877 | m_angularMotorVelocity.Z += (m_angularMotorDirection.Z - m_angularMotorVelocity.Z) / (m_angularMotorTimescale / pTimestep); |
835 | 878 | ||
879 | DetailLog("{0},MoveAngular,angularMotorApply,apply={1},origvel={2},dir={3},vel={4}", | ||
880 | m_prim.LocalID,m_angularMotorApply,origAngularVelocity, m_angularMotorDirection, m_angularMotorVelocity); | ||
881 | |||
836 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected | 882 | m_angularMotorApply--; // This is done so that if script request rate is less than phys frame rate the expected |
837 | // velocity may still be acheived. | 883 | // velocity may still be acheived. |
838 | } | 884 | } |
839 | else | 885 | else |
840 | { | 886 | { |
841 | // no motor recently applied, keep the body velocity | 887 | // No motor recently applied, keep the body velocity |
842 | /* m_angularMotorVelocity.X = angularVelocity.X; | ||
843 | m_angularMotorVelocity.Y = angularVelocity.Y; | ||
844 | m_angularMotorVelocity.Z = angularVelocity.Z; */ | ||
845 | |||
846 | // and decay the velocity | 888 | // and decay the velocity |
847 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); | 889 | m_angularMotorVelocity -= m_angularMotorVelocity / (m_angularMotorDecayTimescale / pTimestep); |
848 | } // end motor section | 890 | } // end motor section |
849 | 891 | ||
850 | // Vertical attractor section | 892 | // Vertical attractor section |
851 | Vector3 vertattr = Vector3.Zero; | 893 | Vector3 vertattr = Vector3.Zero; |
852 | |||
853 | if (m_verticalAttractionTimescale < 300) | 894 | if (m_verticalAttractionTimescale < 300) |
854 | { | 895 | { |
855 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); | 896 | float VAservo = 0.2f / (m_verticalAttractionTimescale * pTimestep); |
@@ -871,7 +912,6 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
871 | // Error is 0 (no error) to +/- 2 (max error) | 912 | // Error is 0 (no error) to +/- 2 (max error) |
872 | // scale it by VAservo | 913 | // scale it by VAservo |
873 | verterr = verterr * VAservo; | 914 | verterr = verterr * VAservo; |
874 | //if (frcount == 0) Console.WriteLine("VAerr=" + verterr); | ||
875 | 915 | ||
876 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so | 916 | // As the body rotates around the X axis, then verterr.Y increases; Rotated around Y then .X increases, so |
877 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. | 917 | // Change Body angular velocity X based on Y, and Y based on X. Z is not changed. |
@@ -884,11 +924,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
884 | vertattr.X += bounce * angularVelocity.X; | 924 | vertattr.X += bounce * angularVelocity.X; |
885 | vertattr.Y += bounce * angularVelocity.Y; | 925 | vertattr.Y += bounce * angularVelocity.Y; |
886 | 926 | ||
927 | DetailLog("{0},MoveAngular,verticalAttraction,verterr={1},bounce={2},vertattr={3}", | ||
928 | m_prim.LocalID, verterr, bounce, vertattr); | ||
929 | |||
887 | } // else vertical attractor is off | 930 | } // else vertical attractor is off |
888 | 931 | ||
889 | // m_lastVertAttractor = vertattr; | 932 | // m_lastVertAttractor = vertattr; |
890 | 933 | ||
891 | // Bank section tba | 934 | // Bank section tba |
935 | |||
892 | // Deflection section tba | 936 | // Deflection section tba |
893 | 937 | ||
894 | // Sum velocities | 938 | // Sum velocities |
@@ -898,11 +942,13 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
898 | { | 942 | { |
899 | m_lastAngularVelocity.X = 0; | 943 | m_lastAngularVelocity.X = 0; |
900 | m_lastAngularVelocity.Y = 0; | 944 | m_lastAngularVelocity.Y = 0; |
945 | DetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); | ||
901 | } | 946 | } |
902 | 947 | ||
903 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) | 948 | if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) |
904 | { | 949 | { |
905 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. | 950 | m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. |
951 | DetailLog("{0},MoveAngular,zeroSmallValues,lastAngular={1}", m_prim.LocalID, m_lastAngularVelocity); | ||
906 | } | 952 | } |
907 | 953 | ||
908 | // apply friction | 954 | // apply friction |
@@ -912,10 +958,12 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
912 | // Apply to the body | 958 | // Apply to the body |
913 | m_prim.RotationalVelocity = m_lastAngularVelocity; | 959 | m_prim.RotationalVelocity = m_lastAngularVelocity; |
914 | 960 | ||
961 | DetailLog("{0},MoveAngular,done,decay={1},lastAngular={2}", m_prim.LocalID, decayamount, m_lastAngularVelocity); | ||
915 | } //end MoveAngular | 962 | } //end MoveAngular |
963 | |||
916 | internal void LimitRotation(float timestep) | 964 | internal void LimitRotation(float timestep) |
917 | { | 965 | { |
918 | Quaternion rotq = m_prim.Orientation; // rotq = rotation of object | 966 | Quaternion rotq = m_prim.Orientation; |
919 | Quaternion m_rot = rotq; | 967 | Quaternion m_rot = rotq; |
920 | bool changed = false; | 968 | bool changed = false; |
921 | if (m_RollreferenceFrame != Quaternion.Identity) | 969 | if (m_RollreferenceFrame != Quaternion.Identity) |
@@ -923,18 +971,22 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
923 | if (rotq.X >= m_RollreferenceFrame.X) | 971 | if (rotq.X >= m_RollreferenceFrame.X) |
924 | { | 972 | { |
925 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); | 973 | m_rot.X = rotq.X - (m_RollreferenceFrame.X / 2); |
974 | changed = true; | ||
926 | } | 975 | } |
927 | if (rotq.Y >= m_RollreferenceFrame.Y) | 976 | if (rotq.Y >= m_RollreferenceFrame.Y) |
928 | { | 977 | { |
929 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); | 978 | m_rot.Y = rotq.Y - (m_RollreferenceFrame.Y / 2); |
979 | changed = true; | ||
930 | } | 980 | } |
931 | if (rotq.X <= -m_RollreferenceFrame.X) | 981 | if (rotq.X <= -m_RollreferenceFrame.X) |
932 | { | 982 | { |
933 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); | 983 | m_rot.X = rotq.X + (m_RollreferenceFrame.X / 2); |
984 | changed = true; | ||
934 | } | 985 | } |
935 | if (rotq.Y <= -m_RollreferenceFrame.Y) | 986 | if (rotq.Y <= -m_RollreferenceFrame.Y) |
936 | { | 987 | { |
937 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); | 988 | m_rot.Y = rotq.Y + (m_RollreferenceFrame.Y / 2); |
989 | changed = true; | ||
938 | } | 990 | } |
939 | changed = true; | 991 | changed = true; |
940 | } | 992 | } |
@@ -944,8 +996,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin | |||
944 | m_rot.Y = 0; | 996 | m_rot.Y = 0; |
945 | changed = true; | 997 | changed = true; |
946 | } | 998 | } |
999 | if ((m_flags & VehicleFlag.LOCK_ROTATION) != 0) | ||
1000 | { | ||
1001 | m_rot.X = 0; | ||
1002 | m_rot.Y = 0; | ||
1003 | changed = true; | ||
1004 | } | ||
947 | if (changed) | 1005 | if (changed) |
948 | m_prim.Orientation = m_rot; | 1006 | m_prim.Orientation = m_rot; |
1007 | |||
1008 | DetailLog("{0},LimitRotation,done,changed={1},orig={2},new={3}", m_prim.LocalID, changed, rotq, m_rot); | ||
1009 | } | ||
1010 | |||
1011 | // Invoke the detailed logger and output something if it's enabled. | ||
1012 | private void DetailLog(string msg, params Object[] args) | ||
1013 | { | ||
1014 | if (m_prim.Scene.VehicleLoggingEnabled) | ||
1015 | m_prim.Scene.PhysicsLogging.Write(msg, args); | ||
949 | } | 1016 | } |
950 | } | 1017 | } |
951 | } | 1018 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs index 130f1ca..71a4303 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs | |||
@@ -42,6 +42,8 @@ public sealed class BSPrim : PhysicsActor | |||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | private static readonly string LogHeader = "[BULLETS PRIM]"; | 43 | private static readonly string LogHeader = "[BULLETS PRIM]"; |
44 | 44 | ||
45 | private void DebugLog(string mm, params Object[] xx) { if (_scene.shouldDebugLog) m_log.DebugFormat(mm, xx); } | ||
46 | |||
45 | private IMesh _mesh; | 47 | private IMesh _mesh; |
46 | private PrimitiveBaseShape _pbs; | 48 | private PrimitiveBaseShape _pbs; |
47 | private ShapeData.PhysicsShapeType _shapeType; | 49 | private ShapeData.PhysicsShapeType _shapeType; |
@@ -50,6 +52,7 @@ public sealed class BSPrim : PhysicsActor | |||
50 | private List<ConvexResult> _hulls; | 52 | private List<ConvexResult> _hulls; |
51 | 53 | ||
52 | private BSScene _scene; | 54 | private BSScene _scene; |
55 | public BSScene Scene { get { return _scene; } } | ||
53 | private String _avName; | 56 | private String _avName; |
54 | private uint _localID = 0; | 57 | private uint _localID = 0; |
55 | 58 | ||
@@ -86,8 +89,8 @@ public sealed class BSPrim : PhysicsActor | |||
86 | private bool _kinematic; | 89 | private bool _kinematic; |
87 | private float _buoyancy; | 90 | private float _buoyancy; |
88 | 91 | ||
89 | private List<BSPrim> _childrenPrims; | ||
90 | private BSPrim _parentPrim; | 92 | private BSPrim _parentPrim; |
93 | private List<BSPrim> _childrenPrims; | ||
91 | 94 | ||
92 | private int _subscribedEventsMs = 0; | 95 | private int _subscribedEventsMs = 0; |
93 | private int _nextCollisionOkTime = 0; | 96 | private int _nextCollisionOkTime = 0; |
@@ -145,9 +148,19 @@ public sealed class BSPrim : PhysicsActor | |||
145 | public void Destroy() | 148 | public void Destroy() |
146 | { | 149 | { |
147 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); | 150 | // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); |
151 | // DetailLog("{0},Destroy", LocalID); | ||
148 | // Undo any vehicle properties | 152 | // Undo any vehicle properties |
149 | _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); | 153 | _vehicle.ProcessTypeChange(Vehicle.TYPE_NONE); |
150 | _scene.RemoveVehiclePrim(this); // just to make sure | 154 | _scene.RemoveVehiclePrim(this); // just to make sure |
155 | |||
156 | // undo any dependance with/on other objects | ||
157 | if (_parentPrim != null) | ||
158 | { | ||
159 | // If I'm someone's child, tell them to forget about me. | ||
160 | _parentPrim.RemoveChildFromLinkset(this); | ||
161 | _parentPrim = null; | ||
162 | } | ||
163 | |||
151 | _scene.TaintedObject(delegate() | 164 | _scene.TaintedObject(delegate() |
152 | { | 165 | { |
153 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. | 166 | // everything in the C# world will get garbage collected. Tell the C++ world to free stuff. |
@@ -202,7 +215,8 @@ public sealed class BSPrim : PhysicsActor | |||
202 | // link me to the specified parent | 215 | // link me to the specified parent |
203 | public override void link(PhysicsActor obj) { | 216 | public override void link(PhysicsActor obj) { |
204 | BSPrim parent = obj as BSPrim; | 217 | BSPrim parent = obj as BSPrim; |
205 | // m_log.DebugFormat("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); | 218 | DebugLog("{0}: link {1}/{2} to {3}", LogHeader, _avName, _localID, obj.LocalID); |
219 | DetailLog("{0},link,parent={1}", LocalID, obj.LocalID); | ||
206 | // TODO: decide if this parent checking needs to happen at taint time | 220 | // TODO: decide if this parent checking needs to happen at taint time |
207 | if (_parentPrim == null) | 221 | if (_parentPrim == null) |
208 | { | 222 | { |
@@ -225,7 +239,7 @@ public sealed class BSPrim : PhysicsActor | |||
225 | else | 239 | else |
226 | { | 240 | { |
227 | // asking to reparent a prim should not happen | 241 | // asking to reparent a prim should not happen |
228 | m_log.ErrorFormat("{0}: Reparenting a prim. ", LogHeader); | 242 | m_log.ErrorFormat("{0}: link(): Reparenting a prim. ", LogHeader); |
229 | } | 243 | } |
230 | } | 244 | } |
231 | } | 245 | } |
@@ -236,7 +250,9 @@ public sealed class BSPrim : PhysicsActor | |||
236 | public override void delink() { | 250 | public override void delink() { |
237 | // TODO: decide if this parent checking needs to happen at taint time | 251 | // TODO: decide if this parent checking needs to happen at taint time |
238 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen | 252 | // Race condition here: if link() and delink() in same simulation tick, the delink will not happen |
239 | // m_log.DebugFormat("{0}: delink {1}/{2}", LogHeader, _avName, _localID); | 253 | DebugLog("{0}: delink {1}/{2}. Parent={3}", LogHeader, _avName, _localID, |
254 | (_parentPrim==null ? "NULL" : _parentPrim._avName+"/"+_parentPrim.LocalID.ToString())); | ||
255 | DetailLog("{0},delink,parent={1}", LocalID, (_parentPrim==null ? "NULL" : _parentPrim.LocalID.ToString())); | ||
240 | if (_parentPrim != null) | 256 | if (_parentPrim != null) |
241 | { | 257 | { |
242 | _parentPrim.RemoveChildFromLinkset(this); | 258 | _parentPrim.RemoveChildFromLinkset(this); |
@@ -252,8 +268,10 @@ public sealed class BSPrim : PhysicsActor | |||
252 | { | 268 | { |
253 | if (!_childrenPrims.Contains(child)) | 269 | if (!_childrenPrims.Contains(child)) |
254 | { | 270 | { |
271 | DebugLog("{0}: AddChildToLinkset: adding child {1} to {2}", LogHeader, child.LocalID, this.LocalID); | ||
272 | DetailLog("{0},AddChildToLinkset,child={1}", LocalID, pchild.LocalID); | ||
255 | _childrenPrims.Add(child); | 273 | _childrenPrims.Add(child); |
256 | child.ParentPrim = this; // the child has gained a parent | 274 | child._parentPrim = this; // the child has gained a parent |
257 | RecreateGeomAndObject(); // rebuild my shape with the new child added | 275 | RecreateGeomAndObject(); // rebuild my shape with the new child added |
258 | } | 276 | } |
259 | }); | 277 | }); |
@@ -269,9 +287,14 @@ public sealed class BSPrim : PhysicsActor | |||
269 | { | 287 | { |
270 | if (_childrenPrims.Contains(child)) | 288 | if (_childrenPrims.Contains(child)) |
271 | { | 289 | { |
272 | BulletSimAPI.RemoveConstraint(_scene.WorldID, child.LocalID, this.LocalID); | 290 | DebugLog("{0}: RemoveChildFromLinkset: Removing constraint to {1}", LogHeader, child.LocalID); |
291 | DetailLog("{0},RemoveChildToLinkset,child={1}", LocalID, pchild.LocalID); | ||
292 | if (!BulletSimAPI.RemoveConstraintByID(_scene.WorldID, child.LocalID)) | ||
293 | { | ||
294 | m_log.ErrorFormat("{0}: RemoveChildFromLinkset: Failed remove constraint for {1}", LogHeader, child.LocalID); | ||
295 | } | ||
273 | _childrenPrims.Remove(child); | 296 | _childrenPrims.Remove(child); |
274 | child.ParentPrim = null; // the child has lost its parent | 297 | child._parentPrim = null; // the child has lost its parent |
275 | RecreateGeomAndObject(); // rebuild my shape with the child removed | 298 | RecreateGeomAndObject(); // rebuild my shape with the child removed |
276 | } | 299 | } |
277 | else | 300 | else |
@@ -282,11 +305,6 @@ public sealed class BSPrim : PhysicsActor | |||
282 | return; | 305 | return; |
283 | } | 306 | } |
284 | 307 | ||
285 | public BSPrim ParentPrim | ||
286 | { | ||
287 | set { _parentPrim = value; } | ||
288 | } | ||
289 | |||
290 | // return true if we are the root of a linkset (there are children to manage) | 308 | // return true if we are the root of a linkset (there are children to manage) |
291 | public bool IsRootOfLinkset | 309 | public bool IsRootOfLinkset |
292 | { | 310 | { |
@@ -304,20 +322,28 @@ public sealed class BSPrim : PhysicsActor | |||
304 | base.RequestPhysicsterseUpdate(); | 322 | base.RequestPhysicsterseUpdate(); |
305 | } | 323 | } |
306 | 324 | ||
307 | public override void LockAngularMotion(OMV.Vector3 axis) { return; } | 325 | public override void LockAngularMotion(OMV.Vector3 axis) |
326 | { | ||
327 | DetailLog("{0},LockAngularMotion,call,axis={1}", LocalID, axis); | ||
328 | return; | ||
329 | } | ||
308 | 330 | ||
309 | public override OMV.Vector3 Position { | 331 | public override OMV.Vector3 Position { |
310 | get { | 332 | get { |
311 | // don't do the following GetObjectPosition because this function is called a zillion times | 333 | // child prims move around based on their parent. Need to get the latest location |
334 | if (_parentPrim != null) | ||
335 | _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | ||
336 | // don't do the GetObjectPosition for root elements because this function is called a zillion times | ||
312 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 337 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
313 | return _position; | 338 | return _position; |
314 | } | 339 | } |
315 | set { | 340 | set { |
316 | _position = value; | 341 | _position = value; |
342 | // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint? | ||
317 | _scene.TaintedObject(delegate() | 343 | _scene.TaintedObject(delegate() |
318 | { | 344 | { |
345 | DetailLog("{0},SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
319 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 346 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
320 | // m_log.DebugFormat("{0}: setPosition: id={1}, position={2}", LogHeader, _localID, _position); | ||
321 | }); | 347 | }); |
322 | } | 348 | } |
323 | } | 349 | } |
@@ -330,6 +356,7 @@ public sealed class BSPrim : PhysicsActor | |||
330 | _force = value; | 356 | _force = value; |
331 | _scene.TaintedObject(delegate() | 357 | _scene.TaintedObject(delegate() |
332 | { | 358 | { |
359 | DetailLog("{0},SetForce,taint,force={1}", LocalID, _force); | ||
333 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | 360 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); |
334 | }); | 361 | }); |
335 | } | 362 | } |
@@ -341,15 +368,23 @@ public sealed class BSPrim : PhysicsActor | |||
341 | } | 368 | } |
342 | set { | 369 | set { |
343 | Vehicle type = (Vehicle)value; | 370 | Vehicle type = (Vehicle)value; |
344 | _vehicle.ProcessTypeChange(type); | ||
345 | _scene.TaintedObject(delegate() | 371 | _scene.TaintedObject(delegate() |
346 | { | 372 | { |
373 | DetailLog("{0},SetVehicleType,taint,type={1}", LocalID, type); | ||
374 | _vehicle.ProcessTypeChange(type); | ||
347 | if (type == Vehicle.TYPE_NONE) | 375 | if (type == Vehicle.TYPE_NONE) |
348 | { | 376 | { |
349 | _scene.RemoveVehiclePrim(this); | 377 | _scene.RemoveVehiclePrim(this); |
350 | } | 378 | } |
351 | else | 379 | else |
352 | { | 380 | { |
381 | _scene.TaintedObject(delegate() | ||
382 | { | ||
383 | // Tell the physics engine to clear state | ||
384 | IntPtr obj = BulletSimAPI.GetBodyHandleWorldID2(_scene.WorldID, LocalID); | ||
385 | BulletSimAPI.ClearForces2(obj); | ||
386 | }); | ||
387 | |||
353 | // make it so the scene will call us each tick to do vehicle things | 388 | // make it so the scene will call us each tick to do vehicle things |
354 | _scene.AddVehiclePrim(this); | 389 | _scene.AddVehiclePrim(this); |
355 | } | 390 | } |
@@ -359,37 +394,52 @@ public sealed class BSPrim : PhysicsActor | |||
359 | } | 394 | } |
360 | public override void VehicleFloatParam(int param, float value) | 395 | public override void VehicleFloatParam(int param, float value) |
361 | { | 396 | { |
362 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value); | 397 | m_log.DebugFormat("{0} VehicleFloatParam. {1} <= {2}", LogHeader, param, value); |
398 | _scene.TaintedObject(delegate() | ||
399 | { | ||
400 | _vehicle.ProcessFloatVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | ||
401 | }); | ||
363 | } | 402 | } |
364 | public override void VehicleVectorParam(int param, OMV.Vector3 value) | 403 | public override void VehicleVectorParam(int param, OMV.Vector3 value) |
365 | { | 404 | { |
366 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value); | 405 | m_log.DebugFormat("{0} VehicleVectorParam. {1} <= {2}", LogHeader, param, value); |
406 | _scene.TaintedObject(delegate() | ||
407 | { | ||
408 | _vehicle.ProcessVectorVehicleParam((Vehicle)param, value, _scene.LastSimulatedTimestep); | ||
409 | }); | ||
367 | } | 410 | } |
368 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) | 411 | public override void VehicleRotationParam(int param, OMV.Quaternion rotation) |
369 | { | 412 | { |
370 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | 413 | m_log.DebugFormat("{0} VehicleRotationParam. {1} <= {2}", LogHeader, param, rotation); |
414 | _scene.TaintedObject(delegate() | ||
415 | { | ||
416 | _vehicle.ProcessRotationVehicleParam((Vehicle)param, rotation); | ||
417 | }); | ||
371 | } | 418 | } |
372 | public override void VehicleFlags(int param, bool remove) | 419 | public override void VehicleFlags(int param, bool remove) |
373 | { | 420 | { |
374 | _vehicle.ProcessVehicleFlags(param, remove); | 421 | m_log.DebugFormat("{0} VehicleFlags. {1}. Remove={2}", LogHeader, param, remove); |
422 | _scene.TaintedObject(delegate() | ||
423 | { | ||
424 | _vehicle.ProcessVehicleFlags(param, remove); | ||
425 | }); | ||
375 | } | 426 | } |
376 | // Called each simulation step to advance vehicle characteristics | 427 | |
428 | // Called each simulation step to advance vehicle characteristics. | ||
429 | // Called from Scene when doing simulation step so we're in taint processing time. | ||
377 | public void StepVehicle(float timeStep) | 430 | public void StepVehicle(float timeStep) |
378 | { | 431 | { |
379 | _vehicle.Step(timeStep, _scene); | 432 | _vehicle.Step(timeStep); |
380 | } | 433 | } |
381 | 434 | ||
382 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more | 435 | // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more |
383 | public override void SetVolumeDetect(int param) { | 436 | public override void SetVolumeDetect(int param) { |
384 | bool newValue = (param != 0); | 437 | bool newValue = (param != 0); |
385 | if (_isVolumeDetect != newValue) | 438 | _isVolumeDetect = newValue; |
439 | _scene.TaintedObject(delegate() | ||
386 | { | 440 | { |
387 | _isVolumeDetect = newValue; | 441 | SetObjectDynamic(); |
388 | _scene.TaintedObject(delegate() | 442 | }); |
389 | { | ||
390 | SetObjectDynamic(); | ||
391 | }); | ||
392 | } | ||
393 | return; | 443 | return; |
394 | } | 444 | } |
395 | 445 | ||
@@ -397,9 +447,11 @@ public sealed class BSPrim : PhysicsActor | |||
397 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } | 447 | public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } |
398 | public override OMV.Vector3 Velocity { | 448 | public override OMV.Vector3 Velocity { |
399 | get { return _velocity; } | 449 | get { return _velocity; } |
400 | set { _velocity = value; | 450 | set { |
451 | _velocity = value; | ||
401 | _scene.TaintedObject(delegate() | 452 | _scene.TaintedObject(delegate() |
402 | { | 453 | { |
454 | DetailLog("{0},SetVelocity,taint,vel={1}", LocalID, _velocity); | ||
403 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); | 455 | BulletSimAPI.SetObjectVelocity(_scene.WorldID, LocalID, _velocity); |
404 | }); | 456 | }); |
405 | } | 457 | } |
@@ -407,6 +459,7 @@ public sealed class BSPrim : PhysicsActor | |||
407 | public override OMV.Vector3 Torque { | 459 | public override OMV.Vector3 Torque { |
408 | get { return _torque; } | 460 | get { return _torque; } |
409 | set { _torque = value; | 461 | set { _torque = value; |
462 | DetailLog("{0},SetTorque,call,torque={1}", LocalID, _torque); | ||
410 | } | 463 | } |
411 | } | 464 | } |
412 | public override float CollisionScore { | 465 | public override float CollisionScore { |
@@ -419,13 +472,21 @@ public sealed class BSPrim : PhysicsActor | |||
419 | set { _acceleration = value; } | 472 | set { _acceleration = value; } |
420 | } | 473 | } |
421 | public override OMV.Quaternion Orientation { | 474 | public override OMV.Quaternion Orientation { |
422 | get { return _orientation; } | 475 | get { |
476 | if (_parentPrim != null) | ||
477 | { | ||
478 | // children move around because tied to parent. Get a fresh value. | ||
479 | _orientation = BulletSimAPI.GetObjectOrientation(_scene.WorldID, LocalID); | ||
480 | } | ||
481 | return _orientation; | ||
482 | } | ||
423 | set { | 483 | set { |
424 | _orientation = value; | 484 | _orientation = value; |
425 | // m_log.DebugFormat("{0}: set orientation: id={1}, ori={2}", LogHeader, LocalID, _orientation); | 485 | // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? |
426 | _scene.TaintedObject(delegate() | 486 | _scene.TaintedObject(delegate() |
427 | { | 487 | { |
428 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); | 488 | // _position = BulletSimAPI.GetObjectPosition(_scene.WorldID, _localID); |
489 | DetailLog("{0},SetOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); | ||
429 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); | 490 | BulletSimAPI.SetObjectTranslation(_scene.WorldID, _localID, _position, _orientation); |
430 | }); | 491 | }); |
431 | } | 492 | } |
@@ -458,8 +519,9 @@ public sealed class BSPrim : PhysicsActor | |||
458 | get { return !IsPhantom && !_isVolumeDetect; } | 519 | get { return !IsPhantom && !_isVolumeDetect; } |
459 | } | 520 | } |
460 | 521 | ||
461 | // make gravity work if the object is physical and not selected | 522 | // Make gravity work if the object is physical and not selected |
462 | // no locking here because only called when it is safe | 523 | // No locking here because only called when it is safe |
524 | // Only called at taint time so it is save to call into Bullet. | ||
463 | private void SetObjectDynamic() | 525 | private void SetObjectDynamic() |
464 | { | 526 | { |
465 | // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); | 527 | // m_log.DebugFormat("{0}: ID={1}, SetObjectDynamic: IsStatic={2}, IsSolid={3}", LogHeader, _localID, IsStatic, IsSolid); |
@@ -476,6 +538,7 @@ public sealed class BSPrim : PhysicsActor | |||
476 | RecreateGeomAndObject(); | 538 | RecreateGeomAndObject(); |
477 | 539 | ||
478 | } | 540 | } |
541 | DetailLog("{0},SetObjectDynamic,taint,static={1},solid={2},mass={3}", LocalID, IsStatic, IsSolid, _mass); | ||
479 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); | 542 | BulletSimAPI.SetObjectProperties(_scene.WorldID, LocalID, IsStatic, IsSolid, SubscribedEvents(), _mass); |
480 | } | 543 | } |
481 | 544 | ||
@@ -516,11 +579,24 @@ public sealed class BSPrim : PhysicsActor | |||
516 | set { _floatOnWater = value; } | 579 | set { _floatOnWater = value; } |
517 | } | 580 | } |
518 | public override OMV.Vector3 RotationalVelocity { | 581 | public override OMV.Vector3 RotationalVelocity { |
519 | get { return _rotationalVelocity; } | 582 | get { |
520 | set { _rotationalVelocity = value; | 583 | /* |
584 | OMV.Vector3 pv = OMV.Vector3.Zero; | ||
585 | // if close to zero, report zero | ||
586 | // This is copied from ODE but I'm not sure why it returns zero but doesn't | ||
587 | // zero the property in the physics engine. | ||
588 | if (_rotationalVelocity.ApproxEquals(pv, 0.2f)) | ||
589 | return pv; | ||
590 | */ | ||
591 | |||
592 | return _rotationalVelocity; | ||
593 | } | ||
594 | set { | ||
595 | _rotationalVelocity = value; | ||
521 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); | 596 | // m_log.DebugFormat("{0}: RotationalVelocity={1}", LogHeader, _rotationalVelocity); |
522 | _scene.TaintedObject(delegate() | 597 | _scene.TaintedObject(delegate() |
523 | { | 598 | { |
599 | DetailLog("{0},SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); | ||
524 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); | 600 | BulletSimAPI.SetObjectAngularVelocity(_scene.WorldID, LocalID, _rotationalVelocity); |
525 | }); | 601 | }); |
526 | } | 602 | } |
@@ -533,11 +609,13 @@ public sealed class BSPrim : PhysicsActor | |||
533 | } | 609 | } |
534 | public override float Buoyancy { | 610 | public override float Buoyancy { |
535 | get { return _buoyancy; } | 611 | get { return _buoyancy; } |
536 | set { _buoyancy = value; | 612 | set { |
537 | _scene.TaintedObject(delegate() | 613 | _buoyancy = value; |
538 | { | 614 | _scene.TaintedObject(delegate() |
539 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | 615 | { |
540 | }); | 616 | DetailLog("{0},SetBuoyancy,taint,buoy={1}", LocalID, _buoyancy); |
617 | BulletSimAPI.SetObjectBuoyancy(_scene.WorldID, _localID, _buoyancy); | ||
618 | }); | ||
541 | } | 619 | } |
542 | } | 620 | } |
543 | 621 | ||
@@ -573,27 +651,45 @@ public sealed class BSPrim : PhysicsActor | |||
573 | public override float APIDStrength { set { return; } } | 651 | public override float APIDStrength { set { return; } } |
574 | public override float APIDDamping { set { return; } } | 652 | public override float APIDDamping { set { return; } } |
575 | 653 | ||
654 | private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>(); | ||
576 | public override void AddForce(OMV.Vector3 force, bool pushforce) { | 655 | public override void AddForce(OMV.Vector3 force, bool pushforce) { |
577 | if (force.IsFinite()) | 656 | if (force.IsFinite()) |
578 | { | 657 | { |
579 | _force.X += force.X; | 658 | // _force += force; |
580 | _force.Y += force.Y; | 659 | lock (m_accumulatedForces) |
581 | _force.Z += force.Z; | 660 | m_accumulatedForces.Add(new OMV.Vector3(force)); |
582 | } | 661 | } |
583 | else | 662 | else |
584 | { | 663 | { |
585 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); | 664 | m_log.WarnFormat("{0}: Got a NaN force applied to a Character", LogHeader); |
665 | return; | ||
586 | } | 666 | } |
587 | _scene.TaintedObject(delegate() | 667 | _scene.TaintedObject(delegate() |
588 | { | 668 | { |
589 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, _force); | 669 | lock (m_accumulatedForces) |
670 | { | ||
671 | if (m_accumulatedForces.Count > 0) | ||
672 | { | ||
673 | OMV.Vector3 fSum = OMV.Vector3.Zero; | ||
674 | foreach (OMV.Vector3 v in m_accumulatedForces) | ||
675 | { | ||
676 | fSum += v; | ||
677 | } | ||
678 | m_accumulatedForces.Clear(); | ||
679 | |||
680 | DetailLog("{0},SetObjectForce,taint,force={1}", LocalID, fSum); | ||
681 | BulletSimAPI.SetObjectForce(_scene.WorldID, _localID, fSum); | ||
682 | } | ||
683 | } | ||
590 | }); | 684 | }); |
591 | } | 685 | } |
592 | 686 | ||
593 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { | 687 | public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { |
688 | DetailLog("{0},AddAngularForce,call,angForce={1},push={2}", LocalID, force, pushforce); | ||
594 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); | 689 | // m_log.DebugFormat("{0}: AddAngularForce. f={1}, push={2}", LogHeader, force, pushforce); |
595 | } | 690 | } |
596 | public override void SetMomentum(OMV.Vector3 momentum) { | 691 | public override void SetMomentum(OMV.Vector3 momentum) { |
692 | DetailLog("{0},SetMomentum,call,mom={1}", LocalID, momentum); | ||
597 | } | 693 | } |
598 | public override void SubscribeEvents(int ms) { | 694 | public override void SubscribeEvents(int ms) { |
599 | _subscribedEventsMs = ms; | 695 | _subscribedEventsMs = ms; |
@@ -918,6 +1014,7 @@ public sealed class BSPrim : PhysicsActor | |||
918 | { | 1014 | { |
919 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); | 1015 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to sphere of size {1}", LogHeader, _size); |
920 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; | 1016 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_SPHERE; |
1017 | DetailLog("{0},CreateGeom,sphere", LocalID); | ||
921 | // Bullet native objects are scaled by the Bullet engine so pass the size in | 1018 | // Bullet native objects are scaled by the Bullet engine so pass the size in |
922 | _scale = _size; | 1019 | _scale = _size; |
923 | } | 1020 | } |
@@ -925,6 +1022,7 @@ public sealed class BSPrim : PhysicsActor | |||
925 | else | 1022 | else |
926 | { | 1023 | { |
927 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); | 1024 | // m_log.DebugFormat("{0}: CreateGeom: Defaulting to box. lid={1}, size={2}", LogHeader, LocalID, _size); |
1025 | DetailLog("{0},CreateGeom,box", LocalID); | ||
928 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; | 1026 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_BOX; |
929 | _scale = _size; | 1027 | _scale = _size; |
930 | } | 1028 | } |
@@ -961,10 +1059,12 @@ public sealed class BSPrim : PhysicsActor | |||
961 | // if this new shape is the same as last time, don't recreate the mesh | 1059 | // if this new shape is the same as last time, don't recreate the mesh |
962 | if (_meshKey == newMeshKey) return; | 1060 | if (_meshKey == newMeshKey) return; |
963 | 1061 | ||
1062 | DetailLog("{0},CreateGeomMesh,create,key={1}", LocalID, _meshKey); | ||
964 | // Since we're recreating new, get rid of any previously generated shape | 1063 | // Since we're recreating new, get rid of any previously generated shape |
965 | if (_meshKey != 0) | 1064 | if (_meshKey != 0) |
966 | { | 1065 | { |
967 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); | 1066 | // m_log.DebugFormat("{0}: CreateGeom: deleting old mesh. lID={1}, Key={2}", LogHeader, _localID, _meshKey); |
1067 | DetailLog("{0},CreateGeomMesh,deleteOld,key={1}", LocalID, _meshKey); | ||
968 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | 1068 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); |
969 | _mesh = null; | 1069 | _mesh = null; |
970 | _meshKey = 0; | 1070 | _meshKey = 0; |
@@ -981,7 +1081,6 @@ public sealed class BSPrim : PhysicsActor | |||
981 | int vi = 0; | 1081 | int vi = 0; |
982 | foreach (OMV.Vector3 vv in vertices) | 1082 | foreach (OMV.Vector3 vv in vertices) |
983 | { | 1083 | { |
984 | // m_log.DebugFormat("{0}: {1}: <{2:0.00}, {3:0.00}, {4:0.00}>", LogHeader, vi / 3, vv.X, vv.Y, vv.Z); | ||
985 | verticesAsFloats[vi++] = vv.X; | 1084 | verticesAsFloats[vi++] = vv.X; |
986 | verticesAsFloats[vi++] = vv.Y; | 1085 | verticesAsFloats[vi++] = vv.Y; |
987 | verticesAsFloats[vi++] = vv.Z; | 1086 | verticesAsFloats[vi++] = vv.Z; |
@@ -995,6 +1094,7 @@ public sealed class BSPrim : PhysicsActor | |||
995 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; | 1094 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_MESH; |
996 | // meshes are already scaled by the meshmerizer | 1095 | // meshes are already scaled by the meshmerizer |
997 | _scale = new OMV.Vector3(1f, 1f, 1f); | 1096 | _scale = new OMV.Vector3(1f, 1f, 1f); |
1097 | DetailLog("{0},CreateGeomMesh,done", LocalID); | ||
998 | return; | 1098 | return; |
999 | } | 1099 | } |
1000 | 1100 | ||
@@ -1008,13 +1108,17 @@ public sealed class BSPrim : PhysicsActor | |||
1008 | // if the hull hasn't changed, don't rebuild it | 1108 | // if the hull hasn't changed, don't rebuild it |
1009 | if (newHullKey == _hullKey) return; | 1109 | if (newHullKey == _hullKey) return; |
1010 | 1110 | ||
1111 | DetailLog("{0},CreateGeomHull,create,key={1}", LocalID, _meshKey); | ||
1112 | |||
1011 | // Since we're recreating new, get rid of any previously generated shape | 1113 | // Since we're recreating new, get rid of any previously generated shape |
1012 | if (_hullKey != 0) | 1114 | if (_hullKey != 0) |
1013 | { | 1115 | { |
1014 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); | 1116 | // m_log.DebugFormat("{0}: CreateGeom: deleting old hull. Key={1}", LogHeader, _hullKey); |
1117 | DetailLog("{0},CreateGeomHull,deleteOldHull,key={1}", LocalID, _meshKey); | ||
1015 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); | 1118 | BulletSimAPI.DestroyHull(_scene.WorldID, _hullKey); |
1016 | _hullKey = 0; | 1119 | _hullKey = 0; |
1017 | _hulls.Clear(); | 1120 | _hulls.Clear(); |
1121 | DetailLog("{0},CreateGeomHull,deleteOldMesh,key={1}", LocalID, _meshKey); | ||
1018 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); | 1122 | BulletSimAPI.DestroyMesh(_scene.WorldID, _meshKey); |
1019 | _mesh = null; // the mesh cannot match either | 1123 | _mesh = null; // the mesh cannot match either |
1020 | _meshKey = 0; | 1124 | _meshKey = 0; |
@@ -1111,6 +1215,7 @@ public sealed class BSPrim : PhysicsActor | |||
1111 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; | 1215 | _shapeType = ShapeData.PhysicsShapeType.SHAPE_HULL; |
1112 | // meshes are already scaled by the meshmerizer | 1216 | // meshes are already scaled by the meshmerizer |
1113 | _scale = new OMV.Vector3(1f, 1f, 1f); | 1217 | _scale = new OMV.Vector3(1f, 1f, 1f); |
1218 | DetailLog("{0},CreateGeomHull,done", LocalID); | ||
1114 | return; | 1219 | return; |
1115 | } | 1220 | } |
1116 | 1221 | ||
@@ -1129,7 +1234,6 @@ public sealed class BSPrim : PhysicsActor | |||
1129 | if (IsRootOfLinkset) | 1234 | if (IsRootOfLinkset) |
1130 | { | 1235 | { |
1131 | // Create a linkset around this object | 1236 | // Create a linkset around this object |
1132 | // CreateLinksetWithCompoundHull(); | ||
1133 | CreateLinksetWithConstraints(); | 1237 | CreateLinksetWithConstraints(); |
1134 | } | 1238 | } |
1135 | else | 1239 | else |
@@ -1191,33 +1295,33 @@ public sealed class BSPrim : PhysicsActor | |||
1191 | // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added | 1295 | // TODO: make this more effeicient: a large linkset gets rebuilt over and over and prims are added |
1192 | void CreateLinksetWithConstraints() | 1296 | void CreateLinksetWithConstraints() |
1193 | { | 1297 | { |
1194 | // m_log.DebugFormat("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); | 1298 | DebugLog("{0}: CreateLinkset. Root prim={1}, prims={2}", LogHeader, LocalID, _childrenPrims.Count+1); |
1195 | 1299 | ||
1196 | // remove any constraints that might be in place | 1300 | // remove any constraints that might be in place |
1197 | foreach (BSPrim prim in _childrenPrims) | 1301 | foreach (BSPrim prim in _childrenPrims) |
1198 | { | 1302 | { |
1199 | // m_log.DebugFormat("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | 1303 | DebugLog("{0}: CreateLinkset: RemoveConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); |
1200 | BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); | 1304 | BulletSimAPI.RemoveConstraint(_scene.WorldID, LocalID, prim.LocalID); |
1201 | } | 1305 | } |
1202 | // create constraints between the root prim and each of the children | 1306 | // create constraints between the root prim and each of the children |
1203 | foreach (BSPrim prim in _childrenPrims) | 1307 | foreach (BSPrim prim in _childrenPrims) |
1204 | { | 1308 | { |
1205 | // m_log.DebugFormat("{0}: CreateLinkset: AddConstraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1206 | |||
1207 | // Zero motion for children so they don't interpolate | 1309 | // Zero motion for children so they don't interpolate |
1208 | prim.ZeroMotion(); | 1310 | prim.ZeroMotion(); |
1209 | 1311 | ||
1210 | // relative position normalized to the root prim | 1312 | // relative position normalized to the root prim |
1211 | OMV.Vector3 childRelativePosition = (prim._position - this._position) * OMV.Quaternion.Inverse(this._orientation); | 1313 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(this._orientation); |
1314 | OMV.Vector3 childRelativePosition = (prim._position - this._position) * invThisOrientation; | ||
1212 | 1315 | ||
1213 | // relative rotation of the child to the parent | 1316 | // relative rotation of the child to the parent |
1214 | OMV.Quaternion relativeRotation = OMV.Quaternion.Inverse(prim._orientation) * this._orientation; | 1317 | OMV.Quaternion childRelativeRotation = invThisOrientation * prim._orientation; |
1215 | 1318 | ||
1216 | // this is a constraint that allows no freedom of movement between the two objects | 1319 | // this is a constraint that allows no freedom of movement between the two objects |
1217 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 1320 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
1321 | DebugLog("{0}: CreateLinkset: Adding a constraint between root prim {1} and child prim {2}", LogHeader, LocalID, prim.LocalID); | ||
1218 | BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, | 1322 | BulletSimAPI.AddConstraint(_scene.WorldID, LocalID, prim.LocalID, |
1219 | childRelativePosition, | 1323 | childRelativePosition, |
1220 | relativeRotation, | 1324 | childRelativeRotation, |
1221 | OMV.Vector3.Zero, | 1325 | OMV.Vector3.Zero, |
1222 | OMV.Quaternion.Identity, | 1326 | OMV.Quaternion.Identity, |
1223 | OMV.Vector3.Zero, OMV.Vector3.Zero, | 1327 | OMV.Vector3.Zero, OMV.Vector3.Zero, |
@@ -1252,78 +1356,71 @@ public sealed class BSPrim : PhysicsActor | |||
1252 | const float POSITION_TOLERANCE = 0.05f; | 1356 | const float POSITION_TOLERANCE = 0.05f; |
1253 | const float ACCELERATION_TOLERANCE = 0.01f; | 1357 | const float ACCELERATION_TOLERANCE = 0.01f; |
1254 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; | 1358 | const float ROTATIONAL_VELOCITY_TOLERANCE = 0.01f; |
1255 | const bool SHOULD_DAMP_UPDATES = false; | ||
1256 | 1359 | ||
1257 | public void UpdateProperties(EntityProperties entprop) | 1360 | public void UpdateProperties(EntityProperties entprop) |
1258 | { | 1361 | { |
1362 | /* | ||
1259 | UpdatedProperties changed = 0; | 1363 | UpdatedProperties changed = 0; |
1260 | if (SHOULD_DAMP_UPDATES) | 1364 | // assign to the local variables so the normal set action does not happen |
1365 | // if (_position != entprop.Position) | ||
1366 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1261 | { | 1367 | { |
1262 | // assign to the local variables so the normal set action does not happen | 1368 | _position = entprop.Position; |
1263 | // if (_position != entprop.Position) | 1369 | changed |= UpdatedProperties.Position; |
1264 | if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE)) | ||
1265 | { | ||
1266 | _position = entprop.Position; | ||
1267 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, pos = {2}", LogHeader, LocalID, _position); | ||
1268 | changed |= UpdatedProperties.Position; | ||
1269 | } | ||
1270 | // if (_orientation != entprop.Rotation) | ||
1271 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1272 | { | ||
1273 | _orientation = entprop.Rotation; | ||
1274 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, rot = {2}", LogHeader, LocalID, _orientation); | ||
1275 | changed |= UpdatedProperties.Rotation; | ||
1276 | } | ||
1277 | // if (_velocity != entprop.Velocity) | ||
1278 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1279 | { | ||
1280 | _velocity = entprop.Velocity; | ||
1281 | // m_log.DebugFormat("{0}: UpdateProperties: velocity = {1}", LogHeader, _velocity); | ||
1282 | changed |= UpdatedProperties.Velocity; | ||
1283 | } | ||
1284 | // if (_acceleration != entprop.Acceleration) | ||
1285 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1286 | { | ||
1287 | _acceleration = entprop.Acceleration; | ||
1288 | // m_log.DebugFormat("{0}: UpdateProperties: acceleration = {1}", LogHeader, _acceleration); | ||
1289 | changed |= UpdatedProperties.Acceleration; | ||
1290 | } | ||
1291 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1292 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1293 | { | ||
1294 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1295 | // m_log.DebugFormat("{0}: UpdateProperties: rotationalVelocity = {1}", LogHeader, _rotationalVelocity); | ||
1296 | changed |= UpdatedProperties.RotationalVel; | ||
1297 | } | ||
1298 | if (changed != 0) | ||
1299 | { | ||
1300 | // m_log.DebugFormat("{0}: UpdateProperties: id={1}, c={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1301 | // Only update the position of single objects and linkset roots | ||
1302 | if (this._parentPrim == null) | ||
1303 | { | ||
1304 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}", LogHeader, LocalID, changed, _position, _orientation); | ||
1305 | base.RequestPhysicsterseUpdate(); | ||
1306 | } | ||
1307 | } | ||
1308 | } | 1370 | } |
1309 | else | 1371 | // if (_orientation != entprop.Rotation) |
1372 | if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE)) | ||
1310 | { | 1373 | { |
1311 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | 1374 | _orientation = entprop.Rotation; |
1312 | 1375 | changed |= UpdatedProperties.Rotation; | |
1313 | // Only updates only for individual prims and for the root object of a linkset. | 1376 | } |
1377 | // if (_velocity != entprop.Velocity) | ||
1378 | if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE)) | ||
1379 | { | ||
1380 | _velocity = entprop.Velocity; | ||
1381 | changed |= UpdatedProperties.Velocity; | ||
1382 | } | ||
1383 | // if (_acceleration != entprop.Acceleration) | ||
1384 | if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE)) | ||
1385 | { | ||
1386 | _acceleration = entprop.Acceleration; | ||
1387 | changed |= UpdatedProperties.Acceleration; | ||
1388 | } | ||
1389 | // if (_rotationalVelocity != entprop.RotationalVelocity) | ||
1390 | if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE)) | ||
1391 | { | ||
1392 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1393 | changed |= UpdatedProperties.RotationalVel; | ||
1394 | } | ||
1395 | if (changed != 0) | ||
1396 | { | ||
1397 | // Only update the position of single objects and linkset roots | ||
1314 | if (this._parentPrim == null) | 1398 | if (this._parentPrim == null) |
1315 | { | 1399 | { |
1316 | // Assign to the local variables so the normal set action does not happen | ||
1317 | _position = entprop.Position; | ||
1318 | _orientation = entprop.Rotation; | ||
1319 | _velocity = entprop.Velocity; | ||
1320 | _acceleration = entprop.Acceleration; | ||
1321 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1322 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", | ||
1323 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1324 | base.RequestPhysicsterseUpdate(); | 1400 | base.RequestPhysicsterseUpdate(); |
1325 | } | 1401 | } |
1326 | } | 1402 | } |
1403 | */ | ||
1404 | |||
1405 | // Don't check for damping here -- it's done in BulletSim and SceneObjectPart. | ||
1406 | |||
1407 | // Updates only for individual prims and for the root object of a linkset. | ||
1408 | if (this._parentPrim == null) | ||
1409 | { | ||
1410 | // Assign to the local variables so the normal set action does not happen | ||
1411 | _position = entprop.Position; | ||
1412 | _orientation = entprop.Rotation; | ||
1413 | _velocity = entprop.Velocity; | ||
1414 | _acceleration = entprop.Acceleration; | ||
1415 | _rotationalVelocity = entprop.RotationalVelocity; | ||
1416 | |||
1417 | // m_log.DebugFormat("{0}: RequestTerseUpdate. id={1}, ch={2}, pos={3}, rot={4}, vel={5}, acc={6}, rvel={7}", | ||
1418 | // LogHeader, LocalID, changed, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1419 | DetailLog("{0},UpdateProperties,call,pos={1},orient={2},vel={3},accel={4},rotVel={5}", | ||
1420 | LocalID, _position, _orientation, _velocity, _acceleration, _rotationalVelocity); | ||
1421 | |||
1422 | base.RequestPhysicsterseUpdate(); | ||
1423 | } | ||
1327 | } | 1424 | } |
1328 | 1425 | ||
1329 | // I've collided with something | 1426 | // I've collided with something |
@@ -1362,5 +1459,11 @@ public sealed class BSPrim : PhysicsActor | |||
1362 | collisionCollection.Clear(); | 1459 | collisionCollection.Clear(); |
1363 | } | 1460 | } |
1364 | } | 1461 | } |
1462 | |||
1463 | // Invoke the detailed logger and output something if it's enabled. | ||
1464 | private void DetailLog(string msg, params Object[] args) | ||
1465 | { | ||
1466 | Scene.PhysicsLogging.Write(msg, args); | ||
1467 | } | ||
1365 | } | 1468 | } |
1366 | } | 1469 | } |
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs index 417cb5f..8773485 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs | |||
@@ -29,12 +29,14 @@ using System.Collections.Generic; | |||
29 | using System.Runtime.InteropServices; | 29 | using System.Runtime.InteropServices; |
30 | using System.Text; | 30 | using System.Text; |
31 | using System.Threading; | 31 | using System.Threading; |
32 | using Nini.Config; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | 32 | using OpenSim.Framework; |
33 | using OpenSim.Region.Framework; | ||
34 | using OpenSim.Region.CoreModules; | ||
35 | using Logging = OpenSim.Region.CoreModules.Framework.Statistics.Logging; | ||
35 | using OpenSim.Region.Physics.Manager; | 36 | using OpenSim.Region.Physics.Manager; |
37 | using Nini.Config; | ||
38 | using log4net; | ||
36 | using OpenMetaverse; | 39 | using OpenMetaverse; |
37 | using OpenSim.Region.Framework; | ||
38 | 40 | ||
39 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) | 41 | // TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim) |
40 | // Debug linkset | 42 | // Debug linkset |
@@ -44,15 +46,17 @@ using OpenSim.Region.Framework; | |||
44 | // Compute physics FPS reasonably | 46 | // Compute physics FPS reasonably |
45 | // Based on material, set density and friction | 47 | // Based on material, set density and friction |
46 | // More efficient memory usage when passing hull information from BSPrim to BulletSim | 48 | // More efficient memory usage when passing hull information from BSPrim to BulletSim |
49 | // Move all logic out of the C++ code and into the C# code for easier future modifications. | ||
47 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? | 50 | // Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly? |
48 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) | 51 | // In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground) |
49 | // At the moment, physical and phantom causes object to drop through the terrain | 52 | // At the moment, physical and phantom causes object to drop through the terrain |
50 | // Physical phantom objects and related typing (collision options ) | 53 | // Physical phantom objects and related typing (collision options ) |
54 | // Use collision masks for collision with terrain and phantom objects | ||
51 | // Check out llVolumeDetect. Must do something for that. | 55 | // Check out llVolumeDetect. Must do something for that. |
52 | // Should prim.link() and prim.delink() membership checking happen at taint time? | 56 | // Should prim.link() and prim.delink() membership checking happen at taint time? |
57 | // changing the position and orientation of a linked prim must rebuild the constraint with the root. | ||
53 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once | 58 | // Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once |
54 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect | 59 | // Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect |
55 | // Use collision masks for collision with terrain and phantom objects | ||
56 | // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) | 60 | // Implement the genCollisions feature in BulletSim::SetObjectProperties (don't pass up unneeded collisions) |
57 | // Implement LockAngularMotion | 61 | // Implement LockAngularMotion |
58 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) | 62 | // Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation) |
@@ -60,9 +64,6 @@ using OpenSim.Region.Framework; | |||
60 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. | 64 | // Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet. |
61 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? | 65 | // Add PID movement operations. What does ScenePresence.MoveToTarget do? |
62 | // Check terrain size. 128 or 127? | 66 | // Check terrain size. 128 or 127? |
63 | // Multiple contact points on collision? | ||
64 | // See code in ode::near... calls to collision_accounting_events() | ||
65 | // (This might not be a problem. ODE collects all the collisions with one object in one tick.) | ||
66 | // Raycast | 67 | // Raycast |
67 | // | 68 | // |
68 | namespace OpenSim.Region.Physics.BulletSPlugin | 69 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -72,6 +73,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
72 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | 73 | private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); |
73 | private static readonly string LogHeader = "[BULLETS SCENE]"; | 74 | private static readonly string LogHeader = "[BULLETS SCENE]"; |
74 | 75 | ||
76 | private void DebugLog(string mm, params Object[] xx) { if (shouldDebugLog) m_log.DebugFormat(mm, xx); } | ||
77 | |||
75 | public string BulletSimVersion = "?"; | 78 | public string BulletSimVersion = "?"; |
76 | 79 | ||
77 | private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); | 80 | private Dictionary<uint, BSCharacter> m_avatars = new Dictionary<uint, BSCharacter>(); |
@@ -105,6 +108,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
105 | private long m_simulationStep = 0; | 108 | private long m_simulationStep = 0; |
106 | public long SimulationStep { get { return m_simulationStep; } } | 109 | public long SimulationStep { get { return m_simulationStep; } } |
107 | 110 | ||
111 | public float LastSimulatedTimestep { get; private set; } | ||
112 | |||
108 | // A value of the time now so all the collision and update routines do not have to get their own | 113 | // A value of the time now so all the collision and update routines do not have to get their own |
109 | // Set to 'now' just before all the prims and actors are called for collisions and updates | 114 | // Set to 'now' just before all the prims and actors are called for collisions and updates |
110 | private int m_simulationNowTime; | 115 | private int m_simulationNowTime; |
@@ -121,6 +126,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
121 | private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed | 126 | private bool _meshSculptedPrim = true; // cause scuplted prims to get meshed |
122 | private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes | 127 | private bool _forceSimplePrimMeshing = false; // if a cube or sphere, let Bullet do internal shapes |
123 | 128 | ||
129 | public float PID_D { get; private set; } // derivative | ||
130 | public float PID_P { get; private set; } // proportional | ||
131 | |||
124 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero | 132 | public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero |
125 | public const uint GROUNDPLANE_ID = 1; | 133 | public const uint GROUNDPLANE_ID = 1; |
126 | 134 | ||
@@ -147,8 +155,20 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
147 | ConfigurationParameters[] m_params; | 155 | ConfigurationParameters[] m_params; |
148 | GCHandle m_paramsHandle; | 156 | GCHandle m_paramsHandle; |
149 | 157 | ||
158 | public bool shouldDebugLog { get; private set; } | ||
159 | |||
150 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; | 160 | private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle; |
151 | 161 | ||
162 | // Sometimes you just have to log everything. | ||
163 | public Logging.LogWriter PhysicsLogging; | ||
164 | private bool m_physicsLoggingEnabled; | ||
165 | private string m_physicsLoggingDir; | ||
166 | private string m_physicsLoggingPrefix; | ||
167 | private int m_physicsLoggingFileMinutes; | ||
168 | |||
169 | private bool m_vehicleLoggingEnabled; | ||
170 | public bool VehicleLoggingEnabled { get { return m_vehicleLoggingEnabled; } } | ||
171 | |||
152 | public BSScene(string identifier) | 172 | public BSScene(string identifier) |
153 | { | 173 | { |
154 | m_initialized = false; | 174 | m_initialized = false; |
@@ -169,17 +189,32 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
169 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; | 189 | m_updateArray = new EntityProperties[m_maxUpdatesPerFrame]; |
170 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); | 190 | m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned); |
171 | 191 | ||
192 | // Enable very detailed logging. | ||
193 | // By creating an empty logger when not logging, the log message invocation code | ||
194 | // can be left in and every call doesn't have to check for null. | ||
195 | if (m_physicsLoggingEnabled) | ||
196 | { | ||
197 | PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); | ||
198 | } | ||
199 | else | ||
200 | { | ||
201 | PhysicsLogging = new Logging.LogWriter(); | ||
202 | } | ||
203 | |||
172 | // Get the version of the DLL | 204 | // Get the version of the DLL |
173 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. | 205 | // TODO: this doesn't work yet. Something wrong with marshaling the returned string. |
174 | // BulletSimVersion = BulletSimAPI.GetVersion(); | 206 | // BulletSimVersion = BulletSimAPI.GetVersion(); |
175 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); | 207 | // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion); |
176 | 208 | ||
177 | // if Debug, enable logging from the unmanaged code | 209 | // if Debug, enable logging from the unmanaged code |
178 | if (m_log.IsDebugEnabled) | 210 | if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) |
179 | { | 211 | { |
180 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); | 212 | m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader); |
181 | // the handle is saved to it doesn't get freed after this call | 213 | if (PhysicsLogging.Enabled) |
182 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | 214 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog); |
215 | else | ||
216 | m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger); | ||
217 | // the handle is saved in a variable to make sure it doesn't get freed after this call | ||
183 | BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); | 218 | BulletSimAPI.SetDebugLogCallback(m_DebugLogCallbackHandle); |
184 | } | 219 | } |
185 | 220 | ||
@@ -209,6 +244,7 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
209 | m_meshLOD = 8f; | 244 | m_meshLOD = 8f; |
210 | m_sculptLOD = 32f; | 245 | m_sculptLOD = 32f; |
211 | 246 | ||
247 | shouldDebugLog = false; | ||
212 | m_detailedStatsStep = 0; // disabled | 248 | m_detailedStatsStep = 0; // disabled |
213 | 249 | ||
214 | m_maxSubSteps = 10; | 250 | m_maxSubSteps = 10; |
@@ -217,6 +253,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
217 | m_maxUpdatesPerFrame = 2048; | 253 | m_maxUpdatesPerFrame = 2048; |
218 | m_maximumObjectMass = 10000.01f; | 254 | m_maximumObjectMass = 10000.01f; |
219 | 255 | ||
256 | PID_D = 2200f; | ||
257 | PID_P = 900f; | ||
258 | |||
220 | parms.defaultFriction = 0.5f; | 259 | parms.defaultFriction = 0.5f; |
221 | parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 | 260 | parms.defaultDensity = 10.000006836f; // Aluminum g/cm3 |
222 | parms.defaultRestitution = 0f; | 261 | parms.defaultRestitution = 0f; |
@@ -261,7 +300,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
261 | _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); | 300 | _meshSculptedPrim = pConfig.GetBoolean("MeshSculptedPrim", _meshSculptedPrim); |
262 | _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); | 301 | _forceSimplePrimMeshing = pConfig.GetBoolean("ForceSimplePrimMeshing", _forceSimplePrimMeshing); |
263 | 302 | ||
303 | shouldDebugLog = pConfig.GetBoolean("ShouldDebugLog", shouldDebugLog); | ||
264 | m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); | 304 | m_detailedStatsStep = pConfig.GetInt("DetailedStatsStep", m_detailedStatsStep); |
305 | |||
265 | m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); | 306 | m_meshLOD = pConfig.GetFloat("MeshLevelOfDetail", m_meshLOD); |
266 | m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); | 307 | m_sculptLOD = pConfig.GetFloat("SculptLevelOfDetail", m_sculptLOD); |
267 | 308 | ||
@@ -271,6 +312,9 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
271 | m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); | 312 | m_maxUpdatesPerFrame = pConfig.GetInt("MaxUpdatesPerFrame", m_maxUpdatesPerFrame); |
272 | m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); | 313 | m_maximumObjectMass = pConfig.GetFloat("MaxObjectMass", m_maximumObjectMass); |
273 | 314 | ||
315 | PID_D = pConfig.GetFloat("PIDDerivative", PID_D); | ||
316 | PID_P = pConfig.GetFloat("PIDProportional", PID_P); | ||
317 | |||
274 | parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); | 318 | parms.defaultFriction = pConfig.GetFloat("DefaultFriction", parms.defaultFriction); |
275 | parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); | 319 | parms.defaultDensity = pConfig.GetFloat("DefaultDensity", parms.defaultDensity); |
276 | parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); | 320 | parms.defaultRestitution = pConfig.GetFloat("DefaultRestitution", parms.defaultRestitution); |
@@ -303,6 +347,14 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
303 | parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands); | 347 | parms.shouldSplitSimulationIslands = ParamBoolean(pConfig, "ShouldSplitSimulationIslands", parms.shouldSplitSimulationIslands); |
304 | parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching); | 348 | parms.shouldEnableFrictionCaching = ParamBoolean(pConfig, "ShouldEnableFrictionCaching", parms.shouldEnableFrictionCaching); |
305 | parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations); | 349 | parms.numberOfSolverIterations = pConfig.GetFloat("NumberOfSolverIterations", parms.numberOfSolverIterations); |
350 | |||
351 | // Very detailed logging for physics debugging | ||
352 | m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); | ||
353 | m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); | ||
354 | m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-"); | ||
355 | m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); | ||
356 | // Very detailed logging for vehicle debugging | ||
357 | m_vehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); | ||
306 | } | 358 | } |
307 | } | 359 | } |
308 | m_params[0] = parms; | 360 | m_params[0] = parms; |
@@ -323,12 +375,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
323 | return ret; | 375 | return ret; |
324 | } | 376 | } |
325 | 377 | ||
326 | |||
327 | // Called directly from unmanaged code so don't do much | 378 | // Called directly from unmanaged code so don't do much |
328 | private void BulletLogger(string msg) | 379 | private void BulletLogger(string msg) |
329 | { | 380 | { |
330 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); | 381 | m_log.Debug("[BULLETS UNMANAGED]:" + msg); |
331 | } | 382 | } |
383 | |||
384 | // Called directly from unmanaged code so don't do much | ||
385 | private void BulletLoggerPhysLog(string msg) | ||
386 | { | ||
387 | PhysicsLogging.Write("[BULLETS UNMANAGED]:" + msg); | ||
388 | } | ||
332 | 389 | ||
333 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) | 390 | public override PhysicsActor AddAvatar(string avName, Vector3 position, Vector3 size, bool isFlying) |
334 | { | 391 | { |
@@ -347,34 +404,42 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
347 | public override void RemoveAvatar(PhysicsActor actor) | 404 | public override void RemoveAvatar(PhysicsActor actor) |
348 | { | 405 | { |
349 | // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); | 406 | // m_log.DebugFormat("{0}: RemoveAvatar", LogHeader); |
350 | if (actor is BSCharacter) | 407 | BSCharacter bsactor = actor as BSCharacter; |
351 | { | 408 | if (bsactor != null) |
352 | ((BSCharacter)actor).Destroy(); | ||
353 | } | ||
354 | try | ||
355 | { | 409 | { |
356 | lock (m_avatars) m_avatars.Remove(actor.LocalID); | 410 | try |
357 | } | 411 | { |
358 | catch (Exception e) | 412 | lock (m_avatars) m_avatars.Remove(actor.LocalID); |
359 | { | 413 | } |
360 | m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); | 414 | catch (Exception e) |
415 | { | ||
416 | m_log.WarnFormat("{0}: Attempt to remove avatar that is not in physics scene: {1}", LogHeader, e); | ||
417 | } | ||
418 | bsactor.Destroy(); | ||
419 | // bsactor.dispose(); | ||
361 | } | 420 | } |
362 | } | 421 | } |
363 | 422 | ||
364 | public override void RemovePrim(PhysicsActor prim) | 423 | public override void RemovePrim(PhysicsActor prim) |
365 | { | 424 | { |
366 | // m_log.DebugFormat("{0}: RemovePrim", LogHeader); | 425 | BSPrim bsprim = prim as BSPrim; |
367 | if (prim is BSPrim) | 426 | if (bsprim != null) |
368 | { | ||
369 | ((BSPrim)prim).Destroy(); | ||
370 | } | ||
371 | try | ||
372 | { | 427 | { |
373 | lock (m_prims) m_prims.Remove(prim.LocalID); | 428 | m_log.DebugFormat("{0}: RemovePrim. id={1}/{2}", LogHeader, bsprim.Name, bsprim.LocalID); |
429 | try | ||
430 | { | ||
431 | lock (m_prims) m_prims.Remove(bsprim.LocalID); | ||
432 | } | ||
433 | catch (Exception e) | ||
434 | { | ||
435 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); | ||
436 | } | ||
437 | bsprim.Destroy(); | ||
438 | // bsprim.dispose(); | ||
374 | } | 439 | } |
375 | catch (Exception e) | 440 | else |
376 | { | 441 | { |
377 | m_log.WarnFormat("{0}: Attempt to remove prim that is not in physics scene: {1}", LogHeader, e); | 442 | m_log.ErrorFormat("{0}: Attempt to remove prim that is not a BSPrim type.", LogHeader); |
378 | } | 443 | } |
379 | } | 444 | } |
380 | 445 | ||
@@ -400,6 +465,8 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
400 | int collidersCount; | 465 | int collidersCount; |
401 | IntPtr collidersPtr; | 466 | IntPtr collidersPtr; |
402 | 467 | ||
468 | LastSimulatedTimestep = timeStep; | ||
469 | |||
403 | // prevent simulation until we've been initialized | 470 | // prevent simulation until we've been initialized |
404 | if (!m_initialized) return 10.0f; | 471 | if (!m_initialized) return 10.0f; |
405 | 472 | ||
@@ -459,7 +526,6 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
459 | for (int ii = 0; ii < updatedEntityCount; ii++) | 526 | for (int ii = 0; ii < updatedEntityCount; ii++) |
460 | { | 527 | { |
461 | EntityProperties entprop = m_updateArray[ii]; | 528 | EntityProperties entprop = m_updateArray[ii]; |
462 | // m_log.DebugFormat("{0}: entprop[{1}]: id={2}, pos={3}", LogHeader, ii, entprop.ID, entprop.Position); | ||
463 | BSPrim prim; | 529 | BSPrim prim; |
464 | if (m_prims.TryGetValue(entprop.ID, out prim)) | 530 | if (m_prims.TryGetValue(entprop.ID, out prim)) |
465 | { | 531 | { |
@@ -532,8 +598,17 @@ public class BSScene : PhysicsScene, IPhysicsParameters | |||
532 | }); | 598 | }); |
533 | } | 599 | } |
534 | 600 | ||
601 | // Someday we will have complex terrain with caves and tunnels | ||
602 | // For the moment, it's flat and convex | ||
603 | public float GetTerrainHeightAtXYZ(Vector3 loc) | ||
604 | { | ||
605 | return GetTerrainHeightAtXY(loc.X, loc.Y); | ||
606 | } | ||
607 | |||
535 | public float GetTerrainHeightAtXY(float tX, float tY) | 608 | public float GetTerrainHeightAtXY(float tX, float tY) |
536 | { | 609 | { |
610 | if (tX < 0 || tX >= Constants.RegionSize || tY < 0 || tY >= Constants.RegionSize) | ||
611 | return 30; | ||
537 | return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; | 612 | return m_heightMap[((int)tX) * Constants.RegionSize + ((int)tY)]; |
538 | } | 613 | } |
539 | 614 | ||
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs index 086f0dc..babb707 100644 --- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs | |||
@@ -146,6 +146,22 @@ public struct ConfigurationParameters | |||
146 | public const float numericFalse = 0f; | 146 | public const float numericFalse = 0f; |
147 | } | 147 | } |
148 | 148 | ||
149 | // Values used by Bullet and BulletSim to control collisions | ||
150 | public enum CollisionFlags : uint | ||
151 | { | ||
152 | STATIC_OBJECT = 1 << 0, | ||
153 | KINEMATIC_OBJECT = 1 << 1, | ||
154 | NO_CONTACT_RESPONSE = 1 << 2, | ||
155 | CUSTOM_MATERIAL_CALLBACK = 1 << 3, | ||
156 | CHARACTER_OBJECT = 1 << 4, | ||
157 | DISABLE_VISUALIZE_OBJECT = 1 << 5, | ||
158 | DISABLE_SPU_COLLISION_PROCESS = 1 << 6, | ||
159 | // Following used by BulletSim to control collisions | ||
160 | VOLUME_DETECT_OBJECT = 1 << 10, | ||
161 | PHANTOM_OBJECT = 1 << 11, | ||
162 | PHYSICAL_OBJECT = 1 << 12, | ||
163 | }; | ||
164 | |||
149 | static class BulletSimAPI { | 165 | static class BulletSimAPI { |
150 | 166 | ||
151 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 167 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -214,6 +230,9 @@ public static extern bool RemoveConstraint(uint worldID, uint id1, uint id2); | |||
214 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); | 230 | public static extern Vector3 GetObjectPosition(uint WorldID, uint id); |
215 | 231 | ||
216 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 232 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
233 | public static extern Quaternion GetObjectOrientation(uint WorldID, uint id); | ||
234 | |||
235 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
217 | public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); | 236 | public static extern bool SetObjectTranslation(uint worldID, uint id, Vector3 position, Quaternion rotation); |
218 | 237 | ||
219 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 238 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
@@ -268,5 +287,37 @@ public static extern void DumpBulletStatistics(); | |||
268 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); | 287 | public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg); |
269 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | 288 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] |
270 | public static extern void SetDebugLogCallback(DebugLogCallback callback); | 289 | public static extern void SetDebugLogCallback(DebugLogCallback callback); |
290 | |||
291 | // =============================================================================== | ||
292 | // =============================================================================== | ||
293 | // =============================================================================== | ||
294 | // A new version of the API that moves all the logic out of the C++ code and into | ||
295 | // the C# code. This will make modifications easier for the next person. | ||
296 | // This interface passes the actual pointers to the objects in the unmanaged | ||
297 | // address space. All the management (calls for creation/destruction/lookup) | ||
298 | // is done in the C# code. | ||
299 | // The names have a 2 tacked on. This will be removed as the code gets rebuilt | ||
300 | // and the old code is removed from the C# code. | ||
301 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
302 | public static extern IntPtr GetSimHandle2(uint worldID); | ||
303 | |||
304 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
305 | public static extern IntPtr GetBodyHandleWorldID2(uint worldID, uint id); | ||
306 | |||
307 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
308 | public static extern IntPtr GetBodyHandle2(IntPtr sim, uint id); | ||
309 | |||
310 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
311 | public static extern IntPtr ClearForces2(IntPtr obj); | ||
312 | |||
313 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
314 | public static extern IntPtr SetCollisionFlags2(IntPtr obj, uint flags); | ||
315 | |||
316 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
317 | public static extern IntPtr AddToCollisionFlags2(IntPtr obj, uint flags); | ||
318 | |||
319 | [DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity] | ||
320 | public static extern IntPtr RemoveFromCollisionFlags2(IntPtr obj, uint flags); | ||
321 | |||
271 | } | 322 | } |
272 | } | 323 | } |