diff options
Diffstat (limited to 'OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs')
-rwxr-xr-x | OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | 494 |
1 files changed, 462 insertions, 32 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs index 4bac222..aaf92c8 100755 --- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs +++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -28,6 +28,8 @@ using System; | |||
28 | using System.Collections.Generic; | 28 | using System.Collections.Generic; |
29 | using System.Text; | 29 | using System.Text; |
30 | 30 | ||
31 | using OpenSim.Region.OptionalModules.Scripting; | ||
32 | |||
31 | using OMV = OpenMetaverse; | 33 | using OMV = OpenMetaverse; |
32 | 34 | ||
33 | namespace OpenSim.Region.Physics.BulletSPlugin | 35 | namespace OpenSim.Region.Physics.BulletSPlugin |
@@ -51,18 +53,32 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
51 | public float cfm; | 53 | public float cfm; |
52 | public float erp; | 54 | public float erp; |
53 | public float solverIterations; | 55 | public float solverIterations; |
56 | // | ||
57 | public OMV.Vector3 frameInAloc; | ||
58 | public OMV.Quaternion frameInArot; | ||
59 | public OMV.Vector3 frameInBloc; | ||
60 | public OMV.Quaternion frameInBrot; | ||
61 | public bool useLinearReferenceFrameA; | ||
62 | // Spring | ||
63 | public bool[] springAxisEnable; | ||
64 | public float[] springDamping; | ||
65 | public float[] springStiffness; | ||
66 | public OMV.Vector3 springLinearEquilibriumPoint; | ||
67 | public OMV.Vector3 springAngularEquilibriumPoint; | ||
54 | 68 | ||
55 | public BSLinkInfoConstraint(BSPrimLinkable pMember) | 69 | public BSLinkInfoConstraint(BSPrimLinkable pMember) |
56 | : base(pMember) | 70 | : base(pMember) |
57 | { | 71 | { |
58 | constraint = null; | 72 | constraint = null; |
59 | ResetToFixedConstraint(); | 73 | ResetLink(); |
74 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); | ||
60 | } | 75 | } |
61 | 76 | ||
62 | // Set all the parameters for this constraint to a fixed, non-movable constraint. | 77 | // Set all the parameters for this constraint to a fixed, non-movable constraint. |
63 | public void ResetToFixedConstraint() | 78 | public override void ResetLink() |
64 | { | 79 | { |
65 | constraintType = ConstraintType.D6_CONSTRAINT_TYPE; | 80 | // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; |
81 | constraintType = ConstraintType.FIXED_CONSTRAINT_TYPE; | ||
66 | linearLimitLow = OMV.Vector3.Zero; | 82 | linearLimitLow = OMV.Vector3.Zero; |
67 | linearLimitHigh = OMV.Vector3.Zero; | 83 | linearLimitHigh = OMV.Vector3.Zero; |
68 | angularLimitLow = OMV.Vector3.Zero; | 84 | angularLimitLow = OMV.Vector3.Zero; |
@@ -74,17 +90,37 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
74 | cfm = BSParam.LinkConstraintCFM; | 90 | cfm = BSParam.LinkConstraintCFM; |
75 | erp = BSParam.LinkConstraintERP; | 91 | erp = BSParam.LinkConstraintERP; |
76 | solverIterations = BSParam.LinkConstraintSolverIterations; | 92 | solverIterations = BSParam.LinkConstraintSolverIterations; |
93 | frameInAloc = OMV.Vector3.Zero; | ||
94 | frameInArot = OMV.Quaternion.Identity; | ||
95 | frameInBloc = OMV.Vector3.Zero; | ||
96 | frameInBrot = OMV.Quaternion.Identity; | ||
97 | useLinearReferenceFrameA = true; | ||
98 | springAxisEnable = new bool[6]; | ||
99 | springDamping = new float[6]; | ||
100 | springStiffness = new float[6]; | ||
101 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
102 | { | ||
103 | springAxisEnable[ii] = false; | ||
104 | springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
105 | springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
106 | } | ||
107 | springLinearEquilibriumPoint = OMV.Vector3.Zero; | ||
108 | springAngularEquilibriumPoint = OMV.Vector3.Zero; | ||
109 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); | ||
77 | } | 110 | } |
78 | 111 | ||
79 | // Given a constraint, apply the current constraint parameters to same. | 112 | // Given a constraint, apply the current constraint parameters to same. |
80 | public void SetConstraintParameters(BSConstraint constrain) | 113 | public override void SetLinkParameters(BSConstraint constrain) |
81 | { | 114 | { |
115 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); | ||
82 | switch (constraintType) | 116 | switch (constraintType) |
83 | { | 117 | { |
118 | case ConstraintType.FIXED_CONSTRAINT_TYPE: | ||
84 | case ConstraintType.D6_CONSTRAINT_TYPE: | 119 | case ConstraintType.D6_CONSTRAINT_TYPE: |
85 | BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; | 120 | BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; |
86 | if (constrain6dof != null) | 121 | if (constrain6dof != null) |
87 | { | 122 | { |
123 | // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. | ||
88 | // zero linear and angular limits makes the objects unable to move in relation to each other | 124 | // zero linear and angular limits makes the objects unable to move in relation to each other |
89 | constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); | 125 | constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); |
90 | constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); | 126 | constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); |
@@ -99,10 +135,55 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
99 | } | 135 | } |
100 | } | 136 | } |
101 | break; | 137 | break; |
138 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
139 | BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; | ||
140 | if (constrainSpring != null) | ||
141 | { | ||
142 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
143 | constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
144 | constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
145 | |||
146 | // tweek the constraint to increase stability | ||
147 | constrainSpring.UseFrameOffset(useFrameOffset); | ||
148 | constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
149 | constrainSpring.SetCFMAndERP(cfm, erp); | ||
150 | if (solverIterations != 0f) | ||
151 | { | ||
152 | constrainSpring.SetSolverIterations(solverIterations); | ||
153 | } | ||
154 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
155 | { | ||
156 | constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); | ||
157 | if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
158 | constrainSpring.SetDamping(ii, springDamping[ii]); | ||
159 | if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
160 | constrainSpring.SetStiffness(ii, springStiffness[ii]); | ||
161 | } | ||
162 | constrainSpring.CalculateTransforms(); | ||
163 | |||
164 | if (springLinearEquilibriumPoint != OMV.Vector3.Zero) | ||
165 | constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); | ||
166 | else | ||
167 | constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); | ||
168 | } | ||
169 | break; | ||
102 | default: | 170 | default: |
103 | break; | 171 | break; |
104 | } | 172 | } |
105 | } | 173 | } |
174 | |||
175 | // Return 'true' if the property updates from the physics engine should be reported | ||
176 | // to the simulator. | ||
177 | // If the constraint is fixed, we don't need to report as the simulator and viewer will | ||
178 | // report the right things. | ||
179 | public override bool ShouldUpdateChildProperties() | ||
180 | { | ||
181 | bool ret = true; | ||
182 | if (constraintType == ConstraintType.FIXED_CONSTRAINT_TYPE) | ||
183 | ret = false; | ||
184 | |||
185 | return ret; | ||
186 | } | ||
106 | } | 187 | } |
107 | 188 | ||
108 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) | 189 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) |
@@ -110,12 +191,15 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
110 | LinksetImpl = LinksetImplementation.Constraint; | 191 | LinksetImpl = LinksetImplementation.Constraint; |
111 | } | 192 | } |
112 | 193 | ||
194 | private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; | ||
195 | |||
113 | // When physical properties are changed the linkset needs to recalculate | 196 | // When physical properties are changed the linkset needs to recalculate |
114 | // its internal properties. | 197 | // its internal properties. |
115 | // This is queued in the 'post taint' queue so the | 198 | // This is queued in the 'post taint' queue so the |
116 | // refresh will happen once after all the other taints are applied. | 199 | // refresh will happen once after all the other taints are applied. |
117 | public override void Refresh(BSPrimLinkable requestor) | 200 | public override void Refresh(BSPrimLinkable requestor) |
118 | { | 201 | { |
202 | ScheduleRebuild(requestor); | ||
119 | base.Refresh(requestor); | 203 | base.Refresh(requestor); |
120 | 204 | ||
121 | } | 205 | } |
@@ -132,10 +216,16 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
132 | { | 216 | { |
133 | // Queue to happen after all the other taint processing | 217 | // Queue to happen after all the other taint processing |
134 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | 218 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() |
219 | { | ||
220 | if (HasAnyChildren) | ||
135 | { | 221 | { |
136 | if (HasAnyChildren) | 222 | // Constraints that have not been changed are not rebuild but make sure |
137 | RecomputeLinksetConstraints(); | 223 | // the constraint of the requestor is rebuilt. |
138 | }); | 224 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); |
225 | // Rebuild the linkset and all its constraints. | ||
226 | RecomputeLinksetConstraints(); | ||
227 | } | ||
228 | }); | ||
139 | } | 229 | } |
140 | } | 230 | } |
141 | 231 | ||
@@ -152,7 +242,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
152 | if (IsRoot(child)) | 242 | if (IsRoot(child)) |
153 | { | 243 | { |
154 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | 244 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. |
155 | ScheduleRebuild(LinksetRoot); | 245 | Refresh(LinksetRoot); |
156 | } | 246 | } |
157 | return ret; | 247 | return ret; |
158 | } | 248 | } |
@@ -171,7 +261,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
171 | if (IsRoot(child)) | 261 | if (IsRoot(child)) |
172 | { | 262 | { |
173 | // Schedule a rebuild to verify that the root shape is set to the real shape. | 263 | // Schedule a rebuild to verify that the root shape is set to the real shape. |
174 | ScheduleRebuild(LinksetRoot); | 264 | Refresh(LinksetRoot); |
175 | } | 265 | } |
176 | return ret; | 266 | return ret; |
177 | } | 267 | } |
@@ -199,7 +289,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
199 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | 289 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. |
200 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | 290 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
201 | // Cause the constraints, et al to be rebuilt before the next simulation step. | 291 | // Cause the constraints, et al to be rebuilt before the next simulation step. |
202 | ScheduleRebuild(LinksetRoot); | 292 | Refresh(LinksetRoot); |
203 | } | 293 | } |
204 | return ret; | 294 | return ret; |
205 | } | 295 | } |
@@ -217,14 +307,14 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
217 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | 307 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); |
218 | 308 | ||
219 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | 309 | // Cause constraints and assorted properties to be recomputed before the next simulation step. |
220 | ScheduleRebuild(LinksetRoot); | 310 | Refresh(LinksetRoot); |
221 | } | 311 | } |
222 | return; | 312 | return; |
223 | } | 313 | } |
224 | 314 | ||
225 | // Remove the specified child from the linkset. | 315 | // Remove the specified child from the linkset. |
226 | // Safe to call even if the child is not really in my linkset. | 316 | // Safe to call even if the child is not really in my linkset. |
227 | protected override void RemoveChildFromLinkset(BSPrimLinkable child) | 317 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) |
228 | { | 318 | { |
229 | if (m_children.Remove(child)) | 319 | if (m_children.Remove(child)) |
230 | { | 320 | { |
@@ -236,12 +326,12 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
236 | rootx.LocalID, rootx.PhysBody.AddrString, | 326 | rootx.LocalID, rootx.PhysBody.AddrString, |
237 | childx.LocalID, childx.PhysBody.AddrString); | 327 | childx.LocalID, childx.PhysBody.AddrString); |
238 | 328 | ||
239 | m_physicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() | 329 | m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() |
240 | { | 330 | { |
241 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | 331 | PhysicallyUnlinkAChildFromRoot(rootx, childx); |
242 | }); | 332 | }); |
243 | // See that the linkset parameters are recomputed at the end of the taint time. | 333 | // See that the linkset parameters are recomputed at the end of the taint time. |
244 | ScheduleRebuild(LinksetRoot); | 334 | Refresh(LinksetRoot); |
245 | } | 335 | } |
246 | else | 336 | else |
247 | { | 337 | { |
@@ -262,8 +352,8 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
262 | // Create a static constraint between the two passed objects | 352 | // Create a static constraint between the two passed objects |
263 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) | 353 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) |
264 | { | 354 | { |
265 | BSLinkInfoConstraint liConstraint = li as BSLinkInfoConstraint; | 355 | BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; |
266 | if (liConstraint == null) | 356 | if (linkInfo == null) |
267 | return null; | 357 | return null; |
268 | 358 | ||
269 | // Zero motion for children so they don't interpolate | 359 | // Zero motion for children so they don't interpolate |
@@ -271,27 +361,26 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
271 | 361 | ||
272 | BSConstraint constrain = null; | 362 | BSConstraint constrain = null; |
273 | 363 | ||
274 | switch (liConstraint.constraintType) | 364 | switch (linkInfo.constraintType) |
275 | { | 365 | { |
366 | case ConstraintType.FIXED_CONSTRAINT_TYPE: | ||
276 | case ConstraintType.D6_CONSTRAINT_TYPE: | 367 | case ConstraintType.D6_CONSTRAINT_TYPE: |
277 | // Relative position normalized to the root prim | 368 | // Relative position normalized to the root prim |
278 | // Essentually a vector pointing from center of rootPrim to center of li.member | 369 | // Essentually a vector pointing from center of rootPrim to center of li.member |
279 | OMV.Vector3 childRelativePosition = liConstraint.member.Position - rootPrim.Position; | 370 | OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; |
280 | 371 | ||
281 | // real world coordinate of midpoint between the two objects | 372 | // real world coordinate of midpoint between the two objects |
282 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | 373 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); |
283 | 374 | ||
284 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", | 375 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", |
285 | rootPrim.LocalID, | 376 | rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, |
286 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | 377 | rootPrim.Position, linkInfo.member.Position, midPoint); |
287 | liConstraint.member.LocalID, liConstraint.member.PhysBody.AddrString, | ||
288 | rootPrim.Position, liConstraint.member.Position, midPoint); | ||
289 | 378 | ||
290 | // create a constraint that allows no freedom of movement between the two objects | 379 | // create a constraint that allows no freedom of movement between the two objects |
291 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | 380 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 |
292 | 381 | ||
293 | constrain = new BSConstraint6Dof( | 382 | constrain = new BSConstraint6Dof( |
294 | m_physicsScene.World, rootPrim.PhysBody, liConstraint.member.PhysBody, midPoint, true, true ); | 383 | m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); |
295 | 384 | ||
296 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | 385 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. |
297 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | 386 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms |
@@ -320,11 +409,23 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
320 | */ | 409 | */ |
321 | 410 | ||
322 | break; | 411 | break; |
412 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
413 | constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, | ||
414 | linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, | ||
415 | linkInfo.useLinearReferenceFrameA, | ||
416 | true /*disableCollisionsBetweenLinkedBodies*/); | ||
417 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", | ||
418 | rootPrim.LocalID, | ||
419 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
420 | linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, | ||
421 | rootPrim.Position, linkInfo.member.Position); | ||
422 | |||
423 | break; | ||
323 | default: | 424 | default: |
324 | break; | 425 | break; |
325 | } | 426 | } |
326 | 427 | ||
327 | liConstraint.SetConstraintParameters(constrain); | 428 | linkInfo.SetLinkParameters(constrain); |
328 | 429 | ||
329 | m_physicsScene.Constraints.AddConstraint(constrain); | 430 | m_physicsScene.Constraints.AddConstraint(constrain); |
330 | 431 | ||
@@ -343,13 +444,22 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
343 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | 444 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, |
344 | childPrim.LocalID, childPrim.PhysBody.AddrString); | 445 | childPrim.LocalID, childPrim.PhysBody.AddrString); |
345 | 446 | ||
346 | // Find the constraint for this link and get rid of it from the overall collection and from my list | 447 | // If asked to unlink root from root, just remove all the constraints |
347 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | 448 | if (rootPrim == childPrim || childPrim == LinksetRoot) |
348 | { | 449 | { |
349 | // Make the child refresh its location | 450 | PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); |
350 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); | ||
351 | ret = true; | 451 | ret = true; |
352 | } | 452 | } |
453 | else | ||
454 | { | ||
455 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
456 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | ||
457 | { | ||
458 | // Make the child refresh its location | ||
459 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); | ||
460 | ret = true; | ||
461 | } | ||
462 | } | ||
353 | 463 | ||
354 | return ret; | 464 | return ret; |
355 | } | 465 | } |
@@ -382,9 +492,9 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
382 | Rebuilding = true; | 492 | Rebuilding = true; |
383 | 493 | ||
384 | // There is no reason to build all this physical stuff for a non-physical linkset. | 494 | // There is no reason to build all this physical stuff for a non-physical linkset. |
385 | if (!LinksetRoot.IsPhysicallyActive) | 495 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) |
386 | { | 496 | { |
387 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysical", LinksetRoot.LocalID); | 497 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); |
388 | return; // Note the 'finally' clause at the botton which will get executed. | 498 | return; // Note the 'finally' clause at the botton which will get executed. |
389 | } | 499 | } |
390 | 500 | ||
@@ -401,6 +511,7 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
401 | // If constraint doesn't exist yet, create it. | 511 | // If constraint doesn't exist yet, create it. |
402 | constrain = BuildConstraint(LinksetRoot, li); | 512 | constrain = BuildConstraint(LinksetRoot, li); |
403 | } | 513 | } |
514 | li.SetLinkParameters(constrain); | ||
404 | constrain.RecomputeConstraintVariables(linksetMass); | 515 | constrain.RecomputeConstraintVariables(linksetMass); |
405 | 516 | ||
406 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG | 517 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG |
@@ -412,5 +523,324 @@ public sealed class BSLinksetConstraints : BSLinkset | |||
412 | Rebuilding = false; | 523 | Rebuilding = false; |
413 | } | 524 | } |
414 | } | 525 | } |
526 | |||
527 | #region Extension | ||
528 | public override object Extension(string pFunct, params object[] pParams) | ||
529 | { | ||
530 | object ret = null; | ||
531 | switch (pFunct) | ||
532 | { | ||
533 | // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] | ||
534 | case ExtendedPhysics.PhysFunctChangeLinkType: | ||
535 | if (pParams.Length > 2) | ||
536 | { | ||
537 | int requestedType = (int)pParams[2]; | ||
538 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); | ||
539 | if (requestedType == (int)ConstraintType.FIXED_CONSTRAINT_TYPE | ||
540 | || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE | ||
541 | || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
542 | || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE | ||
543 | || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
544 | || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
545 | { | ||
546 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
547 | if (child != null) | ||
548 | { | ||
549 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", | ||
550 | LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); | ||
551 | m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() | ||
552 | { | ||
553 | // Pick up all the constraints currently created. | ||
554 | RemoveDependencies(child); | ||
555 | |||
556 | BSLinkInfo linkInfo = null; | ||
557 | if (TryGetLinkInfo(child, out linkInfo)) | ||
558 | { | ||
559 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
560 | if (linkInfoC != null) | ||
561 | { | ||
562 | linkInfoC.constraintType = (ConstraintType)requestedType; | ||
563 | ret = (object)true; | ||
564 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", | ||
565 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
566 | } | ||
567 | else | ||
568 | { | ||
569 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
570 | } | ||
571 | } | ||
572 | else | ||
573 | { | ||
574 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
575 | } | ||
576 | // Cause the whole linkset to be rebuilt in post-taint time. | ||
577 | Refresh(child); | ||
578 | }); | ||
579 | } | ||
580 | else | ||
581 | { | ||
582 | DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); | ||
583 | } | ||
584 | } | ||
585 | else | ||
586 | { | ||
587 | DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", | ||
588 | LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); | ||
589 | } | ||
590 | } | ||
591 | break; | ||
592 | // pParams = [ BSPhysObject root, BSPhysObject child ] | ||
593 | case ExtendedPhysics.PhysFunctGetLinkType: | ||
594 | if (pParams.Length > 0) | ||
595 | { | ||
596 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
597 | if (child != null) | ||
598 | { | ||
599 | BSLinkInfo linkInfo = null; | ||
600 | if (TryGetLinkInfo(child, out linkInfo)) | ||
601 | { | ||
602 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
603 | if (linkInfoC != null) | ||
604 | { | ||
605 | ret = (object)(int)linkInfoC.constraintType; | ||
606 | DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", | ||
607 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
608 | |||
609 | } | ||
610 | } | ||
611 | } | ||
612 | } | ||
613 | break; | ||
614 | // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] | ||
615 | case ExtendedPhysics.PhysFunctChangeLinkParams: | ||
616 | // There should be two parameters: the childActor and a list of parameters to set | ||
617 | if (pParams.Length > 2) | ||
618 | { | ||
619 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
620 | BSLinkInfo baseLinkInfo = null; | ||
621 | if (TryGetLinkInfo(child, out baseLinkInfo)) | ||
622 | { | ||
623 | BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; | ||
624 | if (linkInfo != null) | ||
625 | { | ||
626 | int valueInt; | ||
627 | float valueFloat; | ||
628 | bool valueBool; | ||
629 | OMV.Vector3 valueVector; | ||
630 | OMV.Vector3 valueVector2; | ||
631 | OMV.Quaternion valueQuaternion; | ||
632 | int axisLow, axisHigh; | ||
633 | |||
634 | int opIndex = 2; | ||
635 | while (opIndex < pParams.Length) | ||
636 | { | ||
637 | int thisOp = 0; | ||
638 | string errMsg = ""; | ||
639 | try | ||
640 | { | ||
641 | thisOp = (int)pParams[opIndex]; | ||
642 | DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", | ||
643 | linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); | ||
644 | switch (thisOp) | ||
645 | { | ||
646 | case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: | ||
647 | valueInt = (int)pParams[opIndex + 1]; | ||
648 | ConstraintType valueType = (ConstraintType)valueInt; | ||
649 | if (valueType == ConstraintType.FIXED_CONSTRAINT_TYPE | ||
650 | || valueType == ConstraintType.D6_CONSTRAINT_TYPE | ||
651 | || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
652 | || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE | ||
653 | || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
654 | || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
655 | { | ||
656 | linkInfo.constraintType = valueType; | ||
657 | } | ||
658 | opIndex += 2; | ||
659 | break; | ||
660 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: | ||
661 | errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; | ||
662 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
663 | linkInfo.frameInAloc = valueVector; | ||
664 | opIndex += 2; | ||
665 | break; | ||
666 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: | ||
667 | errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; | ||
668 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
669 | linkInfo.frameInArot = valueQuaternion; | ||
670 | opIndex += 2; | ||
671 | break; | ||
672 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: | ||
673 | errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; | ||
674 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
675 | linkInfo.frameInBloc = valueVector; | ||
676 | opIndex += 2; | ||
677 | break; | ||
678 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: | ||
679 | errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; | ||
680 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
681 | linkInfo.frameInBrot = valueQuaternion; | ||
682 | opIndex += 2; | ||
683 | break; | ||
684 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: | ||
685 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; | ||
686 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
687 | linkInfo.linearLimitLow = valueVector; | ||
688 | opIndex += 2; | ||
689 | break; | ||
690 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: | ||
691 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; | ||
692 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
693 | linkInfo.linearLimitHigh = valueVector; | ||
694 | opIndex += 2; | ||
695 | break; | ||
696 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: | ||
697 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; | ||
698 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
699 | linkInfo.angularLimitLow = valueVector; | ||
700 | opIndex += 2; | ||
701 | break; | ||
702 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: | ||
703 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; | ||
704 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
705 | linkInfo.angularLimitHigh = valueVector; | ||
706 | opIndex += 2; | ||
707 | break; | ||
708 | case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: | ||
709 | errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; | ||
710 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
711 | linkInfo.useFrameOffset = valueBool; | ||
712 | opIndex += 2; | ||
713 | break; | ||
714 | case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: | ||
715 | errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; | ||
716 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
717 | linkInfo.enableTransMotor = valueBool; | ||
718 | opIndex += 2; | ||
719 | break; | ||
720 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: | ||
721 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; | ||
722 | valueFloat = (float)pParams[opIndex + 1]; | ||
723 | linkInfo.transMotorMaxVel = valueFloat; | ||
724 | opIndex += 2; | ||
725 | break; | ||
726 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: | ||
727 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; | ||
728 | valueFloat = (float)pParams[opIndex + 1]; | ||
729 | linkInfo.transMotorMaxForce = valueFloat; | ||
730 | opIndex += 2; | ||
731 | break; | ||
732 | case ExtendedPhysics.PHYS_PARAM_CFM: | ||
733 | errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; | ||
734 | valueFloat = (float)pParams[opIndex + 1]; | ||
735 | linkInfo.cfm = valueFloat; | ||
736 | opIndex += 2; | ||
737 | break; | ||
738 | case ExtendedPhysics.PHYS_PARAM_ERP: | ||
739 | errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; | ||
740 | valueFloat = (float)pParams[opIndex + 1]; | ||
741 | linkInfo.erp = valueFloat; | ||
742 | opIndex += 2; | ||
743 | break; | ||
744 | case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: | ||
745 | errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; | ||
746 | valueFloat = (float)pParams[opIndex + 1]; | ||
747 | linkInfo.solverIterations = valueFloat; | ||
748 | opIndex += 2; | ||
749 | break; | ||
750 | case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: | ||
751 | errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; | ||
752 | valueInt = (int)pParams[opIndex + 1]; | ||
753 | valueBool = ((int)pParams[opIndex + 2]) != 0; | ||
754 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
755 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
756 | linkInfo.springAxisEnable[ii] = valueBool; | ||
757 | opIndex += 3; | ||
758 | break; | ||
759 | case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: | ||
760 | errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; | ||
761 | valueInt = (int)pParams[opIndex + 1]; | ||
762 | valueFloat = (float)pParams[opIndex + 2]; | ||
763 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
764 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
765 | linkInfo.springDamping[ii] = valueFloat; | ||
766 | opIndex += 3; | ||
767 | break; | ||
768 | case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: | ||
769 | errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; | ||
770 | valueInt = (int)pParams[opIndex + 1]; | ||
771 | valueFloat = (float)pParams[opIndex + 2]; | ||
772 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
773 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
774 | linkInfo.springStiffness[ii] = valueFloat; | ||
775 | opIndex += 3; | ||
776 | break; | ||
777 | case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: | ||
778 | errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; | ||
779 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
780 | valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; | ||
781 | linkInfo.springLinearEquilibriumPoint = valueVector; | ||
782 | linkInfo.springAngularEquilibriumPoint = valueVector2; | ||
783 | opIndex += 3; | ||
784 | break; | ||
785 | case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: | ||
786 | errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; | ||
787 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
788 | linkInfo.useLinearReferenceFrameA = valueBool; | ||
789 | opIndex += 2; | ||
790 | break; | ||
791 | default: | ||
792 | break; | ||
793 | } | ||
794 | } | ||
795 | catch (InvalidCastException e) | ||
796 | { | ||
797 | m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", | ||
798 | LogHeader, errMsg, e); | ||
799 | } | ||
800 | catch (Exception e) | ||
801 | { | ||
802 | m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); | ||
803 | } | ||
804 | } | ||
805 | } | ||
806 | // Something changed so a rebuild is in order | ||
807 | Refresh(child); | ||
808 | } | ||
809 | } | ||
810 | break; | ||
811 | default: | ||
812 | ret = base.Extension(pFunct, pParams); | ||
813 | break; | ||
814 | } | ||
815 | return ret; | ||
816 | } | ||
817 | |||
818 | // Bullet constraints keep some limit parameters for each linear and angular axis. | ||
819 | // Setting same is easier if there is an easy way to see all or types. | ||
820 | // This routine returns the array limits for the set of axis. | ||
821 | private void GetAxisRange(int rangeSpec, out int low, out int high) | ||
822 | { | ||
823 | switch (rangeSpec) | ||
824 | { | ||
825 | case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: | ||
826 | low = 0; | ||
827 | high = 2; | ||
828 | break; | ||
829 | case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: | ||
830 | low = 3; | ||
831 | high = 5; | ||
832 | break; | ||
833 | case ExtendedPhysics.PHYS_AXIS_ALL: | ||
834 | low = 0; | ||
835 | high = 5; | ||
836 | break; | ||
837 | default: | ||
838 | low = high = rangeSpec; | ||
839 | break; | ||
840 | } | ||
841 | return; | ||
842 | } | ||
843 | #endregion // Extension | ||
844 | |||
415 | } | 845 | } |
416 | } | 846 | } |