diff options
author | Robert Adams | 2015-09-08 04:54:16 -0700 |
---|---|---|
committer | Robert Adams | 2015-09-08 04:54:16 -0700 |
commit | e5367d822be9b05e74c859afe2d2956a3e95aa33 (patch) | |
tree | e904050a30715df587aa527d7f313755177726a7 /OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs | |
parent | add lost admin_reset_land method (diff) | |
parent | Deleted access control spec from [LoginService] section of standalone config.... (diff) | |
download | opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.zip opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.gz opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.bz2 opensim-SC_OLD-e5367d822be9b05e74c859afe2d2956a3e95aa33.tar.xz |
Merge of ubitworkvarnew with opensim/master as of 20150905.
This integrates the OpenSim refactoring to make physics, etc into modules.
AVN physics hasn't been moved to new location.
Does not compile yet.
Merge branch 'osmaster' into mbworknew1
Diffstat (limited to 'OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs')
-rwxr-xr-x | OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs | 852 |
1 files changed, 852 insertions, 0 deletions
diff --git a/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs new file mode 100755 index 0000000..c4b4c86 --- /dev/null +++ b/OpenSim/Region/PhysicsModules/BulletS/BSLinksetConstraints.cs | |||
@@ -0,0 +1,852 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyrightD | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Text; | ||
30 | |||
31 | using OMV = OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Region.PhysicsModule.BulletS | ||
34 | { | ||
35 | public sealed class BSLinksetConstraints : BSLinkset | ||
36 | { | ||
37 | // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; | ||
38 | |||
39 | public class BSLinkInfoConstraint : BSLinkInfo | ||
40 | { | ||
41 | public ConstraintType constraintType; | ||
42 | public BSConstraint constraint; | ||
43 | public OMV.Vector3 linearLimitLow; | ||
44 | public OMV.Vector3 linearLimitHigh; | ||
45 | public OMV.Vector3 angularLimitLow; | ||
46 | public OMV.Vector3 angularLimitHigh; | ||
47 | public bool useFrameOffset; | ||
48 | public bool enableTransMotor; | ||
49 | public float transMotorMaxVel; | ||
50 | public float transMotorMaxForce; | ||
51 | public float cfm; | ||
52 | public float erp; | ||
53 | public float solverIterations; | ||
54 | // | ||
55 | public OMV.Vector3 frameInAloc; | ||
56 | public OMV.Quaternion frameInArot; | ||
57 | public OMV.Vector3 frameInBloc; | ||
58 | public OMV.Quaternion frameInBrot; | ||
59 | public bool useLinearReferenceFrameA; | ||
60 | // Spring | ||
61 | public bool[] springAxisEnable; | ||
62 | public float[] springDamping; | ||
63 | public float[] springStiffness; | ||
64 | public OMV.Vector3 springLinearEquilibriumPoint; | ||
65 | public OMV.Vector3 springAngularEquilibriumPoint; | ||
66 | |||
67 | public BSLinkInfoConstraint(BSPrimLinkable pMember) | ||
68 | : base(pMember) | ||
69 | { | ||
70 | constraint = null; | ||
71 | ResetLink(); | ||
72 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.creation", member.LocalID); | ||
73 | } | ||
74 | |||
75 | // Set all the parameters for this constraint to a fixed, non-movable constraint. | ||
76 | public override void ResetLink() | ||
77 | { | ||
78 | // constraintType = ConstraintType.D6_CONSTRAINT_TYPE; | ||
79 | constraintType = ConstraintType.BS_FIXED_CONSTRAINT_TYPE; | ||
80 | linearLimitLow = OMV.Vector3.Zero; | ||
81 | linearLimitHigh = OMV.Vector3.Zero; | ||
82 | angularLimitLow = OMV.Vector3.Zero; | ||
83 | angularLimitHigh = OMV.Vector3.Zero; | ||
84 | useFrameOffset = BSParam.LinkConstraintUseFrameOffset; | ||
85 | enableTransMotor = BSParam.LinkConstraintEnableTransMotor; | ||
86 | transMotorMaxVel = BSParam.LinkConstraintTransMotorMaxVel; | ||
87 | transMotorMaxForce = BSParam.LinkConstraintTransMotorMaxForce; | ||
88 | cfm = BSParam.LinkConstraintCFM; | ||
89 | erp = BSParam.LinkConstraintERP; | ||
90 | solverIterations = BSParam.LinkConstraintSolverIterations; | ||
91 | frameInAloc = OMV.Vector3.Zero; | ||
92 | frameInArot = OMV.Quaternion.Identity; | ||
93 | frameInBloc = OMV.Vector3.Zero; | ||
94 | frameInBrot = OMV.Quaternion.Identity; | ||
95 | useLinearReferenceFrameA = true; | ||
96 | springAxisEnable = new bool[6]; | ||
97 | springDamping = new float[6]; | ||
98 | springStiffness = new float[6]; | ||
99 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
100 | { | ||
101 | springAxisEnable[ii] = false; | ||
102 | springDamping[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
103 | springStiffness[ii] = BSAPITemplate.SPRING_NOT_SPECIFIED; | ||
104 | } | ||
105 | springLinearEquilibriumPoint = OMV.Vector3.Zero; | ||
106 | springAngularEquilibriumPoint = OMV.Vector3.Zero; | ||
107 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.ResetLink", member.LocalID); | ||
108 | } | ||
109 | |||
110 | // Given a constraint, apply the current constraint parameters to same. | ||
111 | public override void SetLinkParameters(BSConstraint constrain) | ||
112 | { | ||
113 | member.PhysScene.DetailLog("{0},BSLinkInfoConstraint.SetLinkParameters,type={1}", member.LocalID, constraintType); | ||
114 | switch (constraintType) | ||
115 | { | ||
116 | case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: | ||
117 | case ConstraintType.D6_CONSTRAINT_TYPE: | ||
118 | BSConstraint6Dof constrain6dof = constrain as BSConstraint6Dof; | ||
119 | if (constrain6dof != null) | ||
120 | { | ||
121 | // NOTE: D6_SPRING_CONSTRAINT_TYPE should be updated if you change any of this code. | ||
122 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
123 | constrain6dof.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
124 | constrain6dof.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
125 | |||
126 | // tweek the constraint to increase stability | ||
127 | constrain6dof.UseFrameOffset(useFrameOffset); | ||
128 | constrain6dof.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
129 | constrain6dof.SetCFMAndERP(cfm, erp); | ||
130 | if (solverIterations != 0f) | ||
131 | { | ||
132 | constrain6dof.SetSolverIterations(solverIterations); | ||
133 | } | ||
134 | } | ||
135 | break; | ||
136 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
137 | BSConstraintSpring constrainSpring = constrain as BSConstraintSpring; | ||
138 | if (constrainSpring != null) | ||
139 | { | ||
140 | // zero linear and angular limits makes the objects unable to move in relation to each other | ||
141 | constrainSpring.SetLinearLimits(linearLimitLow, linearLimitHigh); | ||
142 | constrainSpring.SetAngularLimits(angularLimitLow, angularLimitHigh); | ||
143 | |||
144 | // tweek the constraint to increase stability | ||
145 | constrainSpring.UseFrameOffset(useFrameOffset); | ||
146 | constrainSpring.TranslationalLimitMotor(enableTransMotor, transMotorMaxVel, transMotorMaxForce); | ||
147 | constrainSpring.SetCFMAndERP(cfm, erp); | ||
148 | if (solverIterations != 0f) | ||
149 | { | ||
150 | constrainSpring.SetSolverIterations(solverIterations); | ||
151 | } | ||
152 | for (int ii = 0; ii < springAxisEnable.Length; ii++) | ||
153 | { | ||
154 | constrainSpring.SetAxisEnable(ii, springAxisEnable[ii]); | ||
155 | if (springDamping[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
156 | constrainSpring.SetDamping(ii, springDamping[ii]); | ||
157 | if (springStiffness[ii] != BSAPITemplate.SPRING_NOT_SPECIFIED) | ||
158 | constrainSpring.SetStiffness(ii, springStiffness[ii]); | ||
159 | } | ||
160 | constrainSpring.CalculateTransforms(); | ||
161 | |||
162 | if (springLinearEquilibriumPoint != OMV.Vector3.Zero) | ||
163 | constrainSpring.SetEquilibriumPoint(springLinearEquilibriumPoint, springAngularEquilibriumPoint); | ||
164 | else | ||
165 | constrainSpring.SetEquilibriumPoint(BSAPITemplate.SPRING_NOT_SPECIFIED, BSAPITemplate.SPRING_NOT_SPECIFIED); | ||
166 | } | ||
167 | break; | ||
168 | default: | ||
169 | break; | ||
170 | } | ||
171 | } | ||
172 | |||
173 | // Return 'true' if the property updates from the physics engine should be reported | ||
174 | // to the simulator. | ||
175 | // If the constraint is fixed, we don't need to report as the simulator and viewer will | ||
176 | // report the right things. | ||
177 | public override bool ShouldUpdateChildProperties() | ||
178 | { | ||
179 | bool ret = true; | ||
180 | if (constraintType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE) | ||
181 | ret = false; | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | } | ||
186 | |||
187 | public BSLinksetConstraints(BSScene scene, BSPrimLinkable parent) : base(scene, parent) | ||
188 | { | ||
189 | LinksetImpl = LinksetImplementation.Constraint; | ||
190 | } | ||
191 | |||
192 | private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINT]"; | ||
193 | |||
194 | // When physical properties are changed the linkset needs to recalculate | ||
195 | // its internal properties. | ||
196 | // This is queued in the 'post taint' queue so the | ||
197 | // refresh will happen once after all the other taints are applied. | ||
198 | public override void Refresh(BSPrimLinkable requestor) | ||
199 | { | ||
200 | ScheduleRebuild(requestor); | ||
201 | base.Refresh(requestor); | ||
202 | |||
203 | } | ||
204 | |||
205 | private void ScheduleRebuild(BSPrimLinkable requestor) | ||
206 | { | ||
207 | DetailLog("{0},BSLinksetConstraint.ScheduleRebuild,,rebuilding={1},hasChildren={2},actuallyScheduling={3}", | ||
208 | requestor.LocalID, Rebuilding, HasAnyChildren, (!Rebuilding && HasAnyChildren)); | ||
209 | |||
210 | // When rebuilding, it is possible to set properties that would normally require a rebuild. | ||
211 | // If already rebuilding, don't request another rebuild. | ||
212 | // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding. | ||
213 | lock (this) | ||
214 | { | ||
215 | if (!RebuildScheduled) | ||
216 | { | ||
217 | if (!Rebuilding && HasAnyChildren) | ||
218 | { | ||
219 | RebuildScheduled = true; | ||
220 | // Queue to happen after all the other taint processing | ||
221 | m_physicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() | ||
222 | { | ||
223 | if (HasAnyChildren) | ||
224 | { | ||
225 | // Constraints that have not been changed are not rebuild but make sure | ||
226 | // the constraint of the requestor is rebuilt. | ||
227 | PhysicallyUnlinkAChildFromRoot(LinksetRoot, requestor); | ||
228 | // Rebuild the linkset and all its constraints. | ||
229 | RecomputeLinksetConstraints(); | ||
230 | } | ||
231 | RebuildScheduled = false; | ||
232 | }); | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | } | ||
237 | |||
238 | // The object is going dynamic (physical). Do any setup necessary | ||
239 | // for a dynamic linkset. | ||
240 | // Only the state of the passed object can be modified. The rest of the linkset | ||
241 | // has not yet been fully constructed. | ||
242 | // Return 'true' if any properties updated on the passed object. | ||
243 | // Called at taint-time! | ||
244 | public override bool MakeDynamic(BSPrimLinkable child) | ||
245 | { | ||
246 | bool ret = false; | ||
247 | DetailLog("{0},BSLinksetConstraints.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
248 | if (IsRoot(child)) | ||
249 | { | ||
250 | // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly. | ||
251 | Refresh(LinksetRoot); | ||
252 | } | ||
253 | return ret; | ||
254 | } | ||
255 | |||
256 | // The object is going static (non-physical). Do any setup necessary for a static linkset. | ||
257 | // Return 'true' if any properties updated on the passed object. | ||
258 | // This doesn't normally happen -- OpenSim removes the objects from the physical | ||
259 | // world if it is a static linkset. | ||
260 | // Called at taint-time! | ||
261 | public override bool MakeStatic(BSPrimLinkable child) | ||
262 | { | ||
263 | bool ret = false; | ||
264 | |||
265 | DetailLog("{0},BSLinksetConstraint.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); | ||
266 | child.ClearDisplacement(); | ||
267 | if (IsRoot(child)) | ||
268 | { | ||
269 | // Schedule a rebuild to verify that the root shape is set to the real shape. | ||
270 | Refresh(LinksetRoot); | ||
271 | } | ||
272 | return ret; | ||
273 | } | ||
274 | |||
275 | // Called at taint-time!! | ||
276 | public override void UpdateProperties(UpdatedProperties whichUpdated, BSPrimLinkable pObj) | ||
277 | { | ||
278 | // Nothing to do for constraints on property updates | ||
279 | } | ||
280 | |||
281 | // Routine called when rebuilding the body of some member of the linkset. | ||
282 | // Destroy all the constraints have have been made to root and set | ||
283 | // up to rebuild the constraints before the next simulation step. | ||
284 | // Returns 'true' of something was actually removed and would need restoring | ||
285 | // Called at taint-time!! | ||
286 | public override bool RemoveDependencies(BSPrimLinkable child) | ||
287 | { | ||
288 | bool ret = false; | ||
289 | |||
290 | DetailLog("{0},BSLinksetConstraint.RemoveDependencies,removeChildrenForRoot,rID={1},rBody={2}", | ||
291 | child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString); | ||
292 | |||
293 | lock (m_linksetActivityLock) | ||
294 | { | ||
295 | // Just undo all the constraints for this linkset. Rebuild at the end of the step. | ||
296 | ret = PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
297 | // Cause the constraints, et al to be rebuilt before the next simulation step. | ||
298 | Refresh(LinksetRoot); | ||
299 | } | ||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | // ================================================================ | ||
304 | |||
305 | // Add a new child to the linkset. | ||
306 | // Called while LinkActivity is locked. | ||
307 | protected override void AddChildToLinkset(BSPrimLinkable child) | ||
308 | { | ||
309 | if (!HasChild(child)) | ||
310 | { | ||
311 | m_children.Add(child, new BSLinkInfoConstraint(child)); | ||
312 | |||
313 | DetailLog("{0},BSLinksetConstraints.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); | ||
314 | |||
315 | // Cause constraints and assorted properties to be recomputed before the next simulation step. | ||
316 | Refresh(LinksetRoot); | ||
317 | } | ||
318 | return; | ||
319 | } | ||
320 | |||
321 | // Remove the specified child from the linkset. | ||
322 | // Safe to call even if the child is not really in my linkset. | ||
323 | protected override void RemoveChildFromLinkset(BSPrimLinkable child, bool inTaintTime) | ||
324 | { | ||
325 | if (m_children.Remove(child)) | ||
326 | { | ||
327 | BSPrimLinkable rootx = LinksetRoot; // capture the root and body as of now | ||
328 | BSPrimLinkable childx = child; | ||
329 | |||
330 | DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", | ||
331 | childx.LocalID, | ||
332 | rootx.LocalID, rootx.PhysBody.AddrString, | ||
333 | childx.LocalID, childx.PhysBody.AddrString); | ||
334 | |||
335 | m_physicsScene.TaintedObject(inTaintTime, childx.LocalID, "BSLinksetConstraints.RemoveChildFromLinkset", delegate() | ||
336 | { | ||
337 | PhysicallyUnlinkAChildFromRoot(rootx, childx); | ||
338 | }); | ||
339 | // See that the linkset parameters are recomputed at the end of the taint time. | ||
340 | Refresh(LinksetRoot); | ||
341 | } | ||
342 | else | ||
343 | { | ||
344 | // Non-fatal occurance. | ||
345 | // PhysicsScene.Logger.ErrorFormat("{0}: Asked to remove child from linkset that was not in linkset", LogHeader); | ||
346 | } | ||
347 | return; | ||
348 | } | ||
349 | |||
350 | // Create a constraint between me (root of linkset) and the passed prim (the child). | ||
351 | // Called at taint time! | ||
352 | private void PhysicallyLinkAChildToRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) | ||
353 | { | ||
354 | // Don't build the constraint when asked. Put it off until just before the simulation step. | ||
355 | Refresh(rootPrim); | ||
356 | } | ||
357 | |||
358 | // Create a static constraint between the two passed objects | ||
359 | private BSConstraint BuildConstraint(BSPrimLinkable rootPrim, BSLinkInfo li) | ||
360 | { | ||
361 | BSLinkInfoConstraint linkInfo = li as BSLinkInfoConstraint; | ||
362 | if (linkInfo == null) | ||
363 | return null; | ||
364 | |||
365 | // Zero motion for children so they don't interpolate | ||
366 | li.member.ZeroMotion(true); | ||
367 | |||
368 | BSConstraint constrain = null; | ||
369 | |||
370 | switch (linkInfo.constraintType) | ||
371 | { | ||
372 | case ConstraintType.BS_FIXED_CONSTRAINT_TYPE: | ||
373 | case ConstraintType.D6_CONSTRAINT_TYPE: | ||
374 | // Relative position normalized to the root prim | ||
375 | // Essentually a vector pointing from center of rootPrim to center of li.member | ||
376 | OMV.Vector3 childRelativePosition = linkInfo.member.Position - rootPrim.Position; | ||
377 | |||
378 | // real world coordinate of midpoint between the two objects | ||
379 | OMV.Vector3 midPoint = rootPrim.Position + (childRelativePosition / 2); | ||
380 | |||
381 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,6Dof,rBody={1},cBody={2},rLoc={3},cLoc={4},midLoc={5}", | ||
382 | rootPrim.LocalID, rootPrim.PhysBody, linkInfo.member.PhysBody, | ||
383 | rootPrim.Position, linkInfo.member.Position, midPoint); | ||
384 | |||
385 | // create a constraint that allows no freedom of movement between the two objects | ||
386 | // http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=4818 | ||
387 | |||
388 | constrain = new BSConstraint6Dof( | ||
389 | m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, midPoint, true, true ); | ||
390 | |||
391 | /* NOTE: below is an attempt to build constraint with full frame computation, etc. | ||
392 | * Using the midpoint is easier since it lets the Bullet code manipulate the transforms | ||
393 | * of the objects. | ||
394 | * Code left for future programmers. | ||
395 | // ================================================================================== | ||
396 | // relative position normalized to the root prim | ||
397 | OMV.Quaternion invThisOrientation = OMV.Quaternion.Inverse(rootPrim.Orientation); | ||
398 | OMV.Vector3 childRelativePosition = (liConstraint.member.Position - rootPrim.Position) * invThisOrientation; | ||
399 | |||
400 | // relative rotation of the child to the parent | ||
401 | OMV.Quaternion childRelativeRotation = invThisOrientation * liConstraint.member.Orientation; | ||
402 | OMV.Quaternion inverseChildRelativeRotation = OMV.Quaternion.Inverse(childRelativeRotation); | ||
403 | |||
404 | DetailLog("{0},BSLinksetConstraint.PhysicallyLinkAChildToRoot,taint,root={1},child={2}", rootPrim.LocalID, rootPrim.LocalID, liConstraint.member.LocalID); | ||
405 | constrain = new BS6DofConstraint( | ||
406 | PhysicsScene.World, rootPrim.Body, liConstraint.member.Body, | ||
407 | OMV.Vector3.Zero, | ||
408 | OMV.Quaternion.Inverse(rootPrim.Orientation), | ||
409 | OMV.Vector3.Zero, | ||
410 | OMV.Quaternion.Inverse(liConstraint.member.Orientation), | ||
411 | true, | ||
412 | true | ||
413 | ); | ||
414 | // ================================================================================== | ||
415 | */ | ||
416 | |||
417 | break; | ||
418 | case ConstraintType.D6_SPRING_CONSTRAINT_TYPE: | ||
419 | constrain = new BSConstraintSpring(m_physicsScene.World, rootPrim.PhysBody, linkInfo.member.PhysBody, | ||
420 | linkInfo.frameInAloc, linkInfo.frameInArot, linkInfo.frameInBloc, linkInfo.frameInBrot, | ||
421 | linkInfo.useLinearReferenceFrameA, | ||
422 | true /*disableCollisionsBetweenLinkedBodies*/); | ||
423 | DetailLog("{0},BSLinksetConstraint.BuildConstraint,spring,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6}", | ||
424 | rootPrim.LocalID, | ||
425 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
426 | linkInfo.member.LocalID, linkInfo.member.PhysBody.AddrString, | ||
427 | rootPrim.Position, linkInfo.member.Position); | ||
428 | |||
429 | break; | ||
430 | default: | ||
431 | break; | ||
432 | } | ||
433 | |||
434 | linkInfo.SetLinkParameters(constrain); | ||
435 | |||
436 | m_physicsScene.Constraints.AddConstraint(constrain); | ||
437 | |||
438 | return constrain; | ||
439 | } | ||
440 | |||
441 | // Remove linkage between the linkset root and a particular child | ||
442 | // The root and child bodies are passed in because we need to remove the constraint between | ||
443 | // the bodies that were present at unlink time. | ||
444 | // Called at taint time! | ||
445 | private bool PhysicallyUnlinkAChildFromRoot(BSPrimLinkable rootPrim, BSPrimLinkable childPrim) | ||
446 | { | ||
447 | bool ret = false; | ||
448 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", | ||
449 | rootPrim.LocalID, | ||
450 | rootPrim.LocalID, rootPrim.PhysBody.AddrString, | ||
451 | childPrim.LocalID, childPrim.PhysBody.AddrString); | ||
452 | |||
453 | // If asked to unlink root from root, just remove all the constraints | ||
454 | if (rootPrim == childPrim || childPrim == LinksetRoot) | ||
455 | { | ||
456 | PhysicallyUnlinkAllChildrenFromRoot(LinksetRoot); | ||
457 | ret = true; | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | // Find the constraint for this link and get rid of it from the overall collection and from my list | ||
462 | if (m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) | ||
463 | { | ||
464 | // Make the child refresh its location | ||
465 | m_physicsScene.PE.PushUpdate(childPrim.PhysBody); | ||
466 | ret = true; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | return ret; | ||
471 | } | ||
472 | |||
473 | // Remove linkage between myself and any possible children I might have. | ||
474 | // Returns 'true' of any constraints were destroyed. | ||
475 | // Called at taint time! | ||
476 | private bool PhysicallyUnlinkAllChildrenFromRoot(BSPrimLinkable rootPrim) | ||
477 | { | ||
478 | DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAllChildren,taint", rootPrim.LocalID); | ||
479 | |||
480 | return m_physicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody); | ||
481 | } | ||
482 | |||
483 | // Call each of the constraints that make up this linkset and recompute the | ||
484 | // various transforms and variables. Create constraints of not created yet. | ||
485 | // Called before the simulation step to make sure the constraint based linkset | ||
486 | // is all initialized. | ||
487 | // Called at taint time!! | ||
488 | private void RecomputeLinksetConstraints() | ||
489 | { | ||
490 | float linksetMass = LinksetMass; | ||
491 | LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true); | ||
492 | |||
493 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", | ||
494 | LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass); | ||
495 | |||
496 | try | ||
497 | { | ||
498 | Rebuilding = true; | ||
499 | |||
500 | // There is no reason to build all this physical stuff for a non-physical linkset. | ||
501 | if (!LinksetRoot.IsPhysicallyActive || !HasAnyChildren) | ||
502 | { | ||
503 | DetailLog("{0},BSLinksetConstraint.RecomputeLinksetCompound,notPhysicalOrNoChildren", LinksetRoot.LocalID); | ||
504 | return; // Note the 'finally' clause at the botton which will get executed. | ||
505 | } | ||
506 | |||
507 | ForEachLinkInfo((li) => | ||
508 | { | ||
509 | // A child in the linkset physically shows the mass of the whole linkset. | ||
510 | // This allows Bullet to apply enough force on the child to move the whole linkset. | ||
511 | // (Also do the mass stuff before recomputing the constraint so mass is not zero.) | ||
512 | li.member.UpdatePhysicalMassProperties(linksetMass, true); | ||
513 | |||
514 | BSConstraint constrain; | ||
515 | if (!m_physicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, li.member.PhysBody, out constrain)) | ||
516 | { | ||
517 | // If constraint doesn't exist yet, create it. | ||
518 | constrain = BuildConstraint(LinksetRoot, li); | ||
519 | } | ||
520 | li.SetLinkParameters(constrain); | ||
521 | constrain.RecomputeConstraintVariables(linksetMass); | ||
522 | |||
523 | // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG | ||
524 | return false; // 'false' says to keep processing other members | ||
525 | }); | ||
526 | } | ||
527 | finally | ||
528 | { | ||
529 | Rebuilding = false; | ||
530 | } | ||
531 | } | ||
532 | |||
533 | #region Extension | ||
534 | public override object Extension(string pFunct, params object[] pParams) | ||
535 | { | ||
536 | object ret = null; | ||
537 | switch (pFunct) | ||
538 | { | ||
539 | // pParams = [ BSPhysObject root, BSPhysObject child, integer linkType ] | ||
540 | case ExtendedPhysics.PhysFunctChangeLinkType: | ||
541 | if (pParams.Length > 2) | ||
542 | { | ||
543 | int requestedType = (int)pParams[2]; | ||
544 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,requestedType={1}", LinksetRoot.LocalID, requestedType); | ||
545 | if (requestedType == (int)ConstraintType.BS_FIXED_CONSTRAINT_TYPE | ||
546 | || requestedType == (int)ConstraintType.D6_CONSTRAINT_TYPE | ||
547 | || requestedType == (int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
548 | || requestedType == (int)ConstraintType.HINGE_CONSTRAINT_TYPE | ||
549 | || requestedType == (int)ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
550 | || requestedType == (int)ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
551 | { | ||
552 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
553 | if (child != null) | ||
554 | { | ||
555 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,rootID={1},childID={2},type={3}", | ||
556 | LinksetRoot.LocalID, LinksetRoot.LocalID, child.LocalID, requestedType); | ||
557 | m_physicsScene.TaintedObject(child.LocalID, "BSLinksetConstraint.PhysFunctChangeLinkType", delegate() | ||
558 | { | ||
559 | // Pick up all the constraints currently created. | ||
560 | RemoveDependencies(child); | ||
561 | |||
562 | BSLinkInfo linkInfo = null; | ||
563 | if (TryGetLinkInfo(child, out linkInfo)) | ||
564 | { | ||
565 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
566 | if (linkInfoC != null) | ||
567 | { | ||
568 | linkInfoC.constraintType = (ConstraintType)requestedType; | ||
569 | ret = (object)true; | ||
570 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,link={1},type={2}", | ||
571 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,linkInfoNotConstraint,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
576 | } | ||
577 | } | ||
578 | else | ||
579 | { | ||
580 | DetailLog("{0},BSLinksetConstraint.ChangeLinkType,noLinkInfoForChild,childID={1}", LinksetRoot.LocalID, child.LocalID); | ||
581 | } | ||
582 | // Cause the whole linkset to be rebuilt in post-taint time. | ||
583 | Refresh(child); | ||
584 | }); | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | DetailLog("{0},BSLinksetConstraint.SetLinkType,childNotBSPrimLinkable", LinksetRoot.LocalID); | ||
589 | } | ||
590 | } | ||
591 | else | ||
592 | { | ||
593 | DetailLog("{0},BSLinksetConstraint.SetLinkType,illegalRequestedType,reqested={1},spring={2}", | ||
594 | LinksetRoot.LocalID, requestedType, ((int)ConstraintType.D6_SPRING_CONSTRAINT_TYPE)); | ||
595 | } | ||
596 | } | ||
597 | break; | ||
598 | // pParams = [ BSPhysObject root, BSPhysObject child ] | ||
599 | case ExtendedPhysics.PhysFunctGetLinkType: | ||
600 | if (pParams.Length > 0) | ||
601 | { | ||
602 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
603 | if (child != null) | ||
604 | { | ||
605 | BSLinkInfo linkInfo = null; | ||
606 | if (TryGetLinkInfo(child, out linkInfo)) | ||
607 | { | ||
608 | BSLinkInfoConstraint linkInfoC = linkInfo as BSLinkInfoConstraint; | ||
609 | if (linkInfoC != null) | ||
610 | { | ||
611 | ret = (object)(int)linkInfoC.constraintType; | ||
612 | DetailLog("{0},BSLinksetConstraint.GetLinkType,link={1},type={2}", | ||
613 | linkInfo.member.LocalID, linkInfo.member.LocalID, linkInfoC.constraintType); | ||
614 | |||
615 | } | ||
616 | } | ||
617 | } | ||
618 | } | ||
619 | break; | ||
620 | // pParams = [ BSPhysObject root, BSPhysObject child, int op, object opParams, int op, object opParams, ... ] | ||
621 | case ExtendedPhysics.PhysFunctChangeLinkParams: | ||
622 | // There should be two parameters: the childActor and a list of parameters to set | ||
623 | if (pParams.Length > 2) | ||
624 | { | ||
625 | BSPrimLinkable child = pParams[1] as BSPrimLinkable; | ||
626 | BSLinkInfo baseLinkInfo = null; | ||
627 | if (TryGetLinkInfo(child, out baseLinkInfo)) | ||
628 | { | ||
629 | BSLinkInfoConstraint linkInfo = baseLinkInfo as BSLinkInfoConstraint; | ||
630 | if (linkInfo != null) | ||
631 | { | ||
632 | int valueInt; | ||
633 | float valueFloat; | ||
634 | bool valueBool; | ||
635 | OMV.Vector3 valueVector; | ||
636 | OMV.Vector3 valueVector2; | ||
637 | OMV.Quaternion valueQuaternion; | ||
638 | int axisLow, axisHigh; | ||
639 | |||
640 | int opIndex = 2; | ||
641 | while (opIndex < pParams.Length) | ||
642 | { | ||
643 | int thisOp = 0; | ||
644 | string errMsg = ""; | ||
645 | try | ||
646 | { | ||
647 | thisOp = (int)pParams[opIndex]; | ||
648 | DetailLog("{0},BSLinksetConstraint.ChangeLinkParams2,op={1},val={2}", | ||
649 | linkInfo.member.LocalID, thisOp, pParams[opIndex + 1]); | ||
650 | switch (thisOp) | ||
651 | { | ||
652 | case ExtendedPhysics.PHYS_PARAM_LINK_TYPE: | ||
653 | valueInt = (int)pParams[opIndex + 1]; | ||
654 | ConstraintType valueType = (ConstraintType)valueInt; | ||
655 | if (valueType == ConstraintType.BS_FIXED_CONSTRAINT_TYPE | ||
656 | || valueType == ConstraintType.D6_CONSTRAINT_TYPE | ||
657 | || valueType == ConstraintType.D6_SPRING_CONSTRAINT_TYPE | ||
658 | || valueType == ConstraintType.HINGE_CONSTRAINT_TYPE | ||
659 | || valueType == ConstraintType.CONETWIST_CONSTRAINT_TYPE | ||
660 | || valueType == ConstraintType.SLIDER_CONSTRAINT_TYPE) | ||
661 | { | ||
662 | linkInfo.constraintType = valueType; | ||
663 | } | ||
664 | opIndex += 2; | ||
665 | break; | ||
666 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_LOC: | ||
667 | errMsg = "PHYS_PARAM_FRAMEINA_LOC takes one parameter of type vector"; | ||
668 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
669 | linkInfo.frameInAloc = valueVector; | ||
670 | opIndex += 2; | ||
671 | break; | ||
672 | case ExtendedPhysics.PHYS_PARAM_FRAMEINA_ROT: | ||
673 | errMsg = "PHYS_PARAM_FRAMEINA_ROT takes one parameter of type rotation"; | ||
674 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
675 | linkInfo.frameInArot = valueQuaternion; | ||
676 | opIndex += 2; | ||
677 | break; | ||
678 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_LOC: | ||
679 | errMsg = "PHYS_PARAM_FRAMEINB_LOC takes one parameter of type vector"; | ||
680 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
681 | linkInfo.frameInBloc = valueVector; | ||
682 | opIndex += 2; | ||
683 | break; | ||
684 | case ExtendedPhysics.PHYS_PARAM_FRAMEINB_ROT: | ||
685 | errMsg = "PHYS_PARAM_FRAMEINB_ROT takes one parameter of type rotation"; | ||
686 | valueQuaternion = (OMV.Quaternion)pParams[opIndex + 1]; | ||
687 | linkInfo.frameInBrot = valueQuaternion; | ||
688 | opIndex += 2; | ||
689 | break; | ||
690 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_LOW: | ||
691 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_LOW takes one parameter of type vector"; | ||
692 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
693 | linkInfo.linearLimitLow = valueVector; | ||
694 | opIndex += 2; | ||
695 | break; | ||
696 | case ExtendedPhysics.PHYS_PARAM_LINEAR_LIMIT_HIGH: | ||
697 | errMsg = "PHYS_PARAM_LINEAR_LIMIT_HIGH takes one parameter of type vector"; | ||
698 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
699 | linkInfo.linearLimitHigh = valueVector; | ||
700 | opIndex += 2; | ||
701 | break; | ||
702 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_LOW: | ||
703 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_LOW takes one parameter of type vector"; | ||
704 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
705 | linkInfo.angularLimitLow = valueVector; | ||
706 | opIndex += 2; | ||
707 | break; | ||
708 | case ExtendedPhysics.PHYS_PARAM_ANGULAR_LIMIT_HIGH: | ||
709 | errMsg = "PHYS_PARAM_ANGULAR_LIMIT_HIGH takes one parameter of type vector"; | ||
710 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
711 | linkInfo.angularLimitHigh = valueVector; | ||
712 | opIndex += 2; | ||
713 | break; | ||
714 | case ExtendedPhysics.PHYS_PARAM_USE_FRAME_OFFSET: | ||
715 | errMsg = "PHYS_PARAM_USE_FRAME_OFFSET takes one parameter of type integer (bool)"; | ||
716 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
717 | linkInfo.useFrameOffset = valueBool; | ||
718 | opIndex += 2; | ||
719 | break; | ||
720 | case ExtendedPhysics.PHYS_PARAM_ENABLE_TRANSMOTOR: | ||
721 | errMsg = "PHYS_PARAM_ENABLE_TRANSMOTOR takes one parameter of type integer (bool)"; | ||
722 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
723 | linkInfo.enableTransMotor = valueBool; | ||
724 | opIndex += 2; | ||
725 | break; | ||
726 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXVEL: | ||
727 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXVEL takes one parameter of type float"; | ||
728 | valueFloat = (float)pParams[opIndex + 1]; | ||
729 | linkInfo.transMotorMaxVel = valueFloat; | ||
730 | opIndex += 2; | ||
731 | break; | ||
732 | case ExtendedPhysics.PHYS_PARAM_TRANSMOTOR_MAXFORCE: | ||
733 | errMsg = "PHYS_PARAM_TRANSMOTOR_MAXFORCE takes one parameter of type float"; | ||
734 | valueFloat = (float)pParams[opIndex + 1]; | ||
735 | linkInfo.transMotorMaxForce = valueFloat; | ||
736 | opIndex += 2; | ||
737 | break; | ||
738 | case ExtendedPhysics.PHYS_PARAM_CFM: | ||
739 | errMsg = "PHYS_PARAM_CFM takes one parameter of type float"; | ||
740 | valueFloat = (float)pParams[opIndex + 1]; | ||
741 | linkInfo.cfm = valueFloat; | ||
742 | opIndex += 2; | ||
743 | break; | ||
744 | case ExtendedPhysics.PHYS_PARAM_ERP: | ||
745 | errMsg = "PHYS_PARAM_ERP takes one parameter of type float"; | ||
746 | valueFloat = (float)pParams[opIndex + 1]; | ||
747 | linkInfo.erp = valueFloat; | ||
748 | opIndex += 2; | ||
749 | break; | ||
750 | case ExtendedPhysics.PHYS_PARAM_SOLVER_ITERATIONS: | ||
751 | errMsg = "PHYS_PARAM_SOLVER_ITERATIONS takes one parameter of type float"; | ||
752 | valueFloat = (float)pParams[opIndex + 1]; | ||
753 | linkInfo.solverIterations = valueFloat; | ||
754 | opIndex += 2; | ||
755 | break; | ||
756 | case ExtendedPhysics.PHYS_PARAM_SPRING_AXIS_ENABLE: | ||
757 | errMsg = "PHYS_PARAM_SPRING_AXIS_ENABLE takes two parameters of types integer and integer (bool)"; | ||
758 | valueInt = (int)pParams[opIndex + 1]; | ||
759 | valueBool = ((int)pParams[opIndex + 2]) != 0; | ||
760 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
761 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
762 | linkInfo.springAxisEnable[ii] = valueBool; | ||
763 | opIndex += 3; | ||
764 | break; | ||
765 | case ExtendedPhysics.PHYS_PARAM_SPRING_DAMPING: | ||
766 | errMsg = "PHYS_PARAM_SPRING_DAMPING takes two parameters of types integer and float"; | ||
767 | valueInt = (int)pParams[opIndex + 1]; | ||
768 | valueFloat = (float)pParams[opIndex + 2]; | ||
769 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
770 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
771 | linkInfo.springDamping[ii] = valueFloat; | ||
772 | opIndex += 3; | ||
773 | break; | ||
774 | case ExtendedPhysics.PHYS_PARAM_SPRING_STIFFNESS: | ||
775 | errMsg = "PHYS_PARAM_SPRING_STIFFNESS takes two parameters of types integer and float"; | ||
776 | valueInt = (int)pParams[opIndex + 1]; | ||
777 | valueFloat = (float)pParams[opIndex + 2]; | ||
778 | GetAxisRange(valueInt, out axisLow, out axisHigh); | ||
779 | for (int ii = axisLow; ii <= axisHigh; ii++) | ||
780 | linkInfo.springStiffness[ii] = valueFloat; | ||
781 | opIndex += 3; | ||
782 | break; | ||
783 | case ExtendedPhysics.PHYS_PARAM_SPRING_EQUILIBRIUM_POINT: | ||
784 | errMsg = "PHYS_PARAM_SPRING_EQUILIBRIUM_POINT takes two parameters of type vector"; | ||
785 | valueVector = (OMV.Vector3)pParams[opIndex + 1]; | ||
786 | valueVector2 = (OMV.Vector3)pParams[opIndex + 2]; | ||
787 | linkInfo.springLinearEquilibriumPoint = valueVector; | ||
788 | linkInfo.springAngularEquilibriumPoint = valueVector2; | ||
789 | opIndex += 3; | ||
790 | break; | ||
791 | case ExtendedPhysics.PHYS_PARAM_USE_LINEAR_FRAMEA: | ||
792 | errMsg = "PHYS_PARAM_USE_LINEAR_FRAMEA takes one parameter of type integer (bool)"; | ||
793 | valueBool = ((int)pParams[opIndex + 1]) != 0; | ||
794 | linkInfo.useLinearReferenceFrameA = valueBool; | ||
795 | opIndex += 2; | ||
796 | break; | ||
797 | default: | ||
798 | break; | ||
799 | } | ||
800 | } | ||
801 | catch (InvalidCastException e) | ||
802 | { | ||
803 | m_physicsScene.Logger.WarnFormat("{0} value of wrong type in physSetLinksetParams: {1}, err={2}", | ||
804 | LogHeader, errMsg, e); | ||
805 | } | ||
806 | catch (Exception e) | ||
807 | { | ||
808 | m_physicsScene.Logger.WarnFormat("{0} bad parameters in physSetLinksetParams: {1}", LogHeader, e); | ||
809 | } | ||
810 | } | ||
811 | } | ||
812 | // Something changed so a rebuild is in order | ||
813 | Refresh(child); | ||
814 | } | ||
815 | } | ||
816 | break; | ||
817 | default: | ||
818 | ret = base.Extension(pFunct, pParams); | ||
819 | break; | ||
820 | } | ||
821 | return ret; | ||
822 | } | ||
823 | |||
824 | // Bullet constraints keep some limit parameters for each linear and angular axis. | ||
825 | // Setting same is easier if there is an easy way to see all or types. | ||
826 | // This routine returns the array limits for the set of axis. | ||
827 | private void GetAxisRange(int rangeSpec, out int low, out int high) | ||
828 | { | ||
829 | switch (rangeSpec) | ||
830 | { | ||
831 | case ExtendedPhysics.PHYS_AXIS_LINEAR_ALL: | ||
832 | low = 0; | ||
833 | high = 2; | ||
834 | break; | ||
835 | case ExtendedPhysics.PHYS_AXIS_ANGULAR_ALL: | ||
836 | low = 3; | ||
837 | high = 5; | ||
838 | break; | ||
839 | case ExtendedPhysics.PHYS_AXIS_ALL: | ||
840 | low = 0; | ||
841 | high = 5; | ||
842 | break; | ||
843 | default: | ||
844 | low = high = rangeSpec; | ||
845 | break; | ||
846 | } | ||
847 | return; | ||
848 | } | ||
849 | #endregion // Extension | ||
850 | |||
851 | } | ||
852 | } | ||