diff options
author | Teravus Ovares | 2008-12-26 12:58:02 +0000 |
---|---|---|
committer | Teravus Ovares | 2008-12-26 12:58:02 +0000 |
commit | ec2dc354b485491d7879686b4a78027971e3ed92 (patch) | |
tree | 3ea0771a55524ce1b9dec3c3c66f0dac24a006ef /OpenSim/Region/Environment/Scenes | |
parent | Prevent exception in terrain module if just the word terrain is entered at th... (diff) | |
download | opensim-SC-ec2dc354b485491d7879686b4a78027971e3ed92.zip opensim-SC-ec2dc354b485491d7879686b4a78027971e3ed92.tar.gz opensim-SC-ec2dc354b485491d7879686b4a78027971e3ed92.tar.bz2 opensim-SC-ec2dc354b485491d7879686b4a78027971e3ed92.tar.xz |
* Applying Nlin's NINJA Joint patch. v2. Mantis# 2874
* Thanks nlin!
* To try it out, set ninja joints active in the ODEPhysicsSettings
and use the example at:
* http://forge.opensimulator.org/gf/download/frsrelease/142/304/demo-playground.tgz.
* Don't forget to change the .tgz to .oar and load it with load-oar.
Diffstat (limited to 'OpenSim/Region/Environment/Scenes')
-rw-r--r-- | OpenSim/Region/Environment/Scenes/Scene.cs | 167 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/SceneGraph.cs | 17 | ||||
-rw-r--r-- | OpenSim/Region/Environment/Scenes/SceneObjectPart.cs | 282 |
3 files changed, 412 insertions, 54 deletions
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index d4d5b90..2d0743c 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs | |||
@@ -200,8 +200,30 @@ namespace OpenSim.Region.Environment.Scenes | |||
200 | // an instance to the physics plugin's Scene object. | 200 | // an instance to the physics plugin's Scene object. |
201 | public PhysicsScene PhysicsScene | 201 | public PhysicsScene PhysicsScene |
202 | { | 202 | { |
203 | set { m_sceneGraph.PhysicsScene = value; } | ||
204 | get { return m_sceneGraph.PhysicsScene; } | 203 | get { return m_sceneGraph.PhysicsScene; } |
204 | set | ||
205 | { | ||
206 | // If we're not doing the initial set | ||
207 | // Then we've got to remove the previous | ||
208 | // event handler | ||
209 | if (PhysicsScene != null && PhysicsScene.SupportsNINJAJoints) | ||
210 | { | ||
211 | PhysicsScene.OnJointMoved -= jointMoved; | ||
212 | PhysicsScene.OnJointDeactivated -= jointDeactivated; | ||
213 | PhysicsScene.OnJointErrorMessage -= jointErrorMessage; | ||
214 | } | ||
215 | |||
216 | m_sceneGraph.PhysicsScene = value; | ||
217 | |||
218 | if (PhysicsScene != null && m_sceneGraph.PhysicsScene.SupportsNINJAJoints) | ||
219 | { | ||
220 | // register event handlers to respond to joint movement/deactivation | ||
221 | PhysicsScene.OnJointMoved += jointMoved; | ||
222 | PhysicsScene.OnJointDeactivated += jointDeactivated; | ||
223 | PhysicsScene.OnJointErrorMessage += jointErrorMessage; | ||
224 | } | ||
225 | |||
226 | } | ||
205 | } | 227 | } |
206 | 228 | ||
207 | // This gets locked so things stay thread safe. | 229 | // This gets locked so things stay thread safe. |
@@ -1848,7 +1870,11 @@ namespace OpenSim.Region.Environment.Scenes | |||
1848 | 1870 | ||
1849 | foreach (SceneObjectPart part in group.Children.Values) | 1871 | foreach (SceneObjectPart part in group.Children.Values) |
1850 | { | 1872 | { |
1851 | if (part.PhysActor != null) | 1873 | if (part.IsJoint() && ((part.ObjectFlags&(uint)PrimFlags.Physics) != 0) ) |
1874 | { | ||
1875 | PhysicsScene.RequestJointDeletion(part.Name); // FIXME: what if the name changed? | ||
1876 | } | ||
1877 | else if (part.PhysActor != null) | ||
1852 | { | 1878 | { |
1853 | PhysicsScene.RemovePrim(part.PhysActor); | 1879 | PhysicsScene.RemovePrim(part.PhysActor); |
1854 | part.PhysActor = null; | 1880 | part.PhysActor = null; |
@@ -4408,5 +4434,142 @@ namespace OpenSim.Region.Environment.Scenes | |||
4408 | 4434 | ||
4409 | return 0; | 4435 | return 0; |
4410 | } | 4436 | } |
4437 | |||
4438 | // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and | ||
4439 | // update non-physical objects like the joint proxy objects that represent the position | ||
4440 | // of the joints in the scene. | ||
4441 | |||
4442 | // This routine is normally called from within a lock(OdeLock) from within the OdePhysicsScene | ||
4443 | // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called | ||
4444 | // from within the OdePhysicsScene. | ||
4445 | |||
4446 | protected internal void jointMoved(PhysicsJoint joint) | ||
4447 | { | ||
4448 | |||
4449 | // m_parentScene.PhysicsScene.DumpJointInfo(); // non-thread-locked version; we should already be in a lock(OdeLock) when this callback is invoked | ||
4450 | // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary | ||
4451 | SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); | ||
4452 | if (jointProxyObject == null) | ||
4453 | { | ||
4454 | jointErrorMessage(joint, "WARNING, joint proxy not found, name " + joint.ObjectNameInScene); | ||
4455 | return; | ||
4456 | } | ||
4457 | |||
4458 | // now update the joint proxy object in the scene to have the position of the joint as returned by the physics engine | ||
4459 | SceneObjectPart trackedBody = GetSceneObjectPart(joint.TrackedBodyName); // FIXME: causes a sequential lookup | ||
4460 | if (trackedBody == null) return; // the actor may have been deleted but the joint still lingers around a few frames waiting for deletion. during this time, trackedBody is NULL to prevent further motion of the joint proxy. | ||
4461 | jointProxyObject.Velocity = trackedBody.Velocity; | ||
4462 | jointProxyObject.RotationalVelocity = trackedBody.RotationalVelocity; | ||
4463 | switch (joint.Type) | ||
4464 | { | ||
4465 | case PhysicsJointType.Ball: | ||
4466 | { | ||
4467 | PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint); | ||
4468 | Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); | ||
4469 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update | ||
4470 | } | ||
4471 | break; | ||
4472 | |||
4473 | case PhysicsJointType.Hinge: | ||
4474 | { | ||
4475 | PhysicsVector jointAnchor = PhysicsScene.GetJointAnchor(joint); | ||
4476 | |||
4477 | // Normally, we would just ask the physics scene to return the axis for the joint. | ||
4478 | // Unfortunately, ODE sometimes returns <0,0,0> for the joint axis, which should | ||
4479 | // never occur. Therefore we cannot rely on ODE to always return a correct joint axis. | ||
4480 | // Therefore the following call does not always work: | ||
4481 | //PhysicsVector phyJointAxis = _PhyScene.GetJointAxis(joint); | ||
4482 | |||
4483 | // instead we compute the joint orientation by saving the original joint orientation | ||
4484 | // relative to one of the jointed bodies, and applying this transformation | ||
4485 | // to the current position of the jointed bodies (the tracked body) to compute the | ||
4486 | // current joint orientation. | ||
4487 | |||
4488 | if (joint.TrackedBodyName == null) | ||
4489 | { | ||
4490 | jointErrorMessage(joint, "joint.TrackedBodyName is null, joint " + joint.ObjectNameInScene); | ||
4491 | } | ||
4492 | |||
4493 | Vector3 proxyPos = new Vector3(jointAnchor.X, jointAnchor.Y, jointAnchor.Z); | ||
4494 | Quaternion q = trackedBody.RotationOffset * joint.LocalRotation; | ||
4495 | |||
4496 | jointProxyObject.ParentGroup.UpdateGroupPosition(proxyPos); // schedules the entire group for a terse update | ||
4497 | jointProxyObject.ParentGroup.UpdateGroupRotation(q); // schedules the entire group for a terse update | ||
4498 | } | ||
4499 | break; | ||
4500 | } | ||
4501 | } | ||
4502 | |||
4503 | // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and | ||
4504 | // update non-physical objects like the joint proxy objects that represent the position | ||
4505 | // of the joints in the scene. | ||
4506 | |||
4507 | // This routine is normally called from within a lock(OdeLock) from within the OdePhysicsScene | ||
4508 | // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called | ||
4509 | // from within the OdePhysicsScene. | ||
4510 | protected internal void jointDeactivated(PhysicsJoint joint) | ||
4511 | { | ||
4512 | //m_log.Debug("[NINJA] SceneGraph.jointDeactivated, joint:" + joint.ObjectNameInScene); | ||
4513 | // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary | ||
4514 | SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); | ||
4515 | if (jointProxyObject == null) | ||
4516 | { | ||
4517 | jointErrorMessage(joint, "WARNING, trying to deactivate (stop interpolation of) joint proxy, but not found, name " + joint.ObjectNameInScene); | ||
4518 | return; | ||
4519 | } | ||
4520 | |||
4521 | // turn the proxy non-physical, which also stops its client-side interpolation | ||
4522 | bool wasUsingPhysics = ((jointProxyObject.ObjectFlags & (uint)PrimFlags.Physics) != 0); | ||
4523 | if (wasUsingPhysics) | ||
4524 | { | ||
4525 | jointProxyObject.UpdatePrimFlags(false, false, true, false); // FIXME: possible deadlock here; check to make sure all the scene alterations set into motion here won't deadlock | ||
4526 | } | ||
4527 | } | ||
4528 | |||
4529 | // This callback allows the PhysicsScene to call back to its caller (the SceneGraph) and | ||
4530 | // alert the user of errors by using the debug channel in the same way that scripts alert | ||
4531 | // the user of compile errors. | ||
4532 | |||
4533 | // This routine is normally called from within a lock(OdeLock) from within the OdePhysicsScene | ||
4534 | // WARNING: be careful of deadlocks here if you manipulate the scene. Remember you are being called | ||
4535 | // from within the OdePhysicsScene. | ||
4536 | public void jointErrorMessage(PhysicsJoint joint, string message) | ||
4537 | { | ||
4538 | // FIXME: this causes a sequential lookup of all objects in the scene; use a dictionary | ||
4539 | if (joint != null) | ||
4540 | { | ||
4541 | if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages) | ||
4542 | return; | ||
4543 | |||
4544 | SceneObjectPart jointProxyObject = GetSceneObjectPart(joint.ObjectNameInScene); | ||
4545 | if (jointProxyObject != null) | ||
4546 | { | ||
4547 | SimChat(Utils.StringToBytes("[NINJA] " + message), | ||
4548 | ChatTypeEnum.DebugChannel, | ||
4549 | 2147483647, | ||
4550 | jointProxyObject.AbsolutePosition, | ||
4551 | jointProxyObject.Name, | ||
4552 | jointProxyObject.UUID, | ||
4553 | false); | ||
4554 | |||
4555 | joint.ErrorMessageCount++; | ||
4556 | |||
4557 | if (joint.ErrorMessageCount > PhysicsJoint.maxErrorMessages) | ||
4558 | { | ||
4559 | SimChat(Utils.StringToBytes("[NINJA] Too many messages for this joint, suppressing further messages."), | ||
4560 | ChatTypeEnum.DebugChannel, | ||
4561 | 2147483647, | ||
4562 | jointProxyObject.AbsolutePosition, | ||
4563 | jointProxyObject.Name, | ||
4564 | jointProxyObject.UUID, | ||
4565 | false); | ||
4566 | } | ||
4567 | } | ||
4568 | else | ||
4569 | { | ||
4570 | // couldn't find the joint proxy object; the error message is silently suppressed | ||
4571 | } | ||
4572 | } | ||
4573 | } | ||
4411 | } | 4574 | } |
4412 | } | 4575 | } |
diff --git a/OpenSim/Region/Environment/Scenes/SceneGraph.cs b/OpenSim/Region/Environment/Scenes/SceneGraph.cs index dbb8539..d998dbb 100644 --- a/OpenSim/Region/Environment/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Environment/Scenes/SceneGraph.cs | |||
@@ -159,6 +159,22 @@ namespace OpenSim.Region.Environment.Scenes | |||
159 | { | 159 | { |
160 | lock (m_syncRoot) | 160 | lock (m_syncRoot) |
161 | { | 161 | { |
162 | // Here is where the Scene calls the PhysicsScene. This is a one-way | ||
163 | // interaction; the PhysicsScene cannot access the calling Scene directly. | ||
164 | // But with joints, we want a PhysicsActor to be able to influence a | ||
165 | // non-physics SceneObjectPart. In particular, a PhysicsActor that is connected | ||
166 | // with a joint should be able to move the SceneObjectPart which is the visual | ||
167 | // representation of that joint (for editing and serialization purposes). | ||
168 | // However the PhysicsActor normally cannot directly influence anything outside | ||
169 | // of the PhysicsScene, and the non-physical SceneObjectPart which represents | ||
170 | // the joint in the Scene does not exist in the PhysicsScene. | ||
171 | // | ||
172 | // To solve this, we have an event in the PhysicsScene that is fired when a joint | ||
173 | // has changed position (because one of its associated PhysicsActors has changed | ||
174 | // position). | ||
175 | // | ||
176 | // Therefore, JointMoved and JointDeactivated events will be fired as a result of the following Simulate(). | ||
177 | |||
162 | return _PhyScene.Simulate((float)elapsed); | 178 | return _PhyScene.Simulate((float)elapsed); |
163 | } | 179 | } |
164 | } | 180 | } |
@@ -875,6 +891,7 @@ namespace OpenSim.Region.Environment.Scenes | |||
875 | { | 891 | { |
876 | List<EntityBase> EntityList = GetEntities(); | 892 | List<EntityBase> EntityList = GetEntities(); |
877 | 893 | ||
894 | // FIXME: use a dictionary here | ||
878 | foreach (EntityBase ent in EntityList) | 895 | foreach (EntityBase ent in EntityList) |
879 | { | 896 | { |
880 | if (ent is SceneObjectGroup) | 897 | if (ent is SceneObjectGroup) |
diff --git a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs index 3491645..0f3e065 100644 --- a/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs +++ b/OpenSim/Region/Environment/Scenes/SceneObjectPart.cs | |||
@@ -419,7 +419,14 @@ namespace OpenSim.Region.Environment.Scenes | |||
419 | public virtual string Name | 419 | public virtual string Name |
420 | { | 420 | { |
421 | get { return m_name; } | 421 | get { return m_name; } |
422 | set { m_name = value; } | 422 | set |
423 | { | ||
424 | m_name = value; | ||
425 | if (PhysActor != null) | ||
426 | { | ||
427 | PhysActor.SOPName = value; | ||
428 | } | ||
429 | } | ||
423 | } | 430 | } |
424 | 431 | ||
425 | public byte Material | 432 | public byte Material |
@@ -681,7 +688,14 @@ namespace OpenSim.Region.Environment.Scenes | |||
681 | public string Description | 688 | public string Description |
682 | { | 689 | { |
683 | get { return m_description; } | 690 | get { return m_description; } |
684 | set { m_description = value; } | 691 | set |
692 | { | ||
693 | m_description = value; | ||
694 | if (PhysActor != null) | ||
695 | { | ||
696 | PhysActor.SOPDescription = value; | ||
697 | } | ||
698 | } | ||
685 | } | 699 | } |
686 | 700 | ||
687 | public Color Color | 701 | public Color Color |
@@ -1287,30 +1301,39 @@ if (m_shape != null) { | |||
1287 | bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim); | 1301 | bool isPhysical = (((rootObjectFlags & (uint) PrimFlags.Physics) != 0) && m_physicalPrim); |
1288 | bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0); | 1302 | bool isPhantom = ((rootObjectFlags & (uint) PrimFlags.Phantom) != 0); |
1289 | 1303 | ||
1290 | // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored | 1304 | if (IsJoint()) |
1291 | if (VolumeDetectActive) | 1305 | { |
1292 | isPhantom = false; | 1306 | DoPhysicsPropertyUpdate(isPhysical, true); |
1293 | 1307 | } | |
1294 | // Added clarification.. since A rigid body is an object that you can kick around, etc. | 1308 | else |
1295 | bool RigidBody = isPhysical && !isPhantom; | ||
1296 | |||
1297 | // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition | ||
1298 | if (!isPhantom && !IsAttachment) | ||
1299 | { | 1309 | { |
1300 | PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( | 1310 | // Special case for VolumeDetection: If VolumeDetection is set, the phantom flag is locally ignored |
1301 | Name, | 1311 | if (VolumeDetectActive) |
1302 | Shape, | 1312 | isPhantom = false; |
1303 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
1304 | new PhysicsVector(Scale.X, Scale.Y, Scale.Z), | ||
1305 | RotationOffset, | ||
1306 | RigidBody); | ||
1307 | 1313 | ||
1308 | // Basic Physics returns null.. joy joy joy. | 1314 | // Added clarification.. since A rigid body is an object that you can kick around, etc. |
1309 | if (PhysActor != null) | 1315 | bool RigidBody = isPhysical && !isPhantom; |
1316 | |||
1317 | // The only time the physics scene shouldn't know about the prim is if it's phantom or an attachment, which is phantom by definition | ||
1318 | if (!isPhantom && !IsAttachment) | ||
1310 | { | 1319 | { |
1311 | PhysActor.LocalID = LocalId; | 1320 | PhysActor = m_parentGroup.Scene.PhysicsScene.AddPrimShape( |
1312 | DoPhysicsPropertyUpdate(RigidBody, true); | 1321 | Name, |
1313 | PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); | 1322 | Shape, |
1323 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
1324 | new PhysicsVector(Scale.X, Scale.Y, Scale.Z), | ||
1325 | RotationOffset, | ||
1326 | RigidBody); | ||
1327 | |||
1328 | // Basic Physics returns null.. joy joy joy. | ||
1329 | if (PhysActor != null) | ||
1330 | { | ||
1331 | PhysActor.SOPName = this.Name; // save object name and desc into the PhysActor so ODE internals know the joint/body info | ||
1332 | PhysActor.SOPDescription = this.Description; | ||
1333 | PhysActor.LocalID = LocalId; | ||
1334 | DoPhysicsPropertyUpdate(RigidBody, true); | ||
1335 | PhysActor.SetVolumeDetect(VolumeDetectActive ? 1 : 0); | ||
1336 | } | ||
1314 | } | 1337 | } |
1315 | } | 1338 | } |
1316 | } | 1339 | } |
@@ -1421,57 +1444,160 @@ if (m_shape != null) { | |||
1421 | 1444 | ||
1422 | public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) | 1445 | public void DoPhysicsPropertyUpdate(bool UsePhysics, bool isNew) |
1423 | { | 1446 | { |
1424 | if (PhysActor != null) | 1447 | if (IsJoint()) |
1425 | { | 1448 | { |
1426 | if (UsePhysics != PhysActor.IsPhysical || isNew) | 1449 | if (UsePhysics) |
1427 | { | 1450 | { |
1428 | if (PhysActor.IsPhysical) | 1451 | // by turning a joint proxy object physical, we cause creation of a joint in the ODE scene. |
1452 | // note that, as a special case, joints have no bodies or geoms in the physics scene, even though they are physical. | ||
1453 | |||
1454 | PhysicsJointType jointType; | ||
1455 | if (IsHingeJoint()) | ||
1456 | { | ||
1457 | jointType = PhysicsJointType.Hinge; | ||
1458 | } | ||
1459 | else if (IsBallJoint()) | ||
1460 | { | ||
1461 | jointType = PhysicsJointType.Ball; | ||
1462 | } | ||
1463 | else | ||
1464 | { | ||
1465 | jointType = PhysicsJointType.Ball; | ||
1466 | } | ||
1467 | |||
1468 | List<string> bodyNames = new List<string>(); | ||
1469 | string RawParams = Description; | ||
1470 | string[] jointParams = RawParams.Split(' '); | ||
1471 | string trackedBodyName = null; | ||
1472 | if (jointParams.Length >= 2) | ||
1473 | { | ||
1474 | for (int iBodyName = 0; iBodyName < 2; iBodyName++) | ||
1475 | { | ||
1476 | string bodyName = jointParams[iBodyName]; | ||
1477 | bodyNames.Add(bodyName); | ||
1478 | if (bodyName != "NULL") | ||
1479 | { | ||
1480 | if (trackedBodyName == null) | ||
1481 | { | ||
1482 | trackedBodyName = bodyName; | ||
1483 | } | ||
1484 | } | ||
1485 | } | ||
1486 | } | ||
1487 | |||
1488 | SceneObjectPart trackedBody = m_parentGroup.Scene.GetSceneObjectPart(trackedBodyName); // FIXME: causes a sequential lookup | ||
1489 | Quaternion localRotation = Quaternion.Identity; | ||
1490 | if (trackedBody != null) | ||
1429 | { | 1491 | { |
1430 | if (!isNew) | 1492 | localRotation = Quaternion.Inverse(trackedBody.RotationOffset) * this.RotationOffset; |
1431 | ParentGroup.Scene.RemovePhysicalPrim(1); | 1493 | } |
1494 | else | ||
1495 | { | ||
1496 | // error, output it below | ||
1497 | } | ||
1432 | 1498 | ||
1433 | PhysActor.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; | 1499 | PhysicsJoint joint; |
1434 | PhysActor.OnOutOfBounds -= PhysicsOutOfBounds; | 1500 | |
1435 | PhysActor.delink(); | 1501 | joint = m_parentGroup.Scene.PhysicsScene.RequestJointCreation(Name, jointType, |
1502 | new PhysicsVector(AbsolutePosition.X, AbsolutePosition.Y, AbsolutePosition.Z), | ||
1503 | this.RotationOffset, | ||
1504 | Description, | ||
1505 | bodyNames, | ||
1506 | trackedBodyName, | ||
1507 | localRotation); | ||
1508 | |||
1509 | if (trackedBody == null) | ||
1510 | { | ||
1511 | ParentGroup.Scene.jointErrorMessage(joint, "warning: tracked body name not found! joint location will not be updated properly. joint: " + Name); | ||
1436 | } | 1512 | } |
1437 | 1513 | ||
1438 | if (!UsePhysics && !isNew) | 1514 | } |
1515 | else | ||
1516 | { | ||
1517 | if (isNew) | ||
1439 | { | 1518 | { |
1440 | // reset velocity to 0 on physics switch-off. Without that, the client thinks the | 1519 | // if the joint proxy is new, and it is not physical, do nothing. There is no joint in ODE to |
1441 | // prim still has velocity and continues to interpolate its position along the old | 1520 | // delete, and if we try to delete it, due to asynchronous processing, the deletion request |
1442 | // velocity-vector. | 1521 | // will get processed later at an indeterminate time, which could cancel a later-arriving |
1522 | // joint creation request. | ||
1523 | } | ||
1524 | else | ||
1525 | { | ||
1526 | // here we turn off the joint object, so remove the joint from the physics scene | ||
1527 | m_parentGroup.Scene.PhysicsScene.RequestJointDeletion(Name); // FIXME: what if the name changed? | ||
1528 | |||
1529 | // make sure client isn't interpolating the joint proxy object | ||
1443 | Velocity = new Vector3(0, 0, 0); | 1530 | Velocity = new Vector3(0, 0, 0); |
1531 | RotationalVelocity = new Vector3(0, 0, 0); | ||
1444 | Acceleration = new Vector3(0, 0, 0); | 1532 | Acceleration = new Vector3(0, 0, 0); |
1445 | AngularVelocity = new Vector3(0, 0, 0); | ||
1446 | } | 1533 | } |
1534 | } | ||
1535 | } | ||
1536 | else | ||
1537 | { | ||
1538 | if (PhysActor != null) | ||
1539 | { | ||
1540 | if (UsePhysics != PhysActor.IsPhysical || isNew) | ||
1541 | { | ||
1542 | if (PhysActor.IsPhysical) // implies UsePhysics==false for this block | ||
1543 | { | ||
1544 | if (!isNew) | ||
1545 | ParentGroup.Scene.RemovePhysicalPrim(1); | ||
1447 | 1546 | ||
1448 | PhysActor.IsPhysical = UsePhysics; | 1547 | PhysActor.OnRequestTerseUpdate -= PhysicsRequestingTerseUpdate; |
1548 | PhysActor.OnOutOfBounds -= PhysicsOutOfBounds; | ||
1549 | PhysActor.delink(); | ||
1449 | 1550 | ||
1551 | if (ParentGroup.Scene.PhysicsScene.SupportsNINJAJoints && (!isNew)) | ||
1552 | { | ||
1553 | // destroy all joints connected to this now deactivated body | ||
1554 | m_parentGroup.Scene.PhysicsScene.RemoveAllJointsConnectedToActorThreadLocked(PhysActor); | ||
1555 | } | ||
1450 | 1556 | ||
1451 | // If we're not what we're supposed to be in the physics scene, recreate ourselves. | 1557 | // stop client-side interpolation of all joint proxy objects that have just been deleted |
1452 | //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); | 1558 | // this is done because RemoveAllJointsConnectedToActor invokes the OnJointDeactivated callback, |
1453 | /// that's not wholesome. Had to make Scene public | 1559 | // which stops client-side interpolation of deactivated joint proxy objects. |
1454 | //PhysActor = null; | 1560 | } |
1455 | 1561 | ||
1456 | if ((ObjectFlags & (uint) PrimFlags.Phantom) == 0) | 1562 | if (!UsePhysics && !isNew) |
1457 | { | ||
1458 | if (UsePhysics) | ||
1459 | { | 1563 | { |
1460 | ParentGroup.Scene.AddPhysicalPrim(1); | 1564 | // reset velocity to 0 on physics switch-off. Without that, the client thinks the |
1565 | // prim still has velocity and continues to interpolate its position along the old | ||
1566 | // velocity-vector. | ||
1567 | Velocity = new Vector3(0, 0, 0); | ||
1568 | Acceleration = new Vector3(0, 0, 0); | ||
1569 | AngularVelocity = new Vector3(0, 0, 0); | ||
1570 | //RotationalVelocity = new Vector3(0, 0, 0); | ||
1571 | } | ||
1572 | |||
1573 | PhysActor.IsPhysical = UsePhysics; | ||
1461 | 1574 | ||
1462 | PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; | 1575 | |
1463 | PhysActor.OnOutOfBounds += PhysicsOutOfBounds; | 1576 | // If we're not what we're supposed to be in the physics scene, recreate ourselves. |
1464 | if (_parentID != 0 && _parentID != LocalId) | 1577 | //m_parentGroup.Scene.PhysicsScene.RemovePrim(PhysActor); |
1578 | /// that's not wholesome. Had to make Scene public | ||
1579 | //PhysActor = null; | ||
1580 | |||
1581 | if ((ObjectFlags & (uint)PrimFlags.Phantom) == 0) | ||
1582 | { | ||
1583 | if (UsePhysics) | ||
1465 | { | 1584 | { |
1466 | if (ParentGroup.RootPart.PhysActor != null) | 1585 | ParentGroup.Scene.AddPhysicalPrim(1); |
1586 | |||
1587 | PhysActor.OnRequestTerseUpdate += PhysicsRequestingTerseUpdate; | ||
1588 | PhysActor.OnOutOfBounds += PhysicsOutOfBounds; | ||
1589 | if (_parentID != 0 && _parentID != LocalId) | ||
1467 | { | 1590 | { |
1468 | PhysActor.link(ParentGroup.RootPart.PhysActor); | 1591 | if (ParentGroup.RootPart.PhysActor != null) |
1592 | { | ||
1593 | PhysActor.link(ParentGroup.RootPart.PhysActor); | ||
1594 | } | ||
1469 | } | 1595 | } |
1470 | } | 1596 | } |
1471 | } | 1597 | } |
1472 | } | 1598 | } |
1599 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
1473 | } | 1600 | } |
1474 | m_parentGroup.Scene.PhysicsScene.AddPhysicsActorTaint(PhysActor); | ||
1475 | } | 1601 | } |
1476 | } | 1602 | } |
1477 | 1603 | ||
@@ -3190,6 +3316,53 @@ if (m_shape != null) { | |||
3190 | } | 3316 | } |
3191 | } | 3317 | } |
3192 | 3318 | ||
3319 | public bool IsHingeJoint() | ||
3320 | { | ||
3321 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3322 | // In the future, we can support other joint specification schemes such as a | ||
3323 | // custom checkbox in the viewer GUI. | ||
3324 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3325 | { | ||
3326 | string hingeString = "hingejoint"; | ||
3327 | return (Name.Length >= hingeString.Length && Name.Substring(0, hingeString.Length) == hingeString); | ||
3328 | } | ||
3329 | else | ||
3330 | { | ||
3331 | return false; | ||
3332 | } | ||
3333 | } | ||
3334 | |||
3335 | public bool IsBallJoint() | ||
3336 | { | ||
3337 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3338 | // In the future, we can support other joint specification schemes such as a | ||
3339 | // custom checkbox in the viewer GUI. | ||
3340 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3341 | { | ||
3342 | string ballString = "balljoint"; | ||
3343 | return (Name.Length >= ballString.Length && Name.Substring(0, ballString.Length) == ballString); | ||
3344 | } | ||
3345 | else | ||
3346 | { | ||
3347 | return false; | ||
3348 | } | ||
3349 | } | ||
3350 | |||
3351 | public bool IsJoint() | ||
3352 | { | ||
3353 | // For now, we use the NINJA naming scheme for identifying joints. | ||
3354 | // In the future, we can support other joint specification schemes such as a | ||
3355 | // custom checkbox in the viewer GUI. | ||
3356 | if (m_parentGroup.Scene.PhysicsScene.SupportsNINJAJoints) | ||
3357 | { | ||
3358 | return IsHingeJoint() || IsBallJoint(); | ||
3359 | } | ||
3360 | else | ||
3361 | { | ||
3362 | return false; | ||
3363 | } | ||
3364 | } | ||
3365 | |||
3193 | public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) | 3366 | public void UpdatePrimFlags(bool UsePhysics, bool IsTemporary, bool IsPhantom, bool IsVD) |
3194 | { | 3367 | { |
3195 | bool wasUsingPhysics = ((ObjectFlags & (uint) PrimFlags.Physics) != 0); | 3368 | bool wasUsingPhysics = ((ObjectFlags & (uint) PrimFlags.Physics) != 0); |
@@ -3230,6 +3403,11 @@ if (m_shape != null) { | |||
3230 | 3403 | ||
3231 | } | 3404 | } |
3232 | 3405 | ||
3406 | if (UsePhysics && IsJoint()) | ||
3407 | { | ||
3408 | IsPhantom = true; | ||
3409 | } | ||
3410 | |||
3233 | if (UsePhysics) | 3411 | if (UsePhysics) |
3234 | { | 3412 | { |
3235 | AddFlag(PrimFlags.Physics); | 3413 | AddFlag(PrimFlags.Physics); |
@@ -3258,7 +3436,7 @@ if (m_shape != null) { | |||
3258 | } | 3436 | } |
3259 | 3437 | ||
3260 | 3438 | ||
3261 | if (IsPhantom || IsAttachment) | 3439 | if (IsPhantom || IsAttachment) // note: this may have been changed above in the case of joints |
3262 | { | 3440 | { |
3263 | AddFlag(PrimFlags.Phantom); | 3441 | AddFlag(PrimFlags.Phantom); |
3264 | if (PhysActor != null) | 3442 | if (PhysActor != null) |