aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Physics/BulletSPlugin
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs1863
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs1597
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs666
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs400
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs27
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs48
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs4
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs12
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs1044
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs50
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs309
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs79
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs200
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSMotors.cs571
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSParam.cs610
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs147
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs6
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs767
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BSScene.cs918
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs229
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSShapes.cs34
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs55
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs181
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs69
-rw-r--r--OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs1015
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs263
-rwxr-xr-xOpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt276
27 files changed, 8310 insertions, 3130 deletions
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
new file mode 100755
index 0000000..14de2eb
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIUnman.cs
@@ -0,0 +1,1863 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using System.Runtime.InteropServices;
31using System.Security;
32using System.Text;
33
34using OpenSim.Framework;
35
36using OpenMetaverse;
37
38namespace OpenSim.Region.Physics.BulletSPlugin
39{
40public sealed class BSAPIUnman : BSAPITemplate
41{
42
43private sealed class BulletWorldUnman : BulletWorld
44{
45 public IntPtr ptr;
46 public BulletWorldUnman(uint id, BSScene physScene, IntPtr xx)
47 : base(id, physScene)
48 {
49 ptr = xx;
50 }
51}
52
53private sealed class BulletBodyUnman : BulletBody
54{
55 public IntPtr ptr;
56 public BulletBodyUnman(uint id, IntPtr xx)
57 : base(id)
58 {
59 ptr = xx;
60 }
61 public override bool HasPhysicalBody
62 {
63 get { return ptr != IntPtr.Zero; }
64 }
65 public override void Clear()
66 {
67 ptr = IntPtr.Zero;
68 }
69 public override string AddrString
70 {
71 get { return ptr.ToString("X"); }
72 }
73}
74
75private sealed class BulletShapeUnman : BulletShape
76{
77 public IntPtr ptr;
78 public BulletShapeUnman(IntPtr xx, BSPhysicsShapeType typ)
79 : base()
80 {
81 ptr = xx;
82 type = typ;
83 }
84 public override bool HasPhysicalShape
85 {
86 get { return ptr != IntPtr.Zero; }
87 }
88 public override void Clear()
89 {
90 ptr = IntPtr.Zero;
91 }
92 public override BulletShape Clone()
93 {
94 return new BulletShapeUnman(ptr, type);
95 }
96 public override bool ReferenceSame(BulletShape other)
97 {
98 BulletShapeUnman otheru = other as BulletShapeUnman;
99 return (otheru != null) && (this.ptr == otheru.ptr);
100
101 }
102 public override string AddrString
103 {
104 get { return ptr.ToString("X"); }
105 }
106}
107private sealed class BulletConstraintUnman : BulletConstraint
108{
109 public BulletConstraintUnman(IntPtr xx) : base()
110 {
111 ptr = xx;
112 }
113 public IntPtr ptr;
114
115 public override void Clear()
116 {
117 ptr = IntPtr.Zero;
118 }
119 public override bool HasPhysicalConstraint { get { return ptr != IntPtr.Zero; } }
120
121 // Used for log messages for a unique display of the memory/object allocated to this instance
122 public override string AddrString
123 {
124 get { return ptr.ToString("X"); }
125 }
126}
127
128// We pin the memory passed between the managed and unmanaged code.
129GCHandle m_paramsHandle;
130private GCHandle m_collisionArrayPinnedHandle;
131private GCHandle m_updateArrayPinnedHandle;
132
133// Handle to the callback used by the unmanaged code to call into the managed code.
134// Used for debug logging.
135// Need to store the handle in a persistant variable so it won't be freed.
136private BSAPICPP.DebugLogCallback m_DebugLogCallbackHandle;
137
138private BSScene PhysicsScene { get; set; }
139
140public override string BulletEngineName { get { return "BulletUnmanaged"; } }
141public override string BulletEngineVersion { get; protected set; }
142
143public BSAPIUnman(string paramName, BSScene physScene)
144{
145 PhysicsScene = physScene;
146
147 // Do something fancy with the paramName to get the right DLL implementation
148 // like "Bullet-2.80-OpenCL-Intel" loading the version for Intel based OpenCL implementation, etc.
149 if (Util.IsWindows())
150 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
151 // If not Windows, loading is performed by the
152 // Mono loader as specified in
153 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
154}
155
156// Initialization and simulation
157public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
158 int maxCollisions, ref CollisionDesc[] collisionArray,
159 int maxUpdates, ref EntityProperties[] updateArray
160 )
161{
162 // Pin down the memory that will be used to pass object collisions and updates back from unmanaged code
163 m_paramsHandle = GCHandle.Alloc(parms, GCHandleType.Pinned);
164 m_collisionArrayPinnedHandle = GCHandle.Alloc(collisionArray, GCHandleType.Pinned);
165 m_updateArrayPinnedHandle = GCHandle.Alloc(updateArray, GCHandleType.Pinned);
166
167 // If Debug logging level, enable logging from the unmanaged code
168 m_DebugLogCallbackHandle = null;
169 if (BSScene.m_log.IsDebugEnabled || PhysicsScene.PhysicsLogging.Enabled)
170 {
171 BSScene.m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", BSScene.LogHeader);
172 if (PhysicsScene.PhysicsLogging.Enabled)
173 // The handle is saved in a variable to make sure it doesn't get freed after this call
174 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLoggerPhysLog);
175 else
176 m_DebugLogCallbackHandle = new BSAPICPP.DebugLogCallback(BulletLogger);
177 }
178
179 // Get the version of the DLL
180 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
181 // BulletEngineVersion = BulletSimAPI.GetVersion2();
182 BulletEngineVersion = "";
183
184 // Call the unmanaged code with the buffers and other information
185 return new BulletWorldUnman(0, PhysicsScene, BSAPICPP.Initialize2(maxPosition, m_paramsHandle.AddrOfPinnedObject(),
186 maxCollisions, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
187 maxUpdates, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
188 m_DebugLogCallbackHandle));
189
190}
191
192// Called directly from unmanaged code so don't do much
193private void BulletLogger(string msg)
194{
195 BSScene.m_log.Debug("[BULLETS UNMANAGED]:" + msg);
196}
197
198// Called directly from unmanaged code so don't do much
199private void BulletLoggerPhysLog(string msg)
200{
201 PhysicsScene.DetailLog("[BULLETS UNMANAGED]:" + msg);
202}
203
204public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
205 out int updatedEntityCount, out int collidersCount)
206{
207 BulletWorldUnman worldu = world as BulletWorldUnman;
208 return BSAPICPP.PhysicsStep2(worldu.ptr, timeStep, maxSubSteps, fixedTimeStep, out updatedEntityCount, out collidersCount);
209}
210
211public override void Shutdown(BulletWorld world)
212{
213 BulletWorldUnman worldu = world as BulletWorldUnman;
214 BSAPICPP.Shutdown2(worldu.ptr);
215}
216
217public override bool PushUpdate(BulletBody obj)
218{
219 BulletBodyUnman bodyu = obj as BulletBodyUnman;
220 return BSAPICPP.PushUpdate2(bodyu.ptr);
221}
222
223public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value)
224{
225 BulletWorldUnman worldu = world as BulletWorldUnman;
226 return BSAPICPP.UpdateParameter2(worldu.ptr, localID, parm, value);
227}
228
229// =====================================================================================
230// Mesh, hull, shape and body creation helper routines
231public override BulletShape CreateMeshShape(BulletWorld world,
232 int indicesCount, int[] indices,
233 int verticesCount, float[] vertices)
234{
235 BulletWorldUnman worldu = world as BulletWorldUnman;
236 return new BulletShapeUnman(
237 BSAPICPP.CreateMeshShape2(worldu.ptr, indicesCount, indices, verticesCount, vertices),
238 BSPhysicsShapeType.SHAPE_MESH);
239}
240
241public override BulletShape CreateHullShape(BulletWorld world, int hullCount, float[] hulls)
242{
243 BulletWorldUnman worldu = world as BulletWorldUnman;
244 return new BulletShapeUnman(
245 BSAPICPP.CreateHullShape2(worldu.ptr, hullCount, hulls),
246 BSPhysicsShapeType.SHAPE_HULL);
247}
248
249public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape)
250{
251 BulletWorldUnman worldu = world as BulletWorldUnman;
252 BulletShapeUnman shapeu = meshShape as BulletShapeUnman;
253 return new BulletShapeUnman(
254 BSAPICPP.BuildHullShapeFromMesh2(worldu.ptr, shapeu.ptr),
255 BSPhysicsShapeType.SHAPE_HULL);
256}
257
258public override BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData)
259{
260 BulletWorldUnman worldu = world as BulletWorldUnman;
261 return new BulletShapeUnman(BSAPICPP.BuildNativeShape2(worldu.ptr, shapeData), shapeData.Type);
262}
263
264public override bool IsNativeShape(BulletShape shape)
265{
266 BulletShapeUnman shapeu = shape as BulletShapeUnman;
267 if (shapeu != null && shapeu.HasPhysicalShape)
268 return BSAPICPP.IsNativeShape2(shapeu.ptr);
269 return false;
270}
271
272public override void SetShapeCollisionMargin(BulletShape shape, float margin)
273{
274 BulletShapeUnman shapeu = shape as BulletShapeUnman;
275 if (shapeu != null && shapeu.HasPhysicalShape)
276 BSAPICPP.SetShapeCollisionMargin2(shapeu.ptr, margin);
277}
278
279public override BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale)
280{
281 BulletWorldUnman worldu = world as BulletWorldUnman;
282 return new BulletShapeUnman(
283 BSAPICPP.BuildCapsuleShape2(worldu.ptr, radius, height, scale),
284 BSPhysicsShapeType.SHAPE_CAPSULE);
285}
286
287public override BulletShape CreateCompoundShape(BulletWorld world, bool enableDynamicAabbTree)
288{
289 BulletWorldUnman worldu = world as BulletWorldUnman;
290 return new BulletShapeUnman(
291 BSAPICPP.CreateCompoundShape2(worldu.ptr, enableDynamicAabbTree),
292 BSPhysicsShapeType.SHAPE_COMPOUND);
293
294}
295
296public override int GetNumberOfCompoundChildren(BulletShape shape)
297{
298 BulletShapeUnman shapeu = shape as BulletShapeUnman;
299 if (shapeu != null && shapeu.HasPhysicalShape)
300 return BSAPICPP.GetNumberOfCompoundChildren2(shapeu.ptr);
301 return 0;
302}
303
304public override void AddChildShapeToCompoundShape(BulletShape shape, BulletShape addShape, Vector3 pos, Quaternion rot)
305{
306 BulletShapeUnman shapeu = shape as BulletShapeUnman;
307 BulletShapeUnman addShapeu = addShape as BulletShapeUnman;
308 BSAPICPP.AddChildShapeToCompoundShape2(shapeu.ptr, addShapeu.ptr, pos, rot);
309}
310
311public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
312{
313 BulletShapeUnman shapeu = shape as BulletShapeUnman;
314 return new BulletShapeUnman(BSAPICPP.GetChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
315}
316
317public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape shape, int indx)
318{
319 BulletShapeUnman shapeu = shape as BulletShapeUnman;
320 return new BulletShapeUnman(BSAPICPP.RemoveChildShapeFromCompoundShapeIndex2(shapeu.ptr, indx), BSPhysicsShapeType.SHAPE_UNKNOWN);
321}
322
323public override void RemoveChildShapeFromCompoundShape(BulletShape shape, BulletShape removeShape)
324{
325 BulletShapeUnman shapeu = shape as BulletShapeUnman;
326 BulletShapeUnman removeShapeu = removeShape as BulletShapeUnman;
327 BSAPICPP.RemoveChildShapeFromCompoundShape2(shapeu.ptr, removeShapeu.ptr);
328}
329
330public override void RecalculateCompoundShapeLocalAabb(BulletShape shape)
331{
332 BulletShapeUnman shapeu = shape as BulletShapeUnman;
333 BSAPICPP.RecalculateCompoundShapeLocalAabb2(shapeu.ptr);
334}
335
336public override BulletShape DuplicateCollisionShape(BulletWorld world, BulletShape srcShape, uint id)
337{
338 BulletWorldUnman worldu = world as BulletWorldUnman;
339 BulletShapeUnman srcShapeu = srcShape as BulletShapeUnman;
340 return new BulletShapeUnman(BSAPICPP.DuplicateCollisionShape2(worldu.ptr, srcShapeu.ptr, id), srcShape.type);
341}
342
343public override bool DeleteCollisionShape(BulletWorld world, BulletShape shape)
344{
345 BulletWorldUnman worldu = world as BulletWorldUnman;
346 BulletShapeUnman shapeu = shape as BulletShapeUnman;
347 return BSAPICPP.DeleteCollisionShape2(worldu.ptr, shapeu.ptr);
348}
349
350public override CollisionObjectTypes GetBodyType(BulletBody obj)
351{
352 BulletBodyUnman bodyu = obj as BulletBodyUnman;
353 return (CollisionObjectTypes)BSAPICPP.GetBodyType2(bodyu.ptr);
354}
355
356public override BulletBody CreateBodyFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
357{
358 BulletWorldUnman worldu = world as BulletWorldUnman;
359 BulletShapeUnman shapeu = shape as BulletShapeUnman;
360 return new BulletBodyUnman(id, BSAPICPP.CreateBodyFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
361}
362
363public override BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot)
364{
365 BulletShapeUnman shapeu = shape as BulletShapeUnman;
366 return new BulletBodyUnman(id, BSAPICPP.CreateBodyWithDefaultMotionState2(shapeu.ptr, id, pos, rot));
367}
368
369public override BulletBody CreateGhostFromShape(BulletWorld world, BulletShape shape, uint id, Vector3 pos, Quaternion rot)
370{
371 BulletWorldUnman worldu = world as BulletWorldUnman;
372 BulletShapeUnman shapeu = shape as BulletShapeUnman;
373 return new BulletBodyUnman(id, BSAPICPP.CreateGhostFromShape2(worldu.ptr, shapeu.ptr, id, pos, rot));
374}
375
376public override void DestroyObject(BulletWorld world, BulletBody obj)
377{
378 BulletWorldUnman worldu = world as BulletWorldUnman;
379 BulletBodyUnman bodyu = obj as BulletBodyUnman;
380 BSAPICPP.DestroyObject2(worldu.ptr, bodyu.ptr);
381}
382
383// =====================================================================================
384// Terrain creation and helper routines
385public override BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin)
386{
387 return new BulletShapeUnman(BSAPICPP.CreateGroundPlaneShape2(id, height, collisionMargin), BSPhysicsShapeType.SHAPE_GROUNDPLANE);
388}
389
390public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
391 float scaleFactor, float collisionMargin)
392{
393 return new BulletShapeUnman(BSAPICPP.CreateTerrainShape2(id, size, minHeight, maxHeight, heightMap, scaleFactor, collisionMargin),
394 BSPhysicsShapeType.SHAPE_TERRAIN);
395}
396
397// =====================================================================================
398// Constraint creation and helper routines
399public override BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
400 Vector3 frame1loc, Quaternion frame1rot,
401 Vector3 frame2loc, Quaternion frame2rot,
402 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
403{
404 BulletWorldUnman worldu = world as BulletWorldUnman;
405 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
406 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
407 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr, frame1loc, frame1rot,
408 frame2loc, frame2rot, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
409}
410
411public override BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
412 Vector3 joinPoint,
413 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
414{
415 BulletWorldUnman worldu = world as BulletWorldUnman;
416 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
417 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
418 return new BulletConstraintUnman(BSAPICPP.Create6DofConstraintToPoint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
419 joinPoint, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
420}
421
422public override BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
423 Vector3 pivotinA, Vector3 pivotinB,
424 Vector3 axisInA, Vector3 axisInB,
425 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
426{
427 BulletWorldUnman worldu = world as BulletWorldUnman;
428 BulletBodyUnman bodyu1 = obj1 as BulletBodyUnman;
429 BulletBodyUnman bodyu2 = obj2 as BulletBodyUnman;
430 return new BulletConstraintUnman(BSAPICPP.CreateHingeConstraint2(worldu.ptr, bodyu1.ptr, bodyu2.ptr,
431 pivotinA, pivotinB, axisInA, axisInB, useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
432}
433
434public override void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse)
435{
436 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
437 BSAPICPP.SetConstraintEnable2(constrainu.ptr, numericTrueFalse);
438}
439
440public override void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations)
441{
442 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
443 BSAPICPP.SetConstraintNumSolverIterations2(constrainu.ptr, iterations);
444}
445
446public override bool SetFrames(BulletConstraint constrain,
447 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot)
448{
449 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
450 return BSAPICPP.SetFrames2(constrainu.ptr, frameA, frameArot, frameB, frameBrot);
451}
452
453public override bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
454{
455 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
456 return BSAPICPP.SetLinearLimits2(constrainu.ptr, low, hi);
457}
458
459public override bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi)
460{
461 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
462 return BSAPICPP.SetAngularLimits2(constrainu.ptr, low, hi);
463}
464
465public override bool UseFrameOffset(BulletConstraint constrain, float enable)
466{
467 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
468 return BSAPICPP.UseFrameOffset2(constrainu.ptr, enable);
469}
470
471public override bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce)
472{
473 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
474 return BSAPICPP.TranslationalLimitMotor2(constrainu.ptr, enable, targetVel, maxMotorForce);
475}
476
477public override bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold)
478{
479 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
480 return BSAPICPP.SetBreakingImpulseThreshold2(constrainu.ptr, threshold);
481}
482
483public override bool CalculateTransforms(BulletConstraint constrain)
484{
485 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
486 return BSAPICPP.CalculateTransforms2(constrainu.ptr);
487}
488
489public override bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis)
490{
491 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
492 return BSAPICPP.SetConstraintParam2(constrainu.ptr, paramIndex, value, axis);
493}
494
495public override bool DestroyConstraint(BulletWorld world, BulletConstraint constrain)
496{
497 BulletWorldUnman worldu = world as BulletWorldUnman;
498 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
499 return BSAPICPP.DestroyConstraint2(worldu.ptr, constrainu.ptr);
500}
501
502// =====================================================================================
503// btCollisionWorld entries
504public override void UpdateSingleAabb(BulletWorld world, BulletBody obj)
505{
506 BulletWorldUnman worldu = world as BulletWorldUnman;
507 BulletBodyUnman bodyu = obj as BulletBodyUnman;
508 BSAPICPP.UpdateSingleAabb2(worldu.ptr, bodyu.ptr);
509}
510
511public override void UpdateAabbs(BulletWorld world)
512{
513 BulletWorldUnman worldu = world as BulletWorldUnman;
514 BSAPICPP.UpdateAabbs2(worldu.ptr);
515}
516
517public override bool GetForceUpdateAllAabbs(BulletWorld world)
518{
519 BulletWorldUnman worldu = world as BulletWorldUnman;
520 return BSAPICPP.GetForceUpdateAllAabbs2(worldu.ptr);
521}
522
523public override void SetForceUpdateAllAabbs(BulletWorld world, bool force)
524{
525 BulletWorldUnman worldu = world as BulletWorldUnman;
526 BSAPICPP.SetForceUpdateAllAabbs2(worldu.ptr, force);
527}
528
529// =====================================================================================
530// btDynamicsWorld entries
531public override bool AddObjectToWorld(BulletWorld world, BulletBody obj)
532{
533 BulletWorldUnman worldu = world as BulletWorldUnman;
534 BulletBodyUnman bodyu = obj as BulletBodyUnman;
535
536 // Bullet resets several variables when an object is added to the world.
537 // Gravity is reset to world default depending on the static/dynamic
538 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
539 Vector3 origGrav = BSAPICPP.GetGravity2(bodyu.ptr);
540
541 bool ret = BSAPICPP.AddObjectToWorld2(worldu.ptr, bodyu.ptr);
542
543 if (ret)
544 {
545 BSAPICPP.SetGravity2(bodyu.ptr, origGrav);
546 obj.ApplyCollisionMask(world.physicsScene);
547 }
548 return ret;
549}
550
551public override bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj)
552{
553 BulletWorldUnman worldu = world as BulletWorldUnman;
554 BulletBodyUnman bodyu = obj as BulletBodyUnman;
555 return BSAPICPP.RemoveObjectFromWorld2(worldu.ptr, bodyu.ptr);
556}
557
558public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
559{
560 BulletWorldUnman worldu = world as BulletWorldUnman;
561 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
562 return BSAPICPP.AddConstraintToWorld2(worldu.ptr, constrainu.ptr, disableCollisionsBetweenLinkedObjects);
563}
564
565public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
566{
567 BulletWorldUnman worldu = world as BulletWorldUnman;
568 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
569 return BSAPICPP.RemoveConstraintFromWorld2(worldu.ptr, constrainu.ptr);
570}
571// =====================================================================================
572// btCollisionObject entries
573public override Vector3 GetAnisotripicFriction(BulletConstraint constrain)
574{
575 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
576 return BSAPICPP.GetAnisotripicFriction2(constrainu.ptr);
577}
578
579public override Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict)
580{
581 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
582 return BSAPICPP.SetAnisotripicFriction2(constrainu.ptr, frict);
583}
584
585public override bool HasAnisotripicFriction(BulletConstraint constrain)
586{
587 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
588 return BSAPICPP.HasAnisotripicFriction2(constrainu.ptr);
589}
590
591public override void SetContactProcessingThreshold(BulletBody obj, float val)
592{
593 BulletBodyUnman bodyu = obj as BulletBodyUnman;
594 BSAPICPP.SetContactProcessingThreshold2(bodyu.ptr, val);
595}
596
597public override float GetContactProcessingThreshold(BulletBody obj)
598{
599 BulletBodyUnman bodyu = obj as BulletBodyUnman;
600 return BSAPICPP.GetContactProcessingThreshold2(bodyu.ptr);
601}
602
603public override bool IsStaticObject(BulletBody obj)
604{
605 BulletBodyUnman bodyu = obj as BulletBodyUnman;
606 return BSAPICPP.IsStaticObject2(bodyu.ptr);
607}
608
609public override bool IsKinematicObject(BulletBody obj)
610{
611 BulletBodyUnman bodyu = obj as BulletBodyUnman;
612 return BSAPICPP.IsKinematicObject2(bodyu.ptr);
613}
614
615public override bool IsStaticOrKinematicObject(BulletBody obj)
616{
617 BulletBodyUnman bodyu = obj as BulletBodyUnman;
618 return BSAPICPP.IsStaticOrKinematicObject2(bodyu.ptr);
619}
620
621public override bool HasContactResponse(BulletBody obj)
622{
623 BulletBodyUnman bodyu = obj as BulletBodyUnman;
624 return BSAPICPP.HasContactResponse2(bodyu.ptr);
625}
626
627public override void SetCollisionShape(BulletWorld world, BulletBody obj, BulletShape shape)
628{
629 BulletWorldUnman worldu = world as BulletWorldUnman;
630 BulletBodyUnman bodyu = obj as BulletBodyUnman;
631 BulletShapeUnman shapeu = shape as BulletShapeUnman;
632 if (worldu != null && bodyu != null)
633 {
634 // Special case to allow the caller to zero out the reference to any physical shape
635 if (shapeu != null)
636 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, shapeu.ptr);
637 else
638 BSAPICPP.SetCollisionShape2(worldu.ptr, bodyu.ptr, IntPtr.Zero);
639 }
640}
641
642public override BulletShape GetCollisionShape(BulletBody obj)
643{
644 BulletBodyUnman bodyu = obj as BulletBodyUnman;
645 return new BulletShapeUnman(BSAPICPP.GetCollisionShape2(bodyu.ptr), BSPhysicsShapeType.SHAPE_UNKNOWN);
646}
647
648public override int GetActivationState(BulletBody obj)
649{
650 BulletBodyUnman bodyu = obj as BulletBodyUnman;
651 return BSAPICPP.GetActivationState2(bodyu.ptr);
652}
653
654public override void SetActivationState(BulletBody obj, int state)
655{
656 BulletBodyUnman bodyu = obj as BulletBodyUnman;
657 BSAPICPP.SetActivationState2(bodyu.ptr, state);
658}
659
660public override void SetDeactivationTime(BulletBody obj, float dtime)
661{
662 BulletBodyUnman bodyu = obj as BulletBodyUnman;
663 BSAPICPP.SetDeactivationTime2(bodyu.ptr, dtime);
664}
665
666public override float GetDeactivationTime(BulletBody obj)
667{
668 BulletBodyUnman bodyu = obj as BulletBodyUnman;
669 return BSAPICPP.GetDeactivationTime2(bodyu.ptr);
670}
671
672public override void ForceActivationState(BulletBody obj, ActivationState state)
673{
674 BulletBodyUnman bodyu = obj as BulletBodyUnman;
675 BSAPICPP.ForceActivationState2(bodyu.ptr, state);
676}
677
678public override void Activate(BulletBody obj, bool forceActivation)
679{
680 BulletBodyUnman bodyu = obj as BulletBodyUnman;
681 BSAPICPP.Activate2(bodyu.ptr, forceActivation);
682}
683
684public override bool IsActive(BulletBody obj)
685{
686 BulletBodyUnman bodyu = obj as BulletBodyUnman;
687 return BSAPICPP.IsActive2(bodyu.ptr);
688}
689
690public override void SetRestitution(BulletBody obj, float val)
691{
692 BulletBodyUnman bodyu = obj as BulletBodyUnman;
693 BSAPICPP.SetRestitution2(bodyu.ptr, val);
694}
695
696public override float GetRestitution(BulletBody obj)
697{
698 BulletBodyUnman bodyu = obj as BulletBodyUnman;
699 return BSAPICPP.GetRestitution2(bodyu.ptr);
700}
701
702public override void SetFriction(BulletBody obj, float val)
703{
704 BulletBodyUnman bodyu = obj as BulletBodyUnman;
705 BSAPICPP.SetFriction2(bodyu.ptr, val);
706}
707
708public override float GetFriction(BulletBody obj)
709{
710 BulletBodyUnman bodyu = obj as BulletBodyUnman;
711 return BSAPICPP.GetFriction2(bodyu.ptr);
712}
713
714public override Vector3 GetPosition(BulletBody obj)
715{
716 BulletBodyUnman bodyu = obj as BulletBodyUnman;
717 return BSAPICPP.GetPosition2(bodyu.ptr);
718}
719
720public override Quaternion GetOrientation(BulletBody obj)
721{
722 BulletBodyUnman bodyu = obj as BulletBodyUnman;
723 return BSAPICPP.GetOrientation2(bodyu.ptr);
724}
725
726public override void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation)
727{
728 BulletBodyUnman bodyu = obj as BulletBodyUnman;
729 BSAPICPP.SetTranslation2(bodyu.ptr, position, rotation);
730}
731
732 /*
733public override IntPtr GetBroadphaseHandle(BulletBody obj)
734{
735 BulletBodyUnman bodyu = obj as BulletBodyUnman;
736 return BSAPICPP.GetBroadphaseHandle2(bodyu.ptr);
737}
738
739public override void SetBroadphaseHandle(BulletBody obj, IntPtr handle)
740{
741 BulletBodyUnman bodyu = obj as BulletBodyUnman;
742 BSAPICPP.SetUserPointer2(bodyu.ptr, handle);
743}
744 */
745
746public override void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel)
747{
748 BulletBodyUnman bodyu = obj as BulletBodyUnman;
749 BSAPICPP.SetInterpolationLinearVelocity2(bodyu.ptr, vel);
750}
751
752public override void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel)
753{
754 BulletBodyUnman bodyu = obj as BulletBodyUnman;
755 BSAPICPP.SetInterpolationAngularVelocity2(bodyu.ptr, vel);
756}
757
758public override void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel)
759{
760 BulletBodyUnman bodyu = obj as BulletBodyUnman;
761 BSAPICPP.SetInterpolationVelocity2(bodyu.ptr, linearVel, angularVel);
762}
763
764public override float GetHitFraction(BulletBody obj)
765{
766 BulletBodyUnman bodyu = obj as BulletBodyUnman;
767 return BSAPICPP.GetHitFraction2(bodyu.ptr);
768}
769
770public override void SetHitFraction(BulletBody obj, float val)
771{
772 BulletBodyUnman bodyu = obj as BulletBodyUnman;
773 BSAPICPP.SetHitFraction2(bodyu.ptr, val);
774}
775
776public override CollisionFlags GetCollisionFlags(BulletBody obj)
777{
778 BulletBodyUnman bodyu = obj as BulletBodyUnman;
779 return BSAPICPP.GetCollisionFlags2(bodyu.ptr);
780}
781
782public override CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags)
783{
784 BulletBodyUnman bodyu = obj as BulletBodyUnman;
785 return BSAPICPP.SetCollisionFlags2(bodyu.ptr, flags);
786}
787
788public override CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags)
789{
790 BulletBodyUnman bodyu = obj as BulletBodyUnman;
791 return BSAPICPP.AddToCollisionFlags2(bodyu.ptr, flags);
792}
793
794public override CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags)
795{
796 BulletBodyUnman bodyu = obj as BulletBodyUnman;
797 return BSAPICPP.RemoveFromCollisionFlags2(bodyu.ptr, flags);
798}
799
800public override float GetCcdMotionThreshold(BulletBody obj)
801{
802 BulletBodyUnman bodyu = obj as BulletBodyUnman;
803 return BSAPICPP.GetCcdMotionThreshold2(bodyu.ptr);
804}
805
806
807public override void SetCcdMotionThreshold(BulletBody obj, float val)
808{
809 BulletBodyUnman bodyu = obj as BulletBodyUnman;
810 BSAPICPP.SetCcdMotionThreshold2(bodyu.ptr, val);
811}
812
813public override float GetCcdSweptSphereRadius(BulletBody obj)
814{
815 BulletBodyUnman bodyu = obj as BulletBodyUnman;
816 return BSAPICPP.GetCcdSweptSphereRadius2(bodyu.ptr);
817}
818
819public override void SetCcdSweptSphereRadius(BulletBody obj, float val)
820{
821 BulletBodyUnman bodyu = obj as BulletBodyUnman;
822 BSAPICPP.SetCcdSweptSphereRadius2(bodyu.ptr, val);
823}
824
825public override IntPtr GetUserPointer(BulletBody obj)
826{
827 BulletBodyUnman bodyu = obj as BulletBodyUnman;
828 return BSAPICPP.GetUserPointer2(bodyu.ptr);
829}
830
831public override void SetUserPointer(BulletBody obj, IntPtr val)
832{
833 BulletBodyUnman bodyu = obj as BulletBodyUnman;
834 BSAPICPP.SetUserPointer2(bodyu.ptr, val);
835}
836
837// =====================================================================================
838// btRigidBody entries
839public override void ApplyGravity(BulletBody obj)
840{
841 BulletBodyUnman bodyu = obj as BulletBodyUnman;
842 BSAPICPP.ApplyGravity2(bodyu.ptr);
843}
844
845public override void SetGravity(BulletBody obj, Vector3 val)
846{
847 BulletBodyUnman bodyu = obj as BulletBodyUnman;
848 BSAPICPP.SetGravity2(bodyu.ptr, val);
849}
850
851public override Vector3 GetGravity(BulletBody obj)
852{
853 BulletBodyUnman bodyu = obj as BulletBodyUnman;
854 return BSAPICPP.GetGravity2(bodyu.ptr);
855}
856
857public override void SetDamping(BulletBody obj, float lin_damping, float ang_damping)
858{
859 BulletBodyUnman bodyu = obj as BulletBodyUnman;
860 BSAPICPP.SetDamping2(bodyu.ptr, lin_damping, ang_damping);
861}
862
863public override void SetLinearDamping(BulletBody obj, float lin_damping)
864{
865 BulletBodyUnman bodyu = obj as BulletBodyUnman;
866 BSAPICPP.SetLinearDamping2(bodyu.ptr, lin_damping);
867}
868
869public override void SetAngularDamping(BulletBody obj, float ang_damping)
870{
871 BulletBodyUnman bodyu = obj as BulletBodyUnman;
872 BSAPICPP.SetAngularDamping2(bodyu.ptr, ang_damping);
873}
874
875public override float GetLinearDamping(BulletBody obj)
876{
877 BulletBodyUnman bodyu = obj as BulletBodyUnman;
878 return BSAPICPP.GetLinearDamping2(bodyu.ptr);
879}
880
881public override float GetAngularDamping(BulletBody obj)
882{
883 BulletBodyUnman bodyu = obj as BulletBodyUnman;
884 return BSAPICPP.GetAngularDamping2(bodyu.ptr);
885}
886
887public override float GetLinearSleepingThreshold(BulletBody obj)
888{
889 BulletBodyUnman bodyu = obj as BulletBodyUnman;
890 return BSAPICPP.GetLinearSleepingThreshold2(bodyu.ptr);
891}
892
893public override void ApplyDamping(BulletBody obj, float timeStep)
894{
895 BulletBodyUnman bodyu = obj as BulletBodyUnman;
896 BSAPICPP.ApplyDamping2(bodyu.ptr, timeStep);
897}
898
899public override void SetMassProps(BulletBody obj, float mass, Vector3 inertia)
900{
901 BulletBodyUnman bodyu = obj as BulletBodyUnman;
902 BSAPICPP.SetMassProps2(bodyu.ptr, mass, inertia);
903}
904
905public override Vector3 GetLinearFactor(BulletBody obj)
906{
907 BulletBodyUnman bodyu = obj as BulletBodyUnman;
908 return BSAPICPP.GetLinearFactor2(bodyu.ptr);
909}
910
911public override void SetLinearFactor(BulletBody obj, Vector3 factor)
912{
913 BulletBodyUnman bodyu = obj as BulletBodyUnman;
914 BSAPICPP.SetLinearFactor2(bodyu.ptr, factor);
915}
916
917public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot)
918{
919 BulletBodyUnman bodyu = obj as BulletBodyUnman;
920 BSAPICPP.SetCenterOfMassByPosRot2(bodyu.ptr, pos, rot);
921}
922
923// Add a force to the object as if its mass is one.
924// Deep down in Bullet: m_totalForce += force*m_linearFactor;
925public override void ApplyCentralForce(BulletBody obj, Vector3 force)
926{
927 BulletBodyUnman bodyu = obj as BulletBodyUnman;
928 BSAPICPP.ApplyCentralForce2(bodyu.ptr, force);
929}
930
931// Set the force being applied to the object as if its mass is one.
932public override void SetObjectForce(BulletBody obj, Vector3 force)
933{
934 BulletBodyUnman bodyu = obj as BulletBodyUnman;
935 BSAPICPP.SetObjectForce2(bodyu.ptr, force);
936}
937
938public override Vector3 GetTotalForce(BulletBody obj)
939{
940 BulletBodyUnman bodyu = obj as BulletBodyUnman;
941 return BSAPICPP.GetTotalForce2(bodyu.ptr);
942}
943
944public override Vector3 GetTotalTorque(BulletBody obj)
945{
946 BulletBodyUnman bodyu = obj as BulletBodyUnman;
947 return BSAPICPP.GetTotalTorque2(bodyu.ptr);
948}
949
950public override Vector3 GetInvInertiaDiagLocal(BulletBody obj)
951{
952 BulletBodyUnman bodyu = obj as BulletBodyUnman;
953 return BSAPICPP.GetInvInertiaDiagLocal2(bodyu.ptr);
954}
955
956public override void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert)
957{
958 BulletBodyUnman bodyu = obj as BulletBodyUnman;
959 BSAPICPP.SetInvInertiaDiagLocal2(bodyu.ptr, inert);
960}
961
962public override void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold)
963{
964 BulletBodyUnman bodyu = obj as BulletBodyUnman;
965 BSAPICPP.SetSleepingThresholds2(bodyu.ptr, lin_threshold, ang_threshold);
966}
967
968// Deep down in Bullet: m_totalTorque += torque*m_angularFactor;
969public override void ApplyTorque(BulletBody obj, Vector3 torque)
970{
971 BulletBodyUnman bodyu = obj as BulletBodyUnman;
972 BSAPICPP.ApplyTorque2(bodyu.ptr, torque);
973}
974
975// Apply force at the given point. Will add torque to the object.
976// Deep down in Bullet: applyCentralForce(force);
977// applyTorque(rel_pos.cross(force*m_linearFactor));
978public override void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos)
979{
980 BulletBodyUnman bodyu = obj as BulletBodyUnman;
981 BSAPICPP.ApplyForce2(bodyu.ptr, force, pos);
982}
983
984// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
985// Deep down in Bullet: m_linearVelocity += impulse *m_linearFactor * m_inverseMass;
986public override void ApplyCentralImpulse(BulletBody obj, Vector3 imp)
987{
988 BulletBodyUnman bodyu = obj as BulletBodyUnman;
989 BSAPICPP.ApplyCentralImpulse2(bodyu.ptr, imp);
990}
991
992// Apply impulse to the object's torque. Force is scaled by object's mass.
993// Deep down in Bullet: m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor;
994public override void ApplyTorqueImpulse(BulletBody obj, Vector3 imp)
995{
996 BulletBodyUnman bodyu = obj as BulletBodyUnman;
997 BSAPICPP.ApplyTorqueImpulse2(bodyu.ptr, imp);
998}
999
1000// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1001// Deep down in Bullet: applyCentralImpulse(impulse);
1002// applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor));
1003public override void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos)
1004{
1005 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1006 BSAPICPP.ApplyImpulse2(bodyu.ptr, imp, pos);
1007}
1008
1009public override void ClearForces(BulletBody obj)
1010{
1011 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1012 BSAPICPP.ClearForces2(bodyu.ptr);
1013}
1014
1015public override void ClearAllForces(BulletBody obj)
1016{
1017 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1018 BSAPICPP.ClearAllForces2(bodyu.ptr);
1019}
1020
1021public override void UpdateInertiaTensor(BulletBody obj)
1022{
1023 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1024 BSAPICPP.UpdateInertiaTensor2(bodyu.ptr);
1025}
1026
1027public override Vector3 GetLinearVelocity(BulletBody obj)
1028{
1029 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1030 return BSAPICPP.GetLinearVelocity2(bodyu.ptr);
1031}
1032
1033public override Vector3 GetAngularVelocity(BulletBody obj)
1034{
1035 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1036 return BSAPICPP.GetAngularVelocity2(bodyu.ptr);
1037}
1038
1039public override void SetLinearVelocity(BulletBody obj, Vector3 vel)
1040{
1041 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1042 BSAPICPP.SetLinearVelocity2(bodyu.ptr, vel);
1043}
1044
1045public override void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity)
1046{
1047 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1048 BSAPICPP.SetAngularVelocity2(bodyu.ptr, angularVelocity);
1049}
1050
1051public override Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos)
1052{
1053 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1054 return BSAPICPP.GetVelocityInLocalPoint2(bodyu.ptr, pos);
1055}
1056
1057public override void Translate(BulletBody obj, Vector3 trans)
1058{
1059 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1060 BSAPICPP.Translate2(bodyu.ptr, trans);
1061}
1062
1063public override void UpdateDeactivation(BulletBody obj, float timeStep)
1064{
1065 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1066 BSAPICPP.UpdateDeactivation2(bodyu.ptr, timeStep);
1067}
1068
1069public override bool WantsSleeping(BulletBody obj)
1070{
1071 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1072 return BSAPICPP.WantsSleeping2(bodyu.ptr);
1073}
1074
1075public override void SetAngularFactor(BulletBody obj, float factor)
1076{
1077 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1078 BSAPICPP.SetAngularFactor2(bodyu.ptr, factor);
1079}
1080
1081public override void SetAngularFactorV(BulletBody obj, Vector3 factor)
1082{
1083 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1084 BSAPICPP.SetAngularFactorV2(bodyu.ptr, factor);
1085}
1086
1087public override Vector3 GetAngularFactor(BulletBody obj)
1088{
1089 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1090 return BSAPICPP.GetAngularFactor2(bodyu.ptr);
1091}
1092
1093public override bool IsInWorld(BulletWorld world, BulletBody obj)
1094{
1095 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1096 return BSAPICPP.IsInWorld2(bodyu.ptr);
1097}
1098
1099public override void AddConstraintRef(BulletBody obj, BulletConstraint constrain)
1100{
1101 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1102 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1103 BSAPICPP.AddConstraintRef2(bodyu.ptr, constrainu.ptr);
1104}
1105
1106public override void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain)
1107{
1108 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1109 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1110 BSAPICPP.RemoveConstraintRef2(bodyu.ptr, constrainu.ptr);
1111}
1112
1113public override BulletConstraint GetConstraintRef(BulletBody obj, int index)
1114{
1115 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1116 return new BulletConstraintUnman(BSAPICPP.GetConstraintRef2(bodyu.ptr, index));
1117}
1118
1119public override int GetNumConstraintRefs(BulletBody obj)
1120{
1121 BulletBodyUnman bodyu = obj as BulletBodyUnman;
1122 return BSAPICPP.GetNumConstraintRefs2(bodyu.ptr);
1123}
1124
1125public override bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask)
1126{
1127 BulletBodyUnman bodyu = body as BulletBodyUnman;
1128 return BSAPICPP.SetCollisionGroupMask2(bodyu.ptr, filter, mask);
1129}
1130
1131// =====================================================================================
1132// btCollisionShape entries
1133
1134public override float GetAngularMotionDisc(BulletShape shape)
1135{
1136 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1137 return BSAPICPP.GetAngularMotionDisc2(shapeu.ptr);
1138}
1139
1140public override float GetContactBreakingThreshold(BulletShape shape, float defaultFactor)
1141{
1142 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1143 return BSAPICPP.GetContactBreakingThreshold2(shapeu.ptr, defaultFactor);
1144}
1145
1146public override bool IsPolyhedral(BulletShape shape)
1147{
1148 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1149 return BSAPICPP.IsPolyhedral2(shapeu.ptr);
1150}
1151
1152public override bool IsConvex2d(BulletShape shape)
1153{
1154 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1155 return BSAPICPP.IsConvex2d2(shapeu.ptr);
1156}
1157
1158public override bool IsConvex(BulletShape shape)
1159{
1160 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1161 return BSAPICPP.IsConvex2(shapeu.ptr);
1162}
1163
1164public override bool IsNonMoving(BulletShape shape)
1165{
1166 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1167 return BSAPICPP.IsNonMoving2(shapeu.ptr);
1168}
1169
1170public override bool IsConcave(BulletShape shape)
1171{
1172 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1173 return BSAPICPP.IsConcave2(shapeu.ptr);
1174}
1175
1176public override bool IsCompound(BulletShape shape)
1177{
1178 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1179 return BSAPICPP.IsCompound2(shapeu.ptr);
1180}
1181
1182public override bool IsSoftBody(BulletShape shape)
1183{
1184 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1185 return BSAPICPP.IsSoftBody2(shapeu.ptr);
1186}
1187
1188public override bool IsInfinite(BulletShape shape)
1189{
1190 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1191 return BSAPICPP.IsInfinite2(shapeu.ptr);
1192}
1193
1194public override void SetLocalScaling(BulletShape shape, Vector3 scale)
1195{
1196 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1197 BSAPICPP.SetLocalScaling2(shapeu.ptr, scale);
1198}
1199
1200public override Vector3 GetLocalScaling(BulletShape shape)
1201{
1202 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1203 return BSAPICPP.GetLocalScaling2(shapeu.ptr);
1204}
1205
1206public override Vector3 CalculateLocalInertia(BulletShape shape, float mass)
1207{
1208 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1209 return BSAPICPP.CalculateLocalInertia2(shapeu.ptr, mass);
1210}
1211
1212public override int GetShapeType(BulletShape shape)
1213{
1214 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1215 return BSAPICPP.GetShapeType2(shapeu.ptr);
1216}
1217
1218public override void SetMargin(BulletShape shape, float val)
1219{
1220 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1221 BSAPICPP.SetMargin2(shapeu.ptr, val);
1222}
1223
1224public override float GetMargin(BulletShape shape)
1225{
1226 BulletShapeUnman shapeu = shape as BulletShapeUnman;
1227 return BSAPICPP.GetMargin2(shapeu.ptr);
1228}
1229
1230// =====================================================================================
1231// Debugging
1232public override void DumpRigidBody(BulletWorld world, BulletBody collisionObject)
1233{
1234 BulletWorldUnman worldu = world as BulletWorldUnman;
1235 BulletBodyUnman bodyu = collisionObject as BulletBodyUnman;
1236 BSAPICPP.DumpRigidBody2(worldu.ptr, bodyu.ptr);
1237}
1238
1239public override void DumpCollisionShape(BulletWorld world, BulletShape collisionShape)
1240{
1241 BulletWorldUnman worldu = world as BulletWorldUnman;
1242 BulletShapeUnman shapeu = collisionShape as BulletShapeUnman;
1243 BSAPICPP.DumpCollisionShape2(worldu.ptr, shapeu.ptr);
1244}
1245
1246public override void DumpConstraint(BulletWorld world, BulletConstraint constrain)
1247{
1248 BulletWorldUnman worldu = world as BulletWorldUnman;
1249 BulletConstraintUnman constrainu = constrain as BulletConstraintUnman;
1250 BSAPICPP.DumpConstraint2(worldu.ptr, constrainu.ptr);
1251}
1252
1253public override void DumpActivationInfo(BulletWorld world)
1254{
1255 BulletWorldUnman worldu = world as BulletWorldUnman;
1256 BSAPICPP.DumpActivationInfo2(worldu.ptr);
1257}
1258
1259public override void DumpAllInfo(BulletWorld world)
1260{
1261 BulletWorldUnman worldu = world as BulletWorldUnman;
1262 BSAPICPP.DumpAllInfo2(worldu.ptr);
1263}
1264
1265public override void DumpPhysicsStatistics(BulletWorld world)
1266{
1267 BulletWorldUnman worldu = world as BulletWorldUnman;
1268 BSAPICPP.DumpPhysicsStatistics2(worldu.ptr);
1269}
1270public override void ResetBroadphasePool(BulletWorld world)
1271{
1272 BulletWorldUnman worldu = world as BulletWorldUnman;
1273 BSAPICPP.ResetBroadphasePool(worldu.ptr);
1274}
1275public override void ResetConstraintSolver(BulletWorld world)
1276{
1277 BulletWorldUnman worldu = world as BulletWorldUnman;
1278 BSAPICPP.ResetConstraintSolver(worldu.ptr);
1279}
1280
1281// =====================================================================================
1282// =====================================================================================
1283// =====================================================================================
1284// =====================================================================================
1285// =====================================================================================
1286// The actual interface to the unmanaged code
1287static class BSAPICPP
1288{
1289// ===============================================================================
1290// Link back to the managed code for outputting log messages
1291[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
1292public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
1293
1294// ===============================================================================
1295// Initialization and simulation
1296[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1297public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
1298 int maxCollisions, IntPtr collisionArray,
1299 int maxUpdates, IntPtr updateArray,
1300 DebugLogCallback logRoutine);
1301
1302[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1303public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
1304 out int updatedEntityCount, out int collidersCount);
1305
1306[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1307public static extern void Shutdown2(IntPtr sim);
1308
1309[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1310public static extern bool PushUpdate2(IntPtr obj);
1311
1312[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1313public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
1314
1315// =====================================================================================
1316// Mesh, hull, shape and body creation helper routines
1317[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1318public static extern IntPtr CreateMeshShape2(IntPtr world,
1319 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
1320 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
1321
1322[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1323public static extern IntPtr CreateHullShape2(IntPtr world,
1324 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
1325
1326[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1327public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
1328
1329[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1330public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
1331
1332[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1333public static extern bool IsNativeShape2(IntPtr shape);
1334
1335[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1336public static extern void SetShapeCollisionMargin2(IntPtr shape, float margin);
1337
1338[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1339public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
1340
1341[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1342public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
1343
1344[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1345public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
1346
1347[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1348public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
1349
1350[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1351public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1352
1353[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1354public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
1355
1356[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1357public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
1358
1359[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1360public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
1361
1362[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1363public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
1364
1365[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1366public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
1367
1368[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1369public static extern int GetBodyType2(IntPtr obj);
1370
1371[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1372public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1373
1374[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1375public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1376
1377[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1378public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
1379
1380[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1381public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
1382
1383// =====================================================================================
1384// Terrain creation and helper routines
1385[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1386public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
1387
1388[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1389public static extern IntPtr CreateTerrainShape2(uint id, Vector3 size, float minHeight, float maxHeight,
1390 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap,
1391 float scaleFactor, float collisionMargin);
1392
1393// =====================================================================================
1394// Constraint creation and helper routines
1395[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1396public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1397 Vector3 frame1loc, Quaternion frame1rot,
1398 Vector3 frame2loc, Quaternion frame2rot,
1399 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1400
1401[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1402public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1403 Vector3 joinPoint,
1404 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1405
1406[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1407public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
1408 Vector3 pivotinA, Vector3 pivotinB,
1409 Vector3 axisInA, Vector3 axisInB,
1410 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
1411
1412[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1413public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
1414
1415[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1416public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
1417
1418[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1419public static extern bool SetFrames2(IntPtr constrain,
1420 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
1421
1422[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1423public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1424
1425[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1426public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
1427
1428[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1429public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
1430
1431[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1432public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
1433
1434[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1435public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
1436
1437[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1438public static extern bool CalculateTransforms2(IntPtr constrain);
1439
1440[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1441public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
1442
1443[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1444public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
1445
1446// =====================================================================================
1447// btCollisionWorld entries
1448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1449public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
1450
1451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1452public static extern void UpdateAabbs2(IntPtr world);
1453
1454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1455public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
1456
1457[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1458public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
1459
1460// =====================================================================================
1461// btDynamicsWorld entries
1462[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1463public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
1464
1465[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1466public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
1467
1468[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1469public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
1470
1471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1472public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
1473// =====================================================================================
1474// btCollisionObject entries
1475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1476public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
1477
1478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1479public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
1480
1481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1482public static extern bool HasAnisotripicFriction2(IntPtr constrain);
1483
1484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1485public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
1486
1487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1488public static extern float GetContactProcessingThreshold2(IntPtr obj);
1489
1490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1491public static extern bool IsStaticObject2(IntPtr obj);
1492
1493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1494public static extern bool IsKinematicObject2(IntPtr obj);
1495
1496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1497public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
1498
1499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1500public static extern bool HasContactResponse2(IntPtr obj);
1501
1502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1503public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
1504
1505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1506public static extern IntPtr GetCollisionShape2(IntPtr obj);
1507
1508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1509public static extern int GetActivationState2(IntPtr obj);
1510
1511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1512public static extern void SetActivationState2(IntPtr obj, int state);
1513
1514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1515public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
1516
1517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1518public static extern float GetDeactivationTime2(IntPtr obj);
1519
1520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1521public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
1522
1523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1524public static extern void Activate2(IntPtr obj, bool forceActivation);
1525
1526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1527public static extern bool IsActive2(IntPtr obj);
1528
1529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1530public static extern void SetRestitution2(IntPtr obj, float val);
1531
1532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1533public static extern float GetRestitution2(IntPtr obj);
1534
1535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1536public static extern void SetFriction2(IntPtr obj, float val);
1537
1538[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1539public static extern float GetFriction2(IntPtr obj);
1540
1541 /* Haven't defined the type 'Transform'
1542[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1543public static extern Transform GetWorldTransform2(IntPtr obj);
1544
1545[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1546public static extern void setWorldTransform2(IntPtr obj, Transform trans);
1547 */
1548
1549[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1550public static extern Vector3 GetPosition2(IntPtr obj);
1551
1552[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1553public static extern Quaternion GetOrientation2(IntPtr obj);
1554
1555[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1556public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
1557
1558[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1559public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
1560
1561[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1562public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
1563
1564 /*
1565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1566public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
1567
1568[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1569public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
1570 */
1571
1572[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1573public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
1574
1575[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1576public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
1577
1578[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1579public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
1580
1581[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1582public static extern float GetHitFraction2(IntPtr obj);
1583
1584[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1585public static extern void SetHitFraction2(IntPtr obj, float val);
1586
1587[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1588public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
1589
1590[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1591public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
1592
1593[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1594public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
1595
1596[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1597public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
1598
1599[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1600public static extern float GetCcdMotionThreshold2(IntPtr obj);
1601
1602[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1603public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
1604
1605[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1606public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
1607
1608[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1609public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
1610
1611[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1612public static extern IntPtr GetUserPointer2(IntPtr obj);
1613
1614[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1615public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
1616
1617// =====================================================================================
1618// btRigidBody entries
1619[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1620public static extern void ApplyGravity2(IntPtr obj);
1621
1622[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1623public static extern void SetGravity2(IntPtr obj, Vector3 val);
1624
1625[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1626public static extern Vector3 GetGravity2(IntPtr obj);
1627
1628[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1629public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
1630
1631[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1632public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
1633
1634[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1635public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
1636
1637[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1638public static extern float GetLinearDamping2(IntPtr obj);
1639
1640[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1641public static extern float GetAngularDamping2(IntPtr obj);
1642
1643[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1644public static extern float GetLinearSleepingThreshold2(IntPtr obj);
1645
1646[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1647public static extern float GetAngularSleepingThreshold2(IntPtr obj);
1648
1649[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1650public static extern void ApplyDamping2(IntPtr obj, float timeStep);
1651
1652[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1653public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
1654
1655[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1656public static extern Vector3 GetLinearFactor2(IntPtr obj);
1657
1658[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1659public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
1660
1661 /*
1662[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1663public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
1664 */
1665
1666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1667public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
1668
1669// Add a force to the object as if its mass is one.
1670[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1671public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
1672
1673// Set the force being applied to the object as if its mass is one.
1674[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1675public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
1676
1677[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1678public static extern Vector3 GetTotalForce2(IntPtr obj);
1679
1680[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1681public static extern Vector3 GetTotalTorque2(IntPtr obj);
1682
1683[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1684public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
1685
1686[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1687public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
1688
1689[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1690public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
1691
1692[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1693public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
1694
1695// Apply force at the given point. Will add torque to the object.
1696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1697public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
1698
1699// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
1700[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1701public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
1702
1703// Apply impulse to the object's torque. Force is scaled by object's mass.
1704[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1705public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
1706
1707// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
1708[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1709public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
1710
1711[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1712public static extern void ClearForces2(IntPtr obj);
1713
1714[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1715public static extern void ClearAllForces2(IntPtr obj);
1716
1717[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1718public static extern void UpdateInertiaTensor2(IntPtr obj);
1719
1720[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1721public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
1722
1723 /*
1724[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1725public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
1726 */
1727
1728[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1729public static extern Vector3 GetLinearVelocity2(IntPtr obj);
1730
1731[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1732public static extern Vector3 GetAngularVelocity2(IntPtr obj);
1733
1734[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1735public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
1736
1737[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1738public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
1739
1740[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1741public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
1742
1743[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1744public static extern void Translate2(IntPtr obj, Vector3 trans);
1745
1746[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1747public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
1748
1749[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1750public static extern bool WantsSleeping2(IntPtr obj);
1751
1752[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1753public static extern void SetAngularFactor2(IntPtr obj, float factor);
1754
1755[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1756public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
1757
1758[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1759public static extern Vector3 GetAngularFactor2(IntPtr obj);
1760
1761[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1762public static extern bool IsInWorld2(IntPtr obj);
1763
1764[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1765public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
1766
1767[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1768public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
1769
1770[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1771public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
1772
1773[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1774public static extern int GetNumConstraintRefs2(IntPtr obj);
1775
1776[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1777public static extern bool SetCollisionGroupMask2(IntPtr body, uint filter, uint mask);
1778
1779// =====================================================================================
1780// btCollisionShape entries
1781
1782[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1783public static extern float GetAngularMotionDisc2(IntPtr shape);
1784
1785[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1786public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
1787
1788[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1789public static extern bool IsPolyhedral2(IntPtr shape);
1790
1791[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1792public static extern bool IsConvex2d2(IntPtr shape);
1793
1794[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1795public static extern bool IsConvex2(IntPtr shape);
1796
1797[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1798public static extern bool IsNonMoving2(IntPtr shape);
1799
1800[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1801public static extern bool IsConcave2(IntPtr shape);
1802
1803[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1804public static extern bool IsCompound2(IntPtr shape);
1805
1806[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1807public static extern bool IsSoftBody2(IntPtr shape);
1808
1809[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1810public static extern bool IsInfinite2(IntPtr shape);
1811
1812[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1813public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
1814
1815[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1816public static extern Vector3 GetLocalScaling2(IntPtr shape);
1817
1818[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1819public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
1820
1821[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1822public static extern int GetShapeType2(IntPtr shape);
1823
1824[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1825public static extern void SetMargin2(IntPtr shape, float val);
1826
1827[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1828public static extern float GetMargin2(IntPtr shape);
1829
1830// =====================================================================================
1831// Debugging
1832[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1833public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
1834
1835[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1836public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1837
1838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1839public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1840
1841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1842public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1843
1844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1845public static extern void DumpActivationInfo2(IntPtr sim);
1846
1847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1848public static extern void DumpAllInfo2(IntPtr sim);
1849
1850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1851public static extern void DumpPhysicsStatistics2(IntPtr sim);
1852
1853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1854public static extern void ResetBroadphasePool(IntPtr sim);
1855
1856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1857public static extern void ResetConstraintSolver(IntPtr sim);
1858
1859}
1860
1861}
1862
1863}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
new file mode 100755
index 0000000..0c7f315
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSAPIXNA.cs
@@ -0,0 +1,1597 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.IO;
30using System.Text;
31
32using OpenSim.Framework;
33
34using OpenMetaverse;
35
36using BulletXNA;
37using BulletXNA.LinearMath;
38using BulletXNA.BulletCollision;
39using BulletXNA.BulletDynamics;
40using BulletXNA.BulletCollision.CollisionDispatch;
41
42namespace OpenSim.Region.Physics.BulletSPlugin
43{
44public sealed class BSAPIXNA : BSAPITemplate
45{
46private sealed class BulletWorldXNA : BulletWorld
47{
48 public DiscreteDynamicsWorld world;
49 public BulletWorldXNA(uint id, BSScene physScene, DiscreteDynamicsWorld xx)
50 : base(id, physScene)
51 {
52 world = xx;
53 }
54}
55
56private sealed class BulletBodyXNA : BulletBody
57{
58 public CollisionObject body;
59 public RigidBody rigidBody { get { return RigidBody.Upcast(body); } }
60
61 public BulletBodyXNA(uint id, CollisionObject xx)
62 : base(id)
63 {
64 body = xx;
65 }
66 public override bool HasPhysicalBody
67 {
68 get { return body != null; }
69 }
70 public override void Clear()
71 {
72 body = null;
73 }
74 public override string AddrString
75 {
76 get { return "XNARigidBody"; }
77 }
78}
79
80private sealed class BulletShapeXNA : BulletShape
81{
82 public CollisionShape shape;
83 public BulletShapeXNA(CollisionShape xx, BSPhysicsShapeType typ)
84 : base()
85 {
86 shape = xx;
87 type = typ;
88 }
89 public override bool HasPhysicalShape
90 {
91 get { return shape != null; }
92 }
93 public override void Clear()
94 {
95 shape = null;
96 }
97 public override BulletShape Clone()
98 {
99 return new BulletShapeXNA(shape, type);
100 }
101 public override bool ReferenceSame(BulletShape other)
102 {
103 BulletShapeXNA otheru = other as BulletShapeXNA;
104 return (otheru != null) && (this.shape == otheru.shape);
105
106 }
107 public override string AddrString
108 {
109 get { return "XNACollisionShape"; }
110 }
111}
112private sealed class BulletConstraintXNA : BulletConstraint
113{
114 public TypedConstraint constrain;
115 public BulletConstraintXNA(TypedConstraint xx) : base()
116 {
117 constrain = xx;
118 }
119
120 public override void Clear()
121 {
122 constrain = null;
123 }
124 public override bool HasPhysicalConstraint { get { return constrain != null; } }
125
126 // Used for log messages for a unique display of the memory/object allocated to this instance
127 public override string AddrString
128 {
129 get { return "XNAConstraint"; }
130 }
131}
132
133 private static int m_collisionsThisFrame;
134 private BSScene PhysicsScene { get; set; }
135
136 public override string BulletEngineName { get { return "BulletXNA"; } }
137 public override string BulletEngineVersion { get; protected set; }
138
139 public BSAPIXNA(string paramName, BSScene physScene)
140 {
141 PhysicsScene = physScene;
142 }
143
144 /// <summary>
145 ///
146 /// </summary>
147 /// <param name="p"></param>
148 /// <param name="p_2"></param>
149 public override bool RemoveObjectFromWorld(BulletWorld pWorld, BulletBody pBody)
150 {
151 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
152 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
153 world.RemoveRigidBody(body);
154 return true;
155 }
156
157 public override bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects)
158 {
159 /* TODO */
160 return false;
161 }
162
163 public override bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain)
164 {
165 /* TODO */
166 return false;
167 }
168
169 public override void SetRestitution(BulletBody pBody, float pRestitution)
170 {
171 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
172 body.SetRestitution(pRestitution);
173 }
174
175 public override int GetShapeType(BulletShape pShape)
176 {
177 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
178 return (int)shape.GetShapeType();
179 }
180 public override void SetMargin(BulletShape pShape, float pMargin)
181 {
182 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
183 shape.SetMargin(pMargin);
184 }
185
186 public override float GetMargin(BulletShape pShape)
187 {
188 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
189 return shape.GetMargin();
190 }
191
192 public override void SetLocalScaling(BulletShape pShape, Vector3 pScale)
193 {
194 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
195 IndexedVector3 vec = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
196 shape.SetLocalScaling(ref vec);
197
198 }
199
200 public override void SetContactProcessingThreshold(BulletBody pBody, float contactprocessingthreshold)
201 {
202 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
203 body.SetContactProcessingThreshold(contactprocessingthreshold);
204 }
205
206 public override void SetCcdMotionThreshold(BulletBody pBody, float pccdMotionThreashold)
207 {
208 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
209 body.SetCcdMotionThreshold(pccdMotionThreashold);
210 }
211
212 public override void SetCcdSweptSphereRadius(BulletBody pBody, float pCcdSweptSphereRadius)
213 {
214 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
215 body.SetCcdSweptSphereRadius(pCcdSweptSphereRadius);
216 }
217
218 public override void SetAngularFactorV(BulletBody pBody, Vector3 pAngularFactor)
219 {
220 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
221 body.SetAngularFactor(new IndexedVector3(pAngularFactor.X, pAngularFactor.Y, pAngularFactor.Z));
222 }
223
224 public override CollisionFlags AddToCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
225 {
226 CollisionObject body = ((BulletBodyXNA)pBody).body;
227 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
228 existingcollisionFlags |= pcollisionFlags;
229 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
230 return (CollisionFlags) (uint) existingcollisionFlags;
231 }
232
233 public override bool AddObjectToWorld(BulletWorld pWorld, BulletBody pBody)
234 {
235 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
236 CollisionObject cbody = ((BulletBodyXNA)pBody).body;
237 RigidBody rbody = cbody as RigidBody;
238
239 // Bullet resets several variables when an object is added to the world. In particular,
240 // BulletXNA resets position and rotation. Gravity is also reset depending on the static/dynamic
241 // type. Of course, the collision flags in the broadphase proxy are initialized to default.
242 IndexedMatrix origPos = cbody.GetWorldTransform();
243 if (rbody != null)
244 {
245 IndexedVector3 origGrav = rbody.GetGravity();
246 world.AddRigidBody(rbody);
247 rbody.SetGravity(origGrav);
248 }
249 else
250 {
251 world.AddCollisionObject(rbody);
252 }
253 cbody.SetWorldTransform(origPos);
254
255 pBody.ApplyCollisionMask(pWorld.physicsScene);
256
257 //if (body.GetBroadphaseHandle() != null)
258 // world.UpdateSingleAabb(body);
259 return true;
260 }
261
262 public override void ForceActivationState(BulletBody pBody, ActivationState pActivationState)
263 {
264 CollisionObject body = ((BulletBodyXNA)pBody).body;
265 body.ForceActivationState((BulletXNA.BulletCollision.ActivationState)(uint)pActivationState);
266 }
267
268 public override void UpdateSingleAabb(BulletWorld pWorld, BulletBody pBody)
269 {
270 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
271 CollisionObject body = ((BulletBodyXNA)pBody).body;
272 world.UpdateSingleAabb(body);
273 }
274
275 public override void UpdateAabbs(BulletWorld world) { /* TODO */ }
276 public override bool GetForceUpdateAllAabbs(BulletWorld world) { /* TODO */ return false; }
277 public override void SetForceUpdateAllAabbs(BulletWorld world, bool force) { /* TODO */ }
278
279 public override bool SetCollisionGroupMask(BulletBody pBody, uint pGroup, uint pMask)
280 {
281 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
282 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
283 body.GetBroadphaseHandle().m_collisionFilterGroup = (BulletXNA.BulletCollision.CollisionFilterGroups) pGroup;
284 if ((uint) body.GetBroadphaseHandle().m_collisionFilterGroup == 0)
285 return false;
286 return true;
287 }
288
289 public override void ClearAllForces(BulletBody pBody)
290 {
291 CollisionObject body = ((BulletBodyXNA)pBody).body;
292 IndexedVector3 zeroVector = new IndexedVector3(0, 0, 0);
293 body.SetInterpolationLinearVelocity(ref zeroVector);
294 body.SetInterpolationAngularVelocity(ref zeroVector);
295 IndexedMatrix bodytransform = body.GetWorldTransform();
296
297 body.SetInterpolationWorldTransform(ref bodytransform);
298
299 if (body is RigidBody)
300 {
301 RigidBody rigidbody = body as RigidBody;
302 rigidbody.SetLinearVelocity(zeroVector);
303 rigidbody.SetAngularVelocity(zeroVector);
304 rigidbody.ClearForces();
305 }
306 }
307
308 public override void SetInterpolationAngularVelocity(BulletBody pBody, Vector3 pVector3)
309 {
310 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
311 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
312 body.SetInterpolationAngularVelocity(ref vec);
313 }
314
315 public override void SetAngularVelocity(BulletBody pBody, Vector3 pVector3)
316 {
317 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
318 IndexedVector3 vec = new IndexedVector3(pVector3.X, pVector3.Y, pVector3.Z);
319 body.SetAngularVelocity(ref vec);
320 }
321 public override Vector3 GetTotalForce(BulletBody pBody)
322 {
323 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
324 IndexedVector3 iv3 = body.GetTotalForce();
325 return new Vector3(iv3.X, iv3.Y, iv3.Z);
326 }
327 public override Vector3 GetTotalTorque(BulletBody pBody)
328 {
329 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
330 IndexedVector3 iv3 = body.GetTotalTorque();
331 return new Vector3(iv3.X, iv3.Y, iv3.Z);
332 }
333 public override Vector3 GetInvInertiaDiagLocal(BulletBody pBody)
334 {
335 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
336 IndexedVector3 iv3 = body.GetInvInertiaDiagLocal();
337 return new Vector3(iv3.X, iv3.Y, iv3.Z);
338 }
339 public override void SetInvInertiaDiagLocal(BulletBody pBody, Vector3 inert)
340 {
341 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
342 IndexedVector3 iv3 = new IndexedVector3(inert.X, inert.Y, inert.Z);
343 body.SetInvInertiaDiagLocal(ref iv3);
344 }
345 public override void ApplyForce(BulletBody pBody, Vector3 force, Vector3 pos)
346 {
347 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
348 IndexedVector3 forceiv3 = new IndexedVector3(force.X, force.Y, force.Z);
349 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
350 body.ApplyForce(ref forceiv3, ref posiv3);
351 }
352 public override void ApplyImpulse(BulletBody pBody, Vector3 imp, Vector3 pos)
353 {
354 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
355 IndexedVector3 impiv3 = new IndexedVector3(imp.X, imp.Y, imp.Z);
356 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
357 body.ApplyImpulse(ref impiv3, ref posiv3);
358 }
359
360 public override void ClearForces(BulletBody pBody)
361 {
362 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
363 body.ClearForces();
364 }
365
366 public override void SetTranslation(BulletBody pBody, Vector3 _position, Quaternion _orientation)
367 {
368 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
369 IndexedVector3 vposition = new IndexedVector3(_position.X, _position.Y, _position.Z);
370 IndexedQuaternion vquaternion = new IndexedQuaternion(_orientation.X, _orientation.Y, _orientation.Z,
371 _orientation.W);
372 IndexedMatrix mat = IndexedMatrix.CreateFromQuaternion(vquaternion);
373 mat._origin = vposition;
374 body.SetWorldTransform(mat);
375
376 }
377
378 public override Vector3 GetPosition(BulletBody pBody)
379 {
380 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
381 IndexedVector3 pos = body.GetInterpolationWorldTransform()._origin;
382 return new Vector3(pos.X, pos.Y, pos.Z);
383 }
384
385 public override Vector3 CalculateLocalInertia(BulletShape pShape, float pphysMass)
386 {
387 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
388 IndexedVector3 inertia = IndexedVector3.Zero;
389 shape.CalculateLocalInertia(pphysMass, out inertia);
390 return new Vector3(inertia.X, inertia.Y, inertia.Z);
391 }
392
393 public override void SetMassProps(BulletBody pBody, float pphysMass, Vector3 plocalInertia)
394 {
395 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
396 IndexedVector3 inertia = new IndexedVector3(plocalInertia.X, plocalInertia.Y, plocalInertia.Z);
397 body.SetMassProps(pphysMass, inertia);
398 }
399
400
401 public override void SetObjectForce(BulletBody pBody, Vector3 _force)
402 {
403 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
404 IndexedVector3 force = new IndexedVector3(_force.X, _force.Y, _force.Z);
405 body.SetTotalForce(ref force);
406 }
407
408 public override void SetFriction(BulletBody pBody, float _currentFriction)
409 {
410 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
411 body.SetFriction(_currentFriction);
412 }
413
414 public override void SetLinearVelocity(BulletBody pBody, Vector3 _velocity)
415 {
416 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
417 IndexedVector3 velocity = new IndexedVector3(_velocity.X, _velocity.Y, _velocity.Z);
418 body.SetLinearVelocity(velocity);
419 }
420
421 public override void Activate(BulletBody pBody, bool pforceactivation)
422 {
423 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
424 body.Activate(pforceactivation);
425
426 }
427
428 public override Quaternion GetOrientation(BulletBody pBody)
429 {
430 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
431 IndexedQuaternion mat = body.GetInterpolationWorldTransform().GetRotation();
432 return new Quaternion(mat.X, mat.Y, mat.Z, mat.W);
433 }
434
435 public override CollisionFlags RemoveFromCollisionFlags(BulletBody pBody, CollisionFlags pcollisionFlags)
436 {
437 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
438 CollisionFlags existingcollisionFlags = (CollisionFlags)(uint)body.GetCollisionFlags();
439 existingcollisionFlags &= ~pcollisionFlags;
440 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags)(uint)existingcollisionFlags);
441 return (CollisionFlags)(uint)existingcollisionFlags;
442 }
443
444 public override float GetCcdMotionThreshold(BulletBody obj) { /* TODO */ return 0f; }
445
446 public override float GetCcdSweptSphereRadius(BulletBody obj) { /* TODO */ return 0f; }
447
448 public override IntPtr GetUserPointer(BulletBody obj) { /* TODO */ return IntPtr.Zero; }
449
450 public override void SetUserPointer(BulletBody obj, IntPtr val) { /* TODO */ }
451
452 public override void SetGravity(BulletBody pBody, Vector3 pGravity)
453 {
454 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
455 IndexedVector3 gravity = new IndexedVector3(pGravity.X, pGravity.Y, pGravity.Z);
456 body.SetGravity(gravity);
457 }
458
459 public override bool DestroyConstraint(BulletWorld pWorld, BulletConstraint pConstraint)
460 {
461 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
462 TypedConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain;
463 world.RemoveConstraint(constraint);
464 return true;
465 }
466
467 public override bool SetLinearLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
468 {
469 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
470 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
471 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
472 constraint.SetLinearLowerLimit(lowlimit);
473 constraint.SetLinearUpperLimit(highlimit);
474 return true;
475 }
476
477 public override bool SetAngularLimits(BulletConstraint pConstraint, Vector3 low, Vector3 high)
478 {
479 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
480 IndexedVector3 lowlimit = new IndexedVector3(low.X, low.Y, low.Z);
481 IndexedVector3 highlimit = new IndexedVector3(high.X, high.Y, high.Z);
482 constraint.SetAngularLowerLimit(lowlimit);
483 constraint.SetAngularUpperLimit(highlimit);
484 return true;
485 }
486
487 public override void SetConstraintNumSolverIterations(BulletConstraint pConstraint, float cnt)
488 {
489 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
490 constraint.SetOverrideNumSolverIterations((int)cnt);
491 }
492
493 public override bool CalculateTransforms(BulletConstraint pConstraint)
494 {
495 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
496 constraint.CalculateTransforms();
497 return true;
498 }
499
500 public override void SetConstraintEnable(BulletConstraint pConstraint, float p_2)
501 {
502 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
503 constraint.SetEnabled((p_2 == 0) ? false : true);
504 }
505
506
507 //BulletSimAPI.Create6DofConstraint(m_world.ptr, m_body1.ptr, m_body2.ptr,frame1, frame1rot,frame2, frame2rot,useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
508 public override BulletConstraint Create6DofConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
509
510 {
511 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
512 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
513 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
514 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
515 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
516 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
517 frame1._origin = frame1v;
518
519 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
520 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
521 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
522 frame2._origin = frame1v;
523
524 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2,
525 puseLinearReferenceFrameA);
526 consttr.CalculateTransforms();
527 world.AddConstraint(consttr,pdisableCollisionsBetweenLinkedBodies);
528
529 return new BulletConstraintXNA(consttr);
530 }
531
532
533 /// <summary>
534 ///
535 /// </summary>
536 /// <param name="pWorld"></param>
537 /// <param name="pBody1"></param>
538 /// <param name="pBody2"></param>
539 /// <param name="pjoinPoint"></param>
540 /// <param name="puseLinearReferenceFrameA"></param>
541 /// <param name="pdisableCollisionsBetweenLinkedBodies"></param>
542 /// <returns></returns>
543 public override BulletConstraint Create6DofConstraintToPoint(BulletWorld pWorld, BulletBody pBody1, BulletBody pBody2, Vector3 pjoinPoint, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
544 {
545 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
546 RigidBody body1 = ((BulletBodyXNA)pBody1).rigidBody;
547 RigidBody body2 = ((BulletBodyXNA)pBody2).rigidBody;
548 IndexedMatrix frame1 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
549 IndexedMatrix frame2 = new IndexedMatrix(IndexedBasisMatrix.Identity, new IndexedVector3(0, 0, 0));
550
551 IndexedVector3 joinPoint = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
552 IndexedMatrix mat = IndexedMatrix.Identity;
553 mat._origin = new IndexedVector3(pjoinPoint.X, pjoinPoint.Y, pjoinPoint.Z);
554 frame1._origin = body1.GetWorldTransform().Inverse()*joinPoint;
555 frame2._origin = body2.GetWorldTransform().Inverse()*joinPoint;
556
557 Generic6DofConstraint consttr = new Generic6DofConstraint(body1, body2, ref frame1, ref frame2, puseLinearReferenceFrameA);
558 consttr.CalculateTransforms();
559 world.AddConstraint(consttr, pdisableCollisionsBetweenLinkedBodies);
560
561 return new BulletConstraintXNA(consttr);
562 }
563 //SetFrames(m_constraint.ptr, frameA, frameArot, frameB, frameBrot);
564 public override bool SetFrames(BulletConstraint pConstraint, Vector3 pframe1, Quaternion pframe1rot, Vector3 pframe2, Quaternion pframe2rot)
565 {
566 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
567 IndexedVector3 frame1v = new IndexedVector3(pframe1.X, pframe1.Y, pframe1.Z);
568 IndexedQuaternion frame1rot = new IndexedQuaternion(pframe1rot.X, pframe1rot.Y, pframe1rot.Z, pframe1rot.W);
569 IndexedMatrix frame1 = IndexedMatrix.CreateFromQuaternion(frame1rot);
570 frame1._origin = frame1v;
571
572 IndexedVector3 frame2v = new IndexedVector3(pframe2.X, pframe2.Y, pframe2.Z);
573 IndexedQuaternion frame2rot = new IndexedQuaternion(pframe2rot.X, pframe2rot.Y, pframe2rot.Z, pframe2rot.W);
574 IndexedMatrix frame2 = IndexedMatrix.CreateFromQuaternion(frame2rot);
575 frame2._origin = frame1v;
576 constraint.SetFrames(ref frame1, ref frame2);
577 return true;
578 }
579
580 public override Vector3 GetLinearVelocity(BulletBody pBody)
581 {
582 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
583 IndexedVector3 iv3 = body.GetLinearVelocity();
584 return new Vector3(iv3.X, iv3.Y, iv3.Z);
585 }
586 public override Vector3 GetAngularVelocity(BulletBody pBody)
587 {
588 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
589 IndexedVector3 iv3 = body.GetAngularVelocity();
590 return new Vector3(iv3.X, iv3.Y, iv3.Z);
591 }
592 public override Vector3 GetVelocityInLocalPoint(BulletBody pBody, Vector3 pos)
593 {
594 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
595 IndexedVector3 posiv3 = new IndexedVector3(pos.X, pos.Y, pos.Z);
596 IndexedVector3 iv3 = body.GetVelocityInLocalPoint(ref posiv3);
597 return new Vector3(iv3.X, iv3.Y, iv3.Z);
598 }
599 public override void Translate(BulletBody pBody, Vector3 trans)
600 {
601 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
602 }
603 public override void UpdateDeactivation(BulletBody pBody, float timeStep)
604 {
605 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
606 body.UpdateDeactivation(timeStep);
607 }
608
609 public override bool WantsSleeping(BulletBody pBody)
610 {
611 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
612 return body.WantsSleeping();
613 }
614
615 public override void SetAngularFactor(BulletBody pBody, float factor)
616 {
617 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
618 body.SetAngularFactor(factor);
619 }
620
621 public override Vector3 GetAngularFactor(BulletBody pBody)
622 {
623 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
624 IndexedVector3 iv3 = body.GetAngularFactor();
625 return new Vector3(iv3.X, iv3.Y, iv3.Z);
626 }
627
628 public override bool IsInWorld(BulletWorld pWorld, BulletBody pBody)
629 {
630 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
631 CollisionObject body = ((BulletBodyXNA)pBody).body;
632 return world.IsInWorld(body);
633 }
634
635 public override void AddConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
636 {
637 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
638 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
639 body.AddConstraintRef(constrain);
640 }
641
642 public override void RemoveConstraintRef(BulletBody pBody, BulletConstraint pConstrain)
643 {
644 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
645 TypedConstraint constrain = ((BulletConstraintXNA)pConstrain).constrain;
646 body.RemoveConstraintRef(constrain);
647 }
648
649 public override BulletConstraint GetConstraintRef(BulletBody pBody, int index)
650 {
651 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
652 return new BulletConstraintXNA(body.GetConstraintRef(index));
653 }
654
655 public override int GetNumConstraintRefs(BulletBody pBody)
656 {
657 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
658 return body.GetNumConstraintRefs();
659 }
660
661 public override void SetInterpolationLinearVelocity(BulletBody pBody, Vector3 VehicleVelocity)
662 {
663 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
664 IndexedVector3 velocity = new IndexedVector3(VehicleVelocity.X, VehicleVelocity.Y, VehicleVelocity.Z);
665 body.SetInterpolationLinearVelocity(ref velocity);
666 }
667
668 public override bool UseFrameOffset(BulletConstraint pConstraint, float onOff)
669 {
670 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
671 constraint.SetUseFrameOffset((onOff == 0) ? false : true);
672 return true;
673 }
674 //SetBreakingImpulseThreshold(m_constraint.ptr, threshold);
675 public override bool SetBreakingImpulseThreshold(BulletConstraint pConstraint, float threshold)
676 {
677 Generic6DofConstraint constraint = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
678 constraint.SetBreakingImpulseThreshold(threshold);
679 return true;
680 }
681 //BulletSimAPI.SetAngularDamping(Prim.PhysBody.ptr, angularDamping);
682 public override void SetAngularDamping(BulletBody pBody, float angularDamping)
683 {
684 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
685 float lineardamping = body.GetLinearDamping();
686 body.SetDamping(lineardamping, angularDamping);
687
688 }
689
690 public override void UpdateInertiaTensor(BulletBody pBody)
691 {
692 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
693 body.UpdateInertiaTensor();
694 }
695
696 public override void RecalculateCompoundShapeLocalAabb(BulletShape pCompoundShape)
697 {
698 CompoundShape shape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
699 shape.RecalculateLocalAabb();
700 }
701
702 //BulletSimAPI.GetCollisionFlags(PhysBody.ptr)
703 public override CollisionFlags GetCollisionFlags(BulletBody pBody)
704 {
705 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
706 uint flags = (uint)body.GetCollisionFlags();
707 return (CollisionFlags) flags;
708 }
709
710 public override void SetDamping(BulletBody pBody, float pLinear, float pAngular)
711 {
712 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
713 body.SetDamping(pLinear, pAngular);
714 }
715 //PhysBody.ptr, PhysicsScene.Params.deactivationTime);
716 public override void SetDeactivationTime(BulletBody pBody, float pDeactivationTime)
717 {
718 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
719 body.SetDeactivationTime(pDeactivationTime);
720 }
721 //SetSleepingThresholds(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold);
722 public override void SetSleepingThresholds(BulletBody pBody, float plinearSleepingThreshold, float pangularSleepingThreshold)
723 {
724 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
725 body.SetSleepingThresholds(plinearSleepingThreshold, pangularSleepingThreshold);
726 }
727
728 public override CollisionObjectTypes GetBodyType(BulletBody pBody)
729 {
730 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
731 return (CollisionObjectTypes)(int) body.GetInternalType();
732 }
733
734 public override void ApplyGravity(BulletBody obj) { /* TODO */ }
735
736 public override Vector3 GetGravity(BulletBody obj) { /* TODO */ return Vector3.Zero; }
737
738 public override void SetLinearDamping(BulletBody obj, float lin_damping) { /* TODO */ }
739
740 public override float GetLinearDamping(BulletBody obj) { /* TODO */ return 0f; }
741
742 public override float GetAngularDamping(BulletBody obj) { /* TODO */ return 0f; }
743
744 public override float GetLinearSleepingThreshold(BulletBody obj) { /* TODO */ return 0f; }
745
746 public override void ApplyDamping(BulletBody obj, float timeStep) { /* TODO */ }
747
748 public override Vector3 GetLinearFactor(BulletBody obj) { /* TODO */ return Vector3.Zero; }
749
750 public override void SetLinearFactor(BulletBody obj, Vector3 factor) { /* TODO */ }
751
752 public override void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot) { /* TODO */ }
753
754 //BulletSimAPI.ApplyCentralForce(PhysBody.ptr, fSum);
755 public override void ApplyCentralForce(BulletBody pBody, Vector3 pfSum)
756 {
757 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
758 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
759 body.ApplyCentralForce(ref fSum);
760 }
761 public override void ApplyCentralImpulse(BulletBody pBody, Vector3 pfSum)
762 {
763 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
764 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
765 body.ApplyCentralImpulse(ref fSum);
766 }
767 public override void ApplyTorque(BulletBody pBody, Vector3 pfSum)
768 {
769 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
770 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
771 body.ApplyTorque(ref fSum);
772 }
773 public override void ApplyTorqueImpulse(BulletBody pBody, Vector3 pfSum)
774 {
775 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
776 IndexedVector3 fSum = new IndexedVector3(pfSum.X, pfSum.Y, pfSum.Z);
777 body.ApplyTorqueImpulse(ref fSum);
778 }
779
780 public override void DestroyObject(BulletWorld p, BulletBody p_2)
781 {
782 //TODO:
783 }
784
785 public override void Shutdown(BulletWorld pWorld)
786 {
787 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
788 world.Cleanup();
789 }
790
791 public override BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id)
792 {
793 return null;
794 }
795
796 public override bool DeleteCollisionShape(BulletWorld p, BulletShape p_2)
797 {
798 //TODO:
799 return false;
800 }
801 //(sim.ptr, shape.ptr, prim.LocalID, prim.RawPosition, prim.RawOrientation);
802
803 public override BulletBody CreateBodyFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
804 {
805 CollisionWorld world = ((BulletWorldXNA)pWorld).world;
806 IndexedMatrix mat =
807 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
808 pRawOrientation.Z, pRawOrientation.W));
809 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
810 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
811 //UpdateSingleAabb(world, shape);
812 // TODO: Feed Update array into null
813 RigidBody body = new RigidBody(0,new SimMotionState(world,pLocalID,mat,null),shape,IndexedVector3.Zero);
814
815 body.SetUserPointer(pLocalID);
816 return new BulletBodyXNA(pLocalID, body);
817 }
818
819
820 public override BulletBody CreateBodyWithDefaultMotionState( BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
821 {
822
823 IndexedMatrix mat =
824 IndexedMatrix.CreateFromQuaternion(new IndexedQuaternion(pRawOrientation.X, pRawOrientation.Y,
825 pRawOrientation.Z, pRawOrientation.W));
826 mat._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
827
828 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
829
830 // TODO: Feed Update array into null
831 RigidBody body = new RigidBody(0, new DefaultMotionState( mat, IndexedMatrix.Identity), shape, IndexedVector3.Zero);
832 body.SetWorldTransform(mat);
833 body.SetUserPointer(pLocalID);
834 return new BulletBodyXNA(pLocalID, body);
835 }
836 //(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT);
837 public override CollisionFlags SetCollisionFlags(BulletBody pBody, CollisionFlags collisionFlags)
838 {
839 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
840 body.SetCollisionFlags((BulletXNA.BulletCollision.CollisionFlags) (uint) collisionFlags);
841 return (CollisionFlags)body.GetCollisionFlags();
842 }
843
844 public override Vector3 GetAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return Vector3.Zero; }
845 public override Vector3 SetAnisotripicFriction(BulletConstraint pconstrain, Vector3 frict) { /* TODO */ return Vector3.Zero; }
846 public override bool HasAnisotripicFriction(BulletConstraint pconstrain) { /* TODO */ return false; }
847 public override float GetContactProcessingThreshold(BulletBody pBody) { /* TODO */ return 0f; }
848 public override bool IsStaticObject(BulletBody pBody) { /* TODO */ return false; }
849 public override bool IsKinematicObject(BulletBody pBody) { /* TODO */ return false; }
850 public override bool IsStaticOrKinematicObject(BulletBody pBody) { /* TODO */ return false; }
851 public override bool HasContactResponse(BulletBody pBody) { /* TODO */ return false; }
852 public override int GetActivationState(BulletBody pBody) { /* TODO */ return 0; }
853 public override void SetActivationState(BulletBody pBody, int state) { /* TODO */ }
854 public override float GetDeactivationTime(BulletBody pBody) { /* TODO */ return 0f; }
855 public override bool IsActive(BulletBody pBody) { /* TODO */ return false; }
856 public override float GetRestitution(BulletBody pBody) { /* TODO */ return 0f; }
857 public override float GetFriction(BulletBody pBody) { /* TODO */ return 0f; }
858 public override void SetInterpolationVelocity(BulletBody pBody, Vector3 linearVel, Vector3 angularVel) { /* TODO */ }
859 public override float GetHitFraction(BulletBody pBody) { /* TODO */ return 0f; }
860
861 //(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction);
862 public override void SetHitFraction(BulletBody pBody, float pHitFraction)
863 {
864 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
865 body.SetHitFraction(pHitFraction);
866 }
867 //BuildCapsuleShape(physicsScene.World.ptr, 1f, 1f, prim.Scale);
868 public override BulletShape BuildCapsuleShape(BulletWorld pWorld, float pRadius, float pHeight, Vector3 pScale)
869 {
870 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
871 IndexedVector3 scale = new IndexedVector3(pScale.X, pScale.Y, pScale.Z);
872 CapsuleShapeZ capsuleShapeZ = new CapsuleShapeZ(pRadius, pHeight);
873 capsuleShapeZ.SetMargin(world.WorldSettings.Params.collisionMargin);
874 capsuleShapeZ.SetLocalScaling(ref scale);
875
876 return new BulletShapeXNA(capsuleShapeZ, BSPhysicsShapeType.SHAPE_CAPSULE); ;
877 }
878
879 public override BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
880 int maxCollisions, ref CollisionDesc[] collisionArray,
881 int maxUpdates, ref EntityProperties[] updateArray
882 )
883 {
884 /* TODO */
885 return new BulletWorldXNA(1, null, null);
886 }
887
888 private static object Initialize2(Vector3 worldExtent,
889 ConfigurationParameters[] o,
890 int mMaxCollisionsPerFrame, ref List<BulletXNA.CollisionDesc> collisionArray,
891 int mMaxUpdatesPerFrame, ref List<BulletXNA.EntityProperties> updateArray,
892 object mDebugLogCallbackHandle)
893 {
894 CollisionWorld.WorldData.ParamData p = new CollisionWorld.WorldData.ParamData();
895
896 p.angularDamping = o[0].XangularDamping;
897 p.defaultFriction = o[0].defaultFriction;
898 p.defaultFriction = o[0].defaultFriction;
899 p.defaultDensity = o[0].defaultDensity;
900 p.defaultRestitution = o[0].defaultRestitution;
901 p.collisionMargin = o[0].collisionMargin;
902 p.gravity = o[0].gravity;
903
904 p.linearDamping = o[0].XlinearDamping;
905 p.angularDamping = o[0].XangularDamping;
906 p.deactivationTime = o[0].XdeactivationTime;
907 p.linearSleepingThreshold = o[0].XlinearSleepingThreshold;
908 p.angularSleepingThreshold = o[0].XangularSleepingThreshold;
909 p.ccdMotionThreshold = o[0].XccdMotionThreshold;
910 p.ccdSweptSphereRadius = o[0].XccdSweptSphereRadius;
911 p.contactProcessingThreshold = o[0].XcontactProcessingThreshold;
912
913 p.terrainImplementation = o[0].XterrainImplementation;
914 p.terrainFriction = o[0].XterrainFriction;
915
916 p.terrainHitFraction = o[0].XterrainHitFraction;
917 p.terrainRestitution = o[0].XterrainRestitution;
918 p.terrainCollisionMargin = o[0].XterrainCollisionMargin;
919
920 p.avatarFriction = o[0].XavatarFriction;
921 p.avatarStandingFriction = o[0].XavatarStandingFriction;
922 p.avatarDensity = o[0].XavatarDensity;
923 p.avatarRestitution = o[0].XavatarRestitution;
924 p.avatarCapsuleWidth = o[0].XavatarCapsuleWidth;
925 p.avatarCapsuleDepth = o[0].XavatarCapsuleDepth;
926 p.avatarCapsuleHeight = o[0].XavatarCapsuleHeight;
927 p.avatarContactProcessingThreshold = o[0].XavatarContactProcessingThreshold;
928
929 p.vehicleAngularDamping = o[0].XvehicleAngularDamping;
930
931 p.maxPersistantManifoldPoolSize = o[0].maxPersistantManifoldPoolSize;
932 p.maxCollisionAlgorithmPoolSize = o[0].maxCollisionAlgorithmPoolSize;
933 p.shouldDisableContactPoolDynamicAllocation = o[0].shouldDisableContactPoolDynamicAllocation;
934 p.shouldForceUpdateAllAabbs = o[0].shouldForceUpdateAllAabbs;
935 p.shouldRandomizeSolverOrder = o[0].shouldRandomizeSolverOrder;
936 p.shouldSplitSimulationIslands = o[0].shouldSplitSimulationIslands;
937 p.shouldEnableFrictionCaching = o[0].shouldEnableFrictionCaching;
938 p.numberOfSolverIterations = o[0].numberOfSolverIterations;
939
940 p.linksetImplementation = o[0].XlinksetImplementation;
941 p.linkConstraintUseFrameOffset = o[0].XlinkConstraintUseFrameOffset;
942 p.linkConstraintEnableTransMotor = o[0].XlinkConstraintEnableTransMotor;
943 p.linkConstraintTransMotorMaxVel = o[0].XlinkConstraintTransMotorMaxVel;
944 p.linkConstraintTransMotorMaxForce = o[0].XlinkConstraintTransMotorMaxForce;
945 p.linkConstraintERP = o[0].XlinkConstraintERP;
946 p.linkConstraintCFM = o[0].XlinkConstraintCFM;
947 p.linkConstraintSolverIterations = o[0].XlinkConstraintSolverIterations;
948 p.physicsLoggingFrames = o[0].XphysicsLoggingFrames;
949 DefaultCollisionConstructionInfo ccci = new DefaultCollisionConstructionInfo();
950
951 DefaultCollisionConfiguration cci = new DefaultCollisionConfiguration();
952 CollisionDispatcher m_dispatcher = new CollisionDispatcher(cci);
953
954
955 if (p.maxPersistantManifoldPoolSize > 0)
956 cci.m_persistentManifoldPoolSize = (int)p.maxPersistantManifoldPoolSize;
957 if (p.shouldDisableContactPoolDynamicAllocation !=0)
958 m_dispatcher.SetDispatcherFlags(DispatcherFlags.CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
959 //if (p.maxCollisionAlgorithmPoolSize >0 )
960
961 DbvtBroadphase m_broadphase = new DbvtBroadphase();
962 //IndexedVector3 aabbMin = new IndexedVector3(0, 0, 0);
963 //IndexedVector3 aabbMax = new IndexedVector3(256, 256, 256);
964
965 //AxisSweep3Internal m_broadphase2 = new AxisSweep3Internal(ref aabbMin, ref aabbMax, Convert.ToInt32(0xfffe), 0xffff, ushort.MaxValue/2, null, true);
966 m_broadphase.GetOverlappingPairCache().SetInternalGhostPairCallback(new GhostPairCallback());
967
968 SequentialImpulseConstraintSolver m_solver = new SequentialImpulseConstraintSolver();
969
970 DiscreteDynamicsWorld world = new DiscreteDynamicsWorld(m_dispatcher, m_broadphase, m_solver, cci);
971 world.UpdatedObjects = updateArray;
972 world.UpdatedCollisions = collisionArray;
973 world.WorldSettings.Params = p;
974 world.SetForceUpdateAllAabbs(p.shouldForceUpdateAllAabbs != 0);
975 world.GetSolverInfo().m_solverMode = SolverMode.SOLVER_USE_WARMSTARTING | SolverMode.SOLVER_SIMD;
976 if (p.shouldRandomizeSolverOrder != 0)
977 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_RANDMIZE_ORDER;
978
979 world.GetSimulationIslandManager().SetSplitIslands(p.shouldSplitSimulationIslands != 0);
980 //world.GetDispatchInfo().m_enableSatConvex Not implemented in C# port
981
982 if (p.shouldEnableFrictionCaching != 0)
983 world.GetSolverInfo().m_solverMode |= SolverMode.SOLVER_ENABLE_FRICTION_DIRECTION_CACHING;
984
985 if (p.numberOfSolverIterations > 0)
986 world.GetSolverInfo().m_numIterations = (int) p.numberOfSolverIterations;
987
988
989 world.GetSolverInfo().m_damping = world.WorldSettings.Params.linearDamping;
990 world.GetSolverInfo().m_restitution = world.WorldSettings.Params.defaultRestitution;
991 world.GetSolverInfo().m_globalCfm = 0.0f;
992 world.GetSolverInfo().m_tau = 0.6f;
993 world.GetSolverInfo().m_friction = 0.3f;
994 world.GetSolverInfo().m_maxErrorReduction = 20f;
995 world.GetSolverInfo().m_numIterations = 10;
996 world.GetSolverInfo().m_erp = 0.2f;
997 world.GetSolverInfo().m_erp2 = 0.1f;
998 world.GetSolverInfo().m_sor = 1.0f;
999 world.GetSolverInfo().m_splitImpulse = false;
1000 world.GetSolverInfo().m_splitImpulsePenetrationThreshold = -0.02f;
1001 world.GetSolverInfo().m_linearSlop = 0.0f;
1002 world.GetSolverInfo().m_warmstartingFactor = 0.85f;
1003 world.GetSolverInfo().m_restingContactRestitutionThreshold = 2;
1004 world.SetForceUpdateAllAabbs(true);
1005
1006
1007 world.SetGravity(new IndexedVector3(0,0,p.gravity));
1008
1009 return world;
1010 }
1011 //m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL
1012 public override bool SetConstraintParam(BulletConstraint pConstraint, ConstraintParams paramIndex, float paramvalue, ConstraintParamAxis axis)
1013 {
1014 Generic6DofConstraint constrain = ((BulletConstraintXNA)pConstraint).constrain as Generic6DofConstraint;
1015 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1016 {
1017 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 0);
1018 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 1);
1019 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams) (int) paramIndex, paramvalue, 2);
1020 }
1021 if (axis == ConstraintParamAxis.AXIS_ANGULAR_ALL || axis == ConstraintParamAxis.AXIS_ALL)
1022 {
1023 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 3);
1024 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 4);
1025 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, 5);
1026 }
1027 if (axis == ConstraintParamAxis.AXIS_LINEAR_ALL)
1028 {
1029 constrain.SetParam((BulletXNA.BulletDynamics.ConstraintParams)(int)paramIndex, paramvalue, (int)axis);
1030 }
1031 return true;
1032 }
1033
1034 public override bool PushUpdate(BulletBody pCollisionObject)
1035 {
1036 bool ret = false;
1037 RigidBody rb = ((BulletBodyXNA)pCollisionObject).rigidBody;
1038 if (rb != null)
1039 {
1040 SimMotionState sms = rb.GetMotionState() as SimMotionState;
1041 if (sms != null)
1042 {
1043 IndexedMatrix wt = IndexedMatrix.Identity;
1044 sms.GetWorldTransform(out wt);
1045 sms.SetWorldTransform(ref wt, true);
1046 ret = true;
1047 }
1048 }
1049 return ret;
1050
1051 }
1052
1053 public override float GetAngularMotionDisc(BulletShape pShape)
1054 {
1055 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1056 return shape.GetAngularMotionDisc();
1057 }
1058 public override float GetContactBreakingThreshold(BulletShape pShape, float defaultFactor)
1059 {
1060 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1061 return shape.GetContactBreakingThreshold(defaultFactor);
1062 }
1063 public override bool IsCompound(BulletShape pShape)
1064 {
1065 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1066 return shape.IsCompound();
1067 }
1068 public override bool IsSoftBody(BulletShape pShape)
1069 {
1070 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1071 return shape.IsSoftBody();
1072 }
1073 public override bool IsPolyhedral(BulletShape pShape)
1074 {
1075 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1076 return shape.IsPolyhedral();
1077 }
1078 public override bool IsConvex2d(BulletShape pShape)
1079 {
1080 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1081 return shape.IsConvex2d();
1082 }
1083 public override bool IsConvex(BulletShape pShape)
1084 {
1085 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1086 return shape.IsConvex();
1087 }
1088 public override bool IsNonMoving(BulletShape pShape)
1089 {
1090 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1091 return shape.IsNonMoving();
1092 }
1093 public override bool IsConcave(BulletShape pShape)
1094 {
1095 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1096 return shape.IsConcave();
1097 }
1098 public override bool IsInfinite(BulletShape pShape)
1099 {
1100 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1101 return shape.IsInfinite();
1102 }
1103 public override bool IsNativeShape(BulletShape pShape)
1104 {
1105 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1106 bool ret;
1107 switch (shape.GetShapeType())
1108 {
1109 case BroadphaseNativeTypes.BOX_SHAPE_PROXYTYPE:
1110 case BroadphaseNativeTypes.CONE_SHAPE_PROXYTYPE:
1111 case BroadphaseNativeTypes.SPHERE_SHAPE_PROXYTYPE:
1112 case BroadphaseNativeTypes.CYLINDER_SHAPE_PROXYTYPE:
1113 ret = true;
1114 break;
1115 default:
1116 ret = false;
1117 break;
1118 }
1119 return ret;
1120 }
1121
1122 public override void SetShapeCollisionMargin(BulletShape shape, float margin) { /* TODO */ }
1123
1124 //sim.ptr, shape.ptr,prim.LocalID, prim.RawPosition, prim.RawOrientation
1125 public override BulletBody CreateGhostFromShape(BulletWorld pWorld, BulletShape pShape, uint pLocalID, Vector3 pRawPosition, Quaternion pRawOrientation)
1126 {
1127 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1128 IndexedMatrix bodyTransform = new IndexedMatrix();
1129 bodyTransform._origin = new IndexedVector3(pRawPosition.X, pRawPosition.Y, pRawPosition.Z);
1130 bodyTransform.SetRotation(new IndexedQuaternion(pRawOrientation.X,pRawOrientation.Y,pRawOrientation.Z,pRawOrientation.W));
1131 GhostObject gObj = new PairCachingGhostObject();
1132 gObj.SetWorldTransform(bodyTransform);
1133 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1134 gObj.SetCollisionShape(shape);
1135 gObj.SetUserPointer(pLocalID);
1136 // TODO: Add to Special CollisionObjects!
1137 return new BulletBodyXNA(pLocalID, gObj);
1138 }
1139
1140 public override void SetCollisionShape(BulletWorld pWorld, BulletBody pObj, BulletShape pShape)
1141 {
1142 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1143 CollisionObject obj = ((BulletBodyXNA)pObj).body;
1144 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1145 obj.SetCollisionShape(shape);
1146
1147 }
1148 public override BulletShape GetCollisionShape(BulletBody obj) { /* TODO */ return null; }
1149
1150 //(PhysicsScene.World.ptr, nativeShapeData)
1151 public override BulletShape BuildNativeShape(BulletWorld pWorld, ShapeData pShapeData)
1152 {
1153 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1154 CollisionShape shape = null;
1155 switch (pShapeData.Type)
1156 {
1157 case BSPhysicsShapeType.SHAPE_BOX:
1158 shape = new BoxShape(new IndexedVector3(0.5f,0.5f,0.5f));
1159 break;
1160 case BSPhysicsShapeType.SHAPE_CONE:
1161 shape = new ConeShapeZ(0.5f, 1.0f);
1162 break;
1163 case BSPhysicsShapeType.SHAPE_CYLINDER:
1164 shape = new CylinderShapeZ(new IndexedVector3(0.5f, 0.5f, 0.5f));
1165 break;
1166 case BSPhysicsShapeType.SHAPE_SPHERE:
1167 shape = new SphereShape(0.5f);
1168 break;
1169
1170 }
1171 if (shape != null)
1172 {
1173 IndexedVector3 scaling = new IndexedVector3(pShapeData.Scale.X, pShapeData.Scale.Y, pShapeData.Scale.Z);
1174 shape.SetMargin(world.WorldSettings.Params.collisionMargin);
1175 shape.SetLocalScaling(ref scaling);
1176
1177 }
1178 return new BulletShapeXNA(shape, pShapeData.Type);
1179 }
1180 //PhysicsScene.World.ptr, false
1181 public override BulletShape CreateCompoundShape(BulletWorld pWorld, bool enableDynamicAabbTree)
1182 {
1183 return new BulletShapeXNA(new CompoundShape(enableDynamicAabbTree), BSPhysicsShapeType.SHAPE_COMPOUND);
1184 }
1185
1186 public override int GetNumberOfCompoundChildren(BulletShape pCompoundShape)
1187 {
1188 CompoundShape compoundshape = ((BulletShapeXNA)pCompoundShape).shape as CompoundShape;
1189 return compoundshape.GetNumChildShapes();
1190 }
1191 //LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot
1192 public override void AddChildShapeToCompoundShape(BulletShape pCShape, BulletShape paddShape, Vector3 displacementPos, Quaternion displacementRot)
1193 {
1194 IndexedMatrix relativeTransform = new IndexedMatrix();
1195 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1196 CollisionShape addshape = ((BulletShapeXNA)paddShape).shape;
1197
1198 relativeTransform._origin = new IndexedVector3(displacementPos.X, displacementPos.Y, displacementPos.Z);
1199 relativeTransform.SetRotation(new IndexedQuaternion(displacementRot.X,displacementRot.Y,displacementRot.Z,displacementRot.W));
1200 compoundshape.AddChildShape(ref relativeTransform, addshape);
1201
1202 }
1203
1204 public override BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape pCShape, int pii)
1205 {
1206 CompoundShape compoundshape = ((BulletShapeXNA)pCShape).shape as CompoundShape;
1207 CollisionShape ret = null;
1208 ret = compoundshape.GetChildShape(pii);
1209 compoundshape.RemoveChildShapeByIndex(pii);
1210 return new BulletShapeXNA(ret, BSPhysicsShapeType.SHAPE_UNKNOWN);
1211 }
1212
1213 public override BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx) { /* TODO */ return null; }
1214 public override void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape) { /* TODO */ }
1215
1216 public override BulletShape CreateGroundPlaneShape(uint pLocalId, float pheight, float pcollisionMargin)
1217 {
1218 StaticPlaneShape m_planeshape = new StaticPlaneShape(new IndexedVector3(0,0,1),(int)pheight );
1219 m_planeshape.SetMargin(pcollisionMargin);
1220 m_planeshape.SetUserPointer(pLocalId);
1221 return new BulletShapeXNA(m_planeshape, BSPhysicsShapeType.SHAPE_GROUNDPLANE);
1222 }
1223
1224 public override BulletConstraint CreateHingeConstraint(BulletWorld pWorld, BulletBody pBody1, BulletBody ppBody2, Vector3 ppivotInA, Vector3 ppivotInB, Vector3 paxisInA, Vector3 paxisInB, bool puseLinearReferenceFrameA, bool pdisableCollisionsBetweenLinkedBodies)
1225 {
1226 HingeConstraint constrain = null;
1227 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1228 RigidBody rb1 = ((BulletBodyXNA)pBody1).rigidBody;
1229 RigidBody rb2 = ((BulletBodyXNA)ppBody2).rigidBody;
1230 if (rb1 != null && rb2 != null)
1231 {
1232 IndexedVector3 pivotInA = new IndexedVector3(ppivotInA.X, ppivotInA.Y, ppivotInA.Z);
1233 IndexedVector3 pivotInB = new IndexedVector3(ppivotInB.X, ppivotInB.Y, ppivotInB.Z);
1234 IndexedVector3 axisInA = new IndexedVector3(paxisInA.X, paxisInA.Y, paxisInA.Z);
1235 IndexedVector3 axisInB = new IndexedVector3(paxisInB.X, paxisInB.Y, paxisInB.Z);
1236 world.AddConstraint(constrain, pdisableCollisionsBetweenLinkedBodies);
1237 }
1238 return new BulletConstraintXNA(constrain);
1239 }
1240
1241 public override BulletShape CreateHullShape(BulletWorld pWorld, int pHullCount, float[] pConvHulls)
1242 {
1243 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1244 CompoundShape compoundshape = new CompoundShape(false);
1245
1246 compoundshape.SetMargin(world.WorldSettings.Params.collisionMargin);
1247 int ii = 1;
1248
1249 for (int i = 0; i < pHullCount; i++)
1250 {
1251 int vertexCount = (int) pConvHulls[ii];
1252
1253 IndexedVector3 centroid = new IndexedVector3(pConvHulls[ii + 1], pConvHulls[ii + 2], pConvHulls[ii + 3]);
1254 IndexedMatrix childTrans = IndexedMatrix.Identity;
1255 childTrans._origin = centroid;
1256
1257 List<IndexedVector3> virts = new List<IndexedVector3>();
1258 int ender = ((ii + 4) + (vertexCount*3));
1259 for (int iii = ii + 4; iii < ender; iii+=3)
1260 {
1261
1262 virts.Add(new IndexedVector3(pConvHulls[iii], pConvHulls[iii + 1], pConvHulls[iii +2]));
1263 }
1264 ConvexHullShape convexShape = new ConvexHullShape(virts, vertexCount);
1265 convexShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1266 compoundshape.AddChildShape(ref childTrans, convexShape);
1267 ii += (vertexCount*3 + 4);
1268 }
1269
1270 return new BulletShapeXNA(compoundshape, BSPhysicsShapeType.SHAPE_HULL);
1271 }
1272
1273 public override BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape) { /* TODO */ return null; }
1274
1275 public override BulletShape CreateMeshShape(BulletWorld pWorld, int pIndicesCount, int[] indices, int pVerticesCount, float[] verticesAsFloats)
1276 {
1277 //DumpRaw(indices,verticesAsFloats,pIndicesCount,pVerticesCount);
1278
1279 for (int iter = 0; iter < pVerticesCount; iter++)
1280 {
1281 if (verticesAsFloats[iter] > 0 && verticesAsFloats[iter] < 0.0001) verticesAsFloats[iter] = 0;
1282 if (verticesAsFloats[iter] < 0 && verticesAsFloats[iter] > -0.0001) verticesAsFloats[iter] = 0;
1283 }
1284
1285 ObjectArray<int> indicesarr = new ObjectArray<int>(indices);
1286 ObjectArray<float> vertices = new ObjectArray<float>(verticesAsFloats);
1287 DumpRaw(indicesarr,vertices,pIndicesCount,pVerticesCount);
1288 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1289 IndexedMesh mesh = new IndexedMesh();
1290 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1291 mesh.m_numTriangles = pIndicesCount/3;
1292 mesh.m_numVertices = pVerticesCount;
1293 mesh.m_triangleIndexBase = indicesarr;
1294 mesh.m_vertexBase = vertices;
1295 mesh.m_vertexStride = 3;
1296 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1297 mesh.m_triangleIndexStride = 3;
1298
1299 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1300 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1301 BvhTriangleMeshShape meshShape = new BvhTriangleMeshShape(tribuilder, true,true);
1302 meshShape.SetMargin(world.WorldSettings.Params.collisionMargin);
1303 // world.UpdateSingleAabb(meshShape);
1304 return new BulletShapeXNA(meshShape, BSPhysicsShapeType.SHAPE_MESH);
1305
1306 }
1307 public static void DumpRaw(ObjectArray<int>indices, ObjectArray<float> vertices, int pIndicesCount,int pVerticesCount )
1308 {
1309
1310 String fileName = "objTest3.raw";
1311 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1312 StreamWriter sw = new StreamWriter(completePath);
1313 IndexedMesh mesh = new IndexedMesh();
1314
1315 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1316 mesh.m_numTriangles = pIndicesCount / 3;
1317 mesh.m_numVertices = pVerticesCount;
1318 mesh.m_triangleIndexBase = indices;
1319 mesh.m_vertexBase = vertices;
1320 mesh.m_vertexStride = 3;
1321 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1322 mesh.m_triangleIndexStride = 3;
1323
1324 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1325 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1326
1327
1328
1329 for (int i = 0; i < pVerticesCount; i++)
1330 {
1331
1332 string s = vertices[indices[i * 3]].ToString("0.0000");
1333 s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1334 s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1335
1336 sw.Write(s + "\n");
1337 }
1338
1339 sw.Close();
1340 }
1341 public static void DumpRaw(int[] indices, float[] vertices, int pIndicesCount, int pVerticesCount)
1342 {
1343
1344 String fileName = "objTest6.raw";
1345 String completePath = System.IO.Path.Combine(Util.configDir(), fileName);
1346 StreamWriter sw = new StreamWriter(completePath);
1347 IndexedMesh mesh = new IndexedMesh();
1348
1349 mesh.m_indexType = PHY_ScalarType.PHY_INTEGER;
1350 mesh.m_numTriangles = pIndicesCount / 3;
1351 mesh.m_numVertices = pVerticesCount;
1352 mesh.m_triangleIndexBase = indices;
1353 mesh.m_vertexBase = vertices;
1354 mesh.m_vertexStride = 3;
1355 mesh.m_vertexType = PHY_ScalarType.PHY_FLOAT;
1356 mesh.m_triangleIndexStride = 3;
1357
1358 TriangleIndexVertexArray tribuilder = new TriangleIndexVertexArray();
1359 tribuilder.AddIndexedMesh(mesh, PHY_ScalarType.PHY_INTEGER);
1360
1361
1362 sw.WriteLine("Indices");
1363 sw.WriteLine(string.Format("int[] indices = new int[{0}];",pIndicesCount));
1364 for (int iter = 0; iter < indices.Length; iter++)
1365 {
1366 sw.WriteLine(string.Format("indices[{0}]={1};",iter,indices[iter]));
1367 }
1368 sw.WriteLine("VerticesFloats");
1369 sw.WriteLine(string.Format("float[] vertices = new float[{0}];", pVerticesCount));
1370 for (int iter = 0; iter < vertices.Length; iter++)
1371 {
1372 sw.WriteLine(string.Format("Vertices[{0}]={1};", iter, vertices[iter].ToString("0.0000")));
1373 }
1374
1375 // for (int i = 0; i < pVerticesCount; i++)
1376 // {
1377 //
1378 // string s = vertices[indices[i * 3]].ToString("0.0000");
1379 // s += " " + vertices[indices[i * 3 + 1]].ToString("0.0000");
1380 // s += " " + vertices[indices[i * 3 + 2]].ToString("0.0000");
1381 //
1382 // sw.Write(s + "\n");
1383 //}
1384
1385 sw.Close();
1386 }
1387
1388 public override BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
1389 float scaleFactor, float collisionMargin)
1390 {
1391 const int upAxis = 2;
1392 HeightfieldTerrainShape terrainShape = new HeightfieldTerrainShape((int)size.X, (int)size.Y,
1393 heightMap, scaleFactor,
1394 minHeight, maxHeight, upAxis,
1395 false);
1396 terrainShape.SetMargin(collisionMargin + 0.5f);
1397 terrainShape.SetUseDiamondSubdivision(true);
1398 terrainShape.SetUserPointer(id);
1399 return new BulletShapeXNA(terrainShape, BSPhysicsShapeType.SHAPE_TERRAIN);
1400 }
1401
1402 public override bool TranslationalLimitMotor(BulletConstraint pConstraint, float ponOff, float targetVelocity, float maxMotorForce)
1403 {
1404 TypedConstraint tconstrain = ((BulletConstraintXNA)pConstraint).constrain;
1405 bool onOff = ponOff != 0;
1406 bool ret = false;
1407
1408 switch (tconstrain.GetConstraintType())
1409 {
1410 case TypedConstraintType.D6_CONSTRAINT_TYPE:
1411 Generic6DofConstraint constrain = tconstrain as Generic6DofConstraint;
1412 constrain.GetTranslationalLimitMotor().m_enableMotor[0] = onOff;
1413 constrain.GetTranslationalLimitMotor().m_targetVelocity[0] = targetVelocity;
1414 constrain.GetTranslationalLimitMotor().m_maxMotorForce[0] = maxMotorForce;
1415 ret = true;
1416 break;
1417 }
1418
1419
1420 return ret;
1421
1422 }
1423
1424 public override int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
1425 out int updatedEntityCount, out int collidersCount)
1426 {
1427 /* TODO */
1428 updatedEntityCount = 0;
1429 collidersCount = 0;
1430 return 1;
1431 }
1432
1433 private int PhysicsStep2(BulletWorld pWorld, float timeStep, int m_maxSubSteps, float m_fixedTimeStep,
1434 out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities,
1435 out int collidersCount, out List<BulletXNA.CollisionDesc>colliders)
1436 {
1437 int epic = PhysicsStepint(pWorld, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out updatedEntities,
1438 out collidersCount, out colliders);
1439 return epic;
1440 }
1441
1442 private static int PhysicsStepint(BulletWorld pWorld,float timeStep, int m_maxSubSteps, float m_fixedTimeStep, out int updatedEntityCount, out List<BulletXNA.EntityProperties> updatedEntities, out int collidersCount, out List<BulletXNA.CollisionDesc> colliders)
1443 {
1444 int numSimSteps = 0;
1445
1446
1447 //if (updatedEntities is null)
1448 // updatedEntities = new List<BulletXNA.EntityProperties>();
1449
1450 //if (colliders is null)
1451 // colliders = new List<BulletXNA.CollisionDesc>();
1452
1453
1454 if (pWorld is BulletWorldXNA)
1455 {
1456 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1457
1458 numSimSteps = world.StepSimulation(timeStep, m_maxSubSteps, m_fixedTimeStep);
1459 int updates = 0;
1460
1461 updatedEntityCount = world.UpdatedObjects.Count;
1462 updatedEntities = new List<BulletXNA.EntityProperties>(world.UpdatedObjects);
1463 updatedEntityCount = updatedEntities.Count;
1464 world.UpdatedObjects.Clear();
1465
1466
1467 collidersCount = world.UpdatedCollisions.Count;
1468 colliders = new List<BulletXNA.CollisionDesc>(world.UpdatedCollisions);
1469
1470 world.UpdatedCollisions.Clear();
1471 m_collisionsThisFrame = 0;
1472 int numManifolds = world.GetDispatcher().GetNumManifolds();
1473 for (int j = 0; j < numManifolds; j++)
1474 {
1475 PersistentManifold contactManifold = world.GetDispatcher().GetManifoldByIndexInternal(j);
1476 int numContacts = contactManifold.GetNumContacts();
1477 if (numContacts == 0)
1478 continue;
1479
1480 CollisionObject objA = contactManifold.GetBody0() as CollisionObject;
1481 CollisionObject objB = contactManifold.GetBody1() as CollisionObject;
1482
1483 ManifoldPoint manifoldPoint = contactManifold.GetContactPoint(0);
1484 IndexedVector3 contactPoint = manifoldPoint.GetPositionWorldOnB();
1485 IndexedVector3 contactNormal = -manifoldPoint.m_normalWorldOnB; // make relative to A
1486
1487 RecordCollision(world, objA, objB, contactPoint, contactNormal);
1488 m_collisionsThisFrame ++;
1489 if (m_collisionsThisFrame >= 9999999)
1490 break;
1491
1492
1493 }
1494
1495
1496 }
1497 else
1498 {
1499 //if (updatedEntities is null)
1500 updatedEntities = new List<BulletXNA.EntityProperties>();
1501 updatedEntityCount = 0;
1502 //if (colliders is null)
1503 colliders = new List<BulletXNA.CollisionDesc>();
1504 collidersCount = 0;
1505 }
1506 return numSimSteps;
1507 }
1508
1509 private static void RecordCollision(CollisionWorld world, CollisionObject objA, CollisionObject objB, IndexedVector3 contact, IndexedVector3 norm)
1510 {
1511
1512 IndexedVector3 contactNormal = norm;
1513 if ((objA.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0 &&
1514 (objB.GetCollisionFlags() & BulletXNA.BulletCollision.CollisionFlags.BS_WANTS_COLLISIONS) == 0)
1515 {
1516 return;
1517 }
1518 uint idA = (uint)objA.GetUserPointer();
1519 uint idB = (uint)objB.GetUserPointer();
1520 if (idA > idB)
1521 {
1522 uint temp = idA;
1523 idA = idB;
1524 idB = temp;
1525 contactNormal = -contactNormal;
1526 }
1527
1528 ulong collisionID = ((ulong) idA << 32) | idB;
1529
1530 BulletXNA.CollisionDesc cDesc = new BulletXNA.CollisionDesc()
1531 {
1532 aID = idA,
1533 bID = idB,
1534 point = contact,
1535 normal = contactNormal
1536 };
1537 world.UpdatedCollisions.Add(cDesc);
1538 m_collisionsThisFrame++;
1539
1540
1541 }
1542 private static EntityProperties GetDebugProperties(BulletWorld pWorld, BulletBody pBody)
1543 {
1544 EntityProperties ent = new EntityProperties();
1545 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1546 RigidBody body = ((BulletBodyXNA)pBody).rigidBody;
1547 IndexedMatrix transform = body.GetWorldTransform();
1548 IndexedVector3 LinearVelocity = body.GetInterpolationLinearVelocity();
1549 IndexedVector3 AngularVelocity = body.GetInterpolationAngularVelocity();
1550 IndexedQuaternion rotation = transform.GetRotation();
1551 ent.Acceleration = Vector3.Zero;
1552 ent.ID = (uint)body.GetUserPointer();
1553 ent.Position = new Vector3(transform._origin.X,transform._origin.Y,transform._origin.Z);
1554 ent.Rotation = new Quaternion(rotation.X,rotation.Y,rotation.Z,rotation.W);
1555 ent.Velocity = new Vector3(LinearVelocity.X, LinearVelocity.Y, LinearVelocity.Z);
1556 ent.RotationalVelocity = new Vector3(AngularVelocity.X, AngularVelocity.Y, AngularVelocity.Z);
1557 return ent;
1558 }
1559
1560 public override bool UpdateParameter(BulletWorld world, uint localID, String parm, float value) { /* TODO */ return false; }
1561
1562 public override Vector3 GetLocalScaling(BulletShape pShape)
1563 {
1564 CollisionShape shape = ((BulletShapeXNA)pShape).shape;
1565 IndexedVector3 scale = shape.GetLocalScaling();
1566 return new Vector3(scale.X,scale.Y,scale.Z);
1567 }
1568
1569 public bool RayCastGround(BulletWorld pWorld, Vector3 _RayOrigin, float pRayHeight, BulletBody NotMe)
1570 {
1571 DiscreteDynamicsWorld world = ((BulletWorldXNA)pWorld).world;
1572 if (world != null)
1573 {
1574 if (NotMe is BulletBodyXNA && NotMe.HasPhysicalBody)
1575 {
1576 CollisionObject AvoidBody = ((BulletBodyXNA)NotMe).body;
1577
1578 IndexedVector3 rOrigin = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z);
1579 IndexedVector3 rEnd = new IndexedVector3(_RayOrigin.X, _RayOrigin.Y, _RayOrigin.Z - pRayHeight);
1580 using (
1581 ClosestNotMeRayResultCallback rayCallback =
1582 new ClosestNotMeRayResultCallback(rOrigin, rEnd, AvoidBody)
1583 )
1584 {
1585 world.RayTest(ref rOrigin, ref rEnd, rayCallback);
1586 if (rayCallback.HasHit())
1587 {
1588 IndexedVector3 hitLocation = rayCallback.m_hitPointWorld;
1589 }
1590 return rayCallback.HasHit();
1591 }
1592 }
1593 }
1594 return false;
1595 }
1596}
1597}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
new file mode 100644
index 0000000..befb076
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSApiTemplate.cs
@@ -0,0 +1,666 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Runtime.InteropServices;
30using System.Security;
31using System.Text;
32using OpenMetaverse;
33
34namespace OpenSim.Region.Physics.BulletSPlugin {
35
36 // Constraint type values as defined by Bullet
37public enum ConstraintType : int
38{
39 POINT2POINT_CONSTRAINT_TYPE = 3,
40 HINGE_CONSTRAINT_TYPE,
41 CONETWIST_CONSTRAINT_TYPE,
42 D6_CONSTRAINT_TYPE,
43 SLIDER_CONSTRAINT_TYPE,
44 CONTACT_CONSTRAINT_TYPE,
45 D6_SPRING_CONSTRAINT_TYPE,
46 MAX_CONSTRAINT_TYPE
47}
48
49// ===============================================================================
50[StructLayout(LayoutKind.Sequential)]
51public struct ConvexHull
52{
53 Vector3 Offset;
54 int VertexCount;
55 Vector3[] Vertices;
56}
57public enum BSPhysicsShapeType
58{
59 SHAPE_UNKNOWN = 0,
60 SHAPE_CAPSULE = 1,
61 SHAPE_BOX = 2,
62 SHAPE_CONE = 3,
63 SHAPE_CYLINDER = 4,
64 SHAPE_SPHERE = 5,
65 SHAPE_MESH = 6,
66 SHAPE_HULL = 7,
67 // following defined by BulletSim
68 SHAPE_GROUNDPLANE = 20,
69 SHAPE_TERRAIN = 21,
70 SHAPE_COMPOUND = 22,
71 SHAPE_HEIGHTMAP = 23,
72 SHAPE_AVATAR = 24,
73};
74
75// The native shapes have predefined shape hash keys
76public enum FixedShapeKey : ulong
77{
78 KEY_NONE = 0,
79 KEY_BOX = 1,
80 KEY_SPHERE = 2,
81 KEY_CONE = 3,
82 KEY_CYLINDER = 4,
83 KEY_CAPSULE = 5,
84 KEY_AVATAR = 6,
85}
86
87[StructLayout(LayoutKind.Sequential)]
88public struct ShapeData
89{
90 public uint ID;
91 public BSPhysicsShapeType Type;
92 public Vector3 Position;
93 public Quaternion Rotation;
94 public Vector3 Velocity;
95 public Vector3 Scale;
96 public float Mass;
97 public float Buoyancy;
98 public System.UInt64 HullKey;
99 public System.UInt64 MeshKey;
100 public float Friction;
101 public float Restitution;
102 public float Collidable; // true of things bump into this
103 public float Static; // true if a static object. Otherwise gravity, etc.
104 public float Solid; // true if object cannot be passed through
105 public Vector3 Size;
106
107 // note that bools are passed as floats since bool size changes by language and architecture
108 public const float numericTrue = 1f;
109 public const float numericFalse = 0f;
110}
111[StructLayout(LayoutKind.Sequential)]
112public struct SweepHit
113{
114 public uint ID;
115 public float Fraction;
116 public Vector3 Normal;
117 public Vector3 Point;
118}
119[StructLayout(LayoutKind.Sequential)]
120public struct RaycastHit
121{
122 public uint ID;
123 public float Fraction;
124 public Vector3 Normal;
125}
126[StructLayout(LayoutKind.Sequential)]
127public struct CollisionDesc
128{
129 public uint aID;
130 public uint bID;
131 public Vector3 point;
132 public Vector3 normal;
133}
134[StructLayout(LayoutKind.Sequential)]
135public struct EntityProperties
136{
137 public uint ID;
138 public Vector3 Position;
139 public Quaternion Rotation;
140 public Vector3 Velocity;
141 public Vector3 Acceleration;
142 public Vector3 RotationalVelocity;
143}
144
145// Format of this structure must match the definition in the C++ code
146// NOTE: adding the X causes compile breaks if used. These are unused symbols
147// that can be removed from both here and the unmanaged definition of this structure.
148[StructLayout(LayoutKind.Sequential)]
149public struct ConfigurationParameters
150{
151 public float defaultFriction;
152 public float defaultDensity;
153 public float defaultRestitution;
154 public float collisionMargin;
155 public float gravity;
156
157 public float XlinearDamping;
158 public float XangularDamping;
159 public float XdeactivationTime;
160 public float XlinearSleepingThreshold;
161 public float XangularSleepingThreshold;
162 public float XccdMotionThreshold;
163 public float XccdSweptSphereRadius;
164 public float XcontactProcessingThreshold;
165
166 public float XterrainImplementation;
167 public float XterrainFriction;
168 public float XterrainHitFraction;
169 public float XterrainRestitution;
170 public float XterrainCollisionMargin;
171
172 public float XavatarFriction;
173 public float XavatarStandingFriction;
174 public float XavatarDensity;
175 public float XavatarRestitution;
176 public float XavatarCapsuleWidth;
177 public float XavatarCapsuleDepth;
178 public float XavatarCapsuleHeight;
179 public float XavatarContactProcessingThreshold;
180
181 public float XvehicleAngularDamping;
182
183 public float maxPersistantManifoldPoolSize;
184 public float maxCollisionAlgorithmPoolSize;
185 public float shouldDisableContactPoolDynamicAllocation;
186 public float shouldForceUpdateAllAabbs;
187 public float shouldRandomizeSolverOrder;
188 public float shouldSplitSimulationIslands;
189 public float shouldEnableFrictionCaching;
190 public float numberOfSolverIterations;
191
192 public float XlinksetImplementation;
193 public float XlinkConstraintUseFrameOffset;
194 public float XlinkConstraintEnableTransMotor;
195 public float XlinkConstraintTransMotorMaxVel;
196 public float XlinkConstraintTransMotorMaxForce;
197 public float XlinkConstraintERP;
198 public float XlinkConstraintCFM;
199 public float XlinkConstraintSolverIterations;
200
201 public float XphysicsLoggingFrames;
202
203 public const float numericTrue = 1f;
204 public const float numericFalse = 0f;
205}
206
207
208// The states a bullet collision object can have
209public enum ActivationState : uint
210{
211 ACTIVE_TAG = 1,
212 ISLAND_SLEEPING,
213 WANTS_DEACTIVATION,
214 DISABLE_DEACTIVATION,
215 DISABLE_SIMULATION,
216}
217
218public enum CollisionObjectTypes : int
219{
220 CO_COLLISION_OBJECT = 1 << 0,
221 CO_RIGID_BODY = 1 << 1,
222 CO_GHOST_OBJECT = 1 << 2,
223 CO_SOFT_BODY = 1 << 3,
224 CO_HF_FLUID = 1 << 4,
225 CO_USER_TYPE = 1 << 5,
226}
227
228// Values used by Bullet and BulletSim to control object properties.
229// Bullet's "CollisionFlags" has more to do with operations on the
230// object (if collisions happen, if gravity effects it, ...).
231public enum CollisionFlags : uint
232{
233 CF_STATIC_OBJECT = 1 << 0,
234 CF_KINEMATIC_OBJECT = 1 << 1,
235 CF_NO_CONTACT_RESPONSE = 1 << 2,
236 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
237 CF_CHARACTER_OBJECT = 1 << 4,
238 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
239 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
240 // Following used by BulletSim to control collisions and updates
241 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
242 BS_FLOATS_ON_WATER = 1 << 11,
243 BS_VEHICLE_COLLISIONS = 1 << 12,
244 BS_NONE = 0,
245 BS_ALL = 0xFFFFFFFF
246};
247
248// Values f collisions groups and masks
249public enum CollisionFilterGroups : uint
250{
251 // Don't use the bit definitions!! Define the use in a
252 // filter/mask definition below. This way collision interactions
253 // are more easily found and debugged.
254 BNoneGroup = 0,
255 BDefaultGroup = 1 << 0, // 0001
256 BStaticGroup = 1 << 1, // 0002
257 BKinematicGroup = 1 << 2, // 0004
258 BDebrisGroup = 1 << 3, // 0008
259 BSensorTrigger = 1 << 4, // 0010
260 BCharacterGroup = 1 << 5, // 0020
261 BAllGroup = 0x000FFFFF,
262 // Filter groups defined by BulletSim
263 BGroundPlaneGroup = 1 << 10, // 0400
264 BTerrainGroup = 1 << 11, // 0800
265 BRaycastGroup = 1 << 12, // 1000
266 BSolidGroup = 1 << 13, // 2000
267 // BLinksetGroup = xx // a linkset proper is either static or dynamic
268 BLinksetChildGroup = 1 << 14, // 4000
269};
270
271// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
272// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
273public enum ConstraintParams : int
274{
275 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
276 BT_CONSTRAINT_STOP_ERP,
277 BT_CONSTRAINT_CFM,
278 BT_CONSTRAINT_STOP_CFM,
279};
280public enum ConstraintParamAxis : int
281{
282 AXIS_LINEAR_X = 0,
283 AXIS_LINEAR_Y,
284 AXIS_LINEAR_Z,
285 AXIS_ANGULAR_X,
286 AXIS_ANGULAR_Y,
287 AXIS_ANGULAR_Z,
288 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
289 AXIS_ANGULAR_ALL,
290 AXIS_ALL
291};
292
293public abstract class BSAPITemplate
294{
295// Returns the name of the underlying Bullet engine
296public abstract string BulletEngineName { get; }
297public abstract string BulletEngineVersion { get; protected set;}
298
299// Initialization and simulation
300public abstract BulletWorld Initialize(Vector3 maxPosition, ConfigurationParameters parms,
301 int maxCollisions, ref CollisionDesc[] collisionArray,
302 int maxUpdates, ref EntityProperties[] updateArray
303 );
304
305public abstract int PhysicsStep(BulletWorld world, float timeStep, int maxSubSteps, float fixedTimeStep,
306 out int updatedEntityCount, out int collidersCount);
307
308public abstract bool UpdateParameter(BulletWorld world, uint localID, String parm, float value);
309
310public abstract void Shutdown(BulletWorld sim);
311
312public abstract bool PushUpdate(BulletBody obj);
313
314// =====================================================================================
315// Mesh, hull, shape and body creation helper routines
316public abstract BulletShape CreateMeshShape(BulletWorld world,
317 int indicesCount, int[] indices,
318 int verticesCount, float[] vertices );
319
320public abstract BulletShape CreateHullShape(BulletWorld world,
321 int hullCount, float[] hulls);
322
323public abstract BulletShape BuildHullShapeFromMesh(BulletWorld world, BulletShape meshShape);
324
325public abstract BulletShape BuildNativeShape(BulletWorld world, ShapeData shapeData);
326
327public abstract bool IsNativeShape(BulletShape shape);
328
329public abstract void SetShapeCollisionMargin(BulletShape shape, float margin);
330
331public abstract BulletShape BuildCapsuleShape(BulletWorld world, float radius, float height, Vector3 scale);
332
333public abstract BulletShape CreateCompoundShape(BulletWorld sim, bool enableDynamicAabbTree);
334
335public abstract int GetNumberOfCompoundChildren(BulletShape cShape);
336
337public abstract void AddChildShapeToCompoundShape(BulletShape cShape, BulletShape addShape, Vector3 pos, Quaternion rot);
338
339public abstract BulletShape GetChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
340
341public abstract BulletShape RemoveChildShapeFromCompoundShapeIndex(BulletShape cShape, int indx);
342
343public abstract void RemoveChildShapeFromCompoundShape(BulletShape cShape, BulletShape removeShape);
344
345public abstract void RecalculateCompoundShapeLocalAabb(BulletShape cShape);
346
347public abstract BulletShape DuplicateCollisionShape(BulletWorld sim, BulletShape srcShape, uint id);
348
349public abstract bool DeleteCollisionShape(BulletWorld world, BulletShape shape);
350
351public abstract CollisionObjectTypes GetBodyType(BulletBody obj);
352
353public abstract BulletBody CreateBodyFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
354
355public abstract BulletBody CreateBodyWithDefaultMotionState(BulletShape shape, uint id, Vector3 pos, Quaternion rot);
356
357public abstract BulletBody CreateGhostFromShape(BulletWorld sim, BulletShape shape, uint id, Vector3 pos, Quaternion rot);
358
359public abstract void DestroyObject(BulletWorld sim, BulletBody obj);
360
361// =====================================================================================
362public abstract BulletShape CreateGroundPlaneShape(uint id, float height, float collisionMargin);
363
364public abstract BulletShape CreateTerrainShape(uint id, Vector3 size, float minHeight, float maxHeight, float[] heightMap,
365 float scaleFactor, float collisionMargin);
366
367// =====================================================================================
368// Constraint creation and helper routines
369public abstract BulletConstraint Create6DofConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
370 Vector3 frame1loc, Quaternion frame1rot,
371 Vector3 frame2loc, Quaternion frame2rot,
372 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
373
374public abstract BulletConstraint Create6DofConstraintToPoint(BulletWorld world, BulletBody obj1, BulletBody obj2,
375 Vector3 joinPoint,
376 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
377
378public abstract BulletConstraint CreateHingeConstraint(BulletWorld world, BulletBody obj1, BulletBody obj2,
379 Vector3 pivotinA, Vector3 pivotinB,
380 Vector3 axisInA, Vector3 axisInB,
381 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
382
383public abstract void SetConstraintEnable(BulletConstraint constrain, float numericTrueFalse);
384
385public abstract void SetConstraintNumSolverIterations(BulletConstraint constrain, float iterations);
386
387public abstract bool SetFrames(BulletConstraint constrain,
388 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
389
390public abstract bool SetLinearLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
391
392public abstract bool SetAngularLimits(BulletConstraint constrain, Vector3 low, Vector3 hi);
393
394public abstract bool UseFrameOffset(BulletConstraint constrain, float enable);
395
396public abstract bool TranslationalLimitMotor(BulletConstraint constrain, float enable, float targetVel, float maxMotorForce);
397
398public abstract bool SetBreakingImpulseThreshold(BulletConstraint constrain, float threshold);
399
400public abstract bool CalculateTransforms(BulletConstraint constrain);
401
402public abstract bool SetConstraintParam(BulletConstraint constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
403
404public abstract bool DestroyConstraint(BulletWorld world, BulletConstraint constrain);
405
406// =====================================================================================
407// btCollisionWorld entries
408public abstract void UpdateSingleAabb(BulletWorld world, BulletBody obj);
409
410public abstract void UpdateAabbs(BulletWorld world);
411
412public abstract bool GetForceUpdateAllAabbs(BulletWorld world);
413
414public abstract void SetForceUpdateAllAabbs(BulletWorld world, bool force);
415
416// =====================================================================================
417// btDynamicsWorld entries
418// public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj, Vector3 pos, Quaternion rot);
419public abstract bool AddObjectToWorld(BulletWorld world, BulletBody obj);
420
421public abstract bool RemoveObjectFromWorld(BulletWorld world, BulletBody obj);
422
423public abstract bool AddConstraintToWorld(BulletWorld world, BulletConstraint constrain, bool disableCollisionsBetweenLinkedObjects);
424
425public abstract bool RemoveConstraintFromWorld(BulletWorld world, BulletConstraint constrain);
426// =====================================================================================
427// btCollisionObject entries
428public abstract Vector3 GetAnisotripicFriction(BulletConstraint constrain);
429
430public abstract Vector3 SetAnisotripicFriction(BulletConstraint constrain, Vector3 frict);
431
432public abstract bool HasAnisotripicFriction(BulletConstraint constrain);
433
434public abstract void SetContactProcessingThreshold(BulletBody obj, float val);
435
436public abstract float GetContactProcessingThreshold(BulletBody obj);
437
438public abstract bool IsStaticObject(BulletBody obj);
439
440public abstract bool IsKinematicObject(BulletBody obj);
441
442public abstract bool IsStaticOrKinematicObject(BulletBody obj);
443
444public abstract bool HasContactResponse(BulletBody obj);
445
446public abstract void SetCollisionShape(BulletWorld sim, BulletBody obj, BulletShape shape);
447
448public abstract BulletShape GetCollisionShape(BulletBody obj);
449
450public abstract int GetActivationState(BulletBody obj);
451
452public abstract void SetActivationState(BulletBody obj, int state);
453
454public abstract void SetDeactivationTime(BulletBody obj, float dtime);
455
456public abstract float GetDeactivationTime(BulletBody obj);
457
458public abstract void ForceActivationState(BulletBody obj, ActivationState state);
459
460public abstract void Activate(BulletBody obj, bool forceActivation);
461
462public abstract bool IsActive(BulletBody obj);
463
464public abstract void SetRestitution(BulletBody obj, float val);
465
466public abstract float GetRestitution(BulletBody obj);
467
468public abstract void SetFriction(BulletBody obj, float val);
469
470public abstract float GetFriction(BulletBody obj);
471
472public abstract Vector3 GetPosition(BulletBody obj);
473
474public abstract Quaternion GetOrientation(BulletBody obj);
475
476public abstract void SetTranslation(BulletBody obj, Vector3 position, Quaternion rotation);
477
478// public abstract IntPtr GetBroadphaseHandle(BulletBody obj);
479
480// public abstract void SetBroadphaseHandle(BulletBody obj, IntPtr handle);
481
482public abstract void SetInterpolationLinearVelocity(BulletBody obj, Vector3 vel);
483
484public abstract void SetInterpolationAngularVelocity(BulletBody obj, Vector3 vel);
485
486public abstract void SetInterpolationVelocity(BulletBody obj, Vector3 linearVel, Vector3 angularVel);
487
488public abstract float GetHitFraction(BulletBody obj);
489
490public abstract void SetHitFraction(BulletBody obj, float val);
491
492public abstract CollisionFlags GetCollisionFlags(BulletBody obj);
493
494public abstract CollisionFlags SetCollisionFlags(BulletBody obj, CollisionFlags flags);
495
496public abstract CollisionFlags AddToCollisionFlags(BulletBody obj, CollisionFlags flags);
497
498public abstract CollisionFlags RemoveFromCollisionFlags(BulletBody obj, CollisionFlags flags);
499
500public abstract float GetCcdMotionThreshold(BulletBody obj);
501
502public abstract void SetCcdMotionThreshold(BulletBody obj, float val);
503
504public abstract float GetCcdSweptSphereRadius(BulletBody obj);
505
506public abstract void SetCcdSweptSphereRadius(BulletBody obj, float val);
507
508public abstract IntPtr GetUserPointer(BulletBody obj);
509
510public abstract void SetUserPointer(BulletBody obj, IntPtr val);
511
512// =====================================================================================
513// btRigidBody entries
514public abstract void ApplyGravity(BulletBody obj);
515
516public abstract void SetGravity(BulletBody obj, Vector3 val);
517
518public abstract Vector3 GetGravity(BulletBody obj);
519
520public abstract void SetDamping(BulletBody obj, float lin_damping, float ang_damping);
521
522public abstract void SetLinearDamping(BulletBody obj, float lin_damping);
523
524public abstract void SetAngularDamping(BulletBody obj, float ang_damping);
525
526public abstract float GetLinearDamping(BulletBody obj);
527
528public abstract float GetAngularDamping(BulletBody obj);
529
530public abstract float GetLinearSleepingThreshold(BulletBody obj);
531
532public abstract void ApplyDamping(BulletBody obj, float timeStep);
533
534public abstract void SetMassProps(BulletBody obj, float mass, Vector3 inertia);
535
536public abstract Vector3 GetLinearFactor(BulletBody obj);
537
538public abstract void SetLinearFactor(BulletBody obj, Vector3 factor);
539
540public abstract void SetCenterOfMassByPosRot(BulletBody obj, Vector3 pos, Quaternion rot);
541
542// Add a force to the object as if its mass is one.
543public abstract void ApplyCentralForce(BulletBody obj, Vector3 force);
544
545// Set the force being applied to the object as if its mass is one.
546public abstract void SetObjectForce(BulletBody obj, Vector3 force);
547
548public abstract Vector3 GetTotalForce(BulletBody obj);
549
550public abstract Vector3 GetTotalTorque(BulletBody obj);
551
552public abstract Vector3 GetInvInertiaDiagLocal(BulletBody obj);
553
554public abstract void SetInvInertiaDiagLocal(BulletBody obj, Vector3 inert);
555
556public abstract void SetSleepingThresholds(BulletBody obj, float lin_threshold, float ang_threshold);
557
558public abstract void ApplyTorque(BulletBody obj, Vector3 torque);
559
560// Apply force at the given point. Will add torque to the object.
561public abstract void ApplyForce(BulletBody obj, Vector3 force, Vector3 pos);
562
563// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
564public abstract void ApplyCentralImpulse(BulletBody obj, Vector3 imp);
565
566// Apply impulse to the object's torque. Force is scaled by object's mass.
567public abstract void ApplyTorqueImpulse(BulletBody obj, Vector3 imp);
568
569// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
570public abstract void ApplyImpulse(BulletBody obj, Vector3 imp, Vector3 pos);
571
572public abstract void ClearForces(BulletBody obj);
573
574public abstract void ClearAllForces(BulletBody obj);
575
576public abstract void UpdateInertiaTensor(BulletBody obj);
577
578public abstract Vector3 GetLinearVelocity(BulletBody obj);
579
580public abstract Vector3 GetAngularVelocity(BulletBody obj);
581
582public abstract void SetLinearVelocity(BulletBody obj, Vector3 val);
583
584public abstract void SetAngularVelocity(BulletBody obj, Vector3 angularVelocity);
585
586public abstract Vector3 GetVelocityInLocalPoint(BulletBody obj, Vector3 pos);
587
588public abstract void Translate(BulletBody obj, Vector3 trans);
589
590public abstract void UpdateDeactivation(BulletBody obj, float timeStep);
591
592public abstract bool WantsSleeping(BulletBody obj);
593
594public abstract void SetAngularFactor(BulletBody obj, float factor);
595
596public abstract void SetAngularFactorV(BulletBody obj, Vector3 factor);
597
598public abstract Vector3 GetAngularFactor(BulletBody obj);
599
600public abstract bool IsInWorld(BulletWorld world, BulletBody obj);
601
602public abstract void AddConstraintRef(BulletBody obj, BulletConstraint constrain);
603
604public abstract void RemoveConstraintRef(BulletBody obj, BulletConstraint constrain);
605
606public abstract BulletConstraint GetConstraintRef(BulletBody obj, int index);
607
608public abstract int GetNumConstraintRefs(BulletBody obj);
609
610public abstract bool SetCollisionGroupMask(BulletBody body, uint filter, uint mask);
611
612// =====================================================================================
613// btCollisionShape entries
614
615public abstract float GetAngularMotionDisc(BulletShape shape);
616
617public abstract float GetContactBreakingThreshold(BulletShape shape, float defaultFactor);
618
619public abstract bool IsPolyhedral(BulletShape shape);
620
621public abstract bool IsConvex2d(BulletShape shape);
622
623public abstract bool IsConvex(BulletShape shape);
624
625public abstract bool IsNonMoving(BulletShape shape);
626
627public abstract bool IsConcave(BulletShape shape);
628
629public abstract bool IsCompound(BulletShape shape);
630
631public abstract bool IsSoftBody(BulletShape shape);
632
633public abstract bool IsInfinite(BulletShape shape);
634
635public abstract void SetLocalScaling(BulletShape shape, Vector3 scale);
636
637public abstract Vector3 GetLocalScaling(BulletShape shape);
638
639public abstract Vector3 CalculateLocalInertia(BulletShape shape, float mass);
640
641public abstract int GetShapeType(BulletShape shape);
642
643public abstract void SetMargin(BulletShape shape, float val);
644
645public abstract float GetMargin(BulletShape shape);
646
647// =====================================================================================
648// Debugging
649public virtual void DumpRigidBody(BulletWorld sim, BulletBody collisionObject) { }
650
651public virtual void DumpCollisionShape(BulletWorld sim, BulletShape collisionShape) { }
652
653public virtual void DumpConstraint(BulletWorld sim, BulletConstraint constrain) { }
654
655public virtual void DumpActivationInfo(BulletWorld sim) { }
656
657public virtual void DumpAllInfo(BulletWorld sim) { }
658
659public virtual void DumpPhysicsStatistics(BulletWorld sim) { }
660
661public virtual void ResetBroadphasePool(BulletWorld sim) { }
662
663public virtual void ResetConstraintSolver(BulletWorld sim) { }
664
665};
666}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
index 4c195e1..c215e3a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSCharacter.cs
@@ -66,9 +66,10 @@ public sealed class BSCharacter : BSPhysObject
66 private float _buoyancy; 66 private float _buoyancy;
67 67
68 // The friction and velocity of the avatar is modified depending on whether walking or not. 68 // The friction and velocity of the avatar is modified depending on whether walking or not.
69 private OMV.Vector3 _appliedVelocity; // the last velocity applied to the avatar
70 private float _currentFriction; // the friction currently being used (changed by setVelocity). 69 private float _currentFriction; // the friction currently being used (changed by setVelocity).
71 70
71 private BSVMotor _velocityMotor;
72
72 private OMV.Vector3 _PIDTarget; 73 private OMV.Vector3 _PIDTarget;
73 private bool _usePID; 74 private bool _usePID;
74 private float _PIDTau; 75 private float _PIDTau;
@@ -83,34 +84,36 @@ public sealed class BSCharacter : BSPhysObject
83 _physicsActorType = (int)ActorTypes.Agent; 84 _physicsActorType = (int)ActorTypes.Agent;
84 _position = pos; 85 _position = pos;
85 86
86 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
87 // replace with the default values.
88 _size = size;
89 if (_size.X == 0f) _size.X = PhysicsScene.Params.avatarCapsuleDepth;
90 if (_size.Y == 0f) _size.Y = PhysicsScene.Params.avatarCapsuleWidth;
91
92 _flying = isFlying; 87 _flying = isFlying;
93 _orientation = OMV.Quaternion.Identity; 88 _orientation = OMV.Quaternion.Identity;
94 _velocity = OMV.Vector3.Zero; 89 _velocity = OMV.Vector3.Zero;
95 _appliedVelocity = OMV.Vector3.Zero;
96 _buoyancy = ComputeBuoyancyFromFlying(isFlying); 90 _buoyancy = ComputeBuoyancyFromFlying(isFlying);
97 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 91 _currentFriction = BSParam.AvatarStandingFriction;
98 _avatarDensity = PhysicsScene.Params.avatarDensity; 92 _avatarDensity = BSParam.AvatarDensity;
99 93
100 // The dimensions of the avatar capsule are kept in the scale. 94 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
95 // replace with the default values.
96 _size = size;
97 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
98 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
99
100 // The dimensions of the physical capsule are kept in the scale.
101 // Physics creates a unit capsule which is scaled by the physics engine. 101 // Physics creates a unit capsule which is scaled by the physics engine.
102 ComputeAvatarScale(_size); 102 Scale = ComputeAvatarScale(_size);
103 // set _avatarVolume and _mass based on capsule size, _density and Scale 103 // set _avatarVolume and _mass based on capsule size, _density and Scale
104 ComputeAvatarVolumeAndMass(); 104 ComputeAvatarVolumeAndMass();
105
106 SetupMovementMotor();
107
105 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}", 108 DetailLog("{0},BSCharacter.create,call,size={1},scale={2},density={3},volume={4},mass={5}",
106 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 109 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
107 110
108 // do actual create at taint time 111 // do actual creation in taint time
109 PhysicsScene.TaintedObject("BSCharacter.create", delegate() 112 PhysicsScene.TaintedObject("BSCharacter.create", delegate()
110 { 113 {
111 DetailLog("{0},BSCharacter.create,taint", LocalID); 114 DetailLog("{0},BSCharacter.create,taint", LocalID);
112 // New body and shape into PhysBody and PhysShape 115 // New body and shape into PhysBody and PhysShape
113 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this, null, null); 116 PhysicsScene.Shapes.GetBodyAndShape(true, PhysicsScene.World, this);
114 117
115 SetPhysicalProperties(); 118 SetPhysicalProperties();
116 }); 119 });
@@ -120,54 +123,116 @@ public sealed class BSCharacter : BSPhysObject
120 // called when this character is being destroyed and the resources should be released 123 // called when this character is being destroyed and the resources should be released
121 public override void Destroy() 124 public override void Destroy()
122 { 125 {
126 base.Destroy();
127
123 DetailLog("{0},BSCharacter.Destroy", LocalID); 128 DetailLog("{0},BSCharacter.Destroy", LocalID);
124 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate() 129 PhysicsScene.TaintedObject("BSCharacter.destroy", delegate()
125 { 130 {
126 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 131 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
132 PhysBody.Clear();
127 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 133 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
134 PhysShape.Clear();
128 }); 135 });
129 } 136 }
130 137
131 private void SetPhysicalProperties() 138 private void SetPhysicalProperties()
132 { 139 {
133 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 140 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
134 141
135 ZeroMotion(true); 142 ZeroMotion(true);
136 ForcePosition = _position; 143 ForcePosition = _position;
144
137 // Set the velocity and compute the proper friction 145 // Set the velocity and compute the proper friction
146 _velocityMotor.Reset();
147 _velocityMotor.SetTarget(_velocity);
148 _velocityMotor.SetCurrent(_velocity);
138 ForceVelocity = _velocity; 149 ForceVelocity = _velocity;
139 150
140 // This will enable or disable the flying buoyancy of the avatar. 151 // This will enable or disable the flying buoyancy of the avatar.
141 // Needs to be reset especially when an avatar is recreated after crossing a region boundry. 152 // Needs to be reset especially when an avatar is recreated after crossing a region boundry.
142 Flying = _flying; 153 Flying = _flying;
143 154
144 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.avatarRestitution); 155 PhysicsScene.PE.SetRestitution(PhysBody, BSParam.AvatarRestitution);
145 BulletSimAPI.SetMargin2(PhysShape.ptr, PhysicsScene.Params.collisionMargin); 156 PhysicsScene.PE.SetMargin(PhysShape, PhysicsScene.Params.collisionMargin);
146 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 157 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
147 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 158 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
148 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 159 if (BSParam.CcdMotionThreshold > 0f)
149 { 160 {
150 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 161 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
151 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 162 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
152 } 163 }
153 164
154 UpdatePhysicalMassProperties(RawMass); 165 UpdatePhysicalMassProperties(RawMass, false);
155 166
156 // Make so capsule does not fall over 167 // Make so capsule does not fall over
157 BulletSimAPI.SetAngularFactorV2(PhysBody.ptr, OMV.Vector3.Zero); 168 PhysicsScene.PE.SetAngularFactorV(PhysBody, OMV.Vector3.Zero);
158 169
159 BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_CHARACTER_OBJECT); 170 PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_CHARACTER_OBJECT);
160 171
161 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 172 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
162 173
163 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ACTIVE_TAG); 174 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
164 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_DEACTIVATION); 175 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_DEACTIVATION);
165 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 176 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
166 177
167 // Do this after the object has been added to the world 178 // Do this after the object has been added to the world
168 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, 179 PhysBody.collisionType = CollisionType.Avatar;
169 (uint)CollisionFilterGroups.AvatarFilter, 180 PhysBody.ApplyCollisionMask(PhysicsScene);
170 (uint)CollisionFilterGroups.AvatarMask); 181 }
182
183 // The avatar's movement is controlled by this motor that speeds up and slows down
184 // the avatar seeking to reach the motor's target speed.
185 // This motor runs as a prestep action for the avatar so it will keep the avatar
186 // standing as well as moving. Destruction of the avatar will destroy the pre-step action.
187 private void SetupMovementMotor()
188 {
189
190 // Someday, use a PID motor for asymmetric speed up and slow down
191 // _velocityMotor = new BSPIDVMotor("BSCharacter.Velocity", 3f, 5f, BSMotor.InfiniteVector, 1f);
192
193 // Infinite decay and timescale values so motor only changes current to target values.
194 _velocityMotor = new BSVMotor("BSCharacter.Velocity",
195 0.2f, // time scale
196 BSMotor.Infinite, // decay time scale
197 BSMotor.InfiniteVector, // friction timescale
198 1f // efficiency
199 );
200 // _velocityMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
201
202 RegisterPreStepAction("BSCharactor.Movement", LocalID, delegate(float timeStep)
203 {
204 // TODO: Decide if the step parameters should be changed depending on the avatar's
205 // state (flying, colliding, ...). There is code in ODE to do this.
206
207 OMV.Vector3 stepVelocity = _velocityMotor.Step(timeStep);
208
209 // If falling, we keep the world's downward vector no matter what the other axis specify.
210 if (!Flying && !IsColliding)
211 {
212 stepVelocity.Z = _velocity.Z;
213 // DetailLog("{0},BSCharacter.MoveMotor,taint,overrideStepZWithWorldZ,stepVel={1}", LocalID, stepVelocity);
214 }
215
216 // 'stepVelocity' is now the speed we'd like the avatar to move in. Turn that into an instantanous force.
217 OMV.Vector3 moveForce = (stepVelocity - _velocity) * Mass;
218
219 /*
220 // If moveForce is very small, zero things so we don't keep sending microscopic updates to the user
221 float moveForceMagnitudeSquared = moveForce.LengthSquared();
222 if (moveForceMagnitudeSquared < 0.0001)
223 {
224 DetailLog("{0},BSCharacter.MoveMotor,zeroMovement,stepVel={1},vel={2},mass={3},magSq={4},moveForce={5}",
225 LocalID, stepVelocity, _velocity, Mass, moveForceMagnitudeSquared, moveForce);
226 ForceVelocity = OMV.Vector3.Zero;
227 }
228 else
229 {
230 AddForce(moveForce, false, true);
231 }
232 */
233 // DetailLog("{0},BSCharacter.MoveMotor,move,stepVel={1},vel={2},mass={3},moveForce={4}", LocalID, stepVelocity, _velocity, Mass, moveForce);
234 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, moveForce);
235 });
171 } 236 }
172 237
173 public override void RequestPhysicsterseUpdate() 238 public override void RequestPhysicsterseUpdate()
@@ -185,24 +250,31 @@ public sealed class BSCharacter : BSPhysObject
185 } 250 }
186 251
187 set { 252 set {
188 // When an avatar's size is set, only the height is changed.
189 _size = value; 253 _size = value;
190 ComputeAvatarScale(_size); 254 // Old versions of ScenePresence passed only the height. If width and/or depth are zero,
255 // replace with the default values.
256 if (_size.X == 0f) _size.X = BSParam.AvatarCapsuleDepth;
257 if (_size.Y == 0f) _size.Y = BSParam.AvatarCapsuleWidth;
258
259 Scale = ComputeAvatarScale(_size);
191 ComputeAvatarVolumeAndMass(); 260 ComputeAvatarVolumeAndMass();
192 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}", 261 DetailLog("{0},BSCharacter.setSize,call,size={1},scale={2},density={3},volume={4},mass={5}",
193 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass); 262 LocalID, _size, Scale, _avatarDensity, _avatarVolume, RawMass);
194 263
195 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate() 264 PhysicsScene.TaintedObject("BSCharacter.setSize", delegate()
196 { 265 {
197 BulletSimAPI.SetLocalScaling2(PhysShape.ptr, Scale); 266 if (PhysBody.HasPhysicalBody && PhysShape.HasPhysicalShape)
198 UpdatePhysicalMassProperties(RawMass); 267 {
268 PhysicsScene.PE.SetLocalScaling(PhysShape, Scale);
269 UpdatePhysicalMassProperties(RawMass, true);
270 // Make sure this change appears as a property update event
271 PhysicsScene.PE.PushUpdate(PhysBody);
272 }
199 }); 273 });
200 274
201 } 275 }
202 } 276 }
203 277
204 public override OMV.Vector3 Scale { get; set; }
205
206 public override PrimitiveBaseShape Shape 278 public override PrimitiveBaseShape Shape
207 { 279 {
208 set { BaseShape = value; } 280 set { BaseShape = value; }
@@ -236,7 +308,8 @@ public sealed class BSCharacter : BSPhysObject
236 // Zero some other properties directly into the physics engine 308 // Zero some other properties directly into the physics engine
237 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 309 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
238 { 310 {
239 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 311 if (PhysBody.HasPhysicalBody)
312 PhysicsScene.PE.ClearAllForces(PhysBody);
240 }); 313 });
241 } 314 }
242 public override void ZeroAngularMotion(bool inTaintTime) 315 public override void ZeroAngularMotion(bool inTaintTime)
@@ -245,10 +318,13 @@ public sealed class BSCharacter : BSPhysObject
245 318
246 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate() 319 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.ZeroMotion", delegate()
247 { 320 {
248 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 321 if (PhysBody.HasPhysicalBody)
249 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 322 {
250 // The next also get rid of applied linear force but the linear velocity is untouched. 323 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, OMV.Vector3.Zero);
251 BulletSimAPI.ClearForces2(PhysBody.ptr); 324 PhysicsScene.PE.SetAngularVelocity(PhysBody, OMV.Vector3.Zero);
325 // The next also get rid of applied linear force but the linear velocity is untouched.
326 PhysicsScene.PE.ClearForces(PhysBody);
327 }
252 }); 328 });
253 } 329 }
254 330
@@ -263,7 +339,7 @@ public sealed class BSCharacter : BSPhysObject
263 public override OMV.Vector3 Position { 339 public override OMV.Vector3 Position {
264 get { 340 get {
265 // Don't refetch the position because this function is called a zillion times 341 // Don't refetch the position because this function is called a zillion times
266 // _position = BulletSimAPI.GetObjectPosition2(Scene.World.ptr, LocalID); 342 // _position = PhysicsScene.PE.GetObjectPosition(Scene.World, LocalID);
267 return _position; 343 return _position;
268 } 344 }
269 set { 345 set {
@@ -273,19 +349,20 @@ public sealed class BSCharacter : BSPhysObject
273 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate() 349 PhysicsScene.TaintedObject("BSCharacter.setPosition", delegate()
274 { 350 {
275 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 351 DetailLog("{0},BSCharacter.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
276 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 352 if (PhysBody.HasPhysicalBody)
353 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
277 }); 354 });
278 } 355 }
279 } 356 }
280 public override OMV.Vector3 ForcePosition { 357 public override OMV.Vector3 ForcePosition {
281 get { 358 get {
282 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 359 _position = PhysicsScene.PE.GetPosition(PhysBody);
283 return _position; 360 return _position;
284 } 361 }
285 set { 362 set {
286 _position = value; 363 _position = value;
287 PositionSanityCheck(); 364 PositionSanityCheck();
288 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 365 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
289 } 366 }
290 } 367 }
291 368
@@ -297,6 +374,15 @@ public sealed class BSCharacter : BSPhysObject
297 { 374 {
298 bool ret = false; 375 bool ret = false;
299 376
377 // TODO: check for out of bounds
378 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
379 {
380 // The character is out of the known/simulated area.
381 // Upper levels of code will handle the transition to other areas so, for
382 // the time, we just ignore the position.
383 return ret;
384 }
385
300 // If below the ground, move the avatar up 386 // If below the ground, move the avatar up
301 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 387 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
302 if (Position.Z < terrainHeight) 388 if (Position.Z < terrainHeight)
@@ -307,7 +393,7 @@ public sealed class BSCharacter : BSPhysObject
307 } 393 }
308 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 394 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
309 { 395 {
310 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 396 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
311 if (Position.Z < waterHeight) 397 if (Position.Z < waterHeight)
312 { 398 {
313 _position.Z = waterHeight; 399 _position.Z = waterHeight;
@@ -315,7 +401,6 @@ public sealed class BSCharacter : BSPhysObject
315 } 401 }
316 } 402 }
317 403
318 // TODO: check for out of bounds
319 return ret; 404 return ret;
320 } 405 }
321 406
@@ -332,7 +417,8 @@ public sealed class BSCharacter : BSPhysObject
332 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate() 417 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.PositionSanityCheck", delegate()
333 { 418 {
334 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation); 419 DetailLog("{0},BSCharacter.PositionSanityCheck,taint,pos={1},orient={2}", LocalID, _position, _orientation);
335 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 420 if (PhysBody.HasPhysicalBody)
421 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
336 }); 422 });
337 ret = true; 423 ret = true;
338 } 424 }
@@ -345,10 +431,10 @@ public sealed class BSCharacter : BSPhysObject
345 public override float RawMass { 431 public override float RawMass {
346 get {return _mass; } 432 get {return _mass; }
347 } 433 }
348 public override void UpdatePhysicalMassProperties(float physMass) 434 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
349 { 435 {
350 OMV.Vector3 localInertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 436 OMV.Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
351 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, localInertia); 437 PhysicsScene.PE.SetMassProps(PhysBody, physMass, localInertia);
352 } 438 }
353 439
354 public override OMV.Vector3 Force { 440 public override OMV.Vector3 Force {
@@ -359,7 +445,8 @@ public sealed class BSCharacter : BSPhysObject
359 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate() 445 PhysicsScene.TaintedObject("BSCharacter.SetForce", delegate()
360 { 446 {
361 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force); 447 DetailLog("{0},BSCharacter.setForce,taint,force={1}", LocalID, _force);
362 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 448 if (PhysBody.HasPhysicalBody)
449 PhysicsScene.PE.SetObjectForce(PhysBody, _force);
363 }); 450 });
364 } 451 }
365 } 452 }
@@ -376,6 +463,31 @@ public sealed class BSCharacter : BSPhysObject
376 463
377 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } } 464 public override OMV.Vector3 GeometricCenter { get { return OMV.Vector3.Zero; } }
378 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } } 465 public override OMV.Vector3 CenterOfMass { get { return OMV.Vector3.Zero; } }
466
467 // Sets the target in the motor. This starts the changing of the avatar's velocity.
468 public override OMV.Vector3 TargetVelocity
469 {
470 get
471 {
472 return _velocityMotor.TargetValue;
473 }
474 set
475 {
476 DetailLog("{0},BSCharacter.setTargetVelocity,call,vel={1}", LocalID, value);
477 OMV.Vector3 targetVel = value;
478 if (_setAlwaysRun)
479 targetVel *= BSParam.AvatarAlwaysRunFactor;
480
481 PhysicsScene.TaintedObject("BSCharacter.setTargetVelocity", delegate()
482 {
483 _velocityMotor.Reset();
484 _velocityMotor.SetTarget(targetVel);
485 _velocityMotor.SetCurrent(_velocity);
486 _velocityMotor.Enabled = true;
487 });
488 }
489 }
490 // Directly setting velocity means this is what the user really wants now.
379 public override OMV.Vector3 Velocity { 491 public override OMV.Vector3 Velocity {
380 get { return _velocity; } 492 get { return _velocity; }
381 set { 493 set {
@@ -383,6 +495,12 @@ public sealed class BSCharacter : BSPhysObject
383 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity); 495 // m_log.DebugFormat("{0}: set velocity = {1}", LogHeader, _velocity);
384 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate() 496 PhysicsScene.TaintedObject("BSCharacter.setVelocity", delegate()
385 { 497 {
498 _velocityMotor.Reset();
499 _velocityMotor.SetCurrent(_velocity);
500 _velocityMotor.SetTarget(_velocity);
501 // Even though the motor is initialized, it's not used and the velocity goes straight into the avatar.
502 _velocityMotor.Enabled = false;
503
386 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity); 504 DetailLog("{0},BSCharacter.setVelocity,taint,vel={1}", LocalID, _velocity);
387 ForceVelocity = _velocity; 505 ForceVelocity = _velocity;
388 }); 506 });
@@ -391,30 +509,32 @@ public sealed class BSCharacter : BSPhysObject
391 public override OMV.Vector3 ForceVelocity { 509 public override OMV.Vector3 ForceVelocity {
392 get { return _velocity; } 510 get { return _velocity; }
393 set { 511 set {
512 PhysicsScene.AssertInTaintTime("BSCharacter.ForceVelocity");
513
514 _velocity = value;
394 // Depending on whether the avatar is moving or not, change the friction 515 // Depending on whether the avatar is moving or not, change the friction
395 // to keep the avatar from slipping around 516 // to keep the avatar from slipping around
396 if (_velocity.Length() == 0) 517 if (_velocity.Length() == 0)
397 { 518 {
398 if (_currentFriction != PhysicsScene.Params.avatarStandingFriction) 519 if (_currentFriction != BSParam.AvatarStandingFriction)
399 { 520 {
400 _currentFriction = PhysicsScene.Params.avatarStandingFriction; 521 _currentFriction = BSParam.AvatarStandingFriction;
401 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 522 if (PhysBody.HasPhysicalBody)
523 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
402 } 524 }
403 } 525 }
404 else 526 else
405 { 527 {
406 if (_currentFriction != PhysicsScene.Params.avatarFriction) 528 if (_currentFriction != BSParam.AvatarFriction)
407 { 529 {
408 _currentFriction = PhysicsScene.Params.avatarFriction; 530 _currentFriction = BSParam.AvatarFriction;
409 BulletSimAPI.SetFriction2(PhysBody.ptr, _currentFriction); 531 if (PhysBody.HasPhysicalBody)
532 PhysicsScene.PE.SetFriction(PhysBody, _currentFriction);
410 } 533 }
411 } 534 }
412 _velocity = value;
413 // Remember the set velocity so we can suppress the reduction by friction, ...
414 _appliedVelocity = value;
415 535
416 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 536 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
417 BulletSimAPI.Activate2(PhysBody.ptr, true); 537 PhysicsScene.PE.Activate(PhysBody, true);
418 } 538 }
419 } 539 }
420 public override OMV.Vector3 Torque { 540 public override OMV.Vector3 Torque {
@@ -439,13 +559,16 @@ public sealed class BSCharacter : BSPhysObject
439 public override OMV.Quaternion Orientation { 559 public override OMV.Quaternion Orientation {
440 get { return _orientation; } 560 get { return _orientation; }
441 set { 561 set {
442 _orientation = value; 562 // Orientation is set zillions of times when an avatar is walking. It's like
443 // m_log.DebugFormat("{0}: set orientation to {1}", LogHeader, _orientation); 563 // the viewer doesn't trust us.
444 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate() 564 if (_orientation != value)
445 { 565 {
446 // _position = BulletSimAPI.GetPosition2(BSBody.ptr); 566 _orientation = value;
447 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 567 PhysicsScene.TaintedObject("BSCharacter.setOrientation", delegate()
448 }); 568 {
569 ForceOrientation = _orientation;
570 });
571 }
449 } 572 }
450 } 573 }
451 // Go directly to Bullet to get/set the value. 574 // Go directly to Bullet to get/set the value.
@@ -453,13 +576,17 @@ public sealed class BSCharacter : BSPhysObject
453 { 576 {
454 get 577 get
455 { 578 {
456 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 579 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
457 return _orientation; 580 return _orientation;
458 } 581 }
459 set 582 set
460 { 583 {
461 _orientation = value; 584 _orientation = value;
462 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 585 if (PhysBody.HasPhysicalBody)
586 {
587 // _position = PhysicsScene.PE.GetPosition(BSBody);
588 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
589 }
463 } 590 }
464 } 591 }
465 public override int PhysicsActorType { 592 public override int PhysicsActorType {
@@ -482,6 +609,7 @@ public sealed class BSCharacter : BSPhysObject
482 get { return _flying; } 609 get { return _flying; }
483 set { 610 set {
484 _flying = value; 611 _flying = value;
612
485 // simulate flying by changing the effect of gravity 613 // simulate flying by changing the effect of gravity
486 Buoyancy = ComputeBuoyancyFromFlying(_flying); 614 Buoyancy = ComputeBuoyancyFromFlying(_flying);
487 } 615 }
@@ -500,27 +628,18 @@ public sealed class BSCharacter : BSPhysObject
500 get { return _throttleUpdates; } 628 get { return _throttleUpdates; }
501 set { _throttleUpdates = value; } 629 set { _throttleUpdates = value; }
502 } 630 }
503 public override bool IsColliding {
504 get { return (CollidingStep == PhysicsScene.SimulationStep); }
505 set { _isColliding = value; }
506 }
507 public override bool CollidingGround {
508 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
509 set { CollidingGround = value; }
510 }
511 public override bool CollidingObj {
512 get { return _collidingObj; }
513 set { _collidingObj = value; }
514 }
515 public override bool FloatOnWater { 631 public override bool FloatOnWater {
516 set { 632 set {
517 _floatOnWater = value; 633 _floatOnWater = value;
518 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate() 634 PhysicsScene.TaintedObject("BSCharacter.setFloatOnWater", delegate()
519 { 635 {
520 if (_floatOnWater) 636 if (PhysBody.HasPhysicalBody)
521 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 637 {
522 else 638 if (_floatOnWater)
523 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 639 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
640 else
641 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
642 }
524 }); 643 });
525 } 644 }
526 } 645 }
@@ -549,11 +668,15 @@ public sealed class BSCharacter : BSPhysObject
549 } 668 }
550 public override float ForceBuoyancy { 669 public override float ForceBuoyancy {
551 get { return _buoyancy; } 670 get { return _buoyancy; }
552 set { _buoyancy = value; 671 set {
672 PhysicsScene.AssertInTaintTime("BSCharacter.ForceBuoyancy");
673
674 _buoyancy = value;
553 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 675 DetailLog("{0},BSCharacter.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
554 // Buoyancy is faked by changing the gravity applied to the object 676 // Buoyancy is faked by changing the gravity applied to the object
555 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 677 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy);
556 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 678 if (PhysBody.HasPhysicalBody)
679 PhysicsScene.PE.SetGravity(PhysBody, new OMV.Vector3(0f, 0f, grav));
557 } 680 }
558 } 681 }
559 682
@@ -589,24 +712,40 @@ public sealed class BSCharacter : BSPhysObject
589 public override float APIDStrength { set { return; } } 712 public override float APIDStrength { set { return; } }
590 public override float APIDDamping { set { return; } } 713 public override float APIDDamping { set { return; } }
591 714
592 public override void AddForce(OMV.Vector3 force, bool pushforce) { 715 public override void AddForce(OMV.Vector3 force, bool pushforce)
716 {
717 // Since this force is being applied in only one step, make this a force per second.
718 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
719 AddForce(addForce, pushforce, false);
720 }
721 private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
593 if (force.IsFinite()) 722 if (force.IsFinite())
594 { 723 {
595 _force.X += force.X; 724 float magnitude = force.Length();
596 _force.Y += force.Y; 725 if (magnitude > BSParam.MaxAddForceMagnitude)
597 _force.Z += force.Z;
598 // m_log.DebugFormat("{0}: AddForce. adding={1}, newForce={2}", LogHeader, force, _force);
599 PhysicsScene.TaintedObject("BSCharacter.AddForce", delegate()
600 { 726 {
601 DetailLog("{0},BSCharacter.setAddForce,taint,addedForce={1}", LocalID, _force); 727 // Force has a limit
602 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 728 force = force / magnitude * BSParam.MaxAddForceMagnitude;
729 }
730
731 OMV.Vector3 addForce = force;
732 // DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
733
734 PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
735 {
736 // Bullet adds this central force to the total force for this tick
737 // DetailLog("{0},BSCharacter.addForce,taint,force={1}", LocalID, addForce);
738 if (PhysBody.HasPhysicalBody)
739 {
740 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
741 }
603 }); 742 });
604 } 743 }
605 else 744 else
606 { 745 {
607 m_log.ErrorFormat("{0}: Got a NaN force applied to a Character", LogHeader); 746 m_log.WarnFormat("{0}: Got a NaN force applied to a character. LocalID={1}", LogHeader, LocalID);
747 return;
608 } 748 }
609 //m_lastUpdateSent = false;
610 } 749 }
611 750
612 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 751 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
@@ -614,24 +753,31 @@ public sealed class BSCharacter : BSPhysObject
614 public override void SetMomentum(OMV.Vector3 momentum) { 753 public override void SetMomentum(OMV.Vector3 momentum) {
615 } 754 }
616 755
617 private void ComputeAvatarScale(OMV.Vector3 size) 756 private OMV.Vector3 ComputeAvatarScale(OMV.Vector3 size)
618 { 757 {
619 // The 'size' given by the simulator is the mid-point of the avatar 758 OMV.Vector3 newScale;
620 // and X and Y are unspecified. 759
621 760 // Bullet's capsule total height is the "passed height + radius * 2";
622 OMV.Vector3 newScale = size; 761 // The base capsule is 1 diameter and 2 height (passed radius=0.5, passed height = 1)
623 // newScale.X = PhysicsScene.Params.avatarCapsuleWidth; 762 // The number we pass in for 'scaling' is the multiplier to get that base
624 // newScale.Y = PhysicsScene.Params.avatarCapsuleDepth; 763 // shape to be the size desired.
625 764 // So, when creating the scale for the avatar height, we take the passed height
626 // From the total height, remove the capsule half spheres that are at each end 765 // (size.Z) and remove the caps.
627 // The 1.15f came from ODE. Not sure what this factors in. 766 // Another oddity of the Bullet capsule implementation is that it presumes the Y
628 // newScale.Z = (size.Z * 1.15f) - (newScale.X + newScale.Y); 767 // dimension is the radius of the capsule. Even though some of the code allows
768 // for a asymmetrical capsule, other parts of the code presume it is cylindrical.
769
770 // Scale is multiplier of radius with one of "0.5"
771 newScale.X = size.X / 2f;
772 newScale.Y = size.Y / 2f;
629 773
630 // The total scale height is the central cylindar plus the caps on the two ends. 774 // The total scale height is the central cylindar plus the caps on the two ends.
631 newScale.Z = size.Z + (Math.Min(size.X, size.Y) * 2f); 775 newScale.Z = (size.Z + (Math.Min(size.X, size.Y) * 2)) / 2f;
776 // If smaller than the endcaps, just fake like we're almost that small
777 if (newScale.Z < 0)
778 newScale.Z = 0.1f;
632 779
633 // Convert diameters to radii and height to half height -- the way Bullet expects it. 780 return newScale;
634 Scale = newScale / 2f;
635 } 781 }
636 782
637 // set _avatarVolume and _mass based on capsule size, _density and Scale 783 // set _avatarVolume and _mass based on capsule size, _density and Scale
@@ -639,14 +785,14 @@ public sealed class BSCharacter : BSPhysObject
639 { 785 {
640 _avatarVolume = (float)( 786 _avatarVolume = (float)(
641 Math.PI 787 Math.PI
642 * Scale.X 788 * Size.X / 2f
643 * Scale.Y // the area of capsule cylinder 789 * Size.Y / 2f // the area of capsule cylinder
644 * Scale.Z // times height of capsule cylinder 790 * Size.Z // times height of capsule cylinder
645 + 1.33333333f 791 + 1.33333333f
646 * Math.PI 792 * Math.PI
647 * Scale.X 793 * Size.X / 2f
648 * Math.Min(Scale.X, Scale.Y) 794 * Math.Min(Size.X, Size.Y) / 2
649 * Scale.Y // plus the volume of the capsule end caps 795 * Size.Y / 2f // plus the volume of the capsule end caps
650 ); 796 );
651 _mass = _avatarDensity * _avatarVolume; 797 _mass = _avatarDensity * _avatarVolume;
652 } 798 }
@@ -660,6 +806,7 @@ public sealed class BSCharacter : BSPhysObject
660 _velocity = entprop.Velocity; 806 _velocity = entprop.Velocity;
661 _acceleration = entprop.Acceleration; 807 _acceleration = entprop.Acceleration;
662 _rotationalVelocity = entprop.RotationalVelocity; 808 _rotationalVelocity = entprop.RotationalVelocity;
809
663 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds. 810 // Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
664 PositionSanityCheck(true); 811 PositionSanityCheck(true);
665 812
@@ -667,17 +814,8 @@ public sealed class BSCharacter : BSPhysObject
667 LastEntityProperties = CurrentEntityProperties; 814 LastEntityProperties = CurrentEntityProperties;
668 CurrentEntityProperties = entprop; 815 CurrentEntityProperties = entprop;
669 816
670 if (entprop.Velocity != LastEntityProperties.Velocity)
671 {
672 // Changes in the velocity are suppressed in avatars.
673 // That's just the way they are defined.
674 OMV.Vector3 avVel = new OMV.Vector3(_appliedVelocity.X, _appliedVelocity.Y, entprop.Velocity.Z);
675 _velocity = avVel;
676 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, avVel);
677 }
678
679 // Tell the linkset about value changes 817 // Tell the linkset about value changes
680 Linkset.UpdateProperties(this); 818 Linkset.UpdateProperties(this, true);
681 819
682 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop. 820 // Avatars don't report their changes the usual way. Changes are checked for in the heartbeat loop.
683 // base.RequestPhysicsterseUpdate(); 821 // base.RequestPhysicsterseUpdate();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
index 65fac00..b813974 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint.cs
@@ -36,7 +36,8 @@ public abstract class BSConstraint : IDisposable
36{ 36{
37 private static string LogHeader = "[BULLETSIM CONSTRAINT]"; 37 private static string LogHeader = "[BULLETSIM CONSTRAINT]";
38 38
39 protected BulletSim m_world; 39 protected BulletWorld m_world;
40 protected BSScene PhysicsScene;
40 protected BulletBody m_body1; 41 protected BulletBody m_body1;
41 protected BulletBody m_body2; 42 protected BulletBody m_body2;
42 protected BulletConstraint m_constraint; 43 protected BulletConstraint m_constraint;
@@ -48,8 +49,10 @@ public abstract class BSConstraint : IDisposable
48 public abstract ConstraintType Type { get; } 49 public abstract ConstraintType Type { get; }
49 public bool IsEnabled { get { return m_enabled; } } 50 public bool IsEnabled { get { return m_enabled; } }
50 51
51 public BSConstraint() 52 public BSConstraint(BulletWorld world)
52 { 53 {
54 m_world = world;
55 PhysicsScene = m_world.physicsScene;
53 } 56 }
54 57
55 public virtual void Dispose() 58 public virtual void Dispose()
@@ -57,15 +60,15 @@ public abstract class BSConstraint : IDisposable
57 if (m_enabled) 60 if (m_enabled)
58 { 61 {
59 m_enabled = false; 62 m_enabled = false;
60 if (m_constraint.ptr != IntPtr.Zero) 63 if (m_constraint.HasPhysicalConstraint)
61 { 64 {
62 bool success = BulletSimAPI.DestroyConstraint2(m_world.ptr, m_constraint.ptr); 65 bool success = PhysicsScene.PE.DestroyConstraint(m_world, m_constraint);
63 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}", 66 m_world.physicsScene.DetailLog("{0},BSConstraint.Dispose,taint,id1={1},body1={2},id2={3},body2={4},success={5}",
64 BSScene.DetailLogZero, 67 BSScene.DetailLogZero,
65 m_body1.ID, m_body1.ptr.ToString("X"), 68 m_body1.ID, m_body1.AddrString,
66 m_body2.ID, m_body2.ptr.ToString("X"), 69 m_body2.ID, m_body2.AddrString,
67 success); 70 success);
68 m_constraint.ptr = System.IntPtr.Zero; 71 m_constraint.Clear();
69 } 72 }
70 } 73 }
71 } 74 }
@@ -74,7 +77,7 @@ public abstract class BSConstraint : IDisposable
74 { 77 {
75 bool ret = false; 78 bool ret = false;
76 if (m_enabled) 79 if (m_enabled)
77 ret = BulletSimAPI.SetLinearLimits2(m_constraint.ptr, low, high); 80 ret = PhysicsScene.PE.SetLinearLimits(m_constraint, low, high);
78 return ret; 81 return ret;
79 } 82 }
80 83
@@ -82,7 +85,7 @@ public abstract class BSConstraint : IDisposable
82 { 85 {
83 bool ret = false; 86 bool ret = false;
84 if (m_enabled) 87 if (m_enabled)
85 ret = BulletSimAPI.SetAngularLimits2(m_constraint.ptr, low, high); 88 ret = PhysicsScene.PE.SetAngularLimits(m_constraint, low, high);
86 return ret; 89 return ret;
87 } 90 }
88 91
@@ -91,7 +94,7 @@ public abstract class BSConstraint : IDisposable
91 bool ret = false; 94 bool ret = false;
92 if (m_enabled) 95 if (m_enabled)
93 { 96 {
94 BulletSimAPI.SetConstraintNumSolverIterations2(m_constraint.ptr, cnt); 97 PhysicsScene.PE.SetConstraintNumSolverIterations(m_constraint, cnt);
95 ret = true; 98 ret = true;
96 } 99 }
97 return ret; 100 return ret;
@@ -103,7 +106,7 @@ public abstract class BSConstraint : IDisposable
103 if (m_enabled) 106 if (m_enabled)
104 { 107 {
105 // Recompute the internal transforms 108 // Recompute the internal transforms
106 BulletSimAPI.CalculateTransforms2(m_constraint.ptr); 109 PhysicsScene.PE.CalculateTransforms(m_constraint);
107 ret = true; 110 ret = true;
108 } 111 }
109 return ret; 112 return ret;
@@ -122,7 +125,7 @@ public abstract class BSConstraint : IDisposable
122 // Setting an object's mass to zero (making it static like when it's selected) 125 // Setting an object's mass to zero (making it static like when it's selected)
123 // automatically disables the constraints. 126 // automatically disables the constraints.
124 // If the link is enabled, be sure to set the constraint itself to enabled. 127 // If the link is enabled, be sure to set the constraint itself to enabled.
125 BulletSimAPI.SetConstraintEnable2(m_constraint.ptr, m_world.physicsScene.NumericBool(true)); 128 PhysicsScene.PE.SetConstraintEnable(m_constraint, BSParam.NumericBool(true));
126 } 129 }
127 else 130 else
128 { 131 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
index 23ef052..ecb1b32 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraint6Dof.cs
@@ -39,51 +39,49 @@ public sealed class BSConstraint6Dof : BSConstraint
39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } } 39 public override ConstraintType Type { get { return ConstraintType.D6_CONSTRAINT_TYPE; } }
40 40
41 // Create a btGeneric6DofConstraint 41 // Create a btGeneric6DofConstraint
42 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 42 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
43 Vector3 frame1, Quaternion frame1rot, 43 Vector3 frame1, Quaternion frame1rot,
44 Vector3 frame2, Quaternion frame2rot, 44 Vector3 frame2, Quaternion frame2rot,
45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 45 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
46 : base(world)
46 { 47 {
47 m_world = world;
48 m_body1 = obj1; 48 m_body1 = obj1;
49 m_body2 = obj2; 49 m_body2 = obj2;
50 m_constraint = new BulletConstraint( 50 m_constraint = PhysicsScene.PE.Create6DofConstraint(m_world, m_body1, m_body2,
51 BulletSimAPI.Create6DofConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
52 frame1, frame1rot, 51 frame1, frame1rot,
53 frame2, frame2rot, 52 frame2, frame2rot,
54 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 53 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
55 m_enabled = true; 54 m_enabled = true;
56 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 55 world.physicsScene.DetailLog("{0},BS6DofConstraint,createFrame,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
57 BSScene.DetailLogZero, world.worldID, 56 BSScene.DetailLogZero, world.worldID,
58 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 57 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
59 } 58 }
60 59
61 public BSConstraint6Dof(BulletSim world, BulletBody obj1, BulletBody obj2, 60 public BSConstraint6Dof(BulletWorld world, BulletBody obj1, BulletBody obj2,
62 Vector3 joinPoint, 61 Vector3 joinPoint,
63 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 62 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
63 : base(world)
64 { 64 {
65 m_world = world;
66 m_body1 = obj1; 65 m_body1 = obj1;
67 m_body2 = obj2; 66 m_body2 = obj2;
68 if (obj1.ptr == IntPtr.Zero || obj2.ptr == IntPtr.Zero) 67 if (!obj1.HasPhysicalBody || !obj2.HasPhysicalBody)
69 { 68 {
70 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 69 world.physicsScene.DetailLog("{0},BS6DOFConstraint,badBodyPtr,wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
71 BSScene.DetailLogZero, world.worldID, 70 BSScene.DetailLogZero, world.worldID,
72 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 71 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
73 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}", 72 world.physicsScene.Logger.ErrorFormat("{0} Attempt to build 6DOF constraint with missing bodies: wID={1}, rID={2}, rBody={3}, cID={4}, cBody={5}",
74 LogHeader, world.worldID, obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 73 LogHeader, world.worldID, obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
75 m_enabled = false; 74 m_enabled = false;
76 } 75 }
77 else 76 else
78 { 77 {
79 m_constraint = new BulletConstraint( 78 m_constraint = PhysicsScene.PE.Create6DofConstraintToPoint(m_world, m_body1, m_body2,
80 BulletSimAPI.Create6DofConstraintToPoint2(m_world.ptr, m_body1.ptr, m_body2.ptr,
81 joinPoint, 79 joinPoint,
82 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies)); 80 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
83 world.physicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}", 81 PhysicsScene.DetailLog("{0},BS6DofConstraint,createMidPoint,wID={1}, csrt={2}, rID={3}, rBody={4}, cID={5}, cBody={6}",
84 BSScene.DetailLogZero, world.worldID, m_constraint.ptr.ToString("X"), 82 BSScene.DetailLogZero, world.worldID, m_constraint.AddrString,
85 obj1.ID, obj1.ptr.ToString("X"), obj2.ID, obj2.ptr.ToString("X")); 83 obj1.ID, obj1.AddrString, obj2.ID, obj2.AddrString);
86 if (m_constraint.ptr == IntPtr.Zero) 84 if (!m_constraint.HasPhysicalConstraint)
87 { 85 {
88 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}", 86 world.physicsScene.Logger.ErrorFormat("{0} Failed creation of 6Dof constraint. rootID={1}, childID={2}",
89 LogHeader, obj1.ID, obj2.ID); 87 LogHeader, obj1.ID, obj2.ID);
@@ -101,7 +99,7 @@ public sealed class BSConstraint6Dof : BSConstraint
101 bool ret = false; 99 bool ret = false;
102 if (m_enabled) 100 if (m_enabled)
103 { 101 {
104 BulletSimAPI.SetFrames2(m_constraint.ptr, frameA, frameArot, frameB, frameBrot); 102 PhysicsScene.PE.SetFrames(m_constraint, frameA, frameArot, frameB, frameBrot);
105 ret = true; 103 ret = true;
106 } 104 }
107 return ret; 105 return ret;
@@ -112,9 +110,9 @@ public sealed class BSConstraint6Dof : BSConstraint
112 bool ret = false; 110 bool ret = false;
113 if (m_enabled) 111 if (m_enabled)
114 { 112 {
115 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 113 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
116 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL); 114 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_STOP_ERP, erp, ConstraintParamAxis.AXIS_ALL);
117 BulletSimAPI.SetConstraintParam2(m_constraint.ptr, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL); 115 PhysicsScene.PE.SetConstraintParam(m_constraint, ConstraintParams.BT_CONSTRAINT_CFM, cfm, ConstraintParamAxis.AXIS_ALL);
118 ret = true; 116 ret = true;
119 } 117 }
120 return ret; 118 return ret;
@@ -125,7 +123,7 @@ public sealed class BSConstraint6Dof : BSConstraint
125 bool ret = false; 123 bool ret = false;
126 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 124 float onOff = useOffset ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
127 if (m_enabled) 125 if (m_enabled)
128 ret = BulletSimAPI.UseFrameOffset2(m_constraint.ptr, onOff); 126 ret = PhysicsScene.PE.UseFrameOffset(m_constraint, onOff);
129 return ret; 127 return ret;
130 } 128 }
131 129
@@ -135,7 +133,7 @@ public sealed class BSConstraint6Dof : BSConstraint
135 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse; 133 float onOff = enable ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse;
136 if (m_enabled) 134 if (m_enabled)
137 { 135 {
138 ret = BulletSimAPI.TranslationalLimitMotor2(m_constraint.ptr, onOff, targetVelocity, maxMotorForce); 136 ret = PhysicsScene.PE.TranslationalLimitMotor(m_constraint, onOff, targetVelocity, maxMotorForce);
139 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}", 137 m_world.physicsScene.DetailLog("{0},BS6DOFConstraint,TransLimitMotor,enable={1},vel={2},maxForce={3}",
140 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce); 138 BSScene.DetailLogZero, enable, targetVelocity, maxMotorForce);
141 } 139 }
@@ -146,7 +144,7 @@ public sealed class BSConstraint6Dof : BSConstraint
146 { 144 {
147 bool ret = false; 145 bool ret = false;
148 if (m_enabled) 146 if (m_enabled)
149 ret = BulletSimAPI.SetBreakingImpulseThreshold2(m_constraint.ptr, threshold); 147 ret = PhysicsScene.PE.SetBreakingImpulseThreshold(m_constraint, threshold);
150 return ret; 148 return ret;
151 } 149 }
152} 150}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
index a9fd826..2aeff25 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintCollection.cs
@@ -41,9 +41,9 @@ public sealed class BSConstraintCollection : IDisposable
41 delegate bool ConstraintAction(BSConstraint constrain); 41 delegate bool ConstraintAction(BSConstraint constrain);
42 42
43 private List<BSConstraint> m_constraints; 43 private List<BSConstraint> m_constraints;
44 private BulletSim m_world; 44 private BulletWorld m_world;
45 45
46 public BSConstraintCollection(BulletSim world) 46 public BSConstraintCollection(BulletWorld world)
47 { 47 {
48 m_world = world; 48 m_world = world;
49 m_constraints = new List<BSConstraint>(); 49 m_constraints = new List<BSConstraint>();
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
index ed3ffa7..7714a03 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSConstraintHinge.cs
@@ -36,19 +36,17 @@ public sealed class BSConstraintHinge : BSConstraint
36{ 36{
37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } } 37 public override ConstraintType Type { get { return ConstraintType.HINGE_CONSTRAINT_TYPE; } }
38 38
39 public BSConstraintHinge(BulletSim world, BulletBody obj1, BulletBody obj2, 39 public BSConstraintHinge(BulletWorld world, BulletBody obj1, BulletBody obj2,
40 Vector3 pivotInA, Vector3 pivotInB, 40 Vector3 pivotInA, Vector3 pivotInB,
41 Vector3 axisInA, Vector3 axisInB, 41 Vector3 axisInA, Vector3 axisInB,
42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies) 42 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies)
43 : base(world)
43 { 44 {
44 m_world = world;
45 m_body1 = obj1; 45 m_body1 = obj1;
46 m_body2 = obj2; 46 m_body2 = obj2;
47 m_constraint = new BulletConstraint( 47 m_constraint = PhysicsScene.PE.CreateHingeConstraint(world, obj1, obj2,
48 BulletSimAPI.CreateHingeConstraint2(m_world.ptr, m_body1.ptr, m_body2.ptr, 48 pivotInA, pivotInB, axisInA, axisInB,
49 pivotInA, pivotInB, 49 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies);
50 axisInA, axisInB,
51 useLinearReferenceFrameA, disableCollisionsBetweenLinkedBodies));
52 m_enabled = true; 50 m_enabled = true;
53 } 51 }
54 52
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
index dbc9039..13c2539 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSDynamics.cs
@@ -24,30 +24,17 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 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. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * 26 *
27 27 * The quotations from http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial
28/* RA: June 14, 2011. Copied from ODEDynamics.cs and converted to 28 * are Copyright (c) 2009 Linden Research, Inc and are used under their license
29 * call the BulletSim system. 29 * of Creative Commons Attribution-Share Alike 3.0
30 */ 30 * (http://creativecommons.org/licenses/by-sa/3.0/).
31/* Revised Aug, Sept 2009 by Kitto Flora. ODEDynamics.cs replaces
32 * ODEVehicleSettings.cs. It and ODEPrim.cs are re-organised:
33 * ODEPrim.cs contains methods dealing with Prim editing, Prim
34 * characteristics and Kinetic motion.
35 * ODEDynamics.cs contains methods dealing with Prim Physical motion
36 * (dynamics) and the associated settings. Old Linear and angular
37 * motors for dynamic motion have been replace with MoveLinear()
38 * and MoveAngular(); 'Physical' is used only to switch ODE dynamic
39 * simualtion on/off; VEHICAL_TYPE_NONE/VEHICAL_TYPE_<other> is to
40 * switch between 'VEHICLE' parameter use and general dynamics
41 * settings use.
42 */ 31 */
43 32
44using System; 33using System;
45using System.Collections.Generic; 34using System.Collections.Generic;
46using System.Reflection; 35using System.Reflection;
47using System.Runtime.InteropServices; 36using System.Runtime.InteropServices;
48using log4net;
49using OpenMetaverse; 37using OpenMetaverse;
50using OpenSim.Framework;
51using OpenSim.Region.Physics.Manager; 38using OpenSim.Region.Physics.Manager;
52 39
53namespace OpenSim.Region.Physics.BulletSPlugin 40namespace OpenSim.Region.Physics.BulletSPlugin
@@ -80,10 +67,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
80 private Quaternion m_referenceFrame = Quaternion.Identity; 67 private Quaternion m_referenceFrame = Quaternion.Identity;
81 68
82 // Linear properties 69 // Linear properties
70 private BSVMotor m_linearMotor = new BSVMotor("LinearMotor");
83 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time 71 private Vector3 m_linearMotorDirection = Vector3.Zero; // velocity requested by LSL, decayed by time
84 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center 72 private Vector3 m_linearMotorOffset = Vector3.Zero; // the point of force can be offset from the center
85 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL 73 private Vector3 m_linearMotorDirectionLASTSET = Vector3.Zero; // velocity requested by LSL
86 private Vector3 m_newVelocity = Vector3.Zero; // velocity computed to be applied to body
87 private Vector3 m_linearFrictionTimescale = Vector3.Zero; 74 private Vector3 m_linearFrictionTimescale = Vector3.Zero;
88 private float m_linearMotorDecayTimescale = 0; 75 private float m_linearMotorDecayTimescale = 0;
89 private float m_linearMotorTimescale = 0; 76 private float m_linearMotorTimescale = 0;
@@ -93,16 +80,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
93 // private Vector3 m_linearMotorOffset = Vector3.Zero; 80 // private Vector3 m_linearMotorOffset = Vector3.Zero;
94 81
95 //Angular properties 82 //Angular properties
83 private BSVMotor m_angularMotor = new BSVMotor("AngularMotor");
96 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor 84 private Vector3 m_angularMotorDirection = Vector3.Zero; // angular velocity requested by LSL motor
97 // private int m_angularMotorApply = 0; // application frame counter 85 // private int m_angularMotorApply = 0; // application frame counter
98 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity 86 private Vector3 m_angularMotorVelocity = Vector3.Zero; // current angular motor velocity
99 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate 87 private float m_angularMotorTimescale = 0; // motor angular velocity ramp up rate
100 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate 88 private float m_angularMotorDecayTimescale = 0; // motor angular velocity decay rate
101 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate 89 private Vector3 m_angularFrictionTimescale = Vector3.Zero; // body angular velocity decay rate
102 private Vector3 m_lastAngularVelocity = Vector3.Zero; // what was last applied to body 90 private Vector3 m_lastAngularVelocity = Vector3.Zero;
103 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body 91 private Vector3 m_lastVertAttractor = Vector3.Zero; // what VA was last applied to body
104 92
105 //Deflection properties 93 //Deflection properties
94 private BSVMotor m_angularDeflectionMotor = new BSVMotor("AngularDeflection");
106 private float m_angularDeflectionEfficiency = 0; 95 private float m_angularDeflectionEfficiency = 0;
107 private float m_angularDeflectionTimescale = 0; 96 private float m_angularDeflectionTimescale = 0;
108 private float m_linearDeflectionEfficiency = 0; 97 private float m_linearDeflectionEfficiency = 0;
@@ -114,6 +103,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
114 private float m_bankingTimescale = 0; 103 private float m_bankingTimescale = 0;
115 104
116 //Hover and Buoyancy properties 105 //Hover and Buoyancy properties
106 private BSVMotor m_hoverMotor = new BSVMotor("Hover");
117 private float m_VhoverHeight = 0f; 107 private float m_VhoverHeight = 0f;
118 private float m_VhoverEfficiency = 0f; 108 private float m_VhoverEfficiency = 0f;
119 private float m_VhoverTimescale = 0f; 109 private float m_VhoverTimescale = 0f;
@@ -124,8 +114,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
124 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity. 114 // Therefore only m_VehicleBuoyancy=1 (0g) will use the script-requested .Z velocity.
125 115
126 //Attractor properties 116 //Attractor properties
127 private float m_verticalAttractionEfficiency = 1.0f; // damped 117 private BSVMotor m_verticalAttractionMotor = new BSVMotor("VerticalAttraction");
128 private float m_verticalAttractionTimescale = 500f; // Timescale > 300 means no vert attractor. 118 private float m_verticalAttractionEfficiency = 1.0f; // damped
119 private float m_verticalAttractionCutoff = 500f; // per the documentation
120 // Timescale > cutoff means no vert attractor.
121 private float m_verticalAttractionTimescale = 510f;
122
123 // Just some recomputed constants:
124 static readonly float PIOverFour = ((float)Math.PI) / 4f;
125 static readonly float PIOverTwo = ((float)Math.PI) / 2f;
129 126
130 public BSDynamics(BSScene myScene, BSPrim myPrim) 127 public BSDynamics(BSScene myScene, BSPrim myPrim)
131 { 128 {
@@ -137,7 +134,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
137 // Return 'true' if this vehicle is doing vehicle things 134 // Return 'true' if this vehicle is doing vehicle things
138 public bool IsActive 135 public bool IsActive
139 { 136 {
140 get { return Type != Vehicle.TYPE_NONE; } 137 get { return Type != Vehicle.TYPE_NONE && Prim.IsPhysical; }
141 } 138 }
142 139
143 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue) 140 internal void ProcessFloatVehicleParam(Vehicle pParam, float pValue)
@@ -152,13 +149,15 @@ namespace OpenSim.Region.Physics.BulletSPlugin
152 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f); 149 m_angularDeflectionTimescale = Math.Max(pValue, 0.01f);
153 break; 150 break;
154 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE: 151 case Vehicle.ANGULAR_MOTOR_DECAY_TIMESCALE:
155 m_angularMotorDecayTimescale = Math.Max(pValue, 0.01f); 152 m_angularMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
153 m_angularMotor.TargetValueDecayTimeScale = m_angularMotorDecayTimescale;
156 break; 154 break;
157 case Vehicle.ANGULAR_MOTOR_TIMESCALE: 155 case Vehicle.ANGULAR_MOTOR_TIMESCALE:
158 m_angularMotorTimescale = Math.Max(pValue, 0.01f); 156 m_angularMotorTimescale = Math.Max(pValue, 0.01f);
157 m_angularMotor.TimeScale = m_angularMotorTimescale;
159 break; 158 break;
160 case Vehicle.BANKING_EFFICIENCY: 159 case Vehicle.BANKING_EFFICIENCY:
161 m_bankingEfficiency = Math.Max(-1f, Math.Min(pValue, 1f)); 160 m_bankingEfficiency = ClampInRange(-1f, pValue, 1f);
162 break; 161 break;
163 case Vehicle.BANKING_MIX: 162 case Vehicle.BANKING_MIX:
164 m_bankingMix = Math.Max(pValue, 0.01f); 163 m_bankingMix = Math.Max(pValue, 0.01f);
@@ -167,10 +166,10 @@ namespace OpenSim.Region.Physics.BulletSPlugin
167 m_bankingTimescale = Math.Max(pValue, 0.01f); 166 m_bankingTimescale = Math.Max(pValue, 0.01f);
168 break; 167 break;
169 case Vehicle.BUOYANCY: 168 case Vehicle.BUOYANCY:
170 m_VehicleBuoyancy = Math.Max(-1f, Math.Min(pValue, 1f)); 169 m_VehicleBuoyancy = ClampInRange(-1f, pValue, 1f);
171 break; 170 break;
172 case Vehicle.HOVER_EFFICIENCY: 171 case Vehicle.HOVER_EFFICIENCY:
173 m_VhoverEfficiency = Math.Max(0f, Math.Min(pValue, 1f)); 172 m_VhoverEfficiency = ClampInRange(0f, pValue, 1f);
174 break; 173 break;
175 case Vehicle.HOVER_HEIGHT: 174 case Vehicle.HOVER_HEIGHT:
176 m_VhoverHeight = pValue; 175 m_VhoverHeight = pValue;
@@ -185,33 +184,40 @@ namespace OpenSim.Region.Physics.BulletSPlugin
185 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f); 184 m_linearDeflectionTimescale = Math.Max(pValue, 0.01f);
186 break; 185 break;
187 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE: 186 case Vehicle.LINEAR_MOTOR_DECAY_TIMESCALE:
188 m_linearMotorDecayTimescale = Math.Max(pValue, 0.01f); 187 m_linearMotorDecayTimescale = ClampInRange(0.01f, pValue, 120);
188 m_linearMotor.TargetValueDecayTimeScale = m_linearMotorDecayTimescale;
189 break; 189 break;
190 case Vehicle.LINEAR_MOTOR_TIMESCALE: 190 case Vehicle.LINEAR_MOTOR_TIMESCALE:
191 m_linearMotorTimescale = Math.Max(pValue, 0.01f); 191 m_linearMotorTimescale = Math.Max(pValue, 0.01f);
192 m_linearMotor.TimeScale = m_linearMotorTimescale;
192 break; 193 break;
193 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY: 194 case Vehicle.VERTICAL_ATTRACTION_EFFICIENCY:
194 m_verticalAttractionEfficiency = Math.Max(0.1f, Math.Min(pValue, 1f)); 195 m_verticalAttractionEfficiency = ClampInRange(0.1f, pValue, 1f);
196 m_verticalAttractionMotor.Efficiency = m_verticalAttractionEfficiency;
195 break; 197 break;
196 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE: 198 case Vehicle.VERTICAL_ATTRACTION_TIMESCALE:
197 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f); 199 m_verticalAttractionTimescale = Math.Max(pValue, 0.01f);
200 m_verticalAttractionMotor.TimeScale = m_verticalAttractionTimescale;
198 break; 201 break;
199 202
200 // These are vector properties but the engine lets you use a single float value to 203 // These are vector properties but the engine lets you use a single float value to
201 // set all of the components to the same value 204 // set all of the components to the same value
202 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 205 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
203 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue); 206 m_angularFrictionTimescale = new Vector3(pValue, pValue, pValue);
207 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
204 break; 208 break;
205 case Vehicle.ANGULAR_MOTOR_DIRECTION: 209 case Vehicle.ANGULAR_MOTOR_DIRECTION:
206 m_angularMotorDirection = new Vector3(pValue, pValue, pValue); 210 m_angularMotorDirection = new Vector3(pValue, pValue, pValue);
207 // m_angularMotorApply = 100; 211 m_angularMotor.SetTarget(m_angularMotorDirection);
208 break; 212 break;
209 case Vehicle.LINEAR_FRICTION_TIMESCALE: 213 case Vehicle.LINEAR_FRICTION_TIMESCALE:
210 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue); 214 m_linearFrictionTimescale = new Vector3(pValue, pValue, pValue);
215 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
211 break; 216 break;
212 case Vehicle.LINEAR_MOTOR_DIRECTION: 217 case Vehicle.LINEAR_MOTOR_DIRECTION:
213 m_linearMotorDirection = new Vector3(pValue, pValue, pValue); 218 m_linearMotorDirection = new Vector3(pValue, pValue, pValue);
214 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue); 219 m_linearMotorDirectionLASTSET = new Vector3(pValue, pValue, pValue);
220 m_linearMotor.SetTarget(m_linearMotorDirection);
215 break; 221 break;
216 case Vehicle.LINEAR_MOTOR_OFFSET: 222 case Vehicle.LINEAR_MOTOR_OFFSET:
217 m_linearMotorOffset = new Vector3(pValue, pValue, pValue); 223 m_linearMotorOffset = new Vector3(pValue, pValue, pValue);
@@ -227,21 +233,24 @@ namespace OpenSim.Region.Physics.BulletSPlugin
227 { 233 {
228 case Vehicle.ANGULAR_FRICTION_TIMESCALE: 234 case Vehicle.ANGULAR_FRICTION_TIMESCALE:
229 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 235 m_angularFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
236 m_angularMotor.FrictionTimescale = m_angularFrictionTimescale;
230 break; 237 break;
231 case Vehicle.ANGULAR_MOTOR_DIRECTION: 238 case Vehicle.ANGULAR_MOTOR_DIRECTION:
232 // Limit requested angular speed to 2 rps= 4 pi rads/sec 239 // Limit requested angular speed to 2 rps= 4 pi rads/sec
233 pValue.X = Math.Max(-12.56f, Math.Min(pValue.X, 12.56f)); 240 pValue.X = ClampInRange(-12.56f, pValue.X, 12.56f);
234 pValue.Y = Math.Max(-12.56f, Math.Min(pValue.Y, 12.56f)); 241 pValue.Y = ClampInRange(-12.56f, pValue.Y, 12.56f);
235 pValue.Z = Math.Max(-12.56f, Math.Min(pValue.Z, 12.56f)); 242 pValue.Z = ClampInRange(-12.56f, pValue.Z, 12.56f);
236 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 243 m_angularMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
237 // m_angularMotorApply = 100; 244 m_angularMotor.SetTarget(m_angularMotorDirection);
238 break; 245 break;
239 case Vehicle.LINEAR_FRICTION_TIMESCALE: 246 case Vehicle.LINEAR_FRICTION_TIMESCALE:
240 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z); 247 m_linearFrictionTimescale = new Vector3(pValue.X, pValue.Y, pValue.Z);
248 m_linearMotor.FrictionTimescale = m_linearFrictionTimescale;
241 break; 249 break;
242 case Vehicle.LINEAR_MOTOR_DIRECTION: 250 case Vehicle.LINEAR_MOTOR_DIRECTION:
243 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z); 251 m_linearMotorDirection = new Vector3(pValue.X, pValue.Y, pValue.Z);
244 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z); 252 m_linearMotorDirectionLASTSET = new Vector3(pValue.X, pValue.Y, pValue.Z);
253 m_linearMotor.SetTarget(m_linearMotorDirection);
245 break; 254 break;
246 case Vehicle.LINEAR_MOTOR_OFFSET: 255 case Vehicle.LINEAR_MOTOR_OFFSET:
247 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z); 256 m_linearMotorOffset = new Vector3(pValue.X, pValue.Y, pValue.Z);
@@ -303,7 +312,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
303 m_VhoverEfficiency = 0; 312 m_VhoverEfficiency = 0;
304 m_VhoverTimescale = 0; 313 m_VhoverTimescale = 0;
305 m_VehicleBuoyancy = 0; 314 m_VehicleBuoyancy = 0;
306 315
307 m_linearDeflectionEfficiency = 1; 316 m_linearDeflectionEfficiency = 1;
308 m_linearDeflectionTimescale = 1; 317 m_linearDeflectionTimescale = 1;
309 318
@@ -319,6 +328,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
319 328
320 m_referenceFrame = Quaternion.Identity; 329 m_referenceFrame = Quaternion.Identity;
321 m_flags = (VehicleFlag)0; 330 m_flags = (VehicleFlag)0;
331
322 break; 332 break;
323 333
324 case Vehicle.TYPE_SLED: 334 case Vehicle.TYPE_SLED:
@@ -351,10 +361,14 @@ namespace OpenSim.Region.Physics.BulletSPlugin
351 m_bankingMix = 1; 361 m_bankingMix = 1;
352 362
353 m_referenceFrame = Quaternion.Identity; 363 m_referenceFrame = Quaternion.Identity;
354 m_flags |= (VehicleFlag.NO_DEFLECTION_UP | VehicleFlag.LIMIT_ROLL_ONLY | VehicleFlag.LIMIT_MOTOR_UP); 364 m_flags &= ~(VehicleFlag.HOVER_WATER_ONLY
355 m_flags &= 365 | VehicleFlag.HOVER_TERRAIN_ONLY
356 ~(VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | 366 | VehicleFlag.HOVER_GLOBAL_HEIGHT
357 VehicleFlag.HOVER_GLOBAL_HEIGHT | VehicleFlag.HOVER_UP_ONLY); 367 | VehicleFlag.HOVER_UP_ONLY);
368 m_flags |= (VehicleFlag.NO_DEFLECTION_UP
369 | VehicleFlag.LIMIT_ROLL_ONLY
370 | VehicleFlag.LIMIT_MOTOR_UP);
371
358 break; 372 break;
359 case Vehicle.TYPE_CAR: 373 case Vehicle.TYPE_CAR:
360 m_linearMotorDirection = Vector3.Zero; 374 m_linearMotorDirection = Vector3.Zero;
@@ -498,6 +512,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
498 m_bankingEfficiency = 0; 512 m_bankingEfficiency = 0;
499 m_bankingMix = 0.7f; 513 m_bankingMix = 0.7f;
500 m_bankingTimescale = 5; 514 m_bankingTimescale = 5;
515
501 m_referenceFrame = Quaternion.Identity; 516 m_referenceFrame = Quaternion.Identity;
502 517
503 m_referenceFrame = Quaternion.Identity; 518 m_referenceFrame = Quaternion.Identity;
@@ -510,6 +525,26 @@ namespace OpenSim.Region.Physics.BulletSPlugin
510 | VehicleFlag.HOVER_GLOBAL_HEIGHT); 525 | VehicleFlag.HOVER_GLOBAL_HEIGHT);
511 break; 526 break;
512 } 527 }
528
529 // Update any physical parameters based on this type.
530 Refresh();
531
532 m_linearMotor = new BSVMotor("LinearMotor", m_linearMotorTimescale,
533 m_linearMotorDecayTimescale, m_linearFrictionTimescale,
534 1f);
535 m_linearMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
536
537 m_angularMotor = new BSVMotor("AngularMotor", m_angularMotorTimescale,
538 m_angularMotorDecayTimescale, m_angularFrictionTimescale,
539 1f);
540 m_angularMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
541
542 m_verticalAttractionMotor = new BSVMotor("VerticalAttraction", m_verticalAttractionTimescale,
543 BSMotor.Infinite, BSMotor.InfiniteVector,
544 m_verticalAttractionEfficiency);
545 // Z goes away and we keep X and Y
546 m_verticalAttractionMotor.FrictionTimescale = new Vector3(BSMotor.Infinite, BSMotor.Infinite, 0.1f);
547 m_verticalAttractionMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG DEBUG (enables detail logging)
513 } 548 }
514 549
515 // Some of the properties of this prim may have changed. 550 // Some of the properties of this prim may have changed.
@@ -518,13 +553,35 @@ namespace OpenSim.Region.Physics.BulletSPlugin
518 { 553 {
519 if (IsActive) 554 if (IsActive)
520 { 555 {
521 // Friction effects are handled by this vehicle code 556 // Remember the mass so we don't have to fetch it every step
522 BulletSimAPI.SetFriction2(Prim.PhysBody.ptr, 0f); 557 m_vehicleMass = Prim.Linkset.LinksetMass;
523 BulletSimAPI.SetHitFraction2(Prim.PhysBody.ptr, 0f);
524 558
525 // BulletSimAPI.SetAngularDamping2(Prim.PhysBody.ptr, 0.8f); 559 // Friction affects are handled by this vehicle code
560 float friction = 0f;
561 PhysicsScene.PE.SetFriction(Prim.PhysBody, friction);
526 562
527 VDetailLog("{0},BSDynamics.Refresh,zeroingFriction and adding damping", Prim.LocalID); 563 // Moderate angular movement introduced by Bullet.
564 // TODO: possibly set AngularFactor and LinearFactor for the type of vehicle.
565 // Maybe compute linear and angular factor and damping from params.
566 float angularDamping = BSParam.VehicleAngularDamping;
567 PhysicsScene.PE.SetAngularDamping(Prim.PhysBody, angularDamping);
568
569 // Vehicles report collision events so we know when it's on the ground
570 PhysicsScene.PE.AddToCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
571
572 Vector3 localInertia = PhysicsScene.PE.CalculateLocalInertia(Prim.PhysShape, m_vehicleMass);
573 PhysicsScene.PE.SetMassProps(Prim.PhysBody, m_vehicleMass, localInertia);
574 PhysicsScene.PE.UpdateInertiaTensor(Prim.PhysBody);
575
576 Vector3 grav = PhysicsScene.DefaultGravity * (1f - Prim.Buoyancy);
577 PhysicsScene.PE.SetGravity(Prim.PhysBody, grav);
578
579 VDetailLog("{0},BSDynamics.Refresh,mass={1},frict={2},inert={3},aDamp={4}",
580 Prim.LocalID, m_vehicleMass, friction, localInertia, angularDamping);
581 }
582 else
583 {
584 PhysicsScene.PE.RemoveFromCollisionFlags(Prim.PhysBody, CollisionFlags.BS_VEHICLE_COLLISIONS);
528 } 585 }
529 } 586 }
530 587
@@ -546,116 +603,342 @@ namespace OpenSim.Region.Physics.BulletSPlugin
546 Refresh(); 603 Refresh();
547 } 604 }
548 605
606 #region Known vehicle value functions
607 // Vehicle physical parameters that we buffer from constant getting and setting.
608 // The "m_known*" values are unknown until they are fetched and the m_knownHas flag is set.
609 // Changing is remembered and the parameter is stored back into the physics engine only if updated.
610 // This does two things: 1) saves continuious calls into unmanaged code, and
611 // 2) signals when a physics property update must happen back to the simulator
612 // to update values modified for the vehicle.
613 private int m_knownChanged;
614 private int m_knownHas;
615 private float m_knownTerrainHeight;
616 private float m_knownWaterLevel;
617 private Vector3 m_knownPosition;
618 private Vector3 m_knownVelocity;
619 private Vector3 m_knownForce;
620 private Quaternion m_knownOrientation;
621 private Vector3 m_knownRotationalVelocity;
622 private Vector3 m_knownRotationalForce;
623 private Vector3 m_knownForwardVelocity; // vehicle relative forward speed
624
625 private const int m_knownChangedPosition = 1 << 0;
626 private const int m_knownChangedVelocity = 1 << 1;
627 private const int m_knownChangedForce = 1 << 2;
628 private const int m_knownChangedOrientation = 1 << 3;
629 private const int m_knownChangedRotationalVelocity = 1 << 4;
630 private const int m_knownChangedRotationalForce = 1 << 5;
631 private const int m_knownChangedTerrainHeight = 1 << 6;
632 private const int m_knownChangedWaterLevel = 1 << 7;
633 private const int m_knownChangedForwardVelocity = 1 << 8;
634
635 private void ForgetKnownVehicleProperties()
636 {
637 m_knownHas = 0;
638 m_knownChanged = 0;
639 }
640 // Push all the changed values back into the physics engine
641 private void PushKnownChanged()
642 {
643 if (m_knownChanged != 0)
644 {
645 if ((m_knownChanged & m_knownChangedPosition) != 0)
646 Prim.ForcePosition = m_knownPosition;
647
648 if ((m_knownChanged & m_knownChangedOrientation) != 0)
649 Prim.ForceOrientation = m_knownOrientation;
650
651 if ((m_knownChanged & m_knownChangedVelocity) != 0)
652 {
653 Prim.ForceVelocity = m_knownVelocity;
654 PhysicsScene.PE.SetInterpolationLinearVelocity(Prim.PhysBody, VehicleVelocity);
655 }
656
657 if ((m_knownChanged & m_knownChangedForce) != 0)
658 Prim.AddForce((Vector3)m_knownForce, false, true);
659
660 if ((m_knownChanged & m_knownChangedRotationalVelocity) != 0)
661 {
662 Prim.ForceRotationalVelocity = m_knownRotationalVelocity;
663 // Fake out Bullet by making it think the velocity is the same as last time.
664 PhysicsScene.PE.SetInterpolationAngularVelocity(Prim.PhysBody, m_knownRotationalVelocity);
665 }
666
667 if ((m_knownChanged & m_knownChangedRotationalForce) != 0)
668 Prim.AddAngularForce((Vector3)m_knownRotationalForce, false, true);
669
670 // If we set one of the values (ie, the physics engine didn't do it) we must force
671 // an UpdateProperties event to send the changes up to the simulator.
672 PhysicsScene.PE.PushUpdate(Prim.PhysBody);
673 }
674 m_knownChanged = 0;
675 }
676
677 // Since the computation of terrain height can be a little involved, this routine
678 // is used to fetch the height only once for each vehicle simulation step.
679 private float GetTerrainHeight(Vector3 pos)
680 {
681 if ((m_knownHas & m_knownChangedTerrainHeight) == 0)
682 {
683 m_knownTerrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos);
684 m_knownHas |= m_knownChangedTerrainHeight;
685 }
686 return m_knownTerrainHeight;
687 }
688
689 // Since the computation of water level can be a little involved, this routine
690 // is used ot fetch the level only once for each vehicle simulation step.
691 private float GetWaterLevel(Vector3 pos)
692 {
693 if ((m_knownHas & m_knownChangedWaterLevel) == 0)
694 {
695 m_knownWaterLevel = Prim.PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(pos);
696 m_knownHas |= m_knownChangedWaterLevel;
697 }
698 return (float)m_knownWaterLevel;
699 }
700
701 private Vector3 VehiclePosition
702 {
703 get
704 {
705 if ((m_knownHas & m_knownChangedPosition) == 0)
706 {
707 m_knownPosition = Prim.ForcePosition;
708 m_knownHas |= m_knownChangedPosition;
709 }
710 return m_knownPosition;
711 }
712 set
713 {
714 m_knownPosition = value;
715 m_knownChanged |= m_knownChangedPosition;
716 m_knownHas |= m_knownChangedPosition;
717 }
718 }
719
720 private Quaternion VehicleOrientation
721 {
722 get
723 {
724 if ((m_knownHas & m_knownChangedOrientation) == 0)
725 {
726 m_knownOrientation = Prim.ForceOrientation;
727 m_knownHas |= m_knownChangedOrientation;
728 }
729 return m_knownOrientation;
730 }
731 set
732 {
733 m_knownOrientation = value;
734 m_knownChanged |= m_knownChangedOrientation;
735 m_knownHas |= m_knownChangedOrientation;
736 }
737 }
738
739 private Vector3 VehicleVelocity
740 {
741 get
742 {
743 if ((m_knownHas & m_knownChangedVelocity) == 0)
744 {
745 m_knownVelocity = Prim.ForceVelocity;
746 m_knownHas |= m_knownChangedVelocity;
747 }
748 return (Vector3)m_knownVelocity;
749 }
750 set
751 {
752 m_knownVelocity = value;
753 m_knownChanged |= m_knownChangedVelocity;
754 m_knownHas |= m_knownChangedVelocity;
755 }
756 }
757
758 private void VehicleAddForce(Vector3 aForce)
759 {
760 if ((m_knownHas & m_knownChangedForce) == 0)
761 {
762 m_knownForce = Vector3.Zero;
763 }
764 m_knownForce += aForce;
765 m_knownChanged |= m_knownChangedForce;
766 m_knownHas |= m_knownChangedForce;
767 }
768
769 private Vector3 VehicleRotationalVelocity
770 {
771 get
772 {
773 if ((m_knownHas & m_knownChangedRotationalVelocity) == 0)
774 {
775 m_knownRotationalVelocity = Prim.ForceRotationalVelocity;
776 m_knownHas |= m_knownChangedRotationalVelocity;
777 }
778 return (Vector3)m_knownRotationalVelocity;
779 }
780 set
781 {
782 m_knownRotationalVelocity = value;
783 m_knownChanged |= m_knownChangedRotationalVelocity;
784 m_knownHas |= m_knownChangedRotationalVelocity;
785 }
786 }
787 private void VehicleAddAngularForce(Vector3 aForce)
788 {
789 if ((m_knownHas & m_knownChangedRotationalForce) == 0)
790 {
791 m_knownRotationalForce = Vector3.Zero;
792 }
793 m_knownRotationalForce += aForce;
794 m_knownChanged |= m_knownChangedRotationalForce;
795 m_knownHas |= m_knownChangedRotationalForce;
796 }
797 // Vehicle relative forward velocity
798 private Vector3 VehicleForwardVelocity
799 {
800 get
801 {
802 if ((m_knownHas & m_knownChangedForwardVelocity) == 0)
803 {
804 m_knownForwardVelocity = VehicleVelocity * Quaternion.Inverse(Quaternion.Normalize(VehicleOrientation));
805 m_knownHas |= m_knownChangedForwardVelocity;
806 }
807 return m_knownForwardVelocity;
808 }
809 }
810 private float VehicleForwardSpeed
811 {
812 get
813 {
814 return VehicleForwardVelocity.X;
815 }
816 }
817
818 #endregion // Known vehicle value functions
819
549 // One step of the vehicle properties for the next 'pTimestep' seconds. 820 // One step of the vehicle properties for the next 'pTimestep' seconds.
550 internal void Step(float pTimestep) 821 internal void Step(float pTimestep)
551 { 822 {
552 if (!IsActive) return; 823 if (!IsActive) return;
553 824
554 // DEBUG 825 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
555 // Because Bullet does apply forces to the vehicle, our last computed 826 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
556 // linear and angular velocities are not what is happening now.
557 // Vector3 externalAngularVelocity = Prim.ForceRotationalVelocity - m_lastAngularVelocity;
558 // m_lastAngularVelocity += (externalAngularVelocity * 0.5f) * pTimestep;
559 // m_lastAngularVelocity = Prim.ForceRotationalVelocity; // DEBUG: account for what Bullet did last time
560 // m_lastLinearVelocityVector = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG:
561 // END DEBUG
562 827
563 m_vehicleMass = Prim.Linkset.LinksetMass; 828 ForgetKnownVehicleProperties();
564 829
565 MoveLinear(pTimestep); 830 MoveLinear(pTimestep);
566 // Commented out for debug
567 MoveAngular(pTimestep); 831 MoveAngular(pTimestep);
568 // Prim.ApplyTorqueImpulse(-Prim.RotationalVelocity * m_vehicleMass, false); // DEBUG DEBUG
569 // Prim.ForceRotationalVelocity = -Prim.RotationalVelocity; // DEBUG DEBUG
570 832
571 LimitRotation(pTimestep); 833 LimitRotation(pTimestep);
572 834
573 // remember the position so next step we can limit absolute movement effects 835 // remember the position so next step we can limit absolute movement effects
574 m_lastPositionVector = Prim.ForcePosition; 836 m_lastPositionVector = VehiclePosition;
575 837
576 VDetailLog("{0},BSDynamics.Step,frict={1},grav={2},inertia={3},mass={4}", // DEBUG DEBUG 838 // If we forced the changing of some vehicle parameters, update the values and
577 Prim.LocalID, 839 // for the physics engine to note the changes so an UpdateProperties event will happen.
578 BulletSimAPI.GetFriction2(Prim.PhysBody.ptr), 840 PushKnownChanged();
579 BulletSimAPI.GetGravity2(Prim.PhysBody.ptr), 841
580 Prim.Inertia, 842 if (PhysicsScene.VehiclePhysicalLoggingEnabled)
581 m_vehicleMass 843 PhysicsScene.PE.DumpRigidBody(PhysicsScene.World, Prim.PhysBody);
582 ); 844
583 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}", 845 VDetailLog("{0},BSDynamics.Step,done,pos={1},force={2},velocity={3},angvel={4}",
584 Prim.LocalID, Prim.ForcePosition, Prim.Force, Prim.ForceVelocity, Prim.RotationalVelocity); 846 Prim.LocalID, VehiclePosition, Prim.Force, VehicleVelocity, VehicleRotationalVelocity);
585 }// end Step 847 }
586 848
587 // Apply the effect of the linear motor. 849 // Apply the effect of the linear motor and other linear motions (like hover and float).
588 // Also does hover and float.
589 private void MoveLinear(float pTimestep) 850 private void MoveLinear(float pTimestep)
590 { 851 {
591 // m_linearMotorDirection is the target direction we are moving relative to the vehicle coordinates 852 Vector3 linearMotorContribution = m_linearMotor.Step(pTimestep);
592 // m_lastLinearVelocityVector is the current speed we are moving in that direction
593 if (m_linearMotorDirection.LengthSquared() > 0.001f)
594 {
595 Vector3 origDir = m_linearMotorDirection; // DEBUG
596 Vector3 origVel = m_lastLinearVelocityVector; // DEBUG
597 // DEBUG: the vehicle velocity rotated to be relative to vehicle coordinates for comparison
598 Vector3 vehicleVelocity = Prim.ForceVelocity * Quaternion.Inverse(Prim.ForceOrientation); // DEBUG
599 853
600 // Add (desiredVelocity - lastAppliedVelocity) / howLongItShouldTakeToComplete 854 // The movement computed in the linear motor is relative to the vehicle
601 Vector3 addAmount = (m_linearMotorDirection - m_lastLinearVelocityVector)/(m_linearMotorTimescale) * pTimestep; 855 // coordinates. Rotate the movement to world coordinates.
602 m_lastLinearVelocityVector += addAmount; 856 linearMotorContribution *= VehicleOrientation;
603 857
604 float decayFactor = (1.0f / m_linearMotorDecayTimescale) * pTimestep; 858 // ==================================================================
605 m_linearMotorDirection *= (1f - decayFactor); 859 // Buoyancy: force to overcome gravity.
860 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g;
861 // So, if zero, don't change anything (let gravity happen). If one, negate the effect of gravity.
862 Vector3 buoyancyContribution = Prim.PhysicsScene.DefaultGravity * m_VehicleBuoyancy;
606 863
607 // Rotate new object velocity from vehicle relative to world coordinates 864 Vector3 terrainHeightContribution = ComputeLinearTerrainHeightCorrection(pTimestep);
608 m_newVelocity = m_lastLinearVelocityVector * Prim.ForceOrientation;
609 865
610 // Apply friction for next time 866 Vector3 hoverContribution = ComputeLinearHover(pTimestep);
611 Vector3 frictionFactor = (Vector3.One / m_linearFrictionTimescale) * pTimestep;
612 m_lastLinearVelocityVector *= (Vector3.One - frictionFactor);
613 867
614 VDetailLog("{0},MoveLinear,nonZero,origlmDir={1},origlvVel={2},vehVel={3},add={4},decay={5},frict={6},lmDir={7},lvVec={8},newVel={9}", 868 ComputeLinearBlockingEndPoint(pTimestep);
615 Prim.LocalID, origDir, origVel, vehicleVelocity, addAmount, decayFactor, frictionFactor, 869
616 m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity); 870 Vector3 limitMotorUpContribution = ComputeLinearMotorUp(pTimestep);
617 } 871
618 else 872 // ==================================================================
619 { 873 Vector3 newVelocity = linearMotorContribution
620 // if what remains of direction is very small, zero it. 874 + terrainHeightContribution
621 m_linearMotorDirection = Vector3.Zero; 875 + hoverContribution
622 m_lastLinearVelocityVector = Vector3.Zero; 876 + limitMotorUpContribution;
623 m_newVelocity = Vector3.Zero; 877
878 Vector3 newForce = buoyancyContribution;
879
880 // If not changing some axis, reduce out velocity
881 if ((m_flags & (VehicleFlag.NO_X)) != 0)
882 newVelocity.X = 0;
883 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
884 newVelocity.Y = 0;
885 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
886 newVelocity.Z = 0;
624 887
625 VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 888 // ==================================================================
889 // Clamp high or low velocities
890 float newVelocityLengthSq = newVelocity.LengthSquared();
891 if (newVelocityLengthSq > 1000f)
892 {
893 newVelocity /= newVelocity.Length();
894 newVelocity *= 1000f;
626 } 895 }
896 else if (newVelocityLengthSq < 0.001f)
897 newVelocity = Vector3.Zero;
627 898
628 // m_newVelocity is velocity computed from linear motor in world coordinates 899 // ==================================================================
900 // Stuff new linear velocity into the vehicle.
901 // Since the velocity is just being set, it is not scaled by pTimeStep. Bullet will do that for us.
902 VehicleVelocity = newVelocity;
629 903
630 // Gravity and Buoyancy 904 // Other linear forces are applied as forces.
631 // There is some gravity, make a gravity force vector that is applied after object velocity. 905 Vector3 totalDownForce = newForce * m_vehicleMass;
632 // m_VehicleBuoyancy: -1=2g; 0=1g; 1=0g; 906 if (!totalDownForce.ApproxEquals(Vector3.Zero, 0.01f))
633 Vector3 grav = Prim.PhysicsScene.DefaultGravity * (1f - m_VehicleBuoyancy); 907 {
908 VehicleAddForce(totalDownForce);
909 }
634 910
635 /* 911 VDetailLog("{0}, MoveLinear,done,newVel={1},totDown={2},IsColliding={3}",
636 * RA: Not sure why one would do this unless we are hoping external forces are doing gravity, ... 912 Prim.LocalID, newVelocity, totalDownForce, Prim.IsColliding);
637 // Preserve the current Z velocity 913 VDetailLog("{0}, MoveLinear,done,linContrib={1},terrContrib={2},hoverContrib={3},limitContrib={4},buoyContrib={5}",
638 Vector3 vel_now = m_prim.Velocity; 914 Prim.LocalID,
639 m_dir.Z = vel_now.Z; // Preserve the accumulated falling velocity 915 linearMotorContribution, terrainHeightContribution, hoverContribution,
640 */ 916 limitMotorUpContribution, buoyancyContribution
917 );
641 918
642 Vector3 pos = Prim.ForcePosition; 919 } // end MoveLinear()
643// Vector3 accel = new Vector3(-(m_dir.X - m_lastLinearVelocityVector.X / 0.1f), -(m_dir.Y - m_lastLinearVelocityVector.Y / 0.1f), m_dir.Z - m_lastLinearVelocityVector.Z / 0.1f);
644 920
921 public Vector3 ComputeLinearTerrainHeightCorrection(float pTimestep)
922 {
923 Vector3 ret = Vector3.Zero;
645 // If below the terrain, move us above the ground a little. 924 // If below the terrain, move us above the ground a little.
646 float terrainHeight = Prim.PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(pos); 925 // TODO: Consider taking the rotated size of the object or possibly casting a ray.
647 // Taking the rotated size doesn't work here because m_prim.Size is the size of the root prim and not the linkset. 926 if (VehiclePosition.Z < GetTerrainHeight(VehiclePosition))
648 // TODO: Add a m_prim.LinkSet.Size similar to m_prim.LinkSet.Mass.
649 // Vector3 rotatedSize = m_prim.Size * m_prim.ForceOrientation;
650 // if (rotatedSize.Z < terrainHeight)
651 if (pos.Z < terrainHeight)
652 { 927 {
653 pos.Z = terrainHeight + 2; 928 // TODO: correct position by applying force rather than forcing position.
654 Prim.ForcePosition = pos; 929 Vector3 newPosition = VehiclePosition;
655 VDetailLog("{0},MoveLinear,terrainHeight,terrainHeight={1},pos={2}", Prim.LocalID, terrainHeight, pos); 930 newPosition.Z = GetTerrainHeight(VehiclePosition) + 1f;
931 VehiclePosition = newPosition;
932 VDetailLog("{0}, MoveLinear,terrainHeight,terrainHeight={1},pos={2}",
933 Prim.LocalID, GetTerrainHeight(VehiclePosition), VehiclePosition);
656 } 934 }
935 return ret;
936 }
937
938 public Vector3 ComputeLinearHover(float pTimestep)
939 {
940 Vector3 ret = Vector3.Zero;
657 941
658 // Check if hovering
659 // m_VhoverEfficiency: 0=bouncy, 1=totally damped 942 // m_VhoverEfficiency: 0=bouncy, 1=totally damped
660 // m_VhoverTimescale: time to achieve height 943 // m_VhoverTimescale: time to achieve height
661 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0) 944 if ((m_flags & (VehicleFlag.HOVER_WATER_ONLY | VehicleFlag.HOVER_TERRAIN_ONLY | VehicleFlag.HOVER_GLOBAL_HEIGHT)) != 0)
@@ -663,11 +946,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
663 // We should hover, get the target height 946 // We should hover, get the target height
664 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0) 947 if ((m_flags & VehicleFlag.HOVER_WATER_ONLY) != 0)
665 { 948 {
666 m_VhoverTargetHeight = Prim.PhysicsScene.GetWaterLevelAtXYZ(pos) + m_VhoverHeight; 949 m_VhoverTargetHeight = GetWaterLevel(VehiclePosition) + m_VhoverHeight;
667 } 950 }
668 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0) 951 if ((m_flags & VehicleFlag.HOVER_TERRAIN_ONLY) != 0)
669 { 952 {
670 m_VhoverTargetHeight = terrainHeight + m_VhoverHeight; 953 m_VhoverTargetHeight = GetTerrainHeight(VehiclePosition) + m_VhoverHeight;
671 } 954 }
672 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0) 955 if ((m_flags & VehicleFlag.HOVER_GLOBAL_HEIGHT) != 0)
673 { 956 {
@@ -677,45 +960,47 @@ namespace OpenSim.Region.Physics.BulletSPlugin
677 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0) 960 if ((m_flags & VehicleFlag.HOVER_UP_ONLY) != 0)
678 { 961 {
679 // If body is already heigher, use its height as target height 962 // If body is already heigher, use its height as target height
680 if (pos.Z > m_VhoverTargetHeight) 963 if (VehiclePosition.Z > m_VhoverTargetHeight)
681 m_VhoverTargetHeight = pos.Z; 964 m_VhoverTargetHeight = VehiclePosition.Z;
682 } 965 }
966
683 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0) 967 if ((m_flags & VehicleFlag.LOCK_HOVER_HEIGHT) != 0)
684 { 968 {
685 if (Math.Abs(pos.Z - m_VhoverTargetHeight) > 0.2f) 969 if (Math.Abs(VehiclePosition.Z - m_VhoverTargetHeight) > 0.2f)
686 { 970 {
971 Vector3 pos = VehiclePosition;
687 pos.Z = m_VhoverTargetHeight; 972 pos.Z = m_VhoverTargetHeight;
688 Prim.ForcePosition = pos; 973 VehiclePosition = pos;
689 } 974 }
690 } 975 }
691 else 976 else
692 { 977 {
693 float verticalError = pos.Z - m_VhoverTargetHeight; 978 // Error is positive if below the target and negative if above.
694 // RA: where does the 50 come from? 979 float verticalError = m_VhoverTargetHeight - VehiclePosition.Z;
695 float verticalCorrectionVelocity = pTimestep * ((verticalError * 50.0f) / m_VhoverTimescale); 980 float verticalCorrectionVelocity = verticalError / m_VhoverTimescale;
696 // Replace Vertical speed with correction figure if significant 981
697 if (Math.Abs(verticalError) > 0.01f) 982 // TODO: implement m_VhoverEfficiency correctly
698 { 983 if (Math.Abs(verticalError) > m_VhoverEfficiency)
699 m_newVelocity.Z += verticalCorrectionVelocity;
700 //KF: m_VhoverEfficiency is not yet implemented
701 }
702 else if (verticalError < -0.01)
703 {
704 m_newVelocity.Z -= verticalCorrectionVelocity;
705 }
706 else
707 { 984 {
708 m_newVelocity.Z = 0f; 985 ret = new Vector3(0f, 0f, verticalCorrectionVelocity);
709 } 986 }
710 } 987 }
711 988
712 VDetailLog("{0},MoveLinear,hover,pos={1},dir={2},height={3},target={4}", Prim.LocalID, pos, m_newVelocity, m_VhoverHeight, m_VhoverTargetHeight); 989 VDetailLog("{0}, MoveLinear,hover,pos={1},ret={2},hoverTS={3},height={4},target={5}",
990 Prim.LocalID, VehiclePosition, ret, m_VhoverTimescale, m_VhoverHeight, m_VhoverTargetHeight);
713 } 991 }
714 992
993 return ret;
994 }
995
996 public bool ComputeLinearBlockingEndPoint(float pTimestep)
997 {
998 bool changed = false;
999
1000 Vector3 pos = VehiclePosition;
715 Vector3 posChange = pos - m_lastPositionVector; 1001 Vector3 posChange = pos - m_lastPositionVector;
716 if (m_BlockingEndPoint != Vector3.Zero) 1002 if (m_BlockingEndPoint != Vector3.Zero)
717 { 1003 {
718 bool changed = false;
719 if (pos.X >= (m_BlockingEndPoint.X - (float)1)) 1004 if (pos.X >= (m_BlockingEndPoint.X - (float)1))
720 { 1005 {
721 pos.X -= posChange.X + 1; 1006 pos.X -= posChange.X + 1;
@@ -743,233 +1028,109 @@ namespace OpenSim.Region.Physics.BulletSPlugin
743 } 1028 }
744 if (changed) 1029 if (changed)
745 { 1030 {
746 Prim.ForcePosition = pos; 1031 VehiclePosition = pos;
747 VDetailLog("{0},MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}", 1032 VDetailLog("{0}, MoveLinear,blockingEndPoint,block={1},origPos={2},pos={3}",
748 Prim.LocalID, m_BlockingEndPoint, posChange, pos); 1033 Prim.LocalID, m_BlockingEndPoint, posChange, pos);
749 } 1034 }
750 } 1035 }
1036 return changed;
1037 }
751 1038
752 #region downForce 1039 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
753 Vector3 downForce = Vector3.Zero; 1040 // Prevent ground vehicles from motoring into the sky. This flag has a subtle effect when
1041 // used with conjunction with banking: the strength of the banking will decay when the
1042 // vehicle no longer experiences collisions. The decay timescale is the same as
1043 // VEHICLE_BANKING_TIMESCALE. This is to help prevent ground vehicles from steering
1044 // when they are in mid jump.
1045 // TODO: this code is wrong. Also, what should it do for boats (height from water)?
1046 // This is just using the ground and a general collision check. Should really be using
1047 // a downward raycast to find what is below.
1048 public Vector3 ComputeLinearMotorUp(float pTimestep)
1049 {
1050 Vector3 ret = Vector3.Zero;
1051 float distanceAboveGround = 0f;
754 1052
755 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0) 1053 if ((m_flags & (VehicleFlag.LIMIT_MOTOR_UP)) != 0)
756 { 1054 {
757 // If the vehicle is motoring into the sky, get it going back down. 1055 float targetHeight = Type == Vehicle.TYPE_BOAT ? GetWaterLevel(VehiclePosition) : GetTerrainHeight(VehiclePosition);
758 // Is this an angular force or both linear and angular?? 1056 distanceAboveGround = VehiclePosition.Z - targetHeight;
759 float distanceAboveGround = pos.Z - terrainHeight; 1057 // Not colliding if the vehicle is off the ground
760 if (distanceAboveGround > 2f) 1058 if (!Prim.IsColliding)
761 { 1059 {
762 // downForce = new Vector3(0, 0, (-distanceAboveGround / m_bankingTimescale) * pTimestep);
763 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale); 1060 // downForce = new Vector3(0, 0, -distanceAboveGround / m_bankingTimescale);
764 downForce = new Vector3(0, 0, -distanceAboveGround); 1061 ret = new Vector3(0, 0, -distanceAboveGround);
765 } 1062 }
766 // TODO: this calculation is all wrong. From the description at 1063 // TODO: this calculation is wrong. From the description at
767 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce 1064 // (http://wiki.secondlife.com/wiki/Category:LSL_Vehicle), the downForce
768 // has a decay factor. This says this force should 1065 // has a decay factor. This says this force should
769 // be computed with a motor. 1066 // be computed with a motor.
770 VDetailLog("{0},MoveLinear,limitMotorUp,distAbove={1},downForce={2}", 1067 // TODO: add interaction with banking.
771 Prim.LocalID, distanceAboveGround, downForce);
772 }
773 #endregion // downForce
774
775 // If not changing some axis, reduce out velocity
776 if ((m_flags & (VehicleFlag.NO_X)) != 0)
777 m_newVelocity.X = 0;
778 if ((m_flags & (VehicleFlag.NO_Y)) != 0)
779 m_newVelocity.Y = 0;
780 if ((m_flags & (VehicleFlag.NO_Z)) != 0)
781 m_newVelocity.Z = 0;
782
783 // Clamp REALLY high or low velocities
784 if (m_newVelocity.LengthSquared() > 1e6f)
785 {
786 m_newVelocity /= m_newVelocity.Length();
787 m_newVelocity *= 1000f;
788 }
789 else if (m_newVelocity.LengthSquared() < 1e-6f)
790 m_newVelocity = Vector3.Zero;
791
792 // Stuff new linear velocity into the vehicle
793 Prim.ForceVelocity = m_newVelocity;
794 // Prim.ApplyForceImpulse((m_newVelocity - Prim.Velocity) * m_vehicleMass, false); // DEBUG DEBUG
795
796 Vector3 totalDownForce = downForce + grav;
797 if (totalDownForce != Vector3.Zero)
798 {
799 Prim.AddForce(totalDownForce * m_vehicleMass, false);
800 // Prim.ApplyForceImpulse(totalDownForce * m_vehicleMass, false);
801 } 1068 }
802 1069 VDetailLog("{0}, MoveLinear,limitMotorUp,distAbove={1},colliding={2},ret={3}",
803 VDetailLog("{0},MoveLinear,done,lmDir={1},lmVel={2},newVel={3},primVel={4},totalDown={5}", 1070 Prim.LocalID, distanceAboveGround, Prim.IsColliding, ret);
804 Prim.LocalID, m_linearMotorDirection, m_lastLinearVelocityVector, m_newVelocity, Prim.Velocity, totalDownForce); 1071 return ret;
805 1072 }
806 } // end MoveLinear()
807 1073
808 // ======================================================================= 1074 // =======================================================================
1075 // =======================================================================
809 // Apply the effect of the angular motor. 1076 // Apply the effect of the angular motor.
1077 // The 'contribution' is how much angular correction velocity each function wants.
1078 // All the contributions are added together and the resulting velocity is
1079 // set directly on the vehicle.
810 private void MoveAngular(float pTimestep) 1080 private void MoveAngular(float pTimestep)
811 { 1081 {
812 // m_angularMotorDirection // angular velocity requested by LSL motor 1082 // The user wants this many radians per second angular change?
813 // m_angularMotorApply // application frame counter 1083 Vector3 angularMotorContribution = m_angularMotor.Step(pTimestep);
814 // m_angularMotorVelocity // current angular motor velocity (ramps up and down) 1084
815 // m_angularMotorTimescale // motor angular velocity ramp up rate 1085 // ==================================================================
816 // m_angularMotorDecayTimescale // motor angular velocity decay rate 1086 // From http://wiki.secondlife.com/wiki/LlSetVehicleFlags :
817 // m_angularFrictionTimescale // body angular velocity decay rate 1087 // This flag prevents linear deflection parallel to world z-axis. This is useful
818 // m_lastAngularVelocity // what was last applied to body 1088 // for preventing ground vehicles with large linear deflection, like bumper cars,
819 1089 // from climbing their linear deflection into the sky.
820 if (m_angularMotorDirection.LengthSquared() > 0.0001) 1090 // That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
821 { 1091 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
822 Vector3 origVel = m_angularMotorVelocity;
823 Vector3 origDir = m_angularMotorDirection;
824
825 // new velocity += error / ( time to get there / step interval)
826 // requested direction - current vehicle direction
827 m_angularMotorVelocity += (m_angularMotorDirection - m_angularMotorVelocity) / (m_angularMotorTimescale / pTimestep);
828 // decay requested direction
829 m_angularMotorDirection *= (1.0f - (pTimestep * 1.0f/m_angularMotorDecayTimescale));
830
831 VDetailLog("{0},MoveAngular,angularMotorApply,angTScale={1},timeStep={2},origvel={3},origDir={4},vel={5}",
832 Prim.LocalID, m_angularMotorTimescale, pTimestep, origVel, origDir, m_angularMotorVelocity);
833 }
834 else
835 { 1092 {
836 m_angularMotorVelocity = Vector3.Zero; 1093 angularMotorContribution.X = 0f;
1094 angularMotorContribution.Y = 0f;
1095 VDetailLog("{0}, MoveAngular,noDeflectionUp,angularMotorContrib={1}", Prim.LocalID, angularMotorContribution);
837 } 1096 }
838 1097
839 #region Vertical attactor 1098 Vector3 verticalAttractionContribution = ComputeAngularVerticalAttraction();
840
841 Vector3 vertattr = Vector3.Zero;
842 Vector3 deflection = Vector3.Zero;
843 Vector3 banking = Vector3.Zero;
844
845 // If vertical attaction timescale is reasonable and we applied an angular force last time...
846 if (m_verticalAttractionTimescale < 300 && m_lastAngularVelocity != Vector3.Zero)
847 {
848 float VAservo = pTimestep * 0.2f / m_verticalAttractionTimescale;
849 if (Prim.IsColliding)
850 VAservo = pTimestep * 0.05f / (m_verticalAttractionTimescale);
851
852 VAservo *= (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
853
854 // Create a vector of the vehicle "up" in world coordinates
855 Vector3 verticalError = Vector3.UnitZ * Prim.ForceOrientation;
856 // verticalError.X and .Y are the World error amounts. They are 0 when there is no
857 // error (Vehicle Body is 'vertical'), and .Z will be 1. As the body leans to its
858 // side |.X| will increase to 1 and .Z fall to 0. As body inverts |.X| will fall
859 // and .Z will go // negative. Similar for tilt and |.Y|. .X and .Y must be
860 // modulated to prevent a stable inverted body.
861
862 // Error is 0 (no error) to +/- 2 (max error)
863 if (verticalError.Z < 0.0f)
864 {
865 verticalError.X = 2.0f - verticalError.X;
866 verticalError.Y = 2.0f - verticalError.Y;
867 }
868 // scale it by VAservo (timestep and timescale)
869 verticalError = verticalError * VAservo;
870
871 // As the body rotates around the X axis, then verticalError.Y increases; Rotated around Y
872 // then .X increases, so change Body angular velocity X based on Y, and Y based on X.
873 // Z is not changed.
874 vertattr.X = verticalError.Y;
875 vertattr.Y = - verticalError.X;
876 vertattr.Z = 0f;
877 1099
878 // scaling appears better usingsquare-law 1100 Vector3 deflectionContribution = ComputeAngularDeflection();
879 Vector3 angularVelocity = Prim.ForceRotationalVelocity;
880 float bounce = 1.0f - (m_verticalAttractionEfficiency * m_verticalAttractionEfficiency);
881 vertattr.X += bounce * angularVelocity.X;
882 vertattr.Y += bounce * angularVelocity.Y;
883 1101
884 VDetailLog("{0},MoveAngular,verticalAttraction,VAservo={1},effic={2},verticalError={3},bounce={4},vertattr={5}", 1102 Vector3 bankingContribution = ComputeAngularBanking();
885 Prim.LocalID, VAservo, m_verticalAttractionEfficiency, verticalError, bounce, vertattr);
886 1103
887 } 1104 // ==================================================================
888 #endregion // Vertical attactor 1105 m_lastVertAttractor = verticalAttractionContribution;
889 1106
890 #region Deflection 1107 m_lastAngularVelocity = angularMotorContribution
1108 + verticalAttractionContribution
1109 + deflectionContribution
1110 + bankingContribution;
891 1111
892 if (m_angularDeflectionEfficiency != 0) 1112 // ==================================================================
1113 // Apply the correction velocity.
1114 // TODO: Should this be applied as an angular force (torque)?
1115 if (!m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f))
893 { 1116 {
894 // Compute a scaled vector that points in the preferred axis (X direction) 1117 VehicleRotationalVelocity = m_lastAngularVelocity;
895 Vector3 scaledDefaultDirection =
896 new Vector3((pTimestep * 10 * (m_angularDeflectionEfficiency / m_angularDeflectionTimescale)), 0, 0);
897 // Adding the current vehicle orientation and reference frame displaces the orientation to the frame.
898 // Rotate the scaled default axix relative to the actual vehicle direction giving where it should point.
899 Vector3 preferredAxisOfMotion = scaledDefaultDirection * Quaternion.Add(Prim.ForceOrientation, m_referenceFrame);
900
901 // Scale by efficiency and timescale
902 deflection = (preferredAxisOfMotion * (m_angularDeflectionEfficiency) / m_angularDeflectionTimescale) * pTimestep;
903
904 VDetailLog("{0},MoveAngular,Deflection,perfAxis={1},deflection={2}",
905 Prim.LocalID, preferredAxisOfMotion, deflection);
906 // This deflection computation is not correct.
907 deflection = Vector3.Zero;
908 }
909
910 #endregion
911 1118
912 #region Banking 1119 VDetailLog("{0}, MoveAngular,done,nonZero,angMotorContrib={1},vertAttrContrib={2},bankContrib={3},deflectContrib={4},totalContrib={5}",
913 1120 Prim.LocalID,
914 if (m_bankingEfficiency != 0) 1121 angularMotorContribution, verticalAttractionContribution,
1122 bankingContribution, deflectionContribution,
1123 m_lastAngularVelocity
1124 );
1125 }
1126 else
915 { 1127 {
916 Vector3 dir = Vector3.One * Prim.ForceOrientation; 1128 // The vehicle is not adding anything angular wise.
917 float mult = (m_bankingMix*m_bankingMix)*-1*(m_bankingMix < 0 ? -1 : 1); 1129 VehicleRotationalVelocity = Vector3.Zero;
918 //Changes which way it banks in and out of turns 1130 VDetailLog("{0}, MoveAngular,done,zero", Prim.LocalID);
919
920 //Use the square of the efficiency, as it looks much more how SL banking works
921 float effSquared = (m_bankingEfficiency*m_bankingEfficiency);
922 if (m_bankingEfficiency < 0)
923 effSquared *= -1; //Keep the negative!
924
925 float mix = Math.Abs(m_bankingMix);
926 if (m_angularMotorVelocity.X == 0)
927 {
928 /*if (!parent.Orientation.ApproxEquals(this.m_referenceFrame, 0.25f))
929 {
930 Vector3 axisAngle;
931 float angle;
932 parent.Orientation.GetAxisAngle(out axisAngle, out angle);
933 Vector3 rotatedVel = parent.Velocity * parent.Orientation;
934 if ((rotatedVel.X < 0 && axisAngle.Y > 0) || (rotatedVel.X > 0 && axisAngle.Y < 0))
935 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (1f) * 10;
936 else
937 m_angularMotorVelocity.X += (effSquared * (mult * mix)) * (-1f) * 10;
938 }*/
939 }
940 else
941 banking.Z += (effSquared*(mult*mix))*(m_angularMotorVelocity.X) * 4;
942 if (!Prim.IsColliding && Math.Abs(m_angularMotorVelocity.X) > mix)
943 //If they are colliding, we probably shouldn't shove the prim around... probably
944 {
945 float angVelZ = m_angularMotorVelocity.X*-1;
946 /*if(angVelZ > mix)
947 angVelZ = mix;
948 else if(angVelZ < -mix)
949 angVelZ = -mix;*/
950 //This controls how fast and how far the banking occurs
951 Vector3 bankingRot = new Vector3(angVelZ*(effSquared*mult), 0, 0);
952 if (bankingRot.X > 3)
953 bankingRot.X = 3;
954 else if (bankingRot.X < -3)
955 bankingRot.X = -3;
956 bankingRot *= Prim.ForceOrientation;
957 banking += bankingRot;
958 }
959 m_angularMotorVelocity.X *= m_bankingEfficiency == 1 ? 0.0f : 1 - m_bankingEfficiency;
960 VDetailLog("{0},MoveAngular,Banking,bEff={1},angMotVel={2},banking={3}",
961 Prim.LocalID, m_bankingEfficiency, m_angularMotorVelocity, banking);
962 } 1131 }
963 1132
964 #endregion 1133 // ==================================================================
965
966 m_lastVertAttractor = vertattr;
967
968 // Sum velocities
969 m_lastAngularVelocity = m_angularMotorVelocity + vertattr + banking + deflection;
970
971 #region Linear Motor Offset
972
973 //Offset section 1134 //Offset section
974 if (m_linearMotorOffset != Vector3.Zero) 1135 if (m_linearMotorOffset != Vector3.Zero)
975 { 1136 {
@@ -985,8 +1146,8 @@ namespace OpenSim.Region.Physics.BulletSPlugin
985 // 1146 //
986 // The torque created is the linear velocity crossed with the offset 1147 // The torque created is the linear velocity crossed with the offset
987 1148
988 // NOTE: this computation does should be in the linear section 1149 // TODO: this computation should be in the linear section
989 // because there we know the impulse being applied. 1150 // because that is where we know the impulse being applied.
990 Vector3 torqueFromOffset = Vector3.Zero; 1151 Vector3 torqueFromOffset = Vector3.Zero;
991 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse); 1152 // torqueFromOffset = Vector3.Cross(m_linearMotorOffset, appliedImpulse);
992 if (float.IsNaN(torqueFromOffset.X)) 1153 if (float.IsNaN(torqueFromOffset.X))
@@ -995,47 +1156,184 @@ namespace OpenSim.Region.Physics.BulletSPlugin
995 torqueFromOffset.Y = 0; 1156 torqueFromOffset.Y = 0;
996 if (float.IsNaN(torqueFromOffset.Z)) 1157 if (float.IsNaN(torqueFromOffset.Z))
997 torqueFromOffset.Z = 0; 1158 torqueFromOffset.Z = 0;
998 torqueFromOffset *= m_vehicleMass; 1159
999 Prim.ApplyTorqueImpulse(torqueFromOffset, true); 1160 VehicleAddAngularForce(torqueFromOffset * m_vehicleMass);
1000 VDetailLog("{0},BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset); 1161 VDetailLog("{0}, BSDynamic.MoveAngular,motorOffset,applyTorqueImpulse={1}", Prim.LocalID, torqueFromOffset);
1001 } 1162 }
1002 1163
1003 #endregion 1164 }
1165 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1166 // Some vehicles, like boats, should always keep their up-side up. This can be done by
1167 // enabling the "vertical attractor" behavior that springs the vehicle's local z-axis to
1168 // the world z-axis (a.k.a. "up"). To take advantage of this feature you would set the
1169 // VEHICLE_VERTICAL_ATTRACTION_TIMESCALE to control the period of the spring frequency,
1170 // and then set the VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY to control the damping. An
1171 // efficiency of 0.0 will cause the spring to wobble around its equilibrium, while an
1172 // efficiency of 1.0 will cause the spring to reach its equilibrium with exponential decay.
1173 public Vector3 ComputeAngularVerticalAttraction()
1174 {
1175 Vector3 ret = Vector3.Zero;
1004 1176
1005 if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0) 1177 // If vertical attaction timescale is reasonable
1178 if (m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1006 { 1179 {
1007 m_lastAngularVelocity.X = 0; 1180 // Take a vector pointing up and convert it from world to vehicle relative coords.
1008 m_lastAngularVelocity.Y = 0; 1181 Vector3 verticalError = Vector3.UnitZ * VehicleOrientation;
1009 VDetailLog("{0},MoveAngular,noDeflectionUp,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1182
1183 // If vertical attraction correction is needed, the vector that was pointing up (UnitZ)
1184 // is now:
1185 // leaning to one side: rotated around the X axis with the Y value going
1186 // from zero (nearly straight up) to one (completely to the side)) or
1187 // leaning front-to-back: rotated around the Y axis with the value of X being between
1188 // zero and one.
1189 // The value of Z is how far the rotation is off with 1 meaning none and 0 being 90 degrees.
1190
1191 // Y error means needed rotation around X axis and visa versa.
1192 // Since the error goes from zero to one, the asin is the corresponding angle.
1193 ret.X = (float)Math.Asin(verticalError.Y);
1194 // (Tilt forward (positive X) needs to tilt back (rotate negative) around Y axis.)
1195 ret.Y = -(float)Math.Asin(verticalError.X);
1196
1197 // If verticalError.Z is negative, the vehicle is upside down. Add additional push.
1198 if (verticalError.Z < 0f)
1199 {
1200 ret.X += PIOverFour;
1201 ret.Y += PIOverFour;
1202 }
1203
1204 // 'ret' is now the necessary velocity to correct tilt in one second.
1205 // Correction happens over a number of seconds.
1206 Vector3 unscaledContrib = ret;
1207 ret /= m_verticalAttractionTimescale;
1208
1209 VDetailLog("{0}, MoveAngular,verticalAttraction,,verticalError={1},unscaled={2},eff={3},ts={4},vertAttr={5}",
1210 Prim.LocalID, verticalError, unscaledContrib, m_verticalAttractionEfficiency, m_verticalAttractionTimescale, ret);
1010 } 1211 }
1212 return ret;
1213 }
1011 1214
1012 if (m_lastAngularVelocity.ApproxEquals(Vector3.Zero, 0.01f)) 1215 // Return the angular correction to correct the direction the vehicle is pointing to be
1216 // the direction is should want to be pointing.
1217 // The vehicle is moving in some direction and correct its orientation to it is pointing
1218 // in that direction.
1219 // TODO: implement reference frame.
1220 public Vector3 ComputeAngularDeflection()
1221 {
1222 Vector3 ret = Vector3.Zero;
1223 return ret; // DEBUG DEBUG DEBUG
1224 // Disable angular deflection for the moment.
1225 // Since angularMotorUp and angularDeflection are computed independently, they will calculate
1226 // approximately the same X or Y correction. When added together (when contributions are combined)
1227 // this creates an over-correction and then wabbling as the target is overshot.
1228 // TODO: rethink how the different correction computations inter-relate.
1229
1230 if (m_angularDeflectionEfficiency != 0)
1013 { 1231 {
1014 m_lastAngularVelocity = Vector3.Zero; // Reduce small value to zero. 1232 // The direction the vehicle is moving
1015 Prim.ZeroAngularMotion(true); 1233 Vector3 movingDirection = VehicleVelocity;
1016 VDetailLog("{0},MoveAngular,zeroAngularMotion,lastAngular={1}", Prim.LocalID, m_lastAngularVelocity); 1234 movingDirection.Normalize();
1235
1236 // The direction the vehicle is pointing
1237 Vector3 pointingDirection = Vector3.UnitX * VehicleOrientation;
1238 pointingDirection.Normalize();
1239
1240 // The difference between what is and what should be.
1241 Vector3 deflectionError = movingDirection - pointingDirection;
1242
1243 // Don't try to correct very large errors (not our job)
1244 if (Math.Abs(deflectionError.X) > PIOverFour) deflectionError.X = 0f;
1245 if (Math.Abs(deflectionError.Y) > PIOverFour) deflectionError.Y = 0f;
1246 if (Math.Abs(deflectionError.Z) > PIOverFour) deflectionError.Z = 0f;
1247
1248 // ret = m_angularDeflectionCorrectionMotor(1f, deflectionError);
1249
1250 // Scale the correction by recovery timescale and efficiency
1251 ret = (-deflectionError) * m_angularDeflectionEfficiency;
1252 ret /= m_angularDeflectionTimescale;
1253
1254 VDetailLog("{0}, MoveAngular,Deflection,movingDir={1},pointingDir={2},deflectError={3},ret={4}",
1255 Prim.LocalID, movingDirection, pointingDirection, deflectionError, ret);
1256 VDetailLog("{0}, MoveAngular,Deflection,fwdSpd={1},defEff={2},defTS={3}",
1257 Prim.LocalID, VehicleForwardSpeed, m_angularDeflectionEfficiency, m_angularDeflectionTimescale);
1017 } 1258 }
1018 else 1259 return ret;
1260 }
1261
1262 // Return an angular change to rotate the vehicle around the Z axis when the vehicle
1263 // is tipped around the X axis.
1264 // From http://wiki.secondlife.com/wiki/Linden_Vehicle_Tutorial:
1265 // The vertical attractor feature must be enabled in order for the banking behavior to
1266 // function. The way banking works is this: a rotation around the vehicle's roll-axis will
1267 // produce a angular velocity around the yaw-axis, causing the vehicle to turn. The magnitude
1268 // of the yaw effect will be proportional to the
1269 // VEHICLE_BANKING_EFFICIENCY, the angle of the roll rotation, and sometimes the vehicle's
1270 // velocity along its preferred axis of motion.
1271 // The VEHICLE_BANKING_EFFICIENCY can vary between -1 and +1. When it is positive then any
1272 // positive rotation (by the right-hand rule) about the roll-axis will effect a
1273 // (negative) torque around the yaw-axis, making it turn to the right--that is the
1274 // vehicle will lean into the turn, which is how real airplanes and motorcycle's work.
1275 // Negating the banking coefficient will make it so that the vehicle leans to the
1276 // outside of the turn (not very "physical" but might allow interesting vehicles so why not?).
1277 // The VEHICLE_BANKING_MIX is a fake (i.e. non-physical) parameter that is useful for making
1278 // banking vehicles do what you want rather than what the laws of physics allow.
1279 // For example, consider a real motorcycle...it must be moving forward in order for
1280 // it to turn while banking, however video-game motorcycles are often configured
1281 // to turn in place when at a dead stop--because they are often easier to control
1282 // that way using the limited interface of the keyboard or game controller. The
1283 // VEHICLE_BANKING_MIX enables combinations of both realistic and non-realistic
1284 // banking by functioning as a slider between a banking that is correspondingly
1285 // totally static (0.0) and totally dynamic (1.0). By "static" we mean that the
1286 // banking effect depends only on the vehicle's rotation about its roll-axis compared
1287 // to "dynamic" where the banking is also proportional to its velocity along its
1288 // roll-axis. Finding the best value of the "mixture" will probably require trial and error.
1289 // The time it takes for the banking behavior to defeat a preexisting angular velocity about the
1290 // world z-axis is determined by the VEHICLE_BANKING_TIMESCALE. So if you want the vehicle to
1291 // bank quickly then give it a banking timescale of about a second or less, otherwise you can
1292 // make a sluggish vehicle by giving it a timescale of several seconds.
1293 public Vector3 ComputeAngularBanking()
1294 {
1295 Vector3 ret = Vector3.Zero;
1296
1297 if (m_bankingEfficiency != 0 && m_verticalAttractionTimescale < m_verticalAttractionCutoff)
1019 { 1298 {
1020 // Apply to the body. 1299 // This works by rotating a unit vector to the orientation of the vehicle. The
1021 // The above calculates the absolute angular velocity needed. Angular velocity is massless. 1300 // roll (tilt) will be Y component of a tilting Z vector (zero for no tilt
1022 // Since we are stuffing the angular velocity directly into the object, the computed 1301 // up to one for full over).
1023 // velocity needs to be scaled by the timestep. 1302 Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
1024 Vector3 applyAngularForce = ((m_lastAngularVelocity * pTimestep) - Prim.ForceRotationalVelocity); 1303
1025 Prim.ForceRotationalVelocity = applyAngularForce; 1304 // Figure out the yaw value for this much roll.
1026 1305 float turnComponent = rollComponents.Y * rollComponents.Y * m_bankingEfficiency;
1027 // Decay the angular movement for next time 1306 // Keep the sign
1028 Vector3 decayamount = (Vector3.One / m_angularFrictionTimescale) * pTimestep; 1307 if (rollComponents.Y < 0f)
1029 m_lastAngularVelocity *= Vector3.One - decayamount; 1308 turnComponent = -turnComponent;
1030 1309
1031 VDetailLog("{0},MoveAngular,done,newRotVel={1},decay={2},lastAngular={3}", 1310 // TODO: there must be a better computation of the banking force.
1032 Prim.LocalID, applyAngularForce, decayamount, m_lastAngularVelocity); 1311 float bankingTurnForce = turnComponent;
1312
1313 // actual error = static turn error + dynamic turn error
1314 float mixedBankingError = bankingTurnForce * (1f - m_bankingMix) + bankingTurnForce * m_bankingMix * VehicleForwardSpeed;
1315 // TODO: the banking effect should not go to infinity but what to limit it to?
1316 mixedBankingError = ClampInRange(-20f, mixedBankingError, 20f);
1317
1318 // Build the force vector to change rotation from what it is to what it should be
1319 ret.Z = -mixedBankingError;
1320
1321 // Don't do it all at once.
1322 ret /= m_bankingTimescale;
1323
1324 VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},turnComp={3},bankErr={4},mixedBankErr={5},ret={6}",
1325 Prim.LocalID, rollComponents, VehicleForwardSpeed, turnComponent, bankingTurnForce, mixedBankingError, ret);
1033 } 1326 }
1034 } //end MoveAngular 1327 return ret;
1328 }
1035 1329
1330 // This is from previous instantiations of XXXDynamics.cs.
1331 // Applies roll reference frame.
1332 // TODO: is this the right way to separate the code to do this operation?
1333 // Should this be in MoveAngular()?
1036 internal void LimitRotation(float timestep) 1334 internal void LimitRotation(float timestep)
1037 { 1335 {
1038 Quaternion rotq = Prim.ForceOrientation; 1336 Quaternion rotq = VehicleOrientation;
1039 Quaternion m_rot = rotq; 1337 Quaternion m_rot = rotq;
1040 if (m_RollreferenceFrame != Quaternion.Identity) 1338 if (m_RollreferenceFrame != Quaternion.Identity)
1041 { 1339 {
@@ -1063,12 +1361,18 @@ namespace OpenSim.Region.Physics.BulletSPlugin
1063 } 1361 }
1064 if (rotq != m_rot) 1362 if (rotq != m_rot)
1065 { 1363 {
1066 Prim.ForceOrientation = m_rot; 1364 VehicleOrientation = m_rot;
1067 VDetailLog("{0},LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot); 1365 VDetailLog("{0}, LimitRotation,done,orig={1},new={2}", Prim.LocalID, rotq, m_rot);
1068 } 1366 }
1069 1367
1070 } 1368 }
1071 1369
1370 private float ClampInRange(float low, float val, float high)
1371 {
1372 return Math.Max(low, Math.Min(val, high));
1373 // return Utils.Clamp(val, low, high);
1374 }
1375
1072 // Invoke the detailed logger and output something if it's enabled. 1376 // Invoke the detailed logger and output something if it's enabled.
1073 private void VDetailLog(string msg, params Object[] args) 1377 private void VDetailLog(string msg, params Object[] args)
1074 { 1378 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
index 0df4310..756faed 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinkset.cs
@@ -32,6 +32,15 @@ using OMV = OpenMetaverse;
32 32
33namespace OpenSim.Region.Physics.BulletSPlugin 33namespace OpenSim.Region.Physics.BulletSPlugin
34{ 34{
35
36// A BSPrim can get individual information about its linkedness attached
37// to it through an instance of a subclass of LinksetInfo.
38// Each type of linkset will define the information needed for its type.
39public abstract class BSLinksetInfo
40{
41 public virtual void Clear() { }
42}
43
35public abstract class BSLinkset 44public abstract class BSLinkset
36{ 45{
37 // private static string LogHeader = "[BULLETSIM LINKSET]"; 46 // private static string LogHeader = "[BULLETSIM LINKSET]";
@@ -47,7 +56,7 @@ public abstract class BSLinkset
47 { 56 {
48 BSLinkset ret = null; 57 BSLinkset ret = null;
49 58
50 switch ((int)physScene.Params.linksetImplementation) 59 switch ((int)BSParam.LinksetImplementation)
51 { 60 {
52 case (int)LinksetImplementation.Constraint: 61 case (int)LinksetImplementation.Constraint:
53 ret = new BSLinksetConstraints(physScene, parent); 62 ret = new BSLinksetConstraints(physScene, parent);
@@ -87,22 +96,8 @@ public abstract class BSLinkset
87 return BSPhysicsShapeType.SHAPE_UNKNOWN; 96 return BSPhysicsShapeType.SHAPE_UNKNOWN;
88 } 97 }
89 98
90 // Linksets move around the children so the linkset might need to compute the child position
91 public virtual OMV.Vector3 Position(BSPhysObject member)
92 { return member.RawPosition; }
93 public virtual OMV.Quaternion Orientation(BSPhysObject member)
94 { return member.RawOrientation; }
95 // TODO: does this need to be done for Velocity and RotationalVelocityy?
96
97 // We keep the prim's mass in the linkset structure since it could be dependent on other prims 99 // We keep the prim's mass in the linkset structure since it could be dependent on other prims
98 protected float m_mass; 100 public float LinksetMass { get; protected set; }
99 public float LinksetMass
100 {
101 get
102 {
103 return m_mass;
104 }
105 }
106 101
107 public virtual bool LinksetIsColliding { get { return false; } } 102 public virtual bool LinksetIsColliding { get { return false; } }
108 103
@@ -116,7 +111,7 @@ public abstract class BSLinkset
116 get { return ComputeLinksetGeometricCenter(); } 111 get { return ComputeLinksetGeometricCenter(); }
117 } 112 }
118 113
119 protected void Initialize(BSScene scene, BSPhysObject parent) 114 protected BSLinkset(BSScene scene, BSPhysObject parent)
120 { 115 {
121 // A simple linkset of one (no children) 116 // A simple linkset of one (no children)
122 LinksetID = m_nextLinksetID++; 117 LinksetID = m_nextLinksetID++;
@@ -126,7 +121,8 @@ public abstract class BSLinkset
126 PhysicsScene = scene; 121 PhysicsScene = scene;
127 LinksetRoot = parent; 122 LinksetRoot = parent;
128 m_children = new HashSet<BSPhysObject>(); 123 m_children = new HashSet<BSPhysObject>();
129 m_mass = parent.RawMass; 124 LinksetMass = parent.RawMass;
125 Rebuilding = false;
130 } 126 }
131 127
132 // Link to a linkset where the child knows the parent. 128 // Link to a linkset where the child knows the parent.
@@ -140,7 +136,7 @@ public abstract class BSLinkset
140 // Don't add the root to its own linkset 136 // Don't add the root to its own linkset
141 if (!IsRoot(child)) 137 if (!IsRoot(child))
142 AddChildToLinkset(child); 138 AddChildToLinkset(child);
143 m_mass = ComputeLinksetMass(); 139 LinksetMass = ComputeLinksetMass();
144 } 140 }
145 return this; 141 return this;
146 } 142 }
@@ -159,7 +155,7 @@ public abstract class BSLinkset
159 return this; 155 return this;
160 } 156 }
161 RemoveChildFromLinkset(child); 157 RemoveChildFromLinkset(child);
162 m_mass = ComputeLinksetMass(); 158 LinksetMass = ComputeLinksetMass();
163 } 159 }
164 160
165 // The child is down to a linkset of just itself 161 // The child is down to a linkset of just itself
@@ -219,7 +215,7 @@ public abstract class BSLinkset
219 // I am the root of a linkset and a new child is being added 215 // I am the root of a linkset and a new child is being added
220 // Called while LinkActivity is locked. 216 // Called while LinkActivity is locked.
221 protected abstract void AddChildToLinkset(BSPhysObject child); 217 protected abstract void AddChildToLinkset(BSPhysObject child);
222 218
223 // I am the root of a linkset and one of my children is being removed. 219 // I am the root of a linkset and one of my children is being removed.
224 // Safe to call even if the child is not really in my linkset. 220 // Safe to call even if the child is not really in my linkset.
225 protected abstract void RemoveChildFromLinkset(BSPhysObject child); 221 protected abstract void RemoveChildFromLinkset(BSPhysObject child);
@@ -227,7 +223,14 @@ public abstract class BSLinkset
227 // When physical properties are changed the linkset needs to recalculate 223 // When physical properties are changed the linkset needs to recalculate
228 // its internal properties. 224 // its internal properties.
229 // May be called at runtime or taint-time. 225 // May be called at runtime or taint-time.
230 public abstract void Refresh(BSPhysObject requestor); 226 public virtual void Refresh(BSPhysObject requestor)
227 {
228 LinksetMass = ComputeLinksetMass();
229 }
230
231 // Flag denoting the linkset is in the process of being rebuilt.
232 // Used to know not the schedule a rebuild in the middle of a rebuild.
233 protected bool Rebuilding { get; set; }
231 234
232 // The object is going dynamic (physical). Do any setup necessary 235 // The object is going dynamic (physical). Do any setup necessary
233 // for a dynamic linkset. 236 // for a dynamic linkset.
@@ -245,8 +248,9 @@ public abstract class BSLinkset
245 248
246 // Called when a parameter update comes from the physics engine for any object 249 // Called when a parameter update comes from the physics engine for any object
247 // of the linkset is received. 250 // of the linkset is received.
251 // Passed flag is update came from physics engine (true) or the user (false).
248 // Called at taint-time!! 252 // Called at taint-time!!
249 public abstract void UpdateProperties(BSPhysObject physObject); 253 public abstract void UpdateProperties(BSPhysObject physObject, bool physicalUpdate);
250 254
251 // Routine used when rebuilding the body of the root of the linkset 255 // Routine used when rebuilding the body of the root of the linkset
252 // Destroy all the constraints have have been made to root. 256 // Destroy all the constraints have have been made to root.
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
index b9c2cf9..bd03d31 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetCompound.cs
@@ -28,22 +28,54 @@ using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Text; 29using System.Text;
30 30
31using OpenSim.Framework;
32
31using OMV = OpenMetaverse; 33using OMV = OpenMetaverse;
32 34
33namespace OpenSim.Region.Physics.BulletSPlugin 35namespace OpenSim.Region.Physics.BulletSPlugin
34{ 36{
37
38// When a child is linked, the relationship position of the child to the parent
39// is remembered so the child's world position can be recomputed when it is
40// removed from the linkset.
41sealed class BSLinksetCompoundInfo : BSLinksetInfo
42{
43 public OMV.Vector3 OffsetPos;
44 public OMV.Quaternion OffsetRot;
45 public BSLinksetCompoundInfo(OMV.Vector3 p, OMV.Quaternion r)
46 {
47 OffsetPos = p;
48 OffsetRot = r;
49 }
50 public override void Clear()
51 {
52 OffsetPos = OMV.Vector3.Zero;
53 OffsetRot = OMV.Quaternion.Identity;
54 }
55 public override string ToString()
56 {
57 StringBuilder buff = new StringBuilder();
58 buff.Append("<p=");
59 buff.Append(OffsetPos.ToString());
60 buff.Append(",r=");
61 buff.Append(OffsetRot.ToString());
62 buff.Append(">");
63 return buff.ToString();
64 }
65};
66
35public sealed class BSLinksetCompound : BSLinkset 67public sealed class BSLinksetCompound : BSLinkset
36{ 68{
37 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]"; 69 private static string LogHeader = "[BULLETSIM LINKSET COMPOUND]";
38 70
39 public BSLinksetCompound(BSScene scene, BSPhysObject parent) 71 public BSLinksetCompound(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 72 {
41 base.Initialize(scene, parent);
42 } 73 }
43 74
44 // For compound implimented linksets, if there are children, use compound shape for the root. 75 // For compound implimented linksets, if there are children, use compound shape for the root.
45 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor) 76 public override BSPhysicsShapeType PreferredPhysicalShape(BSPhysObject requestor)
46 { 77 {
78 // Returning 'unknown' means we don't have a preference.
47 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN; 79 BSPhysicsShapeType ret = BSPhysicsShapeType.SHAPE_UNKNOWN;
48 if (IsRoot(requestor) && HasAnyChildren) 80 if (IsRoot(requestor) && HasAnyChildren)
49 { 81 {
@@ -55,27 +87,33 @@ public sealed class BSLinksetCompound : BSLinkset
55 87
56 // When physical properties are changed the linkset needs to recalculate 88 // When physical properties are changed the linkset needs to recalculate
57 // its internal properties. 89 // its internal properties.
58 // This is queued in the 'post taint' queue so the
59 // refresh will happen once after all the other taints are applied.
60 public override void Refresh(BSPhysObject requestor) 90 public override void Refresh(BSPhysObject requestor)
61 { 91 {
62 // External request for Refresh (from BSPrim) is not necessary 92 base.Refresh(requestor);
63 // InternalRefresh(requestor); 93
94 // Something changed so do the rebuilding thing
95 // ScheduleRebuild();
64 } 96 }
65 97
66 private void InternalRefresh(BSPhysObject requestor) 98 // Schedule a refresh to happen after all the other taint processing.
99 private void ScheduleRebuild(BSPhysObject requestor)
67 { 100 {
68 DetailLog("{0},BSLinksetCompound.Refresh,schedulingRefresh,requestor={1}", LinksetRoot.LocalID, requestor.LocalID); 101 DetailLog("{0},BSLinksetCompound.ScheduleRebuild,,rebuilding={1},hasChildren={2}",
69 // Queue to happen after all the other taint processing 102 requestor.LocalID, Rebuilding, HasAnyChildren);
70 PhysicsScene.PostTaintObject("BSLinksetCompound.Refresh", requestor.LocalID, delegate() 103 // When rebuilding, it is possible to set properties that would normally require a rebuild.
104 // If already rebuilding, don't request another rebuild.
105 // If a linkset with just a root prim (simple non-linked prim) don't bother rebuilding.
106 if (!Rebuilding && HasAnyChildren)
71 { 107 {
72 if (IsRoot(requestor) && HasAnyChildren) 108 PhysicsScene.PostTaintObject("BSLinksetCompound.ScheduleRebuild", LinksetRoot.LocalID, delegate()
73 RecomputeLinksetCompound(); 109 {
74 }); 110 if (HasAnyChildren)
111 RecomputeLinksetCompound();
112 });
113 }
75 } 114 }
76 115
77 // The object is going dynamic (physical). Do any setup necessary 116 // The object is going dynamic (physical). Do any setup necessary for a dynamic linkset.
78 // for a dynamic linkset.
79 // Only the state of the passed object can be modified. The rest of the linkset 117 // Only the state of the passed object can be modified. The rest of the linkset
80 // has not yet been fully constructed. 118 // has not yet been fully constructed.
81 // Return 'true' if any properties updated on the passed object. 119 // Return 'true' if any properties updated on the passed object.
@@ -84,12 +122,22 @@ public sealed class BSLinksetCompound : BSLinkset
84 { 122 {
85 bool ret = false; 123 bool ret = false;
86 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 124 DetailLog("{0},BSLinksetCompound.MakeDynamic,call,IsRoot={1}", child.LocalID, IsRoot(child));
87 if (!IsRoot(child)) 125 if (IsRoot(child))
126 {
127 // The root is going dynamic. Rebuild the linkset so parts and mass get computed properly.
128 ScheduleRebuild(LinksetRoot);
129 }
130 else
88 { 131 {
89 // Physical children are removed from the world as the shape ofthe root compound 132 // The origional prims are removed from the world as the shape of the root compound
90 // shape takes over. 133 // shape takes over.
91 BulletSimAPI.AddToCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 134 PhysicsScene.PE.AddToCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
92 BulletSimAPI.ForceActivationState2(child.PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 135 PhysicsScene.PE.ForceActivationState(child.PhysBody, ActivationState.DISABLE_SIMULATION);
136 // We don't want collisions from the old linkset children.
137 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
138
139 child.PhysBody.collisionType = CollisionType.LinksetChild;
140
93 ret = true; 141 ret = true;
94 } 142 }
95 return ret; 143 return ret;
@@ -104,33 +152,39 @@ public sealed class BSLinksetCompound : BSLinkset
104 { 152 {
105 bool ret = false; 153 bool ret = false;
106 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child)); 154 DetailLog("{0},BSLinksetCompound.MakeStatic,call,IsRoot={1}", child.LocalID, IsRoot(child));
107 if (!IsRoot(child)) 155 if (IsRoot(child))
156 {
157 ScheduleRebuild(LinksetRoot);
158 }
159 else
108 { 160 {
109 // The non-physical children can come back to life. 161 // The non-physical children can come back to life.
110 BulletSimAPI.RemoveFromCollisionFlags2(child.PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 162 PhysicsScene.PE.RemoveFromCollisionFlags(child.PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
111 // Don't force activation so setting of DISABLE_SIMULATION can stay. 163
112 BulletSimAPI.Activate2(child.PhysBody.ptr, false); 164 child.PhysBody.collisionType = CollisionType.LinksetChild;
165
166 // Don't force activation so setting of DISABLE_SIMULATION can stay if used.
167 PhysicsScene.PE.Activate(child.PhysBody, false);
113 ret = true; 168 ret = true;
114 } 169 }
115 return ret; 170 return ret;
116 } 171 }
117 172
118 // Called at taint-time!! 173 public override void UpdateProperties(BSPhysObject updated, bool physicalUpdate)
119 public override void UpdateProperties(BSPhysObject updated)
120 {
121 // Nothing to do for constraints on property updates
122 }
123
124 // The children move around in relationship to the root.
125 // Just grab the current values of wherever it is right now.
126 public override OMV.Vector3 Position(BSPhysObject member)
127 {
128 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
129 }
130
131 public override OMV.Quaternion Orientation(BSPhysObject member)
132 { 174 {
133 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr); 175 // The user moving a child around requires the rebuilding of the linkset compound shape
176 // One problem is this happens when a border is crossed -- the simulator implementation
177 // is to store the position into the group which causes the move of the object
178 // but it also means all the child positions get updated.
179 // What would cause an unnecessary rebuild so we make sure the linkset is in a
180 // region before bothering to do a rebuild.
181 if (!IsRoot(updated)
182 && !physicalUpdate
183 && PhysicsScene.TerrainManager.IsWithinKnownTerrain(LinksetRoot.RawPosition))
184 {
185 updated.LinksetInfo = null;
186 ScheduleRebuild(updated);
187 }
134 } 188 }
135 189
136 // Routine called when rebuilding the body of some member of the linkset. 190 // Routine called when rebuilding the body of some member of the linkset.
@@ -142,24 +196,62 @@ public sealed class BSLinksetCompound : BSLinkset
142 bool ret = false; 196 bool ret = false;
143 197
144 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}", 198 DetailLog("{0},BSLinksetCompound.RemoveBodyDependencies,refreshIfChild,rID={1},rBody={2},isRoot={3}",
145 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), IsRoot(child)); 199 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, IsRoot(child));
146 200
147 if (!IsRoot(child)) 201 if (!IsRoot(child))
148 { 202 {
149 // Cause the current shape to be freed and the new one to be built. 203 // Because it is a convenient time, recompute child world position and rotation based on
150 InternalRefresh(LinksetRoot); 204 // its position in the linkset.
151 ret = true; 205 RecomputeChildWorldPosition(child, true);
152 } 206 }
153 207
208 // Cannot schedule a refresh/rebuild here because this routine is called when
209 // the linkset is being rebuilt.
210 // InternalRefresh(LinksetRoot);
211
154 return ret; 212 return ret;
155 } 213 }
156 214
157 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true', 215 // Companion to RemoveBodyDependencies(). If RemoveBodyDependencies() returns 'true',
158 // this routine will restore the removed constraints. 216 // this routine will restore the removed constraints.
159 // Called at taint-time!! 217 // Called at taint-time!!
160 public override void RestoreBodyDependencies(BSPrim child) 218 public override void RestoreBodyDependencies(BSPrim child)
161 { 219 {
162 // The Refresh operation queued by RemoveBodyDependencies() will build any missing constraints. 220 }
221
222 // When the linkset is built, the child shape is added to the compound shape relative to the
223 // root shape. The linkset then moves around but this does not move the actual child
224 // prim. The child prim's location must be recomputed based on the location of the root shape.
225 private void RecomputeChildWorldPosition(BSPhysObject child, bool inTaintTime)
226 {
227 BSLinksetCompoundInfo lci = child.LinksetInfo as BSLinksetCompoundInfo;
228 if (lci != null)
229 {
230 if (inTaintTime)
231 {
232 OMV.Vector3 oldPos = child.RawPosition;
233 child.ForcePosition = LinksetRoot.RawPosition + lci.OffsetPos;
234 child.ForceOrientation = LinksetRoot.RawOrientation * lci.OffsetRot;
235 DetailLog("{0},BSLinksetCompound.RecomputeChildWorldPosition,oldPos={1},lci={2},newPos={3}",
236 child.LocalID, oldPos, lci, child.RawPosition);
237 }
238 else
239 {
240 // TaintedObject is not used here so the raw position is set now and not at taint-time.
241 child.Position = LinksetRoot.RawPosition + lci.OffsetPos;
242 child.Orientation = LinksetRoot.RawOrientation * lci.OffsetRot;
243 }
244 }
245 else
246 {
247 // This happens when children have been added to the linkset but the linkset
248 // has not been constructed yet. So like, at taint time, adding children to a linkset
249 // and then changing properties of the children (makePhysical, for instance)
250 // but the post-print action of actually rebuilding the linkset has not yet happened.
251 // PhysicsScene.Logger.WarnFormat("{0} Restoring linkset child position failed because of no relative position computed. ID={1}",
252 // LogHeader, child.LocalID);
253 DetailLog("{0},BSLinksetCompound.recomputeChildWorldPosition,noRelativePositonInfo", child.LocalID);
254 }
163 } 255 }
164 256
165 // ================================================================ 257 // ================================================================
@@ -174,24 +266,25 @@ public sealed class BSLinksetCompound : BSLinkset
174 266
175 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID); 267 DetailLog("{0},BSLinksetCompound.AddChildToLinkset,call,child={1}", LinksetRoot.LocalID, child.LocalID);
176 268
177 // Cause constraints and assorted properties to be recomputed before the next simulation step. 269 // Rebuild the compound shape with the new child shape included
178 InternalRefresh(LinksetRoot); 270 ScheduleRebuild(child);
179 } 271 }
180 return; 272 return;
181 } 273 }
182 274
183 // Remove the specified child from the linkset. 275 // Remove the specified child from the linkset.
184 // Safe to call even if the child is not really in my linkset. 276 // Safe to call even if the child is not really in the linkset.
185 protected override void RemoveChildFromLinkset(BSPhysObject child) 277 protected override void RemoveChildFromLinkset(BSPhysObject child)
186 { 278 {
187 if (m_children.Remove(child)) 279 if (m_children.Remove(child))
188 { 280 {
189 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 281 DetailLog("{0},BSLinksetCompound.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
190 child.LocalID, 282 child.LocalID,
191 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), 283 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString,
192 child.LocalID, child.PhysBody.ptr.ToString("X")); 284 child.LocalID, child.PhysBody.AddrString);
193 285
194 // Cause the child's body to be rebuilt and thus restored to normal operation 286 // Cause the child's body to be rebuilt and thus restored to normal operation
287 RecomputeChildWorldPosition(child, false);
195 child.ForceBodyShapeRebuild(false); 288 child.ForceBodyShapeRebuild(false);
196 289
197 if (!HasAnyChildren) 290 if (!HasAnyChildren)
@@ -201,8 +294,8 @@ public sealed class BSLinksetCompound : BSLinkset
201 } 294 }
202 else 295 else
203 { 296 {
204 // Schedule a rebuild of the linkset before the next simulation tick. 297 // Rebuild the compound shape with the child removed
205 InternalRefresh(LinksetRoot); 298 ScheduleRebuild(child);
206 } 299 }
207 } 300 }
208 return; 301 return;
@@ -215,61 +308,85 @@ public sealed class BSLinksetCompound : BSLinkset
215 // Called at taint time!! 308 // Called at taint time!!
216 private void RecomputeLinksetCompound() 309 private void RecomputeLinksetCompound()
217 { 310 {
218 // Cause the root shape to be rebuilt as a compound object with just the root in it 311 try
219 LinksetRoot.ForceBodyShapeRebuild(true);
220
221 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
222 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
223
224 // Add a shape for each of the other children in the linkset
225 ForEachMember(delegate(BSPhysObject cPrim)
226 { 312 {
227 if (!IsRoot(cPrim)) 313 // Suppress rebuilding while rebuilding
228 { 314 Rebuilding = true;
229 // Each child position and rotation is given relative to the root.
230 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
231 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
232 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
233 315
234 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}", 316 // Cause the root shape to be rebuilt as a compound object with just the root in it
235 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, displacementPos, displacementRot); 317 LinksetRoot.ForceBodyShapeRebuild(true);
236 318
237 if (cPrim.PhysShape.isNativeShape) 319 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,start,rBody={1},rShape={2},numChildren={3}",
238 { 320 LinksetRoot.LocalID, LinksetRoot.PhysBody, LinksetRoot.PhysShape, NumberOfChildren);
239 // Native shapes are not shared so we need to create a new one. 321
240 // A mesh or hull is created because scale is not available on a native shape. 322 // Add a shape for each of the other children in the linkset
241 // (TODO: Bullet does have a btScaledCollisionShape. Can that be used?) 323 ForEachMember(delegate(BSPhysObject cPrim)
242 BulletShape saveShape = cPrim.PhysShape; 324 {
243 cPrim.PhysShape.ptr = IntPtr.Zero; // Don't let the create free the child's shape 325 if (!IsRoot(cPrim))
244 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
245 BulletShape newShape = cPrim.PhysShape;
246 cPrim.PhysShape = saveShape;
247 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, newShape.ptr, displacementPos, displacementRot);
248 }
249 else
250 { 326 {
251 // For the shared shapes (meshes and hulls), just use the shape in the child. 327 // Compute the displacement of the child from the root of the linkset.
252 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape)) 328 // This info is saved in the child prim so the relationship does not
329 // change over time and the new child position can be computed
330 // when the linkset is being disassembled (the linkset may have moved).
331 BSLinksetCompoundInfo lci = cPrim.LinksetInfo as BSLinksetCompoundInfo;
332 if (lci == null)
253 { 333 {
254 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}", 334 // Each child position and rotation is given relative to the root.
255 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape); 335 OMV.Quaternion invRootOrientation = OMV.Quaternion.Inverse(LinksetRoot.RawOrientation);
336 OMV.Vector3 displacementPos = (cPrim.RawPosition - LinksetRoot.RawPosition) * invRootOrientation;
337 OMV.Quaternion displacementRot = cPrim.RawOrientation * invRootOrientation;
338
339 // Save relative position for recomputing child's world position after moving linkset.
340 lci = new BSLinksetCompoundInfo(displacementPos, displacementRot);
341 cPrim.LinksetInfo = lci;
342 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,creatingRelPos,lci={1}", cPrim.LocalID, lci);
256 } 343 }
257 BulletSimAPI.AddChildShapeToCompoundShape2(LinksetRoot.PhysShape.ptr, cPrim.PhysShape.ptr, displacementPos, displacementRot);
258 }
259 }
260 return false; // 'false' says to move onto the next child in the list
261 });
262 344
263 // With all of the linkset packed into the root prim, it has the mass of everyone. 345 DetailLog("{0},BSLinksetCompound.RecomputeLinksetCompound,addMemberToShape,mID={1},mShape={2},dispPos={3},dispRot={4}",
264 float linksetMass = LinksetMass; 346 LinksetRoot.LocalID, cPrim.LocalID, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
265 LinksetRoot.UpdatePhysicalMassProperties(linksetMass);
266 347
267 BulletSimAPI.RecalculateCompoundShapeLocalAabb2(LinksetRoot.PhysShape.ptr); 348 if (cPrim.PhysShape.isNativeShape)
349 {
350 // A native shape is turning into a hull collision shape because native
351 // shapes are not shared so we have to hullify it so it will be tracked
352 // and freed at the correct time. This also solves the scaling problem
353 // (native shapes scaled but hull/meshes are assumed to not be).
354 // TODO: decide of the native shape can just be used in the compound shape.
355 // Use call to CreateGeomNonSpecial().
356 BulletShape saveShape = cPrim.PhysShape;
357 cPrim.PhysShape.Clear(); // Don't let the create free the child's shape
358 // PhysicsScene.Shapes.CreateGeomNonSpecial(true, cPrim, null);
359 PhysicsScene.Shapes.CreateGeomMeshOrHull(cPrim, null);
360 BulletShape newShape = cPrim.PhysShape;
361 cPrim.PhysShape = saveShape;
362 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, newShape, lci.OffsetPos, lci.OffsetRot);
363 }
364 else
365 {
366 // For the shared shapes (meshes and hulls), just use the shape in the child.
367 // The reference count added here will be decremented when the compound shape
368 // is destroyed in BSShapeCollection (the child shapes are looped over and dereferenced).
369 if (PhysicsScene.Shapes.ReferenceShape(cPrim.PhysShape))
370 {
371 PhysicsScene.Logger.ErrorFormat("{0} Rebuilt sharable shape when building linkset! Region={1}, primID={2}, shape={3}",
372 LogHeader, PhysicsScene.RegionName, cPrim.LocalID, cPrim.PhysShape);
373 }
374 PhysicsScene.PE.AddChildShapeToCompoundShape(LinksetRoot.PhysShape, cPrim.PhysShape, lci.OffsetPos, lci.OffsetRot);
375 }
376 }
377 return false; // 'false' says to move onto the next child in the list
378 });
268 379
269 // DEBUG: see of inter-linkset collisions are causing problems for constraint linksets. 380 // With all of the linkset packed into the root prim, it has the mass of everyone.
270 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr, 381 LinksetMass = ComputeLinksetMass();
271 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask); 382 LinksetRoot.UpdatePhysicalMassProperties(LinksetMass, true);
383 }
384 finally
385 {
386 Rebuilding = false;
387 }
272 388
389 PhysicsScene.PE.RecalculateCompoundShapeLocalAabb(LinksetRoot.PhysShape);
273 } 390 }
274} 391}
275} \ No newline at end of file 392} \ No newline at end of file
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
index c855fda..d0b2a56 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSLinksetConstraints.cs
@@ -36,9 +36,8 @@ public sealed class BSLinksetConstraints : BSLinkset
36{ 36{
37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]"; 37 // private static string LogHeader = "[BULLETSIM LINKSET CONSTRAINTS]";
38 38
39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) 39 public BSLinksetConstraints(BSScene scene, BSPhysObject parent) : base(scene, parent)
40 { 40 {
41 base.Initialize(scene, parent);
42 } 41 }
43 42
44 // When physical properties are changed the linkset needs to recalculate 43 // When physical properties are changed the linkset needs to recalculate
@@ -47,12 +46,17 @@ public sealed class BSLinksetConstraints : BSLinkset
47 // refresh will happen once after all the other taints are applied. 46 // refresh will happen once after all the other taints are applied.
48 public override void Refresh(BSPhysObject requestor) 47 public override void Refresh(BSPhysObject requestor)
49 { 48 {
50 // Queue to happen after all the other taint processing 49 base.Refresh(requestor);
51 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate() 50
52 { 51 if (HasAnyChildren && IsRoot(requestor))
53 if (HasAnyChildren && IsRoot(requestor)) 52 {
54 RecomputeLinksetConstraints(); 53 // Queue to happen after all the other taint processing
55 }); 54 PhysicsScene.PostTaintObject("BSLinksetContraints.Refresh", requestor.LocalID, delegate()
55 {
56 if (HasAnyChildren && IsRoot(requestor))
57 RecomputeLinksetConstraints();
58 });
59 }
56 } 60 }
57 61
58 // The object is going dynamic (physical). Do any setup necessary 62 // The object is going dynamic (physical). Do any setup necessary
@@ -79,23 +83,11 @@ public sealed class BSLinksetConstraints : BSLinkset
79 } 83 }
80 84
81 // Called at taint-time!! 85 // Called at taint-time!!
82 public override void UpdateProperties(BSPhysObject updated) 86 public override void UpdateProperties(BSPhysObject updated, bool inTaintTime)
83 { 87 {
84 // Nothing to do for constraints on property updates 88 // Nothing to do for constraints on property updates
85 } 89 }
86 90
87 // The children of the linkset are moved around by the constraints.
88 // Just grab the current values of wherever it is right now.
89 public override OMV.Vector3 Position(BSPhysObject member)
90 {
91 return BulletSimAPI.GetPosition2(member.PhysBody.ptr);
92 }
93
94 public override OMV.Quaternion Orientation(BSPhysObject member)
95 {
96 return BulletSimAPI.GetOrientation2(member.PhysBody.ptr);
97 }
98
99 // Routine called when rebuilding the body of some member of the linkset. 91 // Routine called when rebuilding the body of some member of the linkset.
100 // Destroy all the constraints have have been made to root and set 92 // Destroy all the constraints have have been made to root and set
101 // up to rebuild the constraints before the next simulation step. 93 // up to rebuild the constraints before the next simulation step.
@@ -106,7 +98,7 @@ public sealed class BSLinksetConstraints : BSLinkset
106 bool ret = false; 98 bool ret = false;
107 99
108 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}", 100 DetailLog("{0},BSLinksetConstraint.RemoveBodyDependencies,removeChildrenForRoot,rID={1},rBody={2}",
109 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X")); 101 child.LocalID, LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString);
110 102
111 lock (m_linksetActivityLock) 103 lock (m_linksetActivityLock)
112 { 104 {
@@ -155,8 +147,8 @@ public sealed class BSLinksetConstraints : BSLinkset
155 147
156 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}", 148 DetailLog("{0},BSLinksetConstraints.RemoveChildFromLinkset,call,rID={1},rBody={2},cID={3},cBody={4}",
157 childx.LocalID, 149 childx.LocalID,
158 rootx.LocalID, rootx.PhysBody.ptr.ToString("X"), 150 rootx.LocalID, rootx.PhysBody.AddrString,
159 childx.LocalID, childx.PhysBody.ptr.ToString("X")); 151 childx.LocalID, childx.PhysBody.AddrString);
160 152
161 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate() 153 PhysicsScene.TaintedObject("BSLinksetConstraints.RemoveChildFromLinkset", delegate()
162 { 154 {
@@ -195,8 +187,8 @@ public sealed class BSLinksetConstraints : BSLinkset
195 187
196 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}", 188 DetailLog("{0},BSLinksetConstraint.BuildConstraint,taint,root={1},rBody={2},child={3},cBody={4},rLoc={5},cLoc={6},midLoc={7}",
197 rootPrim.LocalID, 189 rootPrim.LocalID,
198 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 190 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
199 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X"), 191 childPrim.LocalID, childPrim.PhysBody.AddrString,
200 rootPrim.Position, childPrim.Position, midPoint); 192 rootPrim.Position, childPrim.Position, midPoint);
201 193
202 // create a constraint that allows no freedom of movement between the two objects 194 // create a constraint that allows no freedom of movement between the two objects
@@ -239,14 +231,14 @@ public sealed class BSLinksetConstraints : BSLinkset
239 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero); 231 constrain.SetAngularLimits(OMV.Vector3.Zero, OMV.Vector3.Zero);
240 232
241 // tweek the constraint to increase stability 233 // tweek the constraint to increase stability
242 constrain.UseFrameOffset(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintUseFrameOffset)); 234 constrain.UseFrameOffset(BSParam.BoolNumeric(BSParam.LinkConstraintUseFrameOffset));
243 constrain.TranslationalLimitMotor(PhysicsScene.BoolNumeric(PhysicsScene.Params.linkConstraintEnableTransMotor), 235 constrain.TranslationalLimitMotor(BSParam.BoolNumeric(BSParam.LinkConstraintEnableTransMotor),
244 PhysicsScene.Params.linkConstraintTransMotorMaxVel, 236 BSParam.LinkConstraintTransMotorMaxVel,
245 PhysicsScene.Params.linkConstraintTransMotorMaxForce); 237 BSParam.LinkConstraintTransMotorMaxForce);
246 constrain.SetCFMAndERP(PhysicsScene.Params.linkConstraintCFM, PhysicsScene.Params.linkConstraintERP); 238 constrain.SetCFMAndERP(BSParam.LinkConstraintCFM, BSParam.LinkConstraintERP);
247 if (PhysicsScene.Params.linkConstraintSolverIterations != 0f) 239 if (BSParam.LinkConstraintSolverIterations != 0f)
248 { 240 {
249 constrain.SetSolverIterations(PhysicsScene.Params.linkConstraintSolverIterations); 241 constrain.SetSolverIterations(BSParam.LinkConstraintSolverIterations);
250 } 242 }
251 return constrain; 243 return constrain;
252 } 244 }
@@ -260,14 +252,14 @@ public sealed class BSLinksetConstraints : BSLinkset
260 bool ret = false; 252 bool ret = false;
261 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}", 253 DetailLog("{0},BSLinksetConstraint.PhysicallyUnlinkAChildFromRoot,taint,root={1},rBody={2},child={3},cBody={4}",
262 rootPrim.LocalID, 254 rootPrim.LocalID,
263 rootPrim.LocalID, rootPrim.PhysBody.ptr.ToString("X"), 255 rootPrim.LocalID, rootPrim.PhysBody.AddrString,
264 childPrim.LocalID, childPrim.PhysBody.ptr.ToString("X")); 256 childPrim.LocalID, childPrim.PhysBody.AddrString);
265 257
266 // Find the constraint for this link and get rid of it from the overall collection and from my list 258 // Find the constraint for this link and get rid of it from the overall collection and from my list
267 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody)) 259 if (PhysicsScene.Constraints.RemoveAndDestroyConstraint(rootPrim.PhysBody, childPrim.PhysBody))
268 { 260 {
269 // Make the child refresh its location 261 // Make the child refresh its location
270 BulletSimAPI.PushUpdate2(childPrim.PhysBody.ptr); 262 PhysicsScene.PE.PushUpdate(childPrim.PhysBody);
271 ret = true; 263 ret = true;
272 } 264 }
273 265
@@ -292,20 +284,17 @@ public sealed class BSLinksetConstraints : BSLinkset
292 private void RecomputeLinksetConstraints() 284 private void RecomputeLinksetConstraints()
293 { 285 {
294 float linksetMass = LinksetMass; 286 float linksetMass = LinksetMass;
295 LinksetRoot.UpdatePhysicalMassProperties(linksetMass); 287 LinksetRoot.UpdatePhysicalMassProperties(linksetMass, true);
296 288
297 // DEBUG: see of inter-linkset collisions are causing problems
298 // BulletSimAPI.SetCollisionFilterMask2(LinksetRoot.BSBody.ptr,
299 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
300 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}", 289 DetailLog("{0},BSLinksetConstraint.RecomputeLinksetConstraints,set,rBody={1},linksetMass={2}",
301 LinksetRoot.LocalID, LinksetRoot.PhysBody.ptr.ToString("X"), linksetMass); 290 LinksetRoot.LocalID, LinksetRoot.PhysBody.AddrString, linksetMass);
302 291
303 foreach (BSPhysObject child in m_children) 292 foreach (BSPhysObject child in m_children)
304 { 293 {
305 // A child in the linkset physically shows the mass of the whole linkset. 294 // A child in the linkset physically shows the mass of the whole linkset.
306 // This allows Bullet to apply enough force on the child to move the whole linkset. 295 // This allows Bullet to apply enough force on the child to move the whole linkset.
307 // (Also do the mass stuff before recomputing the constraint so mass is not zero.) 296 // (Also do the mass stuff before recomputing the constraint so mass is not zero.)
308 child.UpdatePhysicalMassProperties(linksetMass); 297 child.UpdatePhysicalMassProperties(linksetMass, true);
309 298
310 BSConstraint constrain; 299 BSConstraint constrain;
311 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain)) 300 if (!PhysicsScene.Constraints.TryGetConstraint(LinksetRoot.PhysBody, child.PhysBody, out constrain))
@@ -315,11 +304,7 @@ public sealed class BSLinksetConstraints : BSLinkset
315 } 304 }
316 constrain.RecomputeConstraintVariables(linksetMass); 305 constrain.RecomputeConstraintVariables(linksetMass);
317 306
318 // DEBUG: see of inter-linkset collisions are causing problems 307 // PhysicsScene.PE.DumpConstraint(PhysicsScene.World, constrain.Constraint); // DEBUG DEBUG
319 // BulletSimAPI.SetCollisionFilterMask2(child.BSBody.ptr,
320 // (uint)CollisionFilterGroups.LinksetFilter, (uint)CollisionFilterGroups.LinksetMask);
321
322 // BulletSimAPI.DumpConstraint2(PhysicsScene.World.ptr, constrain.Constraint.ptr); // DEBUG DEBUG
323 } 308 }
324 309
325 } 310 }
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
new file mode 100755
index 0000000..92d62ff
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMaterials.cs
@@ -0,0 +1,200 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using System.Reflection;
31using Nini.Config;
32
33namespace OpenSim.Region.Physics.BulletSPlugin
34{
35
36public struct MaterialAttributes
37{
38 // Material type values that correspond with definitions for LSL
39 public enum Material : int
40 {
41 Stone = 0,
42 Metal,
43 Glass,
44 Wood,
45 Flesh,
46 Plastic,
47 Rubber,
48 Light,
49 // Hereafter are BulletSim additions
50 Avatar,
51 NumberOfTypes // the count of types in the enum.
52 }
53
54 // Names must be in the order of the above enum.
55 // These names must coorespond to the lower case field names in the MaterialAttributes
56 // structure as reflection is used to select the field to put the value in.
57 public static readonly string[] MaterialAttribs = { "Density", "Friction", "Restitution"};
58
59 public MaterialAttributes(string t, float d, float f, float r)
60 {
61 type = t;
62 density = d;
63 friction = f;
64 restitution = r;
65 }
66 public string type;
67 public float density;
68 public float friction;
69 public float restitution;
70}
71
72public static class BSMaterials
73{
74 // Attributes for each material type
75 private static readonly MaterialAttributes[] Attributes;
76
77 // Map of material name to material type code
78 public static readonly Dictionary<string, MaterialAttributes.Material> MaterialMap;
79
80 static BSMaterials()
81 {
82 // Attribute sets for both the non-physical and physical instances of materials.
83 Attributes = new MaterialAttributes[(int)MaterialAttributes.Material.NumberOfTypes * 2];
84
85 // Map of name to type code.
86 MaterialMap = new Dictionary<string, MaterialAttributes.Material>();
87 MaterialMap.Add("Stone", MaterialAttributes.Material.Stone);
88 MaterialMap.Add("Metal", MaterialAttributes.Material.Metal);
89 MaterialMap.Add("Glass", MaterialAttributes.Material.Glass);
90 MaterialMap.Add("Wood", MaterialAttributes.Material.Wood);
91 MaterialMap.Add("Flesh", MaterialAttributes.Material.Flesh);
92 MaterialMap.Add("Plastic", MaterialAttributes.Material.Plastic);
93 MaterialMap.Add("Rubber", MaterialAttributes.Material.Rubber);
94 MaterialMap.Add("Light", MaterialAttributes.Material.Light);
95 MaterialMap.Add("Avatar", MaterialAttributes.Material.Avatar);
96 }
97
98 // This is where all the default material attributes are defined.
99 public static void InitializeFromDefaults(ConfigurationParameters parms)
100 {
101 // Values from http://wiki.secondlife.com/wiki/PRIM_MATERIAL
102 float dDensity = parms.defaultDensity;
103 float dFriction = parms.defaultFriction;
104 float dRestitution = parms.defaultRestitution;
105 Attributes[(int)MaterialAttributes.Material.Stone] =
106 new MaterialAttributes("stone",dDensity, 0.8f, 0.4f);
107 Attributes[(int)MaterialAttributes.Material.Metal] =
108 new MaterialAttributes("metal",dDensity, 0.3f, 0.4f);
109 Attributes[(int)MaterialAttributes.Material.Glass] =
110 new MaterialAttributes("glass",dDensity, 0.2f, 0.7f);
111 Attributes[(int)MaterialAttributes.Material.Wood] =
112 new MaterialAttributes("wood",dDensity, 0.6f, 0.5f);
113 Attributes[(int)MaterialAttributes.Material.Flesh] =
114 new MaterialAttributes("flesh",dDensity, 0.9f, 0.3f);
115 Attributes[(int)MaterialAttributes.Material.Plastic] =
116 new MaterialAttributes("plastic",dDensity, 0.4f, 0.7f);
117 Attributes[(int)MaterialAttributes.Material.Rubber] =
118 new MaterialAttributes("rubber",dDensity, 0.9f, 0.9f);
119 Attributes[(int)MaterialAttributes.Material.Light] =
120 new MaterialAttributes("light",dDensity, dFriction, dRestitution);
121 Attributes[(int)MaterialAttributes.Material.Avatar] =
122 new MaterialAttributes("avatar",3.5f, 0.2f, 0f);
123
124 Attributes[(int)MaterialAttributes.Material.Stone + (int)MaterialAttributes.Material.NumberOfTypes] =
125 new MaterialAttributes("stonePhysical",dDensity, 0.8f, 0.4f);
126 Attributes[(int)MaterialAttributes.Material.Metal + (int)MaterialAttributes.Material.NumberOfTypes] =
127 new MaterialAttributes("metalPhysical",dDensity, 0.3f, 0.4f);
128 Attributes[(int)MaterialAttributes.Material.Glass + (int)MaterialAttributes.Material.NumberOfTypes] =
129 new MaterialAttributes("glassPhysical",dDensity, 0.2f, 0.7f);
130 Attributes[(int)MaterialAttributes.Material.Wood + (int)MaterialAttributes.Material.NumberOfTypes] =
131 new MaterialAttributes("woodPhysical",dDensity, 0.6f, 0.5f);
132 Attributes[(int)MaterialAttributes.Material.Flesh + (int)MaterialAttributes.Material.NumberOfTypes] =
133 new MaterialAttributes("fleshPhysical",dDensity, 0.9f, 0.3f);
134 Attributes[(int)MaterialAttributes.Material.Plastic + (int)MaterialAttributes.Material.NumberOfTypes] =
135 new MaterialAttributes("plasticPhysical",dDensity, 0.4f, 0.7f);
136 Attributes[(int)MaterialAttributes.Material.Rubber + (int)MaterialAttributes.Material.NumberOfTypes] =
137 new MaterialAttributes("rubberPhysical",dDensity, 0.9f, 0.9f);
138 Attributes[(int)MaterialAttributes.Material.Light + (int)MaterialAttributes.Material.NumberOfTypes] =
139 new MaterialAttributes("lightPhysical",dDensity, dFriction, dRestitution);
140 Attributes[(int)MaterialAttributes.Material.Avatar + (int)MaterialAttributes.Material.NumberOfTypes] =
141 new MaterialAttributes("avatarPhysical",3.5f, 0.2f, 0f);
142 }
143
144 // Under the [BulletSim] section, one can change the individual material
145 // attribute values. The format of the configuration parameter is:
146 // <materialName><Attribute>["Physical"] = floatValue
147 // For instance:
148 // [BulletSim]
149 // StoneFriction = 0.2
150 // FleshRestitutionPhysical = 0.8
151 // Materials can have different parameters for their static and
152 // physical instantiations. When setting the non-physical value,
153 // both values are changed. Setting the physical value only changes
154 // the physical value.
155 public static void InitializefromParameters(IConfig pConfig)
156 {
157 foreach (KeyValuePair<string, MaterialAttributes.Material> kvp in MaterialMap)
158 {
159 string matName = kvp.Key;
160 foreach (string attribName in MaterialAttributes.MaterialAttribs)
161 {
162 string paramName = matName + attribName;
163 if (pConfig.Contains(paramName))
164 {
165 float paramValue = pConfig.GetFloat(paramName);
166 SetAttributeValue((int)kvp.Value, attribName, paramValue);
167 // set the physical value also
168 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
169 }
170 paramName += "Physical";
171 if (pConfig.Contains(paramName))
172 {
173 float paramValue = pConfig.GetFloat(paramName);
174 SetAttributeValue((int)kvp.Value + (int)MaterialAttributes.Material.NumberOfTypes, attribName, paramValue);
175 }
176 }
177 }
178 }
179
180 // Use reflection to set the value in the attribute structure.
181 private static void SetAttributeValue(int matType, string attribName, float val)
182 {
183 MaterialAttributes thisAttrib = Attributes[matType];
184 FieldInfo fieldInfo = thisAttrib.GetType().GetField(attribName.ToLower());
185 if (fieldInfo != null)
186 {
187 fieldInfo.SetValue(thisAttrib, val);
188 Attributes[matType] = thisAttrib;
189 }
190 }
191
192 // Given a material type, return a structure of attributes.
193 public static MaterialAttributes GetAttributes(MaterialAttributes.Material type, bool isPhysical)
194 {
195 int ind = (int)type;
196 if (isPhysical) ind += (int)MaterialAttributes.Material.NumberOfTypes;
197 return Attributes[ind];
198 }
199}
200}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
index bc6e4c4..6d0db2e 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSMotors.cs
@@ -1,104 +1,467 @@
1using System; 1/*
2using System.Collections.Generic; 2 * Copyright (c) Contributors, http://opensimulator.org/
3using System.Text; 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4using OpenMetaverse; 4 *
5 5 * Redistribution and use in source and binary forms, with or without
6namespace OpenSim.Region.Physics.BulletSPlugin 6 * modification, are permitted provided that the following conditions are met:
7{ 7 * * Redistributions of source code must retain the above copyright
8public abstract class BSMotor 8 * notice, this list of conditions and the following disclaimer.
9{ 9 * * Redistributions in binary form must reproduce the above copyright
10 public virtual void Reset() { } 10 * notice, this list of conditions and the following disclaimer in the
11 public virtual void Zero() { } 11 * documentation and/or other materials provided with the distribution.
12} 12 * * Neither the name of the OpenSimulator Project nor the
13// Can all the incremental stepping be replaced with motor classes? 13 * names of its contributors may be used to endorse or promote products
14public class BSVMotor : BSMotor 14 * derived from this software without specific prior written permission.
15{ 15 *
16 public Vector3 FrameOfReference { get; set; } 16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 public Vector3 Offset { get; set; } 17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 public float TimeScale { get; set; } 19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 public float TargetValueDecayTimeScale { get; set; } 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 public Vector3 CurrentValueReductionTimescale { get; set; } 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 public float Efficiency { get; set; } 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 public Vector3 TargetValue { get; private set; } 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 public Vector3 CurrentValue { get; private set; } 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 26 *
27 27 */
28 28using System;
29 BSVMotor(float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency) 29using System.Collections.Generic;
30 { 30using System.Text;
31 TimeScale = timeScale; 31using OpenMetaverse;
32 TargetValueDecayTimeScale = decayTimeScale; 32using OpenSim.Framework;
33 CurrentValueReductionTimescale = frictionTimeScale; 33
34 Efficiency = efficiency; 34namespace OpenSim.Region.Physics.BulletSPlugin
35 } 35{
36 public void SetCurrent(Vector3 current) 36public abstract class BSMotor
37 { 37{
38 CurrentValue = current; 38 // Timescales and other things can be turned off by setting them to 'infinite'.
39 } 39 public const float Infinite = 12345.6f;
40 public void SetTarget(Vector3 target) 40 public readonly static Vector3 InfiniteVector = new Vector3(BSMotor.Infinite, BSMotor.Infinite, BSMotor.Infinite);
41 { 41
42 TargetValue = target; 42 public BSMotor(string useName)
43 } 43 {
44 public Vector3 Step(float timeStep) 44 UseName = useName;
45 { 45 PhysicsScene = null;
46 if (CurrentValue.LengthSquared() > 0.001f) 46 Enabled = true;
47 { 47 }
48 // Vector3 origDir = Target; // DEBUG 48 public virtual bool Enabled { get; set; }
49 // Vector3 origVel = CurrentValue; // DEBUG 49 public virtual void Reset() { }
50 50 public virtual void Zero() { }
51 // Add (desiredVelocity - currentAppliedVelocity) / howLongItShouldTakeToComplete 51 public virtual void GenerateTestOutput(float timeStep) { }
52 Vector3 addAmount = (TargetValue - CurrentValue)/(TargetValue) * timeStep; 52
53 CurrentValue += addAmount; 53 // A name passed at motor creation for easily identifyable debugging messages.
54 54 public string UseName { get; private set; }
55 float decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep; 55
56 TargetValue *= (1f - decayFactor); 56 // Used only for outputting debug information. Might not be set so check for null.
57 57 public BSScene PhysicsScene { get; set; }
58 Vector3 frictionFactor = (Vector3.One / CurrentValueReductionTimescale) * timeStep; 58 protected void MDetailLog(string msg, params Object[] parms)
59 CurrentValue *= (Vector3.One - frictionFactor); 59 {
60 } 60 if (PhysicsScene != null)
61 else 61 {
62 { 62 PhysicsScene.DetailLog(msg, parms);
63 // if what remains of direction is very small, zero it. 63 }
64 TargetValue = Vector3.Zero; 64 }
65 CurrentValue = Vector3.Zero; 65}
66 66
67 // VDetailLog("{0},MoveLinear,zeroed", Prim.LocalID); 67// Motor which moves CurrentValue to TargetValue over TimeScale seconds.
68 } 68// The TargetValue decays in TargetValueDecayTimeScale and
69 return CurrentValue; 69// the CurrentValue will be held back by FrictionTimeScale.
70 } 70// This motor will "zero itself" over time in that the targetValue will
71} 71// decay to zero and the currentValue will follow it to that zero.
72 72// The overall effect is for the returned correction value to go from large
73public class BSFMotor : BSMotor 73// values (the total difference between current and target minus friction)
74{ 74// to small and eventually zero values.
75 public float TimeScale { get; set; } 75// TimeScale and TargetDelayTimeScale may be 'infinite' which means no decay.
76 public float DecayTimeScale { get; set; } 76
77 public float Friction { get; set; } 77// For instance, if something is moving at speed X and the desired speed is Y,
78 public float Efficiency { get; set; } 78// CurrentValue is X and TargetValue is Y. As the motor is stepped, new
79 79// values of CurrentValue are returned that approach the TargetValue.
80 public float Target { get; private set; } 80// The feature of decaying TargetValue is so vehicles will eventually
81 public float CurrentValue { get; private set; } 81// come to a stop rather than run forever. This can be disabled by
82 82// setting TargetValueDecayTimescale to 'infinite'.
83 BSFMotor(float timeScale, float decayTimescale, float friction, float efficiency) 83// The change from CurrentValue to TargetValue is linear over TimeScale seconds.
84 { 84public class BSVMotor : BSMotor
85 } 85{
86 public void SetCurrent(float target) 86 // public Vector3 FrameOfReference { get; set; }
87 { 87 // public Vector3 Offset { get; set; }
88 } 88
89 public void SetTarget(float target) 89 public virtual float TimeScale { get; set; }
90 { 90 public virtual float TargetValueDecayTimeScale { get; set; }
91 } 91 public virtual Vector3 FrictionTimescale { get; set; }
92 public float Step(float timeStep) 92 public virtual float Efficiency { get; set; }
93 { 93
94 return 0f; 94 public virtual float ErrorZeroThreshold { get; set; }
95 } 95
96} 96 public virtual Vector3 TargetValue { get; protected set; }
97public class BSPIDMotor : BSMotor 97 public virtual Vector3 CurrentValue { get; protected set; }
98{ 98 public virtual Vector3 LastError { get; protected set; }
99 // TODO: write and use this one 99
100 BSPIDMotor() 100 public virtual bool ErrorIsZero()
101 { 101 {
102 } 102 return ErrorIsZero(LastError);
103} 103 }
104} 104 public virtual bool ErrorIsZero(Vector3 err)
105 {
106 return (err == Vector3.Zero || err.ApproxEquals(Vector3.Zero, ErrorZeroThreshold));
107 }
108
109 public BSVMotor(string useName)
110 : base(useName)
111 {
112 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
113 Efficiency = 1f;
114 FrictionTimescale = BSMotor.InfiniteVector;
115 CurrentValue = TargetValue = Vector3.Zero;
116 ErrorZeroThreshold = 0.001f;
117 }
118 public BSVMotor(string useName, float timeScale, float decayTimeScale, Vector3 frictionTimeScale, float efficiency)
119 : this(useName)
120 {
121 TimeScale = timeScale;
122 TargetValueDecayTimeScale = decayTimeScale;
123 FrictionTimescale = frictionTimeScale;
124 Efficiency = efficiency;
125 CurrentValue = TargetValue = Vector3.Zero;
126 }
127 public void SetCurrent(Vector3 current)
128 {
129 CurrentValue = current;
130 }
131 public void SetTarget(Vector3 target)
132 {
133 TargetValue = target;
134 }
135 public override void Zero()
136 {
137 base.Zero();
138 CurrentValue = TargetValue = Vector3.Zero;
139 }
140
141 // Compute the next step and return the new current value
142 public virtual Vector3 Step(float timeStep)
143 {
144 if (!Enabled) return TargetValue;
145
146 Vector3 origTarget = TargetValue; // DEBUG
147 Vector3 origCurrVal = CurrentValue; // DEBUG
148
149 Vector3 correction = Vector3.Zero;
150 Vector3 error = TargetValue - CurrentValue;
151 if (!ErrorIsZero(error))
152 {
153 correction = Step(timeStep, error);
154
155 CurrentValue += correction;
156
157 // The desired value reduces to zero which also reduces the difference with current.
158 // If the decay time is infinite, don't decay at all.
159 float decayFactor = 0f;
160 if (TargetValueDecayTimeScale != BSMotor.Infinite)
161 {
162 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
163 TargetValue *= (1f - decayFactor);
164 }
165
166 // The amount we can correct the error is reduced by the friction
167 Vector3 frictionFactor = Vector3.Zero;
168 if (FrictionTimescale != BSMotor.InfiniteVector)
169 {
170 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
171 // Individual friction components can be 'infinite' so compute each separately.
172 frictionFactor.X = (FrictionTimescale.X == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.X);
173 frictionFactor.Y = (FrictionTimescale.Y == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Y);
174 frictionFactor.Z = (FrictionTimescale.Z == BSMotor.Infinite) ? 0f : (1f / FrictionTimescale.Z);
175 frictionFactor *= timeStep;
176 CurrentValue *= (Vector3.One - frictionFactor);
177 }
178
179 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
180 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
181 timeStep, error, correction);
182 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
183 BSScene.DetailLogZero, UseName,
184 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
185 TargetValue, CurrentValue);
186 }
187 else
188 {
189 // Difference between what we have and target is small. Motor is done.
190 CurrentValue = TargetValue;
191 MDetailLog("{0}, BSVMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
192 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
193 }
194
195 return CurrentValue;
196 }
197 public virtual Vector3 Step(float timeStep, Vector3 error)
198 {
199 if (!Enabled) return Vector3.Zero;
200
201 LastError = error;
202 Vector3 returnCorrection = Vector3.Zero;
203 if (!ErrorIsZero())
204 {
205 // correction = error / secondsItShouldTakeToCorrect
206 Vector3 correctionAmount;
207 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
208 correctionAmount = error * timeStep;
209 else
210 correctionAmount = error / TimeScale * timeStep;
211
212 returnCorrection = correctionAmount;
213 MDetailLog("{0}, BSVMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
214 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
215 }
216 return returnCorrection;
217 }
218
219 // The user sets all the parameters and calls this which outputs values until error is zero.
220 public override void GenerateTestOutput(float timeStep)
221 {
222 // maximum number of outputs to generate.
223 int maxOutput = 50;
224 MDetailLog("{0},BSVMotor.Test,{1},===================================== BEGIN Test Output", BSScene.DetailLogZero, UseName);
225 MDetailLog("{0},BSVMotor.Test,{1},timeScale={2},targDlyTS={3},frictTS={4},eff={5},curr={6},tgt={7}",
226 BSScene.DetailLogZero, UseName,
227 TimeScale, TargetValueDecayTimeScale, FrictionTimescale, Efficiency,
228 CurrentValue, TargetValue);
229
230 LastError = BSMotor.InfiniteVector;
231 while (maxOutput-- > 0 && !LastError.ApproxEquals(Vector3.Zero, ErrorZeroThreshold))
232 {
233 Vector3 lastStep = Step(timeStep);
234 MDetailLog("{0},BSVMotor.Test,{1},cur={2},tgt={3},lastError={4},lastStep={5}",
235 BSScene.DetailLogZero, UseName, CurrentValue, TargetValue, LastError, lastStep);
236 }
237 MDetailLog("{0},BSVMotor.Test,{1},===================================== END Test Output", BSScene.DetailLogZero, UseName);
238
239
240 }
241
242 public override string ToString()
243 {
244 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
245 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
246 }
247}
248
249// ============================================================================
250// ============================================================================
251public class BSFMotor : BSMotor
252{
253 public virtual float TimeScale { get; set; }
254 public virtual float TargetValueDecayTimeScale { get; set; }
255 public virtual float FrictionTimescale { get; set; }
256 public virtual float Efficiency { get; set; }
257
258 public virtual float ErrorZeroThreshold { get; set; }
259
260 public virtual float TargetValue { get; protected set; }
261 public virtual float CurrentValue { get; protected set; }
262 public virtual float LastError { get; protected set; }
263
264 public virtual bool ErrorIsZero()
265 {
266 return ErrorIsZero(LastError);
267 }
268 public virtual bool ErrorIsZero(float err)
269 {
270 return (err >= -ErrorZeroThreshold && err <= ErrorZeroThreshold);
271 }
272
273 public BSFMotor(string useName, float timeScale, float decayTimescale, float friction, float efficiency)
274 : base(useName)
275 {
276 TimeScale = TargetValueDecayTimeScale = BSMotor.Infinite;
277 Efficiency = 1f;
278 FrictionTimescale = BSMotor.Infinite;
279 CurrentValue = TargetValue = 0f;
280 ErrorZeroThreshold = 0.01f;
281 }
282 public void SetCurrent(float current)
283 {
284 CurrentValue = current;
285 }
286 public void SetTarget(float target)
287 {
288 TargetValue = target;
289 }
290 public override void Zero()
291 {
292 base.Zero();
293 CurrentValue = TargetValue = 0f;
294 }
295
296 public virtual float Step(float timeStep)
297 {
298 if (!Enabled) return TargetValue;
299
300 float origTarget = TargetValue; // DEBUG
301 float origCurrVal = CurrentValue; // DEBUG
302
303 float correction = 0f;
304 float error = TargetValue - CurrentValue;
305 if (!ErrorIsZero(error))
306 {
307 correction = Step(timeStep, error);
308
309 CurrentValue += correction;
310
311 // The desired value reduces to zero which also reduces the difference with current.
312 // If the decay time is infinite, don't decay at all.
313 float decayFactor = 0f;
314 if (TargetValueDecayTimeScale != BSMotor.Infinite)
315 {
316 decayFactor = (1.0f / TargetValueDecayTimeScale) * timeStep;
317 TargetValue *= (1f - decayFactor);
318 }
319
320 // The amount we can correct the error is reduced by the friction
321 float frictionFactor = 0f;
322 if (FrictionTimescale != BSMotor.Infinite)
323 {
324 // frictionFactor = (Vector3.One / FrictionTimescale) * timeStep;
325 // Individual friction components can be 'infinite' so compute each separately.
326 frictionFactor = 1f / FrictionTimescale;
327 frictionFactor *= timeStep;
328 CurrentValue *= (1f - frictionFactor);
329 }
330
331 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},origCurr={2},origTarget={3},timeStep={4},err={5},corr={6}",
332 BSScene.DetailLogZero, UseName, origCurrVal, origTarget,
333 timeStep, error, correction);
334 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},tgtDecayTS={2},decayFact={3},frictTS={4},frictFact={5},tgt={6},curr={7}",
335 BSScene.DetailLogZero, UseName,
336 TargetValueDecayTimeScale, decayFactor, FrictionTimescale, frictionFactor,
337 TargetValue, CurrentValue);
338 }
339 else
340 {
341 // Difference between what we have and target is small. Motor is done.
342 CurrentValue = TargetValue;
343 MDetailLog("{0}, BSFMotor.Step,zero,{1},origTgt={2},origCurr={3},ret={4}",
344 BSScene.DetailLogZero, UseName, origCurrVal, origTarget, CurrentValue);
345 }
346
347 return CurrentValue;
348 }
349
350 public virtual float Step(float timeStep, float error)
351 {
352 if (!Enabled) return 0f;
353
354 LastError = error;
355 float returnCorrection = 0f;
356 if (!ErrorIsZero())
357 {
358 // correction = error / secondsItShouldTakeToCorrect
359 float correctionAmount;
360 if (TimeScale == 0f || TimeScale == BSMotor.Infinite)
361 correctionAmount = error * timeStep;
362 else
363 correctionAmount = error / TimeScale * timeStep;
364
365 returnCorrection = correctionAmount;
366 MDetailLog("{0}, BSFMotor.Step,nonZero,{1},timeStep={2},timeScale={3},err={4},corr={5}",
367 BSScene.DetailLogZero, UseName, timeStep, TimeScale, error, correctionAmount);
368 }
369 return returnCorrection;
370 }
371
372 public override string ToString()
373 {
374 return String.Format("<{0},curr={1},targ={2},lastErr={3},decayTS={4},frictTS={5}>",
375 UseName, CurrentValue, TargetValue, LastError, TargetValueDecayTimeScale, FrictionTimescale);
376 }
377
378}
379
380// ============================================================================
381// ============================================================================
382// Proportional, Integral, Derivitive Motor
383// Good description at http://www.answers.com/topic/pid-controller . Includes processes for choosing p, i and d factors.
384public class BSPIDVMotor : BSVMotor
385{
386 // Larger makes more overshoot, smaller means converge quicker. Range of 0.1 to 10.
387 public Vector3 proportionFactor { get; set; }
388 public Vector3 integralFactor { get; set; }
389 public Vector3 derivFactor { get; set; }
390
391 // The factors are vectors for the three dimensions. This is the proportional of each
392 // that is applied. This could be multiplied through the actual factors but it
393 // is sometimes easier to manipulate the factors and their mix separately.
394 // to
395 public Vector3 FactorMix;
396
397 // Arbritrary factor range.
398 // EfficiencyHigh means move quickly to the correct number. EfficiencyLow means might over correct.
399 public float EfficiencyHigh = 0.4f;
400 public float EfficiencyLow = 4.0f;
401
402 // Running integration of the error
403 Vector3 RunningIntegration { get; set; }
404
405 public BSPIDVMotor(string useName)
406 : base(useName)
407 {
408 proportionFactor = new Vector3(1.00f, 1.00f, 1.00f);
409 integralFactor = new Vector3(1.00f, 1.00f, 1.00f);
410 derivFactor = new Vector3(1.00f, 1.00f, 1.00f);
411 FactorMix = new Vector3(0.5f, 0.25f, 0.25f);
412 RunningIntegration = Vector3.Zero;
413 LastError = Vector3.Zero;
414 }
415
416 public override void Zero()
417 {
418 base.Zero();
419 }
420
421 public override float Efficiency
422 {
423 get { return base.Efficiency; }
424 set
425 {
426 base.Efficiency = Util.Clamp(value, 0f, 1f);
427
428 // Compute factors based on efficiency.
429 // If efficiency is high (1f), use a factor value that moves the error value to zero with little overshoot.
430 // If efficiency is low (0f), use a factor value that overcorrects.
431 // TODO: might want to vary contribution of different factor depending on efficiency.
432 float factor = ((1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow) / 3f;
433 // float factor = (1f - this.Efficiency) * EfficiencyHigh + EfficiencyLow;
434
435 proportionFactor = new Vector3(factor, factor, factor);
436 integralFactor = new Vector3(factor, factor, factor);
437 derivFactor = new Vector3(factor, factor, factor);
438
439 MDetailLog("{0},BSPIDVMotor.setEfficiency,eff={1},factor={2}", BSScene.DetailLogZero, Efficiency, factor);
440 }
441 }
442
443 // Ignore Current and Target Values and just advance the PID computation on this error.
444 public override Vector3 Step(float timeStep, Vector3 error)
445 {
446 if (!Enabled) return Vector3.Zero;
447
448 // Add up the error so we can integrate over the accumulated errors
449 RunningIntegration += error * timeStep;
450
451 // A simple derivitive is the rate of change from the last error.
452 Vector3 derivitive = (error - LastError) * timeStep;
453 LastError = error;
454
455 // Correction = (proportionOfPresentError + accumulationOfPastError + rateOfChangeOfError)
456 Vector3 ret = error * timeStep * proportionFactor * FactorMix.X
457 + RunningIntegration * integralFactor * FactorMix.Y
458 + derivitive * derivFactor * FactorMix.Z
459 ;
460
461 MDetailLog("{0},BSPIDVMotor.step,ts={1},err={2},runnInt={3},deriv={4},ret={5}",
462 BSScene.DetailLogZero, timeStep, error, RunningIntegration, derivitive, ret);
463
464 return ret;
465 }
466}
467}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
new file mode 100755
index 0000000..b9bd0bf
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSParam.cs
@@ -0,0 +1,610 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30
31using OpenSim.Region.Physics.Manager;
32
33using OpenMetaverse;
34using Nini.Config;
35
36namespace OpenSim.Region.Physics.BulletSPlugin
37{
38public static class BSParam
39{
40 // Level of Detail values kept as float because that's what the Meshmerizer wants
41 public static float MeshLOD { get; private set; }
42 public static float MeshMegaPrimLOD { get; private set; }
43 public static float MeshMegaPrimThreshold { get; private set; }
44 public static float SculptLOD { get; private set; }
45
46 public static float MinimumObjectMass { get; private set; }
47 public static float MaximumObjectMass { get; private set; }
48
49 public static float LinearDamping { get; private set; }
50 public static float AngularDamping { get; private set; }
51 public static float DeactivationTime { get; private set; }
52 public static float LinearSleepingThreshold { get; private set; }
53 public static float AngularSleepingThreshold { get; private set; }
54 public static float CcdMotionThreshold { get; private set; }
55 public static float CcdSweptSphereRadius { get; private set; }
56 public static float ContactProcessingThreshold { get; private set; }
57
58 public static bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
59 public static bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
60 public static bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
61
62 public static float TerrainImplementation { get; private set; }
63 public static float TerrainFriction { get; private set; }
64 public static float TerrainHitFraction { get; private set; }
65 public static float TerrainRestitution { get; private set; }
66 public static float TerrainCollisionMargin { get; private set; }
67
68 // Avatar parameters
69 public static float AvatarFriction { get; private set; }
70 public static float AvatarStandingFriction { get; private set; }
71 public static float AvatarAlwaysRunFactor { get; private set; }
72 public static float AvatarDensity { get; private set; }
73 public static float AvatarRestitution { get; private set; }
74 public static float AvatarCapsuleWidth { get; private set; }
75 public static float AvatarCapsuleDepth { get; private set; }
76 public static float AvatarCapsuleHeight { get; private set; }
77 public static float AvatarContactProcessingThreshold { get; private set; }
78
79 public static float VehicleAngularDamping { get; private set; }
80
81 public static float LinksetImplementation { get; private set; }
82 public static float LinkConstraintUseFrameOffset { get; private set; }
83 public static float LinkConstraintEnableTransMotor { get; private set; }
84 public static float LinkConstraintTransMotorMaxVel { get; private set; }
85 public static float LinkConstraintTransMotorMaxForce { get; private set; }
86 public static float LinkConstraintERP { get; private set; }
87 public static float LinkConstraintCFM { get; private set; }
88 public static float LinkConstraintSolverIterations { get; private set; }
89
90 public static float PID_D { get; private set; } // derivative
91 public static float PID_P { get; private set; } // proportional
92
93 // Various constants that come from that other virtual world that shall not be named
94 public const float MinGravityZ = -1f;
95 public const float MaxGravityZ = 28f;
96 public const float MinFriction = 0f;
97 public const float MaxFriction = 255f;
98 public const float MinDensity = 0f;
99 public const float MaxDensity = 22587f;
100 public const float MinRestitution = 0f;
101 public const float MaxRestitution = 1f;
102 public const float MaxAddForceMagnitude = 20000f;
103
104 // ===========================================================================
105 public delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
106 public delegate float ParamGet(BSScene scene);
107 public delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
108 public delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
109
110 public struct ParameterDefn
111 {
112 public string name; // string name of the parameter
113 public string desc; // a short description of what the parameter means
114 public float defaultValue; // default value if not specified anywhere else
115 public ParamUser userParam; // get the value from the configuration file
116 public ParamGet getter; // return the current value stored for this parameter
117 public ParamSet setter; // set the current value for this parameter
118 public SetOnObject onObject; // set the value on an object in the physical domain
119 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
120 {
121 name = n;
122 desc = d;
123 defaultValue = v;
124 userParam = u;
125 getter = g;
126 setter = s;
127 onObject = null;
128 }
129 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
130 {
131 name = n;
132 desc = d;
133 defaultValue = v;
134 userParam = u;
135 getter = g;
136 setter = s;
137 onObject = o;
138 }
139 }
140
141 // List of all of the externally visible parameters.
142 // For each parameter, this table maps a text name to getter and setters.
143 // To add a new externally referencable/settable parameter, add the paramter storage
144 // location somewhere in the program and make an entry in this table with the
145 // getters and setters.
146 // It is easiest to find an existing definition and copy it.
147 // Parameter values are floats. Booleans are converted to a floating value.
148 //
149 // A ParameterDefn() takes the following parameters:
150 // -- the text name of the parameter. This is used for console input and ini file.
151 // -- a short text description of the parameter. This shows up in the console listing.
152 // -- a default value (float)
153 // -- a delegate for fetching the parameter from the ini file.
154 // Should handle fetching the right type from the ini file and converting it.
155 // -- a delegate for getting the value as a float
156 // -- a delegate for setting the value from a float
157 // -- an optional delegate to update the value in the world. Most often used to
158 // push the new value to an in-world object.
159 //
160 // The single letter parameters for the delegates are:
161 // s = BSScene
162 // o = BSPhysObject
163 // p = string parameter name
164 // l = localID of referenced object
165 // v = value (float)
166 // cf = parameter configuration class (for fetching values from ini file)
167 private static ParameterDefn[] ParameterDefinitions =
168 {
169 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
170 ConfigurationParameters.numericTrue,
171 (s,cf,p,v) => { ShouldMeshSculptedPrim = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
172 (s) => { return BSParam.NumericBool(ShouldMeshSculptedPrim); },
173 (s,p,l,v) => { ShouldMeshSculptedPrim = BSParam.BoolNumeric(v); } ),
174 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
175 ConfigurationParameters.numericFalse,
176 (s,cf,p,v) => { ShouldForceSimplePrimMeshing = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
177 (s) => { return BSParam.NumericBool(ShouldForceSimplePrimMeshing); },
178 (s,p,l,v) => { ShouldForceSimplePrimMeshing = BSParam.BoolNumeric(v); } ),
179 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
180 ConfigurationParameters.numericTrue,
181 (s,cf,p,v) => { ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, BSParam.BoolNumeric(v)); },
182 (s) => { return BSParam.NumericBool(ShouldUseHullsForPhysicalObjects); },
183 (s,p,l,v) => { ShouldUseHullsForPhysicalObjects = BSParam.BoolNumeric(v); } ),
184
185 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
186 8f,
187 (s,cf,p,v) => { MeshLOD = (float)cf.GetInt(p, (int)v); },
188 (s) => { return MeshLOD; },
189 (s,p,l,v) => { MeshLOD = v; } ),
190 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
191 16f,
192 (s,cf,p,v) => { MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
193 (s) => { return MeshMegaPrimLOD; },
194 (s,p,l,v) => { MeshMegaPrimLOD = v; } ),
195 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
196 10f,
197 (s,cf,p,v) => { MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
198 (s) => { return MeshMegaPrimThreshold; },
199 (s,p,l,v) => { MeshMegaPrimThreshold = v; } ),
200 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
201 32f,
202 (s,cf,p,v) => { SculptLOD = (float)cf.GetInt(p, (int)v); },
203 (s) => { return SculptLOD; },
204 (s,p,l,v) => { SculptLOD = v; } ),
205
206 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
207 10f,
208 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
209 (s) => { return (float)s.m_maxSubSteps; },
210 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
211 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
212 1f / 60f,
213 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
214 (s) => { return (float)s.m_fixedTimeStep; },
215 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
216 new ParameterDefn("NominalFrameRate", "The base frame rate we claim",
217 55f,
218 (s,cf,p,v) => { s.NominalFrameRate = cf.GetInt(p, (int)v); },
219 (s) => { return (float)s.NominalFrameRate; },
220 (s,p,l,v) => { s.NominalFrameRate = (int)v; } ),
221 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
222 2048f,
223 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
224 (s) => { return (float)s.m_maxCollisionsPerFrame; },
225 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
226 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
227 8000f,
228 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
229 (s) => { return (float)s.m_maxUpdatesPerFrame; },
230 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
231 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
232 500f,
233 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
234 (s) => { return (float)s.m_taintsToProcessPerStep; },
235 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
236 new ParameterDefn("MinObjectMass", "Minimum object mass (0.0001)",
237 0.0001f,
238 (s,cf,p,v) => { MinimumObjectMass = cf.GetFloat(p, v); },
239 (s) => { return (float)MinimumObjectMass; },
240 (s,p,l,v) => { MinimumObjectMass = v; } ),
241 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
242 10000.01f,
243 (s,cf,p,v) => { MaximumObjectMass = cf.GetFloat(p, v); },
244 (s) => { return (float)MaximumObjectMass; },
245 (s,p,l,v) => { MaximumObjectMass = v; } ),
246
247 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
248 2200f,
249 (s,cf,p,v) => { PID_D = cf.GetFloat(p, v); },
250 (s) => { return (float)PID_D; },
251 (s,p,l,v) => { PID_D = v; } ),
252 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
253 900f,
254 (s,cf,p,v) => { PID_P = cf.GetFloat(p, v); },
255 (s) => { return (float)PID_P; },
256 (s,p,l,v) => { PID_P = v; } ),
257
258 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
259 0.2f,
260 (s,cf,p,v) => { s.UnmanagedParams[0].defaultFriction = cf.GetFloat(p, v); },
261 (s) => { return s.UnmanagedParams[0].defaultFriction; },
262 (s,p,l,v) => { s.UnmanagedParams[0].defaultFriction = v; } ),
263 new ParameterDefn("DefaultDensity", "Density for new objects" ,
264 10.000006836f, // Aluminum g/cm3
265 (s,cf,p,v) => { s.UnmanagedParams[0].defaultDensity = cf.GetFloat(p, v); },
266 (s) => { return s.UnmanagedParams[0].defaultDensity; },
267 (s,p,l,v) => { s.UnmanagedParams[0].defaultDensity = v; } ),
268 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
269 0f,
270 (s,cf,p,v) => { s.UnmanagedParams[0].defaultRestitution = cf.GetFloat(p, v); },
271 (s) => { return s.UnmanagedParams[0].defaultRestitution; },
272 (s,p,l,v) => { s.UnmanagedParams[0].defaultRestitution = v; } ),
273 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
274 0.04f,
275 (s,cf,p,v) => { s.UnmanagedParams[0].collisionMargin = cf.GetFloat(p, v); },
276 (s) => { return s.UnmanagedParams[0].collisionMargin; },
277 (s,p,l,v) => { s.UnmanagedParams[0].collisionMargin = v; } ),
278 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
279 -9.80665f,
280 (s,cf,p,v) => { s.UnmanagedParams[0].gravity = cf.GetFloat(p, v); },
281 (s) => { return s.UnmanagedParams[0].gravity; },
282 (s,p,l,v) => { s.UpdateParameterObject((x)=>{s.UnmanagedParams[0].gravity=x;}, p, PhysParameterEntry.APPLY_TO_NONE, v); },
283 (s,o,v) => { s.PE.SetGravity(o.PhysBody, new Vector3(0f,0f,v)); } ),
284
285
286 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
287 0f,
288 (s,cf,p,v) => { LinearDamping = cf.GetFloat(p, v); },
289 (s) => { return LinearDamping; },
290 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearDamping=x;}, p, l, v); },
291 (s,o,v) => { s.PE.SetDamping(o.PhysBody, v, AngularDamping); } ),
292 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
293 0f,
294 (s,cf,p,v) => { AngularDamping = cf.GetFloat(p, v); },
295 (s) => { return AngularDamping; },
296 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularDamping=x;}, p, l, v); },
297 (s,o,v) => { s.PE.SetDamping(o.PhysBody, LinearDamping, v); } ),
298 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
299 0.2f,
300 (s,cf,p,v) => { DeactivationTime = cf.GetFloat(p, v); },
301 (s) => { return DeactivationTime; },
302 (s,p,l,v) => { s.UpdateParameterObject((x)=>{DeactivationTime=x;}, p, l, v); },
303 (s,o,v) => { s.PE.SetDeactivationTime(o.PhysBody, v); } ),
304 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
305 0.8f,
306 (s,cf,p,v) => { LinearSleepingThreshold = cf.GetFloat(p, v); },
307 (s) => { return LinearSleepingThreshold; },
308 (s,p,l,v) => { s.UpdateParameterObject((x)=>{LinearSleepingThreshold=x;}, p, l, v); },
309 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
310 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
311 1.0f,
312 (s,cf,p,v) => { AngularSleepingThreshold = cf.GetFloat(p, v); },
313 (s) => { return AngularSleepingThreshold; },
314 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AngularSleepingThreshold=x;}, p, l, v); },
315 (s,o,v) => { s.PE.SetSleepingThresholds(o.PhysBody, v, v); } ),
316 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
317 0f, // set to zero to disable
318 (s,cf,p,v) => { CcdMotionThreshold = cf.GetFloat(p, v); },
319 (s) => { return CcdMotionThreshold; },
320 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdMotionThreshold=x;}, p, l, v); },
321 (s,o,v) => { s.PE.SetCcdMotionThreshold(o.PhysBody, v); } ),
322 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
323 0f,
324 (s,cf,p,v) => { CcdSweptSphereRadius = cf.GetFloat(p, v); },
325 (s) => { return CcdSweptSphereRadius; },
326 (s,p,l,v) => { s.UpdateParameterObject((x)=>{CcdSweptSphereRadius=x;}, p, l, v); },
327 (s,o,v) => { s.PE.SetCcdSweptSphereRadius(o.PhysBody, v); } ),
328 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
329 0.1f,
330 (s,cf,p,v) => { ContactProcessingThreshold = cf.GetFloat(p, v); },
331 (s) => { return ContactProcessingThreshold; },
332 (s,p,l,v) => { s.UpdateParameterObject((x)=>{ContactProcessingThreshold=x;}, p, l, v); },
333 (s,o,v) => { s.PE.SetContactProcessingThreshold(o.PhysBody, v); } ),
334
335 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
336 (float)BSTerrainPhys.TerrainImplementation.Mesh,
337 (s,cf,p,v) => { TerrainImplementation = cf.GetFloat(p,v); },
338 (s) => { return TerrainImplementation; },
339 (s,p,l,v) => { TerrainImplementation = v; } ),
340 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
341 0.3f,
342 (s,cf,p,v) => { TerrainFriction = cf.GetFloat(p, v); },
343 (s) => { return TerrainFriction; },
344 (s,p,l,v) => { TerrainFriction = v; /* TODO: set on real terrain */} ),
345 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
346 0.8f,
347 (s,cf,p,v) => { TerrainHitFraction = cf.GetFloat(p, v); },
348 (s) => { return TerrainHitFraction; },
349 (s,p,l,v) => { TerrainHitFraction = v; /* TODO: set on real terrain */ } ),
350 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
351 0f,
352 (s,cf,p,v) => { TerrainRestitution = cf.GetFloat(p, v); },
353 (s) => { return TerrainRestitution; },
354 (s,p,l,v) => { TerrainRestitution = v; /* TODO: set on real terrain */ } ),
355 new ParameterDefn("TerrainCollisionMargin", "Margin where collision checking starts" ,
356 0.04f,
357 (s,cf,p,v) => { TerrainCollisionMargin = cf.GetFloat(p, v); },
358 (s) => { return TerrainCollisionMargin; },
359 (s,p,l,v) => { TerrainCollisionMargin = v; /* TODO: set on real terrain */ } ),
360
361 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
362 0.2f,
363 (s,cf,p,v) => { AvatarFriction = cf.GetFloat(p, v); },
364 (s) => { return AvatarFriction; },
365 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarFriction=x;}, p, l, v); } ),
366 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
367 10.0f,
368 (s,cf,p,v) => { AvatarStandingFriction = cf.GetFloat(p, v); },
369 (s) => { return AvatarStandingFriction; },
370 (s,p,l,v) => { AvatarStandingFriction = v; } ),
371 new ParameterDefn("AvatarAlwaysRunFactor", "Speed multiplier if avatar is set to always run",
372 1.3f,
373 (s,cf,p,v) => { AvatarAlwaysRunFactor = cf.GetFloat(p, v); },
374 (s) => { return AvatarAlwaysRunFactor; },
375 (s,p,l,v) => { AvatarAlwaysRunFactor = v; } ),
376 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
377 3.5f,
378 (s,cf,p,v) => { AvatarDensity = cf.GetFloat(p, v); },
379 (s) => { return AvatarDensity; },
380 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarDensity=x;}, p, l, v); } ),
381 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
382 0f,
383 (s,cf,p,v) => { AvatarRestitution = cf.GetFloat(p, v); },
384 (s) => { return AvatarRestitution; },
385 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarRestitution=x;}, p, l, v); } ),
386 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
387 0.6f,
388 (s,cf,p,v) => { AvatarCapsuleWidth = cf.GetFloat(p, v); },
389 (s) => { return AvatarCapsuleWidth; },
390 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleWidth=x;}, p, l, v); } ),
391 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
392 0.45f,
393 (s,cf,p,v) => { AvatarCapsuleDepth = cf.GetFloat(p, v); },
394 (s) => { return AvatarCapsuleDepth; },
395 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleDepth=x;}, p, l, v); } ),
396 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
397 1.5f,
398 (s,cf,p,v) => { AvatarCapsuleHeight = cf.GetFloat(p, v); },
399 (s) => { return AvatarCapsuleHeight; },
400 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarCapsuleHeight=x;}, p, l, v); } ),
401 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
402 0.1f,
403 (s,cf,p,v) => { AvatarContactProcessingThreshold = cf.GetFloat(p, v); },
404 (s) => { return AvatarContactProcessingThreshold; },
405 (s,p,l,v) => { s.UpdateParameterObject((x)=>{AvatarContactProcessingThreshold=x;}, p, l, v); } ),
406
407 new ParameterDefn("VehicleAngularDamping", "Factor to damp vehicle angular movement per second (0.0 - 1.0)",
408 0.95f,
409 (s,cf,p,v) => { VehicleAngularDamping = cf.GetFloat(p, v); },
410 (s) => { return VehicleAngularDamping; },
411 (s,p,l,v) => { VehicleAngularDamping = v; } ),
412
413 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
414 0f,
415 (s,cf,p,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
416 (s) => { return s.UnmanagedParams[0].maxPersistantManifoldPoolSize; },
417 (s,p,l,v) => { s.UnmanagedParams[0].maxPersistantManifoldPoolSize = v; } ),
418 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
419 0f,
420 (s,cf,p,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
421 (s) => { return s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize; },
422 (s,p,l,v) => { s.UnmanagedParams[0].maxCollisionAlgorithmPoolSize = v; } ),
423 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
424 ConfigurationParameters.numericFalse,
425 (s,cf,p,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
426 (s) => { return s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation; },
427 (s,p,l,v) => { s.UnmanagedParams[0].shouldDisableContactPoolDynamicAllocation = v; } ),
428 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
429 ConfigurationParameters.numericFalse,
430 (s,cf,p,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
431 (s) => { return s.UnmanagedParams[0].shouldForceUpdateAllAabbs; },
432 (s,p,l,v) => { s.UnmanagedParams[0].shouldForceUpdateAllAabbs = v; } ),
433 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
434 ConfigurationParameters.numericTrue,
435 (s,cf,p,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
436 (s) => { return s.UnmanagedParams[0].shouldRandomizeSolverOrder; },
437 (s,p,l,v) => { s.UnmanagedParams[0].shouldRandomizeSolverOrder = v; } ),
438 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
439 ConfigurationParameters.numericTrue,
440 (s,cf,p,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
441 (s) => { return s.UnmanagedParams[0].shouldSplitSimulationIslands; },
442 (s,p,l,v) => { s.UnmanagedParams[0].shouldSplitSimulationIslands = v; } ),
443 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
444 ConfigurationParameters.numericFalse,
445 (s,cf,p,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
446 (s) => { return s.UnmanagedParams[0].shouldEnableFrictionCaching; },
447 (s,p,l,v) => { s.UnmanagedParams[0].shouldEnableFrictionCaching = v; } ),
448 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
449 0f, // zero says use Bullet default
450 (s,cf,p,v) => { s.UnmanagedParams[0].numberOfSolverIterations = cf.GetFloat(p, v); },
451 (s) => { return s.UnmanagedParams[0].numberOfSolverIterations; },
452 (s,p,l,v) => { s.UnmanagedParams[0].numberOfSolverIterations = v; } ),
453
454 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
455 (float)BSLinkset.LinksetImplementation.Compound,
456 (s,cf,p,v) => { LinksetImplementation = cf.GetFloat(p,v); },
457 (s) => { return LinksetImplementation; },
458 (s,p,l,v) => { LinksetImplementation = v; } ),
459 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
460 ConfigurationParameters.numericFalse,
461 (s,cf,p,v) => { LinkConstraintUseFrameOffset = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
462 (s) => { return LinkConstraintUseFrameOffset; },
463 (s,p,l,v) => { LinkConstraintUseFrameOffset = v; } ),
464 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
465 ConfigurationParameters.numericTrue,
466 (s,cf,p,v) => { LinkConstraintEnableTransMotor = BSParam.NumericBool(cf.GetBoolean(p, BSParam.BoolNumeric(v))); },
467 (s) => { return LinkConstraintEnableTransMotor; },
468 (s,p,l,v) => { LinkConstraintEnableTransMotor = v; } ),
469 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
470 5.0f,
471 (s,cf,p,v) => { LinkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
472 (s) => { return LinkConstraintTransMotorMaxVel; },
473 (s,p,l,v) => { LinkConstraintTransMotorMaxVel = v; } ),
474 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
475 0.1f,
476 (s,cf,p,v) => { LinkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
477 (s) => { return LinkConstraintTransMotorMaxForce; },
478 (s,p,l,v) => { LinkConstraintTransMotorMaxForce = v; } ),
479 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
480 0.1f,
481 (s,cf,p,v) => { LinkConstraintCFM = cf.GetFloat(p, v); },
482 (s) => { return LinkConstraintCFM; },
483 (s,p,l,v) => { LinkConstraintCFM = v; } ),
484 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
485 0.1f,
486 (s,cf,p,v) => { LinkConstraintERP = cf.GetFloat(p, v); },
487 (s) => { return LinkConstraintERP; },
488 (s,p,l,v) => { LinkConstraintERP = v; } ),
489 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
490 40,
491 (s,cf,p,v) => { LinkConstraintSolverIterations = cf.GetFloat(p, v); },
492 (s) => { return LinkConstraintSolverIterations; },
493 (s,p,l,v) => { LinkConstraintSolverIterations = v; } ),
494
495 new ParameterDefn("PhysicsMetricFrames", "Frames between outputting detailed phys metrics. (0 is off)",
496 0f,
497 (s,cf,p,v) => { s.PhysicsMetricDumpFrames = cf.GetFloat(p, (int)v); },
498 (s) => { return (float)s.PhysicsMetricDumpFrames; },
499 (s,p,l,v) => { s.PhysicsMetricDumpFrames = (int)v; } ),
500 new ParameterDefn("ResetBroadphasePool", "Setting this is any value resets the broadphase collision pool",
501 0f,
502 (s,cf,p,v) => { ; },
503 (s) => { return 0f; },
504 (s,p,l,v) => { BSParam.ResetBroadphasePoolTainted(s, v); } ),
505 new ParameterDefn("ResetConstraintSolver", "Setting this is any value resets the constraint solver",
506 0f,
507 (s,cf,p,v) => { ; },
508 (s) => { return 0f; },
509 (s,p,l,v) => { BSParam.ResetConstraintSolverTainted(s, v); } ),
510 };
511
512 // Convert a boolean to our numeric true and false values
513 public static float NumericBool(bool b)
514 {
515 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
516 }
517
518 // Convert numeric true and false values to a boolean
519 public static bool BoolNumeric(float b)
520 {
521 return (b == ConfigurationParameters.numericTrue ? true : false);
522 }
523
524 private static void ResetBroadphasePoolTainted(BSScene pPhysScene, float v)
525 {
526 BSScene physScene = pPhysScene;
527 physScene.TaintedObject("BSParam.ResetBroadphasePoolTainted", delegate()
528 {
529 physScene.PE.ResetBroadphasePool(physScene.World);
530 });
531 }
532
533 private static void ResetConstraintSolverTainted(BSScene pPhysScene, float v)
534 {
535 BSScene physScene = pPhysScene;
536 physScene.TaintedObject("BSParam.ResetConstraintSolver", delegate()
537 {
538 physScene.PE.ResetConstraintSolver(physScene.World);
539 });
540 }
541
542 // Search through the parameter definitions and return the matching
543 // ParameterDefn structure.
544 // Case does not matter as names are compared after converting to lower case.
545 // Returns 'false' if the parameter is not found.
546 internal static bool TryGetParameter(string paramName, out ParameterDefn defn)
547 {
548 bool ret = false;
549 ParameterDefn foundDefn = new ParameterDefn();
550 string pName = paramName.ToLower();
551
552 foreach (ParameterDefn parm in ParameterDefinitions)
553 {
554 if (pName == parm.name.ToLower())
555 {
556 foundDefn = parm;
557 ret = true;
558 break;
559 }
560 }
561 defn = foundDefn;
562 return ret;
563 }
564
565 // Pass through the settable parameters and set the default values
566 internal static void SetParameterDefaultValues(BSScene physicsScene)
567 {
568 foreach (ParameterDefn parm in ParameterDefinitions)
569 {
570 parm.setter(physicsScene, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
571 }
572 }
573
574 // Get user set values out of the ini file.
575 internal static void SetParameterConfigurationValues(BSScene physicsScene, IConfig cfg)
576 {
577 foreach (ParameterDefn parm in ParameterDefinitions)
578 {
579 parm.userParam(physicsScene, cfg, parm.name, parm.defaultValue);
580 }
581 }
582
583 internal static PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
584
585 // This creates an array in the correct format for returning the list of
586 // parameters. This is used by the 'list' option of the 'physics' command.
587 internal static void BuildParameterTable()
588 {
589 if (SettableParameters.Length < ParameterDefinitions.Length)
590 {
591 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
592 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
593 {
594 ParameterDefn pd = ParameterDefinitions[ii];
595 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
596 }
597
598 // make the list in alphabetical order for estetic reasons
599 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
600 {
601 return ppe1.name.CompareTo(ppe2.name);
602 });
603
604 SettableParameters = entries.ToArray();
605 }
606 }
607
608
609}
610}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
index f6a890e..534f929 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPhysObject.cs
@@ -45,6 +45,16 @@ namespace OpenSim.Region.Physics.BulletSPlugin
45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine. 45 * ForceVariableName: direct reference (store and fetch) to the value in the physics engine.
46 * The last two (and certainly the last one) should be referenced only in taint-time. 46 * The last two (and certainly the last one) should be referenced only in taint-time.
47 */ 47 */
48
49/*
50 * As of 20121221, the following are the call sequences (going down) for different script physical functions:
51 * llApplyImpulse llApplyRotImpulse llSetTorque llSetForce
52 * SOP.ApplyImpulse SOP.ApplyAngularImpulse SOP.SetAngularImpulse SOP.SetForce
53 * SOG.ApplyImpulse SOG.ApplyAngularImpulse SOG.SetAngularImpulse
54 * PA.AddForce PA.AddAngularForce PA.Torque = v PA.Force = v
55 * BS.ApplyCentralForce BS.ApplyTorque
56 */
57
48public abstract class BSPhysObject : PhysicsActor 58public abstract class BSPhysObject : PhysicsActor
49{ 59{
50 protected BSPhysObject() 60 protected BSPhysObject()
@@ -57,26 +67,42 @@ public abstract class BSPhysObject : PhysicsActor
57 PhysObjectName = name; 67 PhysObjectName = name;
58 TypeName = typeName; 68 TypeName = typeName;
59 69
70 // We don't have any physical representation yet.
71 PhysBody = new BulletBody(localID);
72 PhysShape = new BulletShape();
73
74 // A linkset of just me
60 Linkset = BSLinkset.Factory(PhysicsScene, this); 75 Linkset = BSLinkset.Factory(PhysicsScene, this);
61 LastAssetBuildFailed = false; 76 LastAssetBuildFailed = false;
62 77
78 // Default material type
79 Material = MaterialAttributes.Material.Wood;
80
63 CollisionCollection = new CollisionEventUpdate(); 81 CollisionCollection = new CollisionEventUpdate();
64 SubscribedEventsMs = 0; 82 SubscribedEventsMs = 0;
65 CollidingStep = 0; 83 CollidingStep = 0;
66 CollidingGroundStep = 0; 84 CollidingGroundStep = 0;
67 } 85 }
68 86
87 // Tell the object to clean up.
88 public virtual void Destroy()
89 {
90 UnRegisterAllPreStepActions();
91 }
92
69 public BSScene PhysicsScene { get; protected set; } 93 public BSScene PhysicsScene { get; protected set; }
70 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor 94 // public override uint LocalID { get; set; } // Use the LocalID definition in PhysicsActor
71 public string PhysObjectName { get; protected set; } 95 public string PhysObjectName { get; protected set; }
72 public string TypeName { get; protected set; } 96 public string TypeName { get; protected set; }
73 97
74 public BSLinkset Linkset { get; set; } 98 public BSLinkset Linkset { get; set; }
99 public BSLinksetInfo LinksetInfo { get; set; }
75 100
76 // Return the object mass without calculating it or having side effects 101 // Return the object mass without calculating it or having side effects
77 public abstract float RawMass { get; } 102 public abstract float RawMass { get; }
78 // Set the raw mass but also update physical mass properties (inertia, ...) 103 // Set the raw mass but also update physical mass properties (inertia, ...)
79 public abstract void UpdatePhysicalMassProperties(float mass); 104 // 'inWorld' true if the object has already been added to the dynamic world.
105 public abstract void UpdatePhysicalMassProperties(float mass, bool inWorld);
80 106
81 // The last value calculated for the prim's inertia 107 // The last value calculated for the prim's inertia
82 public OMV.Vector3 Inertia { get; set; } 108 public OMV.Vector3 Inertia { get; set; }
@@ -105,10 +131,17 @@ public abstract class BSPhysObject : PhysicsActor
105 public EntityProperties CurrentEntityProperties { get; set; } 131 public EntityProperties CurrentEntityProperties { get; set; }
106 public EntityProperties LastEntityProperties { get; set; } 132 public EntityProperties LastEntityProperties { get; set; }
107 133
108 public abstract OMV.Vector3 Scale { get; set; } 134 public virtual OMV.Vector3 Scale { get; set; }
109 public abstract bool IsSolid { get; } 135 public abstract bool IsSolid { get; }
110 public abstract bool IsStatic { get; } 136 public abstract bool IsStatic { get; }
111 137
138 // Materialness
139 public MaterialAttributes.Material Material { get; private set; }
140 public override void SetMaterial(int material)
141 {
142 Material = (MaterialAttributes.Material)material;
143 }
144
112 // Stop all physical motion. 145 // Stop all physical motion.
113 public abstract void ZeroMotion(bool inTaintTime); 146 public abstract void ZeroMotion(bool inTaintTime);
114 public abstract void ZeroAngularMotion(bool inTaintTime); 147 public abstract void ZeroAngularMotion(bool inTaintTime);
@@ -119,15 +152,23 @@ public abstract class BSPhysObject : PhysicsActor
119 // Update the physical location and motion of the object. Called with data from Bullet. 152 // Update the physical location and motion of the object. Called with data from Bullet.
120 public abstract void UpdateProperties(EntityProperties entprop); 153 public abstract void UpdateProperties(EntityProperties entprop);
121 154
122 // Tell the object to clean up.
123 public abstract void Destroy();
124
125 public abstract OMV.Vector3 RawPosition { get; set; } 155 public abstract OMV.Vector3 RawPosition { get; set; }
126 public abstract OMV.Vector3 ForcePosition { get; set; } 156 public abstract OMV.Vector3 ForcePosition { get; set; }
127 157
128 public abstract OMV.Quaternion RawOrientation { get; set; } 158 public abstract OMV.Quaternion RawOrientation { get; set; }
129 public abstract OMV.Quaternion ForceOrientation { get; set; } 159 public abstract OMV.Quaternion ForceOrientation { get; set; }
130 160
161 // The system is telling us the velocity it wants to move at.
162 // protected OMV.Vector3 m_targetVelocity; // use the definition in PhysicsActor
163 public override OMV.Vector3 TargetVelocity
164 {
165 get { return m_targetVelocity; }
166 set
167 {
168 m_targetVelocity = value;
169 Velocity = value;
170 }
171 }
131 public abstract OMV.Vector3 ForceVelocity { get; set; } 172 public abstract OMV.Vector3 ForceVelocity { get; set; }
132 173
133 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; } 174 public abstract OMV.Vector3 ForceRotationalVelocity { get; set; }
@@ -146,9 +187,40 @@ public abstract class BSPhysObject : PhysicsActor
146 protected long CollidingStep { get; set; } 187 protected long CollidingStep { get; set; }
147 // The simulation step that last had a collision with the ground 188 // The simulation step that last had a collision with the ground
148 protected long CollidingGroundStep { get; set; } 189 protected long CollidingGroundStep { get; set; }
190 // The simulation step that last collided with an object
191 protected long CollidingObjectStep { get; set; }
149 // The collision flags we think are set in Bullet 192 // The collision flags we think are set in Bullet
150 protected CollisionFlags CurrentCollisionFlags { get; set; } 193 protected CollisionFlags CurrentCollisionFlags { get; set; }
151 194
195 public override bool IsColliding {
196 get { return (CollidingStep == PhysicsScene.SimulationStep); }
197 set {
198 if (value)
199 CollidingStep = PhysicsScene.SimulationStep;
200 else
201 CollidingStep = 0;
202 }
203 }
204 public override bool CollidingGround {
205 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
206 set
207 {
208 if (value)
209 CollidingGroundStep = PhysicsScene.SimulationStep;
210 else
211 CollidingGroundStep = 0;
212 }
213 }
214 public override bool CollidingObj {
215 get { return (CollidingObjectStep == PhysicsScene.SimulationStep); }
216 set {
217 if (value)
218 CollidingObjectStep = PhysicsScene.SimulationStep;
219 else
220 CollidingObjectStep = 0;
221 }
222 }
223
152 // The collisions that have been collected this tick 224 // The collisions that have been collected this tick
153 protected CollisionEventUpdate CollisionCollection; 225 protected CollisionEventUpdate CollisionCollection;
154 226
@@ -160,12 +232,16 @@ public abstract class BSPhysObject : PhysicsActor
160 { 232 {
161 bool ret = false; 233 bool ret = false;
162 234
163 // The following lines make IsColliding() and IsCollidingGround() work 235 // The following lines make IsColliding(), CollidingGround() and CollidingObj work
164 CollidingStep = PhysicsScene.SimulationStep; 236 CollidingStep = PhysicsScene.SimulationStep;
165 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID) 237 if (collidingWith <= PhysicsScene.TerrainManager.HighestTerrainID)
166 { 238 {
167 CollidingGroundStep = PhysicsScene.SimulationStep; 239 CollidingGroundStep = PhysicsScene.SimulationStep;
168 } 240 }
241 else
242 {
243 CollidingObjectStep = PhysicsScene.SimulationStep;
244 }
169 245
170 // prims in the same linkset cannot collide with each other 246 // prims in the same linkset cannot collide with each other
171 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID)) 247 if (collidee != null && (this.Linkset.LinksetID == collidee.Linkset.LinksetID))
@@ -192,7 +268,7 @@ public abstract class BSPhysObject : PhysicsActor
192 { 268 {
193 bool ret = true; 269 bool ret = true;
194 // If the 'no collision' call, force it to happen right now so quick collision_end 270 // If the 'no collision' call, force it to happen right now so quick collision_end
195 bool force = CollisionCollection.Count == 0; 271 bool force = (CollisionCollection.Count == 0);
196 272
197 // throttle the collisions to the number of milliseconds specified in the subscription 273 // throttle the collisions to the number of milliseconds specified in the subscription
198 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime)) 274 if (force || (PhysicsScene.SimulationNowTime >= NextCollisionOkTime))
@@ -210,8 +286,10 @@ public abstract class BSPhysObject : PhysicsActor
210 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count); 286 // DetailLog("{0},{1}.SendCollisionUpdate,call,numCollisions={2}", LocalID, TypeName, CollisionCollection.Count);
211 base.SendCollisionUpdate(CollisionCollection); 287 base.SendCollisionUpdate(CollisionCollection);
212 288
213 // The collisionCollection structure is passed around in the simulator. 289 // The CollisionCollection instance is passed around in the simulator.
214 // Make sure we don't have a handle to that one and that a new one is used for next time. 290 // Make sure we don't have a handle to that one and that a new one is used for next time.
291 // This fixes an interesting 'gotcha'. If we call CollisionCollection.Clear() here,
292 // a race condition is created for the other users of this instance.
215 CollisionCollection = new CollisionEventUpdate(); 293 CollisionCollection = new CollisionEventUpdate();
216 } 294 }
217 return ret; 295 return ret;
@@ -229,7 +307,8 @@ public abstract class BSPhysObject : PhysicsActor
229 307
230 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate() 308 PhysicsScene.TaintedObject(TypeName+".SubscribeEvents", delegate()
231 { 309 {
232 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 310 if (PhysBody.HasPhysicalBody)
311 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
233 }); 312 });
234 } 313 }
235 else 314 else
@@ -243,7 +322,9 @@ public abstract class BSPhysObject : PhysicsActor
243 SubscribedEventsMs = 0; 322 SubscribedEventsMs = 0;
244 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate() 323 PhysicsScene.TaintedObject(TypeName+".UnSubscribeEvents", delegate()
245 { 324 {
246 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 325 // Make sure there is a body there because sometimes destruction happens in an un-ideal order.
326 if (PhysBody.HasPhysicalBody)
327 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
247 }); 328 });
248 } 329 }
249 // Return 'true' if the simulator wants collision events 330 // Return 'true' if the simulator wants collision events
@@ -253,11 +334,57 @@ public abstract class BSPhysObject : PhysicsActor
253 334
254 #endregion // Collisions 335 #endregion // Collisions
255 336
337 #region Per Simulation Step actions
338 // There are some actions that must be performed for a physical object before each simulation step.
339 // These actions are optional so, rather than scanning all the physical objects and asking them
340 // if they have anything to do, a physical object registers for an event call before the step is performed.
341 // This bookkeeping makes it easy to add, remove and clean up after all these registrations.
342 private Dictionary<string, BSScene.PreStepAction> RegisteredActions = new Dictionary<string, BSScene.PreStepAction>();
343 protected void RegisterPreStepAction(string op, uint id, BSScene.PreStepAction actn)
344 {
345 string identifier = op + "-" + id.ToString();
346
347 // Clean out any existing action
348 UnRegisterPreStepAction(op, id);
349
350 RegisteredActions[identifier] = actn;
351 PhysicsScene.BeforeStep += actn;
352 DetailLog("{0},BSPhysObject.RegisterPreStepAction,id={1}", LocalID, identifier);
353 }
354
355 // Unregister a pre step action. Safe to call if the action has not been registered.
356 protected void UnRegisterPreStepAction(string op, uint id)
357 {
358 string identifier = op + "-" + id.ToString();
359 bool removed = false;
360 if (RegisteredActions.ContainsKey(identifier))
361 {
362 PhysicsScene.BeforeStep -= RegisteredActions[identifier];
363 RegisteredActions.Remove(identifier);
364 removed = true;
365 }
366 DetailLog("{0},BSPhysObject.UnRegisterPreStepAction,id={1},removed={2}", LocalID, identifier, removed);
367 }
368
369 protected void UnRegisterAllPreStepActions()
370 {
371 foreach (KeyValuePair<string, BSScene.PreStepAction> kvp in RegisteredActions)
372 {
373 PhysicsScene.BeforeStep -= kvp.Value;
374 }
375 RegisteredActions.Clear();
376 DetailLog("{0},BSPhysObject.UnRegisterAllPreStepActions,", LocalID);
377 }
378
379
380 #endregion // Per Simulation Step actions
381
256 // High performance detailed logging routine used by the physical objects. 382 // High performance detailed logging routine used by the physical objects.
257 protected void DetailLog(string msg, params Object[] args) 383 protected void DetailLog(string msg, params Object[] args)
258 { 384 {
259 if (PhysicsScene.PhysicsLogging.Enabled) 385 if (PhysicsScene.PhysicsLogging.Enabled)
260 PhysicsScene.DetailLog(msg, args); 386 PhysicsScene.DetailLog(msg, args);
261 } 387 }
388
262} 389}
263} 390}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
index 20f5180..65be52a 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPlugin.cs
@@ -59,12 +59,6 @@ public class BSPlugin : IPhysicsPlugin
59 { 59 {
60 if (_mScene == null) 60 if (_mScene == null)
61 { 61 {
62 if (Util.IsWindows())
63 Util.LoadArchSpecificWindowsDll("BulletSim.dll");
64 // If not Windows, loading is performed by the
65 // Mono loader as specified in
66 // "bin/Physics/OpenSim.Region.Physics.BulletSPlugin.dll.config".
67
68 _mScene = new BSScene(sceneIdentifier); 62 _mScene = new BSScene(sceneIdentifier);
69 } 63 }
70 return (_mScene); 64 return (_mScene);
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
index 2b3fa25..94b63e5 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSPrim.cs
@@ -45,7 +45,6 @@ public sealed class BSPrim : BSPhysObject
45 private static readonly string LogHeader = "[BULLETS PRIM]"; 45 private static readonly string LogHeader = "[BULLETS PRIM]";
46 46
47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh. 47 // _size is what the user passed. Scale is what we pass to the physics engine with the mesh.
48 // Often Scale is unity because the meshmerizer will apply _size when creating the mesh.
49 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user 48 private OMV.Vector3 _size; // the multiplier for each mesh dimension as passed by the user
50 49
51 private bool _grabbed; 50 private bool _grabbed;
@@ -67,9 +66,6 @@ public sealed class BSPrim : BSPhysObject
67 private float _restitution; 66 private float _restitution;
68 private bool _setAlwaysRun; 67 private bool _setAlwaysRun;
69 private bool _throttleUpdates; 68 private bool _throttleUpdates;
70 private bool _isColliding;
71 private bool _collidingGround;
72 private bool _collidingObj;
73 private bool _floatOnWater; 69 private bool _floatOnWater;
74 private OMV.Vector3 _rotationalVelocity; 70 private OMV.Vector3 _rotationalVelocity;
75 private bool _kinematic; 71 private bool _kinematic;
@@ -77,13 +73,14 @@ public sealed class BSPrim : BSPhysObject
77 73
78 private BSDynamics _vehicle; 74 private BSDynamics _vehicle;
79 75
76 private BSVMotor _targetMotor;
80 private OMV.Vector3 _PIDTarget; 77 private OMV.Vector3 _PIDTarget;
81 private bool _usePID;
82 private float _PIDTau; 78 private float _PIDTau;
83 private bool _useHoverPID; 79
80 private BSFMotor _hoverMotor;
84 private float _PIDHoverHeight; 81 private float _PIDHoverHeight;
85 private PIDHoverType _PIDHoverType; 82 private PIDHoverType _PIDHoverType;
86 private float _PIDHoverTao; 83 private float _PIDHoverTau;
87 84
88 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size, 85 public BSPrim(uint localID, String primName, BSScene parent_scene, OMV.Vector3 pos, OMV.Vector3 size,
89 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical) 86 OMV.Quaternion rotation, PrimitiveBaseShape pbs, bool pisPhysical)
@@ -93,23 +90,27 @@ public sealed class BSPrim : BSPhysObject
93 _physicsActorType = (int)ActorTypes.Prim; 90 _physicsActorType = (int)ActorTypes.Prim;
94 _position = pos; 91 _position = pos;
95 _size = size; 92 _size = size;
96 Scale = size; // the scale will be set by CreateGeom depending on object type 93 Scale = size; // prims are the size the user wants them to be (different for BSCharactes).
97 _orientation = rotation; 94 _orientation = rotation;
98 _buoyancy = 1f; 95 _buoyancy = 0f;
99 _velocity = OMV.Vector3.Zero; 96 _velocity = OMV.Vector3.Zero;
100 _rotationalVelocity = OMV.Vector3.Zero; 97 _rotationalVelocity = OMV.Vector3.Zero;
101 BaseShape = pbs; 98 BaseShape = pbs;
102 _isPhysical = pisPhysical; 99 _isPhysical = pisPhysical;
103 _isVolumeDetect = false; 100 _isVolumeDetect = false;
104 _friction = PhysicsScene.Params.defaultFriction; // TODO: compute based on object material 101
105 _density = PhysicsScene.Params.defaultDensity; // TODO: compute based on object material 102 // Someday set default attributes based on the material but, for now, we don't know the prim material yet.
103 // MaterialAttributes primMat = BSMaterials.GetAttributes(Material, pisPhysical);
104 _density = PhysicsScene.Params.defaultDensity;
105 _friction = PhysicsScene.Params.defaultFriction;
106 _restitution = PhysicsScene.Params.defaultRestitution; 106 _restitution = PhysicsScene.Params.defaultRestitution;
107
107 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness 108 _vehicle = new BSDynamics(PhysicsScene, this); // add vehicleness
109
108 _mass = CalculateMass(); 110 _mass = CalculateMass();
109 111
110 // No body or shape yet 112 // Cause linkset variables to be initialized (like mass)
111 PhysBody = new BulletBody(LocalID, IntPtr.Zero); 113 Linkset.Refresh(this);
112 PhysShape = new BulletShape(IntPtr.Zero);
113 114
114 DetailLog("{0},BSPrim.constructor,call", LocalID); 115 DetailLog("{0},BSPrim.constructor,call", LocalID);
115 // do the actual object creation at taint time 116 // do the actual object creation at taint time
@@ -117,7 +118,7 @@ public sealed class BSPrim : BSPhysObject
117 { 118 {
118 CreateGeomAndObject(true); 119 CreateGeomAndObject(true);
119 120
120 CurrentCollisionFlags = BulletSimAPI.GetCollisionFlags2(PhysBody.ptr); 121 CurrentCollisionFlags = PhysicsScene.PE.GetCollisionFlags(PhysBody);
121 }); 122 });
122 } 123 }
123 124
@@ -125,6 +126,7 @@ public sealed class BSPrim : BSPhysObject
125 public override void Destroy() 126 public override void Destroy()
126 { 127 {
127 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID); 128 // m_log.DebugFormat("{0}: Destroy, id={1}", LogHeader, LocalID);
129 base.Destroy();
128 130
129 // Undo any links between me and any other object 131 // Undo any links between me and any other object
130 BSPhysObject parentBefore = Linkset.LinksetRoot; 132 BSPhysObject parentBefore = Linkset.LinksetRoot;
@@ -143,7 +145,9 @@ public sealed class BSPrim : BSPhysObject
143 DetailLog("{0},BSPrim.Destroy,taint,", LocalID); 145 DetailLog("{0},BSPrim.Destroy,taint,", LocalID);
144 // If there are physical body and shape, release my use of same. 146 // If there are physical body and shape, release my use of same.
145 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null); 147 PhysicsScene.Shapes.DereferenceBody(PhysBody, true, null);
148 PhysBody.Clear();
146 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null); 149 PhysicsScene.Shapes.DereferenceShape(PhysShape, true, null);
150 PhysShape.Clear();
147 }); 151 });
148 } 152 }
149 153
@@ -157,12 +161,10 @@ public sealed class BSPrim : BSPhysObject
157 // We presume the scale and size are the same. If scale must be changed for 161 // We presume the scale and size are the same. If scale must be changed for
158 // the physical shape, that is done when the geometry is built. 162 // the physical shape, that is done when the geometry is built.
159 _size = value; 163 _size = value;
164 Scale = _size;
160 ForceBodyShapeRebuild(false); 165 ForceBodyShapeRebuild(false);
161 } 166 }
162 } 167 }
163 // Scale is what we set in the physics engine. It is different than 'size' in that
164 // 'size' can be encorporated into the mesh. In that case, the scale is <1,1,1>.
165 public override OMV.Vector3 Scale { get; set; }
166 168
167 public override PrimitiveBaseShape Shape { 169 public override PrimitiveBaseShape Shape {
168 set { 170 set {
@@ -189,13 +191,17 @@ public sealed class BSPrim : BSPhysObject
189 } 191 }
190 } 192 }
191 public override bool Selected { 193 public override bool Selected {
192 set { 194 set
193 _isSelected = value; 195 {
194 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate() 196 if (value != _isSelected)
195 { 197 {
196 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected); 198 _isSelected = value;
197 SetObjectDynamic(false); 199 PhysicsScene.TaintedObject("BSPrim.setSelected", delegate()
198 }); 200 {
201 DetailLog("{0},BSPrim.selected,taint,selected={1}", LocalID, _isSelected);
202 SetObjectDynamic(false);
203 });
204 }
199 } 205 }
200 } 206 }
201 public override void CrossingFailure() { return; } 207 public override void CrossingFailure() { return; }
@@ -244,7 +250,8 @@ public sealed class BSPrim : BSPhysObject
244 // Zero some other properties in the physics engine 250 // Zero some other properties in the physics engine
245 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 251 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
246 { 252 {
247 BulletSimAPI.ClearAllForces2(PhysBody.ptr); 253 if (PhysBody.HasPhysicalBody)
254 PhysicsScene.PE.ClearAllForces(PhysBody);
248 }); 255 });
249 } 256 }
250 public override void ZeroAngularMotion(bool inTaintTime) 257 public override void ZeroAngularMotion(bool inTaintTime)
@@ -253,8 +260,12 @@ public sealed class BSPrim : BSPhysObject
253 // Zero some other properties in the physics engine 260 // Zero some other properties in the physics engine
254 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate() 261 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ZeroMotion", delegate()
255 { 262 {
256 BulletSimAPI.SetInterpolationAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 263 // DetailLog("{0},BSPrim.ZeroAngularMotion,call,rotVel={1}", LocalID, _rotationalVelocity);
257 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, OMV.Vector3.Zero); 264 if (PhysBody.HasPhysicalBody)
265 {
266 PhysicsScene.PE.SetInterpolationAngularVelocity(PhysBody, _rotationalVelocity);
267 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
268 }
258 }); 269 });
259 } 270 }
260 271
@@ -271,41 +282,50 @@ public sealed class BSPrim : BSPhysObject
271 } 282 }
272 public override OMV.Vector3 Position { 283 public override OMV.Vector3 Position {
273 get { 284 get {
285 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
286 * and does not fetch this position info for children. Thus this is commented out.
274 // child prims move around based on their parent. Need to get the latest location 287 // child prims move around based on their parent. Need to get the latest location
275 if (!Linkset.IsRoot(this)) 288 if (!Linkset.IsRoot(this))
276 _position = Linkset.Position(this); 289 _position = Linkset.PositionGet(this);
290 */
277 291
278 // don't do the GetObjectPosition for root elements because this function is called a zillion times. 292 // don't do the GetObjectPosition for root elements because this function is called a zillion times.
279 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 293 // _position = PhysicsScene.PE.GetObjectPosition2(PhysicsScene.World, BSBody);
280 return _position; 294 return _position;
281 } 295 }
282 set { 296 set {
283 // If the position must be forced into the physics engine, use ForcePosition. 297 // If the position must be forced into the physics engine, use ForcePosition.
298 // All positions are given in world positions.
284 if (_position == value) 299 if (_position == value)
285 { 300 {
301 DetailLog("{0},BSPrim.setPosition,call,positionNotChanging,pos={1},orient={2}", LocalID, _position, _orientation);
286 return; 302 return;
287 } 303 }
288 _position = value; 304 _position = value;
289 // TODO: what does it mean to set the position of a child prim?? Rebuild the constraint?
290 PositionSanityCheck(false); 305 PositionSanityCheck(false);
306
307 // A linkset might need to know if a component information changed.
308 Linkset.UpdateProperties(this, false);
309
291 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate() 310 PhysicsScene.TaintedObject("BSPrim.setPosition", delegate()
292 { 311 {
293 // DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation); 312 DetailLog("{0},BSPrim.SetPosition,taint,pos={1},orient={2}", LocalID, _position, _orientation);
294 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 313 ForcePosition = _position;
295 ActivateIfPhysical(false);
296 }); 314 });
297 } 315 }
298 } 316 }
299 public override OMV.Vector3 ForcePosition { 317 public override OMV.Vector3 ForcePosition {
300 get { 318 get {
301 _position = BulletSimAPI.GetPosition2(PhysBody.ptr); 319 _position = PhysicsScene.PE.GetPosition(PhysBody);
302 return _position; 320 return _position;
303 } 321 }
304 set { 322 set {
305 _position = value; 323 _position = value;
306 // PositionSanityCheck(); // Don't do this! Causes a loop and caller should know better. 324 if (PhysBody.HasPhysicalBody)
307 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 325 {
308 ActivateIfPhysical(false); 326 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
327 ActivateIfPhysical(false);
328 }
309 } 329 }
310 } 330 }
311 331
@@ -316,51 +336,58 @@ public sealed class BSPrim : BSPhysObject
316 { 336 {
317 bool ret = false; 337 bool ret = false;
318 338
339 if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(_position))
340 {
341 // The physical object is out of the known/simulated area.
342 // Upper levels of code will handle the transition to other areas so, for
343 // the time, we just ignore the position.
344 return ret;
345 }
346
319 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position); 347 float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(_position);
320 OMV.Vector3 upForce = OMV.Vector3.Zero; 348 OMV.Vector3 upForce = OMV.Vector3.Zero;
321 if (Position.Z < terrainHeight) 349 if (RawPosition.Z < terrainHeight)
322 { 350 {
323 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight); 351 DetailLog("{0},BSPrim.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
324 float targetHeight = terrainHeight + (Size.Z / 2f); 352 float targetHeight = terrainHeight + (Size.Z / 2f);
325 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec. 353 // Upforce proportional to the distance away from the terrain. Correct the error in 1 sec.
326 upForce.Z = (terrainHeight - Position.Z) * 1f; 354 upForce.Z = (terrainHeight - RawPosition.Z) * 1f;
327 ret = true; 355 ret = true;
328 } 356 }
329 357
330 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0) 358 if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
331 { 359 {
332 float waterHeight = PhysicsScene.GetWaterLevelAtXYZ(_position); 360 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(_position);
333 // TODO: a floating motor so object will bob in the water 361 // TODO: a floating motor so object will bob in the water
334 if (Math.Abs(Position.Z - waterHeight) > 0.1f) 362 if (Math.Abs(RawPosition.Z - waterHeight) > 0.1f)
335 { 363 {
336 // Upforce proportional to the distance away from the water. Correct the error in 1 sec. 364 // Upforce proportional to the distance away from the water. Correct the error in 1 sec.
337 upForce.Z = (waterHeight - Position.Z) * 1f; 365 upForce.Z = (waterHeight - RawPosition.Z) * 1f;
338 ret = true; 366 ret = true;
339 } 367 }
340 } 368 }
341 369
342 // TODO: check for out of bounds
343
344 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same. 370 // The above code computes a force to apply to correct any out-of-bounds problems. Apply same.
371 // TODO: This should be intergrated with a geneal physics action mechanism.
372 // TODO: This should be moderated with PID'ness.
345 if (ret) 373 if (ret)
346 { 374 {
347 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.PositionSanityCheck:belowTerrain", delegate() 375 // Apply upforce and overcome gravity.
348 { 376 OMV.Vector3 correctionForce = upForce - PhysicsScene.DefaultGravity;
349 // Apply upforce and overcome gravity. 377 DetailLog("{0},BSPrim.PositionSanityCheck,applyForce,pos={1},upForce={2},correctionForce={3}", LocalID, _position, upForce, correctionForce);
350 ForceVelocity = ForceVelocity + upForce - PhysicsScene.DefaultGravity; 378 AddForce(correctionForce, false, inTaintTime);
351 });
352 } 379 }
353 return ret; 380 return ret;
354 } 381 }
355 382
356 // Return the effective mass of the object. 383 // Return the effective mass of the object.
357 // If there are multiple items in the linkset, add them together for the root 384 // The definition of this call is to return the mass of the prim.
385 // If the simulator cares about the mass of the linkset, it will sum it itself.
358 public override float Mass 386 public override float Mass
359 { 387 {
360 get 388 get
361 { 389 {
362 return Linkset.LinksetMass; 390 return _mass;
363 // return _mass;
364 } 391 }
365 } 392 }
366 393
@@ -370,25 +397,64 @@ public sealed class BSPrim : BSPhysObject
370 } 397 }
371 // Set the physical mass to the passed mass. 398 // Set the physical mass to the passed mass.
372 // Note that this does not change _mass! 399 // Note that this does not change _mass!
373 public override void UpdatePhysicalMassProperties(float physMass) 400 public override void UpdatePhysicalMassProperties(float physMass, bool inWorld)
374 { 401 {
375 if (IsStatic) 402 if (PhysBody.HasPhysicalBody)
376 {
377 Inertia = OMV.Vector3.Zero;
378 BulletSimAPI.SetMassProps2(PhysBody.ptr, 0f, Inertia);
379 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr);
380 }
381 else
382 { 403 {
383 Inertia = BulletSimAPI.CalculateLocalInertia2(PhysShape.ptr, physMass); 404 if (IsStatic)
384 BulletSimAPI.SetMassProps2(PhysBody.ptr, physMass, Inertia); 405 {
385 BulletSimAPI.UpdateInertiaTensor2(PhysBody.ptr); 406 PhysicsScene.PE.SetGravity(PhysBody, PhysicsScene.DefaultGravity);
386 // center of mass is at the zero of the object 407 Inertia = OMV.Vector3.Zero;
387 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(PhysBody.ptr, ForcePosition, ForceOrientation); 408 PhysicsScene.PE.SetMassProps(PhysBody, 0f, Inertia);
388 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2}", LocalID, physMass, Inertia); 409 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
410 }
411 else
412 {
413 OMV.Vector3 grav = ComputeGravity();
414
415 if (inWorld)
416 {
417 // Changing interesting properties doesn't change proxy and collision cache
418 // information. The Bullet solution is to re-add the object to the world
419 // after parameters are changed.
420 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
421 }
422
423 // The computation of mass props requires gravity to be set on the object.
424 PhysicsScene.PE.SetGravity(PhysBody, grav);
425
426 Inertia = PhysicsScene.PE.CalculateLocalInertia(PhysShape, physMass);
427 PhysicsScene.PE.SetMassProps(PhysBody, physMass, Inertia);
428 PhysicsScene.PE.UpdateInertiaTensor(PhysBody);
429
430 // center of mass is at the zero of the object
431 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(PhysBody, ForcePosition, ForceOrientation);
432 DetailLog("{0},BSPrim.UpdateMassProperties,mass={1},localInertia={2},grav={3},inWorld={4}", LocalID, physMass, Inertia, grav, inWorld);
433
434 if (inWorld)
435 {
436 AddObjectToPhysicalWorld();
437 }
438
439 // Must set gravity after it has been added to the world because, for unknown reasons,
440 // adding the object resets the object's gravity to world gravity
441 PhysicsScene.PE.SetGravity(PhysBody, grav);
442
443 }
389 } 444 }
390 } 445 }
391 446
447 // Return what gravity should be set to this very moment
448 private OMV.Vector3 ComputeGravity()
449 {
450 OMV.Vector3 ret = PhysicsScene.DefaultGravity;
451
452 if (!IsStatic)
453 ret *= (1f - Buoyancy);
454
455 return ret;
456 }
457
392 // Is this used? 458 // Is this used?
393 public override OMV.Vector3 CenterOfMass 459 public override OMV.Vector3 CenterOfMass
394 { 460 {
@@ -405,11 +471,26 @@ public sealed class BSPrim : BSPhysObject
405 get { return _force; } 471 get { return _force; }
406 set { 472 set {
407 _force = value; 473 _force = value;
408 PhysicsScene.TaintedObject("BSPrim.setForce", delegate() 474 if (_force != OMV.Vector3.Zero)
409 { 475 {
410 // DetailLog("{0},BSPrim.setForce,taint,force={1}", LocalID, _force); 476 // If the force is non-zero, it must be reapplied each tick because
411 BulletSimAPI.SetObjectForce2(PhysBody.ptr, _force); 477 // Bullet clears the forces applied last frame.
412 }); 478 RegisterPreStepAction("BSPrim.setForce", LocalID,
479 delegate(float timeStep)
480 {
481 DetailLog("{0},BSPrim.setForce,preStep,force={1}", LocalID, _force);
482 if (PhysBody.HasPhysicalBody)
483 {
484 PhysicsScene.PE.ApplyCentralForce(PhysBody, _force);
485 ActivateIfPhysical(false);
486 }
487 }
488 );
489 }
490 else
491 {
492 UnRegisterPreStepAction("BSPrim.setForce", LocalID);
493 }
413 } 494 }
414 } 495 }
415 496
@@ -420,15 +501,18 @@ public sealed class BSPrim : BSPhysObject
420 set { 501 set {
421 Vehicle type = (Vehicle)value; 502 Vehicle type = (Vehicle)value;
422 503
423 // Tell the scene about the vehicle so it will get processing each frame.
424 PhysicsScene.VehicleInSceneTypeChanged(this, type);
425
426 PhysicsScene.TaintedObject("setVehicleType", delegate() 504 PhysicsScene.TaintedObject("setVehicleType", delegate()
427 { 505 {
428 // Done at taint time so we're sure the physics engine is not using the variables 506 // Done at taint time so we're sure the physics engine is not using the variables
429 // Vehicle code changes the parameters for this vehicle type. 507 // Vehicle code changes the parameters for this vehicle type.
430 _vehicle.ProcessTypeChange(type); 508 _vehicle.ProcessTypeChange(type);
431 ActivateIfPhysical(false); 509 ActivateIfPhysical(false);
510
511 // If an active vehicle, register the vehicle code to be called before each step
512 if (_vehicle.Type == Vehicle.TYPE_NONE)
513 UnRegisterPreStepAction("BSPrim.Vehicle", LocalID);
514 else
515 RegisterPreStepAction("BSPrim.Vehicle", LocalID, _vehicle.Step);
432 }); 516 });
433 } 517 }
434 } 518 }
@@ -464,23 +548,6 @@ public sealed class BSPrim : BSPhysObject
464 }); 548 });
465 } 549 }
466 550
467 // Called each simulation step to advance vehicle characteristics.
468 // Called from Scene when doing simulation step so we're in taint processing time.
469 public override void StepVehicle(float timeStep)
470 {
471 if (IsPhysical && _vehicle.IsActive)
472 {
473 _vehicle.Step(timeStep);
474 /* // TEST TEST DEBUG DEBUG -- trying to reduce the extra action of Bullet simulation step
475 PhysicsScene.PostTaintObject("BSPrim.StepVehicles", LocalID, delegate()
476 {
477 // This resets the interpolation values and recomputes the tensor variables
478 BulletSimAPI.SetCenterOfMassByPosRot2(BSBody.ptr, ForcePosition, ForceOrientation);
479 });
480 */
481 }
482 }
483
484 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more 551 // Allows the detection of collisions with inherently non-physical prims. see llVolumeDetect for more
485 public override void SetVolumeDetect(int param) { 552 public override void SetVolumeDetect(int param) {
486 bool newValue = (param != 0); 553 bool newValue = (param != 0);
@@ -495,6 +562,11 @@ public sealed class BSPrim : BSPhysObject
495 } 562 }
496 return; 563 return;
497 } 564 }
565 public OMV.Vector3 RawVelocity
566 {
567 get { return _velocity; }
568 set { _velocity = value; }
569 }
498 public override OMV.Vector3 Velocity { 570 public override OMV.Vector3 Velocity {
499 get { return _velocity; } 571 get { return _velocity; }
500 set { 572 set {
@@ -502,22 +574,43 @@ public sealed class BSPrim : BSPhysObject
502 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate() 574 PhysicsScene.TaintedObject("BSPrim.setVelocity", delegate()
503 { 575 {
504 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity); 576 // DetailLog("{0},BSPrim.SetVelocity,taint,vel={1}", LocalID, _velocity);
505 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 577 ForceVelocity = _velocity;
506 }); 578 });
507 } 579 }
508 } 580 }
509 public override OMV.Vector3 ForceVelocity { 581 public override OMV.Vector3 ForceVelocity {
510 get { return _velocity; } 582 get { return _velocity; }
511 set { 583 set {
584 PhysicsScene.AssertInTaintTime("BSPrim.ForceVelocity");
585
512 _velocity = value; 586 _velocity = value;
513 BulletSimAPI.SetLinearVelocity2(PhysBody.ptr, _velocity); 587 if (PhysBody.HasPhysicalBody)
588 {
589 PhysicsScene.PE.SetLinearVelocity(PhysBody, _velocity);
590 ActivateIfPhysical(false);
591 }
514 } 592 }
515 } 593 }
516 public override OMV.Vector3 Torque { 594 public override OMV.Vector3 Torque {
517 get { return _torque; } 595 get { return _torque; }
518 set { 596 set {
519 _torque = value; 597 _torque = value;
520 AddAngularForce(_torque, false, false); 598 if (_torque != OMV.Vector3.Zero)
599 {
600 // If the torque is non-zero, it must be reapplied each tick because
601 // Bullet clears the forces applied last frame.
602 RegisterPreStepAction("BSPrim.setTorque", LocalID,
603 delegate(float timeStep)
604 {
605 if (PhysBody.HasPhysicalBody)
606 AddAngularForce(_torque, false, true);
607 }
608 );
609 }
610 else
611 {
612 UnRegisterPreStepAction("BSPrim.setTorque", LocalID);
613 }
521 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque); 614 // DetailLog("{0},BSPrim.SetTorque,call,torque={1}", LocalID, _torque);
522 } 615 }
523 } 616 }
@@ -537,23 +630,32 @@ public sealed class BSPrim : BSPhysObject
537 } 630 }
538 public override OMV.Quaternion Orientation { 631 public override OMV.Quaternion Orientation {
539 get { 632 get {
633 /* NOTE: this refetch is not necessary. The simulator knows about linkset children
634 * and does not fetch this position info for children. Thus this is commented out.
540 // Children move around because tied to parent. Get a fresh value. 635 // Children move around because tied to parent. Get a fresh value.
541 if (!Linkset.IsRoot(this)) 636 if (!Linkset.IsRoot(this))
542 { 637 {
543 _orientation = Linkset.Orientation(this); 638 _orientation = Linkset.OrientationGet(this);
544 } 639 }
640 */
545 return _orientation; 641 return _orientation;
546 } 642 }
547 set { 643 set {
548 if (_orientation == value) 644 if (_orientation == value)
549 return; 645 return;
550 _orientation = value; 646 _orientation = value;
551 // TODO: what does it mean if a child in a linkset changes its orientation? Rebuild the constraint? 647
648 // A linkset might need to know if a component information changed.
649 Linkset.UpdateProperties(this, false);
650
552 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate() 651 PhysicsScene.TaintedObject("BSPrim.setOrientation", delegate()
553 { 652 {
554 // _position = BulletSimAPI.GetObjectPosition2(PhysicsScene.World.ptr, BSBody.ptr); 653 if (PhysBody.HasPhysicalBody)
555 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation); 654 {
556 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 655 // _position = PhysicsScene.PE.GetObjectPosition(PhysicsScene.World, BSBody);
656 // DetailLog("{0},BSPrim.setOrientation,taint,pos={1},orient={2}", LocalID, _position, _orientation);
657 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
658 }
557 }); 659 });
558 } 660 }
559 } 661 }
@@ -562,13 +664,13 @@ public sealed class BSPrim : BSPhysObject
562 { 664 {
563 get 665 get
564 { 666 {
565 _orientation = BulletSimAPI.GetOrientation2(PhysBody.ptr); 667 _orientation = PhysicsScene.PE.GetOrientation(PhysBody);
566 return _orientation; 668 return _orientation;
567 } 669 }
568 set 670 set
569 { 671 {
570 _orientation = value; 672 _orientation = value;
571 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 673 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
572 } 674 }
573 } 675 }
574 public override int PhysicsActorType { 676 public override int PhysicsActorType {
@@ -583,7 +685,7 @@ public sealed class BSPrim : BSPhysObject
583 _isPhysical = value; 685 _isPhysical = value;
584 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate() 686 PhysicsScene.TaintedObject("BSPrim.setIsPhysical", delegate()
585 { 687 {
586 // DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical); 688 DetailLog("{0},setIsPhysical,taint,isPhys={1}", LocalID, _isPhysical);
587 SetObjectDynamic(true); 689 SetObjectDynamic(true);
588 // whether phys-to-static or static-to-phys, the object is not moving. 690 // whether phys-to-static or static-to-phys, the object is not moving.
589 ZeroMotion(true); 691 ZeroMotion(true);
@@ -624,7 +726,7 @@ public sealed class BSPrim : BSPhysObject
624 726
625 // Mangling all the physical properties requires the object not be in the physical world. 727 // Mangling all the physical properties requires the object not be in the physical world.
626 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found). 728 // This is a NOOP if the object is not in the world (BulletSim and Bullet ignore objects not found).
627 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 729 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, PhysBody);
628 730
629 // Set up the object physicalness (does gravity and collisions move this object) 731 // Set up the object physicalness (does gravity and collisions move this object)
630 MakeDynamic(IsStatic); 732 MakeDynamic(IsStatic);
@@ -638,16 +740,10 @@ public sealed class BSPrim : BSPhysObject
638 // Make solid or not (do things bounce off or pass through this object). 740 // Make solid or not (do things bounce off or pass through this object).
639 MakeSolid(IsSolid); 741 MakeSolid(IsSolid);
640 742
641 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, PhysBody.ptr); 743 AddObjectToPhysicalWorld();
642 744
643 // Rebuild its shape 745 // Rebuild its shape
644 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, PhysBody.ptr); 746 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, PhysBody);
645
646 // Collision filter can be set only when the object is in the world
647 if (PhysBody.collisionFilter != 0 || PhysBody.collisionMask != 0)
648 {
649 BulletSimAPI.SetCollisionFilterMask2(PhysBody.ptr, (uint)PhysBody.collisionFilter, (uint)PhysBody.collisionMask);
650 }
651 747
652 // Recompute any linkset parameters. 748 // Recompute any linkset parameters.
653 // When going from non-physical to physical, this re-enables the constraints that 749 // When going from non-physical to physical, this re-enables the constraints that
@@ -655,8 +751,8 @@ public sealed class BSPrim : BSPhysObject
655 // For compound based linksets, this enables and disables interactions of the children. 751 // For compound based linksets, this enables and disables interactions of the children.
656 Linkset.Refresh(this); 752 Linkset.Refresh(this);
657 753
658 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},body={6},shape={7}", 754 DetailLog("{0},BSPrim.UpdatePhysicalParameters,taintExit,static={1},solid={2},mass={3},collide={4},cf={5:X},cType={6},body={7},shape={8}",
659 LocalID, IsStatic, IsSolid, _mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody, PhysShape); 755 LocalID, IsStatic, IsSolid, Mass, SubscribedEvents(), CurrentCollisionFlags, PhysBody.collisionType, PhysBody, PhysShape);
660 } 756 }
661 757
662 // "Making dynamic" means changing to and from static. 758 // "Making dynamic" means changing to and from static.
@@ -669,74 +765,80 @@ public sealed class BSPrim : BSPhysObject
669 if (makeStatic) 765 if (makeStatic)
670 { 766 {
671 // Become a Bullet 'static' object type 767 // Become a Bullet 'static' object type
672 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 768 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
673 // Stop all movement 769 // Stop all movement
674 ZeroMotion(true); 770 ZeroMotion(true);
675 // Center of mass is at the center of the object 771
676 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 772 // Set various physical properties so other object interact properly
773 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, false);
774 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
775 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
776
677 // Mass is zero which disables a bunch of physics stuff in Bullet 777 // Mass is zero which disables a bunch of physics stuff in Bullet
678 UpdatePhysicalMassProperties(0f); 778 UpdatePhysicalMassProperties(0f, false);
679 // Set collision detection parameters 779 // Set collision detection parameters
680 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 780 if (BSParam.CcdMotionThreshold > 0f)
681 { 781 {
682 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 782 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
683 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 783 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
684 } 784 }
685 // There can be special things needed for implementing linksets 785
686 Linkset.MakeStatic(this);
687 // The activation state is 'disabled' so Bullet will not try to act on it. 786 // The activation state is 'disabled' so Bullet will not try to act on it.
688 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.DISABLE_SIMULATION); 787 // PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.DISABLE_SIMULATION);
689 // Start it out sleeping and physical actions could wake it up. 788 // Start it out sleeping and physical actions could wake it up.
690 // BulletSimAPI.ForceActivationState2(BSBody.ptr, ActivationState.ISLAND_SLEEPING); 789 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ISLAND_SLEEPING);
790
791 // This collides like a static object
792 PhysBody.collisionType = CollisionType.Static;
691 793
692 PhysBody.collisionFilter = CollisionFilterGroups.StaticObjectFilter; 794 // There can be special things needed for implementing linksets
693 PhysBody.collisionMask = CollisionFilterGroups.StaticObjectMask; 795 Linkset.MakeStatic(this);
694 } 796 }
695 else 797 else
696 { 798 {
697 // Not a Bullet static object 799 // Not a Bullet static object
698 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 800 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_STATIC_OBJECT);
699 801
700 // Set various physical properties so internal dynamic properties will get computed correctly as they are set 802 // Set various physical properties so other object interact properly
701 BulletSimAPI.SetFriction2(PhysBody.ptr, PhysicsScene.Params.defaultFriction); 803 MaterialAttributes matAttrib = BSMaterials.GetAttributes(Material, true);
702 BulletSimAPI.SetRestitution2(PhysBody.ptr, PhysicsScene.Params.defaultRestitution); 804 PhysicsScene.PE.SetFriction(PhysBody, matAttrib.friction);
805 PhysicsScene.PE.SetRestitution(PhysBody, matAttrib.restitution);
703 806
704 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382 807 // per http://www.bulletphysics.org/Bullet/phpBB3/viewtopic.php?t=3382
705 // Since this can be called multiple times, only zero forces when becoming physical 808 // Since this can be called multiple times, only zero forces when becoming physical
706 // BulletSimAPI.ClearAllForces2(BSBody.ptr); 809 // PhysicsScene.PE.ClearAllForces(BSBody);
707 810
708 // For good measure, make sure the transform is set through to the motion state 811 // For good measure, make sure the transform is set through to the motion state
709 BulletSimAPI.SetTranslation2(PhysBody.ptr, _position, _orientation); 812 PhysicsScene.PE.SetTranslation(PhysBody, _position, _orientation);
710 813
711 // Center of mass is at the center of the object 814 // Center of mass is at the center of the object
712 // DEBUG DEBUG BulletSimAPI.SetCenterOfMassByPosRot2(Linkset.LinksetRoot.PhysBody.ptr, _position, _orientation); 815 // DEBUG DEBUG PhysicsScene.PE.SetCenterOfMassByPosRot(Linkset.LinksetRoot.PhysBody, _position, _orientation);
713 816
714 // A dynamic object has mass 817 // A dynamic object has mass
715 UpdatePhysicalMassProperties(RawMass); 818 UpdatePhysicalMassProperties(RawMass, false);
716 819
717 // Set collision detection parameters 820 // Set collision detection parameters
718 if (PhysicsScene.Params.ccdMotionThreshold > 0f) 821 if (BSParam.CcdMotionThreshold > 0f)
719 { 822 {
720 BulletSimAPI.SetCcdMotionThreshold2(PhysBody.ptr, PhysicsScene.Params.ccdMotionThreshold); 823 PhysicsScene.PE.SetCcdMotionThreshold(PhysBody, BSParam.CcdMotionThreshold);
721 BulletSimAPI.SetCcdSweptSphereRadius2(PhysBody.ptr, PhysicsScene.Params.ccdSweptSphereRadius); 824 PhysicsScene.PE.SetCcdSweptSphereRadius(PhysBody, BSParam.CcdSweptSphereRadius);
722 } 825 }
723 826
724 // Various values for simulation limits 827 // Various values for simulation limits
725 BulletSimAPI.SetDamping2(PhysBody.ptr, PhysicsScene.Params.linearDamping, PhysicsScene.Params.angularDamping); 828 PhysicsScene.PE.SetDamping(PhysBody, BSParam.LinearDamping, BSParam.AngularDamping);
726 BulletSimAPI.SetDeactivationTime2(PhysBody.ptr, PhysicsScene.Params.deactivationTime); 829 PhysicsScene.PE.SetDeactivationTime(PhysBody, BSParam.DeactivationTime);
727 BulletSimAPI.SetSleepingThresholds2(PhysBody.ptr, PhysicsScene.Params.linearSleepingThreshold, PhysicsScene.Params.angularSleepingThreshold); 830 PhysicsScene.PE.SetSleepingThresholds(PhysBody, BSParam.LinearSleepingThreshold, BSParam.AngularSleepingThreshold);
728 BulletSimAPI.SetContactProcessingThreshold2(PhysBody.ptr, PhysicsScene.Params.contactProcessingThreshold); 831 PhysicsScene.PE.SetContactProcessingThreshold(PhysBody, BSParam.ContactProcessingThreshold);
729 832
730 // There might be special things needed for implementing linksets. 833 // This collides like an object.
731 Linkset.MakeDynamic(this); 834 PhysBody.collisionType = CollisionType.Dynamic;
732 835
733 // Force activation of the object so Bullet will act on it. 836 // Force activation of the object so Bullet will act on it.
734 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects. 837 // Must do the ForceActivationState2() to overcome the DISABLE_SIMULATION from static objects.
735 BulletSimAPI.ForceActivationState2(PhysBody.ptr, ActivationState.ACTIVE_TAG); 838 PhysicsScene.PE.ForceActivationState(PhysBody, ActivationState.ACTIVE_TAG);
736 // BulletSimAPI.Activate2(BSBody.ptr, true);
737 839
738 PhysBody.collisionFilter = CollisionFilterGroups.ObjectFilter; 840 // There might be special things needed for implementing linksets.
739 PhysBody.collisionMask = CollisionFilterGroups.ObjectMask; 841 Linkset.MakeDynamic(this);
740 } 842 }
741 } 843 }
742 844
@@ -746,7 +848,7 @@ public sealed class BSPrim : BSPhysObject
746 // the functions after this one set up the state of a possibly newly created collision body. 848 // the functions after this one set up the state of a possibly newly created collision body.
747 private void MakeSolid(bool makeSolid) 849 private void MakeSolid(bool makeSolid)
748 { 850 {
749 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(PhysBody.ptr); 851 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(PhysBody);
750 if (makeSolid) 852 if (makeSolid)
751 { 853 {
752 // Verify the previous code created the correct shape for this type of thing. 854 // Verify the previous code created the correct shape for this type of thing.
@@ -754,7 +856,7 @@ public sealed class BSPrim : BSPhysObject
754 { 856 {
755 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType); 857 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for solidity. id={1}, type={2}", LogHeader, LocalID, bodyType);
756 } 858 }
757 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 859 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
758 } 860 }
759 else 861 else
760 { 862 {
@@ -762,9 +864,10 @@ public sealed class BSPrim : BSPhysObject
762 { 864 {
763 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType); 865 m_log.ErrorFormat("{0} MakeSolid: physical body of wrong type for non-solidness. id={1}, type={2}", LogHeader, LocalID, bodyType);
764 } 866 }
765 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.CF_NO_CONTACT_RESPONSE); 867 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.CF_NO_CONTACT_RESPONSE);
766 PhysBody.collisionFilter = CollisionFilterGroups.VolumeDetectFilter; 868
767 PhysBody.collisionMask = CollisionFilterGroups.VolumeDetectMask; 869 // Change collision info from a static object to a ghosty collision object
870 PhysBody.collisionType = CollisionType.VolumeDetect;
768 } 871 }
769 } 872 }
770 873
@@ -773,8 +876,8 @@ public sealed class BSPrim : BSPhysObject
773 // Called in taint-time!! 876 // Called in taint-time!!
774 private void ActivateIfPhysical(bool forceIt) 877 private void ActivateIfPhysical(bool forceIt)
775 { 878 {
776 if (IsPhysical) 879 if (IsPhysical && PhysBody.HasPhysicalBody)
777 BulletSimAPI.Activate2(PhysBody.ptr, forceIt); 880 PhysicsScene.PE.Activate(PhysBody, forceIt);
778 } 881 }
779 882
780 // Turn on or off the flag controlling whether collision events are returned to the simulator. 883 // Turn on or off the flag controlling whether collision events are returned to the simulator.
@@ -782,11 +885,27 @@ public sealed class BSPrim : BSPhysObject
782 { 885 {
783 if (wantsCollisionEvents) 886 if (wantsCollisionEvents)
784 { 887 {
785 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 888 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
889 }
890 else
891 {
892 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS);
893 }
894 }
895
896 // Add me to the physical world.
897 // Object MUST NOT already be in the world.
898 // This routine exists because some assorted properties get mangled by adding to the world.
899 internal void AddObjectToPhysicalWorld()
900 {
901 if (PhysBody.HasPhysicalBody)
902 {
903 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, PhysBody);
786 } 904 }
787 else 905 else
788 { 906 {
789 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_SUBSCRIBE_COLLISION_EVENTS); 907 m_log.ErrorFormat("{0} Attempt to add physical object without body. id={1}", LogHeader, LocalID);
908 DetailLog("{0},BSPrim.UpdatePhysicalParameters,addObjectWithoutBody,cType={1}", LocalID, PhysBody.collisionType);
790 } 909 }
791 } 910 }
792 911
@@ -805,18 +924,6 @@ public sealed class BSPrim : BSPhysObject
805 get { return _throttleUpdates; } 924 get { return _throttleUpdates; }
806 set { _throttleUpdates = value; } 925 set { _throttleUpdates = value; }
807 } 926 }
808 public override bool IsColliding {
809 get { return (CollidingStep == PhysicsScene.SimulationStep); }
810 set { _isColliding = value; }
811 }
812 public override bool CollidingGround {
813 get { return (CollidingGroundStep == PhysicsScene.SimulationStep); }
814 set { _collidingGround = value; }
815 }
816 public override bool CollidingObj {
817 get { return _collidingObj; }
818 set { _collidingObj = value; }
819 }
820 public bool IsPhantom { 927 public bool IsPhantom {
821 get { 928 get {
822 // SceneObjectPart removes phantom objects from the physics scene 929 // SceneObjectPart removes phantom objects from the physics scene
@@ -831,23 +938,14 @@ public sealed class BSPrim : BSPhysObject
831 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate() 938 PhysicsScene.TaintedObject("BSPrim.setFloatOnWater", delegate()
832 { 939 {
833 if (_floatOnWater) 940 if (_floatOnWater)
834 CurrentCollisionFlags = BulletSimAPI.AddToCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 941 CurrentCollisionFlags = PhysicsScene.PE.AddToCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
835 else 942 else
836 CurrentCollisionFlags = BulletSimAPI.RemoveFromCollisionFlags2(PhysBody.ptr, CollisionFlags.BS_FLOATS_ON_WATER); 943 CurrentCollisionFlags = PhysicsScene.PE.RemoveFromCollisionFlags(PhysBody, CollisionFlags.BS_FLOATS_ON_WATER);
837 }); 944 });
838 } 945 }
839 } 946 }
840 public override OMV.Vector3 RotationalVelocity { 947 public override OMV.Vector3 RotationalVelocity {
841 get { 948 get {
842 /*
843 OMV.Vector3 pv = OMV.Vector3.Zero;
844 // if close to zero, report zero
845 // This is copied from ODE but I'm not sure why it returns zero but doesn't
846 // zero the property in the physics engine.
847 if (_rotationalVelocity.ApproxEquals(pv, 0.2f))
848 return pv;
849 */
850
851 return _rotationalVelocity; 949 return _rotationalVelocity;
852 } 950 }
853 set { 951 set {
@@ -856,7 +954,7 @@ public sealed class BSPrim : BSPhysObject
856 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate() 954 PhysicsScene.TaintedObject("BSPrim.setRotationalVelocity", delegate()
857 { 955 {
858 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity); 956 DetailLog("{0},BSPrim.SetRotationalVel,taint,rotvel={1}", LocalID, _rotationalVelocity);
859 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 957 ForceRotationalVelocity = _rotationalVelocity;
860 }); 958 });
861 } 959 }
862 } 960 }
@@ -866,7 +964,11 @@ public sealed class BSPrim : BSPhysObject
866 } 964 }
867 set { 965 set {
868 _rotationalVelocity = value; 966 _rotationalVelocity = value;
869 BulletSimAPI.SetAngularVelocity2(PhysBody.ptr, _rotationalVelocity); 967 if (PhysBody.HasPhysicalBody)
968 {
969 PhysicsScene.PE.SetAngularVelocity(PhysBody, _rotationalVelocity);
970 ActivateIfPhysical(false);
971 }
870 } 972 }
871 } 973 }
872 public override bool Kinematic { 974 public override bool Kinematic {
@@ -890,9 +992,10 @@ public sealed class BSPrim : BSPhysObject
890 set { 992 set {
891 _buoyancy = value; 993 _buoyancy = value;
892 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy); 994 // DetailLog("{0},BSPrim.setForceBuoyancy,taint,buoy={1}", LocalID, _buoyancy);
893 // Buoyancy is faked by changing the gravity applied to the object 995 // Force the recalculation of the various inertia,etc variables in the object
894 float grav = PhysicsScene.Params.gravity * (1f - _buoyancy); 996 DetailLog("{0},BSPrim.ForceBuoyancy,buoy={1},mass={2}", LocalID, _buoyancy, _mass);
895 BulletSimAPI.SetGravity2(PhysBody.ptr, new OMV.Vector3(0f, 0f, grav)); 997 UpdatePhysicalMassProperties(_mass, true);
998 ActivateIfPhysical(false);
896 } 999 }
897 } 1000 }
898 1001
@@ -900,17 +1003,103 @@ public sealed class BSPrim : BSPhysObject
900 public override OMV.Vector3 PIDTarget { 1003 public override OMV.Vector3 PIDTarget {
901 set { _PIDTarget = value; } 1004 set { _PIDTarget = value; }
902 } 1005 }
903 public override bool PIDActive {
904 set { _usePID = value; }
905 }
906 public override float PIDTau { 1006 public override float PIDTau {
907 set { _PIDTau = value; } 1007 set { _PIDTau = value; }
908 } 1008 }
1009 public override bool PIDActive {
1010 set {
1011 if (value)
1012 {
1013 // We're taking over after this.
1014 ZeroMotion(true);
1015
1016 _targetMotor = new BSVMotor("BSPrim.PIDTarget",
1017 _PIDTau, // timeScale
1018 BSMotor.Infinite, // decay time scale
1019 BSMotor.InfiniteVector, // friction timescale
1020 1f // efficiency
1021 );
1022 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1023 _targetMotor.SetTarget(_PIDTarget);
1024 _targetMotor.SetCurrent(RawPosition);
1025 /*
1026 _targetMotor = new BSPIDVMotor("BSPrim.PIDTarget");
1027 _targetMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1028
1029 _targetMotor.SetTarget(_PIDTarget);
1030 _targetMotor.SetCurrent(RawPosition);
1031 _targetMotor.TimeScale = _PIDTau;
1032 _targetMotor.Efficiency = 1f;
1033 */
1034
1035 RegisterPreStepAction("BSPrim.PIDTarget", LocalID, delegate(float timeStep)
1036 {
1037 OMV.Vector3 origPosition = RawPosition; // DEBUG DEBUG (for printout below)
1038
1039 // 'movePosition' is where we'd like the prim to be at this moment.
1040 OMV.Vector3 movePosition = _targetMotor.Step(timeStep);
1041
1042 // If we are very close to our target, turn off the movement motor.
1043 if (_targetMotor.ErrorIsZero())
1044 {
1045 DetailLog("{0},BSPrim.PIDTarget,zeroMovement,movePos={1},pos={2},mass={3}",
1046 LocalID, movePosition, RawPosition, Mass);
1047 ForcePosition = _targetMotor.TargetValue;
1048 _targetMotor.Enabled = false;
1049 }
1050 else
1051 {
1052 ForcePosition = movePosition;
1053 }
1054 DetailLog("{0},BSPrim.PIDTarget,move,fromPos={1},movePos={2}", LocalID, origPosition, movePosition);
1055 });
1056 }
1057 else
1058 {
1059 // Stop any targetting
1060 UnRegisterPreStepAction("BSPrim.PIDTarget", LocalID);
1061 }
1062 }
1063 }
909 1064
910 // Used for llSetHoverHeight and maybe vehicle height 1065 // Used for llSetHoverHeight and maybe vehicle height
911 // Hover Height will override MoveTo target's Z 1066 // Hover Height will override MoveTo target's Z
912 public override bool PIDHoverActive { 1067 public override bool PIDHoverActive {
913 set { _useHoverPID = value; } 1068 set {
1069 if (value)
1070 {
1071 // Turning the target on
1072 _hoverMotor = new BSFMotor("BSPrim.Hover",
1073 _PIDHoverTau, // timeScale
1074 BSMotor.Infinite, // decay time scale
1075 BSMotor.Infinite, // friction timescale
1076 1f // efficiency
1077 );
1078 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1079 _hoverMotor.SetCurrent(RawPosition.Z);
1080 _hoverMotor.PhysicsScene = PhysicsScene; // DEBUG DEBUG so motor will output detail log messages.
1081
1082 RegisterPreStepAction("BSPrim.Hover", LocalID, delegate(float timeStep)
1083 {
1084 _hoverMotor.SetCurrent(RawPosition.Z);
1085 _hoverMotor.SetTarget(ComputeCurrentPIDHoverHeight());
1086 float targetHeight = _hoverMotor.Step(timeStep);
1087
1088 // 'targetHeight' is where we'd like the Z of the prim to be at this moment.
1089 // Compute the amount of force to push us there.
1090 float moveForce = (targetHeight - RawPosition.Z) * Mass;
1091 // Undo anything the object thinks it's doing at the moment
1092 moveForce = -RawVelocity.Z * Mass;
1093
1094 PhysicsScene.PE.ApplyCentralImpulse(PhysBody, new OMV.Vector3(0f, 0f, moveForce));
1095 DetailLog("{0},BSPrim.Hover,move,targHt={1},moveForce={2},mass={3}", LocalID, targetHeight, moveForce, Mass);
1096 });
1097 }
1098 else
1099 {
1100 UnRegisterPreStepAction("BSPrim.Hover", LocalID);
1101 }
1102 }
914 } 1103 }
915 public override float PIDHoverHeight { 1104 public override float PIDHoverHeight {
916 set { _PIDHoverHeight = value; } 1105 set { _PIDHoverHeight = value; }
@@ -919,8 +1108,35 @@ public sealed class BSPrim : BSPhysObject
919 set { _PIDHoverType = value; } 1108 set { _PIDHoverType = value; }
920 } 1109 }
921 public override float PIDHoverTau { 1110 public override float PIDHoverTau {
922 set { _PIDHoverTao = value; } 1111 set { _PIDHoverTau = value; }
923 } 1112 }
1113 // Based on current position, determine what we should be hovering at now.
1114 // Must recompute often. What if we walked offa cliff>
1115 private float ComputeCurrentPIDHoverHeight()
1116 {
1117 float ret = _PIDHoverHeight;
1118 float groundHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
1119
1120 switch (_PIDHoverType)
1121 {
1122 case PIDHoverType.Ground:
1123 ret = groundHeight + _PIDHoverHeight;
1124 break;
1125 case PIDHoverType.GroundAndWater:
1126 float waterHeight = PhysicsScene.TerrainManager.GetWaterLevelAtXYZ(RawPosition);
1127 if (groundHeight > waterHeight)
1128 {
1129 ret = groundHeight + _PIDHoverHeight;
1130 }
1131 else
1132 {
1133 ret = waterHeight + _PIDHoverHeight;
1134 }
1135 break;
1136 }
1137 return ret;
1138 }
1139
924 1140
925 // For RotLookAt 1141 // For RotLookAt
926 public override OMV.Quaternion APIDTarget { set { return; } } 1142 public override OMV.Quaternion APIDTarget { set { return; } }
@@ -928,54 +1144,45 @@ public sealed class BSPrim : BSPhysObject
928 public override float APIDStrength { set { return; } } 1144 public override float APIDStrength { set { return; } }
929 public override float APIDDamping { set { return; } } 1145 public override float APIDDamping { set { return; } }
930 1146
931 private List<OMV.Vector3> m_accumulatedForces = new List<OMV.Vector3>();
932 public override void AddForce(OMV.Vector3 force, bool pushforce) { 1147 public override void AddForce(OMV.Vector3 force, bool pushforce) {
933 AddForce(force, pushforce, false); 1148 // Since this force is being applied in only one step, make this a force per second.
1149 OMV.Vector3 addForce = force / PhysicsScene.LastTimeStep;
1150 AddForce(addForce, pushforce, false);
934 } 1151 }
935 // Applying a force just adds this to the total force on the object. 1152 // Applying a force just adds this to the total force on the object.
1153 // This added force will only last the next simulation tick.
936 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) { 1154 public void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
937 // for an object, doesn't matter if force is a pushforce or not 1155 // for an object, doesn't matter if force is a pushforce or not
938 if (force.IsFinite()) 1156 if (!IsStatic && force.IsFinite())
939 { 1157 {
940 // _force += force; 1158 float magnitude = force.Length();
941 lock (m_accumulatedForces) 1159 if (magnitude > BSParam.MaxAddForceMagnitude)
942 m_accumulatedForces.Add(new OMV.Vector3(force)); 1160 {
1161 // Force has a limit
1162 force = force / magnitude * BSParam.MaxAddForceMagnitude;
1163 }
1164
1165 OMV.Vector3 addForce = force;
1166 // DetailLog("{0},BSPrim.addForce,call,force={1}", LocalID, addForce);
1167
1168 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
1169 {
1170 // Bullet adds this central force to the total force for this tick
1171 DetailLog("{0},BSPrim.addForce,taint,force={1}", LocalID, addForce);
1172 if (PhysBody.HasPhysicalBody)
1173 {
1174 PhysicsScene.PE.ApplyCentralForce(PhysBody, addForce);
1175 ActivateIfPhysical(false);
1176 }
1177 });
943 } 1178 }
944 else 1179 else
945 { 1180 {
946 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1181 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
947 return; 1182 return;
948 } 1183 }
949 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddForce", delegate()
950 {
951 OMV.Vector3 fSum = OMV.Vector3.Zero;
952 lock (m_accumulatedForces)
953 {
954 // Sum the accumulated additional forces for one big force to apply once.
955 foreach (OMV.Vector3 v in m_accumulatedForces)
956 {
957 fSum += v;
958 }
959 m_accumulatedForces.Clear();
960 }
961 DetailLog("{0},BSPrim.AddForce,taint,force={1}", LocalID, fSum);
962 if (fSum != OMV.Vector3.Zero)
963 BulletSimAPI.ApplyCentralForce2(PhysBody.ptr, fSum);
964 });
965 } 1184 }
966 1185
967 // An impulse force is scaled by the mass of the object.
968 public void ApplyForceImpulse(OMV.Vector3 impulse, bool inTaintTime)
969 {
970 OMV.Vector3 applyImpulse = impulse;
971 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyForceImpulse", delegate()
972 {
973 DetailLog("{0},BSPrim.ApplyForceImpulse,taint,tImpulse={1}", LocalID, applyImpulse);
974 BulletSimAPI.ApplyCentralImpulse2(PhysBody.ptr, applyImpulse);
975 });
976 }
977
978 private List<OMV.Vector3> m_accumulatedAngularForces = new List<OMV.Vector3>();
979 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) { 1186 public override void AddAngularForce(OMV.Vector3 force, bool pushforce) {
980 AddAngularForce(force, pushforce, false); 1187 AddAngularForce(force, pushforce, false);
981 } 1188 }
@@ -983,42 +1190,37 @@ public sealed class BSPrim : BSPhysObject
983 { 1190 {
984 if (force.IsFinite()) 1191 if (force.IsFinite())
985 { 1192 {
986 // _force += force; 1193 OMV.Vector3 angForce = force;
987 lock (m_accumulatedAngularForces) 1194 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
988 m_accumulatedAngularForces.Add(new OMV.Vector3(force)); 1195 {
1196 if (PhysBody.HasPhysicalBody)
1197 {
1198 PhysicsScene.PE.ApplyTorque(PhysBody, angForce);
1199 ActivateIfPhysical(false);
1200 }
1201 });
989 } 1202 }
990 else 1203 else
991 { 1204 {
992 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID); 1205 m_log.WarnFormat("{0}: Got a NaN force applied to a prim. LocalID={1}", LogHeader, LocalID);
993 return; 1206 return;
994 } 1207 }
995 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.AddAngularForce", delegate()
996 {
997 OMV.Vector3 fSum = OMV.Vector3.Zero;
998 lock (m_accumulatedAngularForces)
999 {
1000 // Sum the accumulated additional forces for one big force to apply once.
1001 foreach (OMV.Vector3 v in m_accumulatedAngularForces)
1002 {
1003 fSum += v;
1004 }
1005 m_accumulatedAngularForces.Clear();
1006 }
1007 DetailLog("{0},BSPrim.AddAngularForce,taint,aForce={1}", LocalID, fSum);
1008 if (fSum != OMV.Vector3.Zero)
1009 {
1010 BulletSimAPI.ApplyTorque2(PhysBody.ptr, fSum);
1011 _torque = fSum;
1012 }
1013 });
1014 } 1208 }
1209
1015 // A torque impulse. 1210 // A torque impulse.
1211 // ApplyTorqueImpulse adds torque directly to the angularVelocity.
1212 // AddAngularForce accumulates the force and applied it to the angular velocity all at once.
1213 // Computed as: angularVelocity += impulse * inertia;
1016 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime) 1214 public void ApplyTorqueImpulse(OMV.Vector3 impulse, bool inTaintTime)
1017 { 1215 {
1018 OMV.Vector3 applyImpulse = impulse; 1216 OMV.Vector3 applyImpulse = impulse;
1019 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate() 1217 PhysicsScene.TaintedObject(inTaintTime, "BSPrim.ApplyTorqueImpulse", delegate()
1020 { 1218 {
1021 BulletSimAPI.ApplyTorqueImpulse2(PhysBody.ptr, applyImpulse); 1219 if (PhysBody.HasPhysicalBody)
1220 {
1221 PhysicsScene.PE.ApplyTorqueImpulse(PhysBody, applyImpulse);
1222 ActivateIfPhysical(false);
1223 }
1022 }); 1224 });
1023 } 1225 }
1024 1226
@@ -1313,11 +1515,7 @@ public sealed class BSPrim : BSPhysObject
1313 } 1515 }
1314 */ 1516 */
1315 1517
1316 if (returnMass <= 0) 1518 returnMass = Util.Clamp(returnMass, BSParam.MinimumObjectMass, BSParam.MaximumObjectMass);
1317 returnMass = 0.0001f;
1318
1319 if (returnMass > PhysicsScene.MaximumObjectMass)
1320 returnMass = PhysicsScene.MaximumObjectMass;
1321 1519
1322 return returnMass; 1520 return returnMass;
1323 }// end CalculateMass 1521 }// end CalculateMass
@@ -1326,7 +1524,7 @@ public sealed class BSPrim : BSPhysObject
1326 // Rebuild the geometry and object. 1524 // Rebuild the geometry and object.
1327 // This is called when the shape changes so we need to recreate the mesh/hull. 1525 // This is called when the shape changes so we need to recreate the mesh/hull.
1328 // Called at taint-time!!! 1526 // Called at taint-time!!!
1329 private void CreateGeomAndObject(bool forceRebuild) 1527 public void CreateGeomAndObject(bool forceRebuild)
1330 { 1528 {
1331 // If this prim is part of a linkset, we must remove and restore the physical 1529 // If this prim is part of a linkset, we must remove and restore the physical
1332 // links if the body is rebuilt. 1530 // links if the body is rebuilt.
@@ -1336,12 +1534,11 @@ public sealed class BSPrim : BSPhysObject
1336 // Create the correct physical representation for this type of object. 1534 // Create the correct physical representation for this type of object.
1337 // Updates PhysBody and PhysShape with the new information. 1535 // Updates PhysBody and PhysShape with the new information.
1338 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary. 1536 // Ignore 'forceRebuild'. This routine makes the right choices and changes of necessary.
1339 // Returns 'true' if either the body or the shape was changed.
1340 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody) 1537 PhysicsScene.Shapes.GetBodyAndShape(false, PhysicsScene.World, this, null, delegate(BulletBody dBody)
1341 { 1538 {
1342 // Called if the current prim body is about to be destroyed. 1539 // Called if the current prim body is about to be destroyed.
1343 // Remove all the physical dependencies on the old body. 1540 // Remove all the physical dependencies on the old body.
1344 // (Maybe someday make the changing of BSShape an event handled by BSLinkset.) 1541 // (Maybe someday make the changing of BSShape an event to be subscribed to by BSLinkset, ...)
1345 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this); 1542 needToRestoreLinkset = Linkset.RemoveBodyDependencies(this);
1346 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this); 1543 needToRestoreVehicle = _vehicle.RemoveBodyDependencies(this);
1347 }); 1544 });
@@ -1381,54 +1578,16 @@ public sealed class BSPrim : BSPhysObject
1381 1578
1382 public override void UpdateProperties(EntityProperties entprop) 1579 public override void UpdateProperties(EntityProperties entprop)
1383 { 1580 {
1384 /* 1581 // Updates only for individual prims and for the root object of a linkset.
1385 UpdatedProperties changed = 0; 1582 if (Linkset.IsRoot(this))
1386 // assign to the local variables so the normal set action does not happen
1387 // if (_position != entprop.Position)
1388 if (!_position.ApproxEquals(entprop.Position, POSITION_TOLERANCE))
1389 {
1390 _position = entprop.Position;
1391 changed |= UpdatedProperties.Position;
1392 }
1393 // if (_orientation != entprop.Rotation)
1394 if (!_orientation.ApproxEquals(entprop.Rotation, ROTATION_TOLERANCE))
1395 {
1396 _orientation = entprop.Rotation;
1397 changed |= UpdatedProperties.Rotation;
1398 }
1399 // if (_velocity != entprop.Velocity)
1400 if (!_velocity.ApproxEquals(entprop.Velocity, VELOCITY_TOLERANCE))
1401 {
1402 _velocity = entprop.Velocity;
1403 changed |= UpdatedProperties.Velocity;
1404 }
1405 // if (_acceleration != entprop.Acceleration)
1406 if (!_acceleration.ApproxEquals(entprop.Acceleration, ACCELERATION_TOLERANCE))
1407 {
1408 _acceleration = entprop.Acceleration;
1409 changed |= UpdatedProperties.Acceleration;
1410 }
1411 // if (_rotationalVelocity != entprop.RotationalVelocity)
1412 if (!_rotationalVelocity.ApproxEquals(entprop.RotationalVelocity, ROTATIONAL_VELOCITY_TOLERANCE))
1413 {
1414 _rotationalVelocity = entprop.RotationalVelocity;
1415 changed |= UpdatedProperties.RotationalVel;
1416 }
1417 if (changed != 0)
1418 { 1583 {
1419 // Only update the position of single objects and linkset roots 1584 // A temporary kludge to suppress the rotational effects introduced on vehicles by Bullet
1420 if (Linkset.IsRoot(this)) 1585 // TODO: handle physics introduced by Bullet with computed vehicle physics.
1586 if (_vehicle.IsActive)
1421 { 1587 {
1422 base.RequestPhysicsterseUpdate(); 1588 entprop.RotationalVelocity = OMV.Vector3.Zero;
1423 } 1589 }
1424 }
1425 */
1426
1427 // Don't check for damping here -- it's done in BulletSim and SceneObjectPart.
1428 1590
1429 // Updates only for individual prims and for the root object of a linkset.
1430 if (Linkset.IsRoot(this))
1431 {
1432 // Assign directly to the local variables so the normal set action does not happen 1591 // Assign directly to the local variables so the normal set action does not happen
1433 _position = entprop.Position; 1592 _position = entprop.Position;
1434 _orientation = entprop.Rotation; 1593 _orientation = entprop.Rotation;
@@ -1437,21 +1596,19 @@ public sealed class BSPrim : BSPhysObject
1437 _rotationalVelocity = entprop.RotationalVelocity; 1596 _rotationalVelocity = entprop.RotationalVelocity;
1438 1597
1439 // The sanity check can change the velocity and/or position. 1598 // The sanity check can change the velocity and/or position.
1440 if (PositionSanityCheck(true)) 1599 if (IsPhysical && PositionSanityCheck(true))
1441 { 1600 {
1442 entprop.Position = _position; 1601 entprop.Position = _position;
1443 entprop.Velocity = _velocity; 1602 entprop.Velocity = _velocity;
1444 } 1603 }
1445 1604
1446 // remember the current and last set values 1605 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation; // DEBUG DEBUG DEBUG
1447 LastEntityProperties = CurrentEntityProperties;
1448 CurrentEntityProperties = entprop;
1449
1450 OMV.Vector3 direction = OMV.Vector3.UnitX * _orientation;
1451 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}", 1606 DetailLog("{0},BSPrim.UpdateProperties,call,pos={1},orient={2},dir={3},vel={4},rotVel={5}",
1452 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity); 1607 LocalID, _position, _orientation, direction, _velocity, _rotationalVelocity);
1453 1608
1454 // BulletSimAPI.DumpRigidBody2(PhysicsScene.World.ptr, BSBody.ptr); // DEBUG DEBUG DEBUG 1609 // remember the current and last set values
1610 LastEntityProperties = CurrentEntityProperties;
1611 CurrentEntityProperties = entprop;
1455 1612
1456 base.RequestPhysicsterseUpdate(); 1613 base.RequestPhysicsterseUpdate();
1457 } 1614 }
@@ -1466,7 +1623,7 @@ public sealed class BSPrim : BSPhysObject
1466 */ 1623 */
1467 1624
1468 // The linkset implimentation might want to know about this. 1625 // The linkset implimentation might want to know about this.
1469 Linkset.UpdateProperties(this); 1626 Linkset.UpdateProperties(this, true);
1470 } 1627 }
1471} 1628}
1472} 1629}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
index 27a78d1..7017194 100644
--- a/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSScene.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27using System; 27using System;
28using System.Collections.Generic; 28using System.Collections.Generic;
29using System.Reflection;
29using System.Runtime.InteropServices; 30using System.Runtime.InteropServices;
30using System.Text; 31using System.Text;
31using System.Threading; 32using System.Threading;
@@ -38,40 +39,22 @@ using Nini.Config;
38using log4net; 39using log4net;
39using OpenMetaverse; 40using OpenMetaverse;
40 41
41// TODOs for BulletSim (for BSScene, BSPrim, BSCharacter and BulletSim)
42// Test sculpties (verified that they don't work)
43// Compute physics FPS reasonably
44// Based on material, set density and friction
45// Don't use constraints in linksets of non-physical objects. Means having to move children manually.
46// Four states of prim: Physical, regular, phantom and selected. Are we modeling these correctly?
47// In SL one can set both physical and phantom (gravity, does not effect others, makes collisions with ground)
48// At the moment, physical and phantom causes object to drop through the terrain
49// Physical phantom objects and related typing (collision options )
50// Check out llVolumeDetect. Must do something for that.
51// Use collision masks for collision with terrain and phantom objects
52// More efficient memory usage when passing hull information from BSPrim to BulletSim
53// Should prim.link() and prim.delink() membership checking happen at taint time?
54// Mesh sharing. Use meshHash to tell if we already have a hull of that shape and only create once.
55// Do attachments need to be handled separately? Need collision events. Do not collide with VolumeDetect
56// Implement LockAngularMotion
57// Decide if clearing forces is the right thing to do when setting position (BulletSim::SetObjectTranslation)
58// Remove mesh and Hull stuff. Use mesh passed to bullet and use convexdecom from bullet.
59// Add PID movement operations. What does ScenePresence.MoveToTarget do?
60// Check terrain size. 128 or 127?
61// Raycast
62//
63namespace OpenSim.Region.Physics.BulletSPlugin 42namespace OpenSim.Region.Physics.BulletSPlugin
64{ 43{
65public sealed class BSScene : PhysicsScene, IPhysicsParameters 44public sealed class BSScene : PhysicsScene, IPhysicsParameters
66{ 45{
67 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 46 internal static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
68 private static readonly string LogHeader = "[BULLETS SCENE]"; 47 internal static readonly string LogHeader = "[BULLETS SCENE]";
69 48
70 // The name of the region we're working for. 49 // The name of the region we're working for.
71 public string RegionName { get; private set; } 50 public string RegionName { get; private set; }
72 51
73 public string BulletSimVersion = "?"; 52 public string BulletSimVersion = "?";
74 53
54 // The handle to the underlying managed or unmanaged version of Bullet being used.
55 public string BulletEngineName { get; private set; }
56 public BSAPITemplate PE;
57
75 public Dictionary<uint, BSPhysObject> PhysObjects; 58 public Dictionary<uint, BSPhysObject> PhysObjects;
76 public BSShapeCollection Shapes; 59 public BSShapeCollection Shapes;
77 60
@@ -82,32 +65,30 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
82 // every tick so OpenSim will update its animation. 65 // every tick so OpenSim will update its animation.
83 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>(); 66 private HashSet<BSPhysObject> m_avatars = new HashSet<BSPhysObject>();
84 67
85 // List of all the objects that have vehicle properties and should be called
86 // to update each physics step.
87 private List<BSPhysObject> m_vehicles = new List<BSPhysObject>();
88
89 // let my minuions use my logger 68 // let my minuions use my logger
90 public ILog Logger { get { return m_log; } } 69 public ILog Logger { get { return m_log; } }
91 70
92 public IMesher mesher; 71 public IMesher mesher;
93 // Level of Detail values kept as float because that's what the Meshmerizer wants
94 public float MeshLOD { get; private set; }
95 public float MeshMegaPrimLOD { get; private set; }
96 public float MeshMegaPrimThreshold { get; private set; }
97 public float SculptLOD { get; private set; }
98
99 public uint WorldID { get; private set; } 72 public uint WorldID { get; private set; }
100 public BulletSim World { get; private set; } 73 public BulletWorld World { get; private set; }
101 74
102 // All the constraints that have been allocated in this instance. 75 // All the constraints that have been allocated in this instance.
103 public BSConstraintCollection Constraints { get; private set; } 76 public BSConstraintCollection Constraints { get; private set; }
104 77
105 // Simulation parameters 78 // Simulation parameters
106 private int m_maxSubSteps; 79 internal int m_maxSubSteps;
107 private float m_fixedTimeStep; 80 internal float m_fixedTimeStep;
108 private long m_simulationStep = 0; 81 internal long m_simulationStep = 0;
82 internal float NominalFrameRate { get; set; }
109 public long SimulationStep { get { return m_simulationStep; } } 83 public long SimulationStep { get { return m_simulationStep; } }
110 private int m_taintsToProcessPerStep; 84 internal int m_taintsToProcessPerStep;
85 internal float LastTimeStep { get; private set; }
86
87 // Physical objects can register for prestep or poststep events
88 public delegate void PreStepAction(float timeStep);
89 public delegate void PostStepAction(float timeStep);
90 public event PreStepAction BeforeStep;
91 public event PreStepAction AfterStep;
111 92
112 // A value of the time now so all the collision and update routines do not have to get their own 93 // A value of the time now so all the collision and update routines do not have to get their own
113 // Set to 'now' just before all the prims and actors are called for collisions and updates 94 // Set to 'now' just before all the prims and actors are called for collisions and updates
@@ -121,31 +102,22 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
121 public bool InTaintTime { get; private set; } 102 public bool InTaintTime { get; private set; }
122 103
123 // Pinned memory used to pass step information between managed and unmanaged 104 // Pinned memory used to pass step information between managed and unmanaged
124 private int m_maxCollisionsPerFrame; 105 internal int m_maxCollisionsPerFrame;
125 private CollisionDesc[] m_collisionArray; 106 internal CollisionDesc[] m_collisionArray;
126 private GCHandle m_collisionArrayPinnedHandle;
127 107
128 private int m_maxUpdatesPerFrame; 108 internal int m_maxUpdatesPerFrame;
129 private EntityProperties[] m_updateArray; 109 internal EntityProperties[] m_updateArray;
130 private GCHandle m_updateArrayPinnedHandle;
131
132 public bool ShouldMeshSculptedPrim { get; private set; } // cause scuplted prims to get meshed
133 public bool ShouldForceSimplePrimMeshing { get; private set; } // if a cube or sphere, let Bullet do internal shapes
134 public bool ShouldUseHullsForPhysicalObjects { get; private set; } // 'true' if should create hulls for physical objects
135
136 public float PID_D { get; private set; } // derivative
137 public float PID_P { get; private set; } // proportional
138 110
139 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero 111 public const uint TERRAIN_ID = 0; // OpenSim senses terrain with a localID of zero
140 public const uint GROUNDPLANE_ID = 1; 112 public const uint GROUNDPLANE_ID = 1;
141 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here 113 public const uint CHILDTERRAIN_ID = 2; // Terrain allocated based on our mega-prim childre start here
142 114
143 private float m_waterLevel; 115 public float SimpleWaterLevel { get; set; }
144 public BSTerrainManager TerrainManager { get; private set; } 116 public BSTerrainManager TerrainManager { get; private set; }
145 117
146 public ConfigurationParameters Params 118 public ConfigurationParameters Params
147 { 119 {
148 get { return m_params[0]; } 120 get { return UnmanagedParams[0]; }
149 } 121 }
150 public Vector3 DefaultGravity 122 public Vector3 DefaultGravity
151 { 123 {
@@ -157,8 +129,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
157 get { return Params.gravity; } 129 get { return Params.gravity; }
158 } 130 }
159 131
160 public float MaximumObjectMass { get; private set; }
161
162 // When functions in the unmanaged code must be called, it is only 132 // When functions in the unmanaged code must be called, it is only
163 // done at a known time just before the simulation step. The taint 133 // done at a known time just before the simulation step. The taint
164 // system saves all these function calls and executes them in 134 // system saves all these function calls and executes them in
@@ -181,13 +151,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
181 151
182 // A pointer to an instance if this structure is passed to the C++ code 152 // A pointer to an instance if this structure is passed to the C++ code
183 // Used to pass basic configuration values to the unmanaged code. 153 // Used to pass basic configuration values to the unmanaged code.
184 ConfigurationParameters[] m_params; 154 internal ConfigurationParameters[] UnmanagedParams;
185 GCHandle m_paramsHandle;
186
187 // Handle to the callback used by the unmanaged code to call into the managed code.
188 // Used for debug logging.
189 // Need to store the handle in a persistant variable so it won't be freed.
190 private BulletSimAPI.DebugLogCallback m_DebugLogCallbackHandle;
191 155
192 // Sometimes you just have to log everything. 156 // Sometimes you just have to log everything.
193 public Logging.LogWriter PhysicsLogging; 157 public Logging.LogWriter PhysicsLogging;
@@ -195,8 +159,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
195 private string m_physicsLoggingDir; 159 private string m_physicsLoggingDir;
196 private string m_physicsLoggingPrefix; 160 private string m_physicsLoggingPrefix;
197 private int m_physicsLoggingFileMinutes; 161 private int m_physicsLoggingFileMinutes;
162 private bool m_physicsLoggingDoFlush;
163 private bool m_physicsPhysicalDumpEnabled;
164 public float PhysicsMetricDumpFrames { get; set; }
198 // 'true' of the vehicle code is to log lots of details 165 // 'true' of the vehicle code is to log lots of details
199 public bool VehicleLoggingEnabled { get; private set; } 166 public bool VehicleLoggingEnabled { get; private set; }
167 public bool VehiclePhysicalLoggingEnabled { get; private set; }
200 168
201 #region Construction and Initialization 169 #region Construction and Initialization
202 public BSScene(string identifier) 170 public BSScene(string identifier)
@@ -216,17 +184,13 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
216 Shapes = new BSShapeCollection(this); 184 Shapes = new BSShapeCollection(this);
217 185
218 // Allocate pinned memory to pass parameters. 186 // Allocate pinned memory to pass parameters.
219 m_params = new ConfigurationParameters[1]; 187 UnmanagedParams = new ConfigurationParameters[1];
220 m_paramsHandle = GCHandle.Alloc(m_params, GCHandleType.Pinned);
221 188
222 // Set default values for physics parameters plus any overrides from the ini file 189 // Set default values for physics parameters plus any overrides from the ini file
223 GetInitialParameterValues(config); 190 GetInitialParameterValues(config);
224 191
225 // allocate more pinned memory close to the above in an attempt to get the memory all together 192 // Get the connection to the physics engine (could be native or one of many DLLs)
226 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame]; 193 PE = SelectUnderlyingBulletEngine(BulletEngineName);
227 m_collisionArrayPinnedHandle = GCHandle.Alloc(m_collisionArray, GCHandleType.Pinned);
228 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
229 m_updateArrayPinnedHandle = GCHandle.Alloc(m_updateArray, GCHandleType.Pinned);
230 194
231 // Enable very detailed logging. 195 // Enable very detailed logging.
232 // By creating an empty logger when not logging, the log message invocation code 196 // By creating an empty logger when not logging, the log message invocation code
@@ -234,28 +198,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
234 if (m_physicsLoggingEnabled) 198 if (m_physicsLoggingEnabled)
235 { 199 {
236 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes); 200 PhysicsLogging = new Logging.LogWriter(m_physicsLoggingDir, m_physicsLoggingPrefix, m_physicsLoggingFileMinutes);
201 PhysicsLogging.ErrorLogger = m_log; // for DEBUG. Let's the logger output error messages.
237 } 202 }
238 else 203 else
239 { 204 {
240 PhysicsLogging = new Logging.LogWriter(); 205 PhysicsLogging = new Logging.LogWriter();
241 } 206 }
242 207
243 // If Debug logging level, enable logging from the unmanaged code 208 // Allocate memory for returning of the updates and collisions from the physics engine
244 m_DebugLogCallbackHandle = null; 209 m_collisionArray = new CollisionDesc[m_maxCollisionsPerFrame];
245 if (m_log.IsDebugEnabled || PhysicsLogging.Enabled) 210 m_updateArray = new EntityProperties[m_maxUpdatesPerFrame];
246 {
247 m_log.DebugFormat("{0}: Initialize: Setting debug callback for unmanaged code", LogHeader);
248 if (PhysicsLogging.Enabled)
249 // The handle is saved in a variable to make sure it doesn't get freed after this call
250 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLoggerPhysLog);
251 else
252 m_DebugLogCallbackHandle = new BulletSimAPI.DebugLogCallback(BulletLogger);
253 }
254
255 // Get the version of the DLL
256 // TODO: this doesn't work yet. Something wrong with marshaling the returned string.
257 // BulletSimVersion = BulletSimAPI.GetVersion();
258 // m_log.WarnFormat("{0}: BulletSim.dll version='{1}'", LogHeader, BulletSimVersion);
259 211
260 // The bounding box for the simulated world. The origin is 0,0,0 unless we're 212 // The bounding box for the simulated world. The origin is 0,0,0 unless we're
261 // a child in a mega-region. 213 // a child in a mega-region.
@@ -263,18 +215,14 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
263 // area. It tracks active objects no matter where they are. 215 // area. It tracks active objects no matter where they are.
264 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 216 Vector3 worldExtent = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
265 217
266 // m_log.DebugFormat("{0}: Initialize: Calling BulletSimAPI.Initialize.", LogHeader); 218 World = PE.Initialize(worldExtent, Params, m_maxCollisionsPerFrame, ref m_collisionArray, m_maxUpdatesPerFrame, ref m_updateArray);
267 World = new BulletSim(0, this, BulletSimAPI.Initialize2(worldExtent, m_paramsHandle.AddrOfPinnedObject(),
268 m_maxCollisionsPerFrame, m_collisionArrayPinnedHandle.AddrOfPinnedObject(),
269 m_maxUpdatesPerFrame, m_updateArrayPinnedHandle.AddrOfPinnedObject(),
270 m_DebugLogCallbackHandle));
271 219
272 Constraints = new BSConstraintCollection(World); 220 Constraints = new BSConstraintCollection(World);
273 221
274 TerrainManager = new BSTerrainManager(this); 222 TerrainManager = new BSTerrainManager(this);
275 TerrainManager.CreateInitialGroundPlaneAndTerrain(); 223 TerrainManager.CreateInitialGroundPlaneAndTerrain();
276 224
277 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)Params.linksetImplementation); 225 m_log.WarnFormat("{0} Linksets implemented with {1}", LogHeader, (BSLinkset.LinksetImplementation)BSParam.LinksetImplementation);
278 226
279 InTaintTime = false; 227 InTaintTime = false;
280 m_initialized = true; 228 m_initialized = true;
@@ -285,9 +233,9 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
285 private void GetInitialParameterValues(IConfigSource config) 233 private void GetInitialParameterValues(IConfigSource config)
286 { 234 {
287 ConfigurationParameters parms = new ConfigurationParameters(); 235 ConfigurationParameters parms = new ConfigurationParameters();
288 m_params[0] = parms; 236 UnmanagedParams[0] = parms;
289 237
290 SetParameterDefaultValues(); 238 BSParam.SetParameterDefaultValues(this);
291 239
292 if (config != null) 240 if (config != null)
293 { 241 {
@@ -295,19 +243,34 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
295 IConfig pConfig = config.Configs["BulletSim"]; 243 IConfig pConfig = config.Configs["BulletSim"];
296 if (pConfig != null) 244 if (pConfig != null)
297 { 245 {
298 SetParameterConfigurationValues(pConfig); 246 BSParam.SetParameterConfigurationValues(this, pConfig);
247
248 // There are two Bullet implementations to choose from
249 BulletEngineName = pConfig.GetString("BulletEngine", "BulletUnmanaged");
299 250
300 // Very detailed logging for physics debugging 251 // Very detailed logging for physics debugging
252 // TODO: the boolean values can be moved to the normal parameter processing.
301 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false); 253 m_physicsLoggingEnabled = pConfig.GetBoolean("PhysicsLoggingEnabled", false);
302 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", "."); 254 m_physicsLoggingDir = pConfig.GetString("PhysicsLoggingDir", ".");
303 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-"); 255 m_physicsLoggingPrefix = pConfig.GetString("PhysicsLoggingPrefix", "physics-%REGIONNAME%-");
304 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5); 256 m_physicsLoggingFileMinutes = pConfig.GetInt("PhysicsLoggingFileMinutes", 5);
257 m_physicsLoggingDoFlush = pConfig.GetBoolean("PhysicsLoggingDoFlush", false);
258 m_physicsPhysicalDumpEnabled = pConfig.GetBoolean("PhysicsPhysicalDumpEnabled", false);
305 // Very detailed logging for vehicle debugging 259 // Very detailed logging for vehicle debugging
306 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false); 260 VehicleLoggingEnabled = pConfig.GetBoolean("VehicleLoggingEnabled", false);
261 VehiclePhysicalLoggingEnabled = pConfig.GetBoolean("VehiclePhysicalLoggingEnabled", false);
307 262
308 // Do any replacements in the parameters 263 // Do any replacements in the parameters
309 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName); 264 m_physicsLoggingPrefix = m_physicsLoggingPrefix.Replace("%REGIONNAME%", RegionName);
310 } 265 }
266
267 // The material characteristics.
268 BSMaterials.InitializeFromDefaults(Params);
269 if (pConfig != null)
270 {
271 // Let the user add new and interesting material property values.
272 BSMaterials.InitializefromParameters(pConfig);
273 }
311 } 274 }
312 } 275 }
313 276
@@ -326,16 +289,41 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
326 return ret; 289 return ret;
327 } 290 }
328 291
329 // Called directly from unmanaged code so don't do much 292 // Select the connection to the actual Bullet implementation.
330 private void BulletLogger(string msg) 293 // The main engine selection is the engineName up to the first hypen.
294 // So "Bullet-2.80-OpenCL-Intel" specifies the 'bullet' class here and the whole name
295 // is passed to the engine to do its special selection, etc.
296 private BSAPITemplate SelectUnderlyingBulletEngine(string engineName)
331 { 297 {
332 m_log.Debug("[BULLETS UNMANAGED]:" + msg); 298 // For the moment, do a simple switch statement.
333 } 299 // Someday do fancyness with looking up the interfaces in the assembly.
300 BSAPITemplate ret = null;
334 301
335 // Called directly from unmanaged code so don't do much 302 string selectionName = engineName.ToLower();
336 private void BulletLoggerPhysLog(string msg) 303 int hyphenIndex = engineName.IndexOf("-");
337 { 304 if (hyphenIndex > 0)
338 DetailLog("[BULLETS UNMANAGED]:" + msg); 305 selectionName = engineName.ToLower().Substring(0, hyphenIndex - 1);
306
307 switch (selectionName)
308 {
309 case "bulletunmanaged":
310 ret = new BSAPIUnman(engineName, this);
311 break;
312 case "bulletxna":
313 ret = new BSAPIXNA(engineName, this);
314 break;
315 }
316
317 if (ret == null)
318 {
319 m_log.ErrorFormat("{0) COULD NOT SELECT BULLET ENGINE: '[BulletSim]PhysicsEngine' must be either 'BulletUnmanaged-*' or 'BulletXNA-*'", LogHeader);
320 }
321 else
322 {
323 m_log.WarnFormat("{0} Selected bullet engine {1} -> {2}/{3}", LogHeader, engineName, ret.BulletEngineName, ret.BulletEngineVersion);
324 }
325
326 return ret;
339 } 327 }
340 328
341 public override void Dispose() 329 public override void Dispose()
@@ -345,8 +333,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
345 // make sure no stepping happens while we're deleting stuff 333 // make sure no stepping happens while we're deleting stuff
346 m_initialized = false; 334 m_initialized = false;
347 335
348 TerrainManager.ReleaseGroundPlaneAndTerrain();
349
350 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects) 336 foreach (KeyValuePair<uint, BSPhysObject> kvp in PhysObjects)
351 { 337 {
352 kvp.Value.Destroy(); 338 kvp.Value.Destroy();
@@ -366,8 +352,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
366 Shapes = null; 352 Shapes = null;
367 } 353 }
368 354
355 if (TerrainManager != null)
356 {
357 TerrainManager.ReleaseGroundPlaneAndTerrain();
358 TerrainManager.Dispose();
359 TerrainManager = null;
360 }
361
369 // Anything left in the unmanaged code should be cleaned out 362 // Anything left in the unmanaged code should be cleaned out
370 BulletSimAPI.Shutdown2(World.ptr); 363 PE.Shutdown(World);
371 364
372 // Not logging any more 365 // Not logging any more
373 PhysicsLogging.Close(); 366 PhysicsLogging.Close();
@@ -474,41 +467,55 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
474 // Simulate one timestep 467 // Simulate one timestep
475 public override float Simulate(float timeStep) 468 public override float Simulate(float timeStep)
476 { 469 {
470 // prevent simulation until we've been initialized
471 if (!m_initialized) return 5.0f;
472
473 LastTimeStep = timeStep;
474
477 int updatedEntityCount = 0; 475 int updatedEntityCount = 0;
478 IntPtr updatedEntitiesPtr;
479 int collidersCount = 0; 476 int collidersCount = 0;
480 IntPtr collidersPtr;
481 477
482 int beforeTime = 0; 478 int beforeTime = 0;
483 int simTime = 0; 479 int simTime = 0;
484 480
485 // prevent simulation until we've been initialized
486 if (!m_initialized) return 5.0f;
487
488 // update the prim states while we know the physics engine is not busy 481 // update the prim states while we know the physics engine is not busy
489 int numTaints = _taintOperations.Count; 482 int numTaints = _taintOperations.Count;
483
484 InTaintTime = true; // Only used for debugging so locking is not necessary.
485
486 ProcessTaints();
487
488 // Some of the physical objects requre individual, pre-step calls
489 TriggerPreStepEvent(timeStep);
490
491 // the prestep actions might have added taints
492 numTaints += _taintOperations.Count;
490 ProcessTaints(); 493 ProcessTaints();
491 494
492 // Some of the prims operate with special vehicle properties 495 InTaintTime = false; // Only used for debugging so locking is not necessary.
493 ProcessVehicles(timeStep); 496
494 ProcessTaints(); // the vehicles might have added taints 497 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
498 // Only enable this in a limited test world with few objects.
499 if (m_physicsPhysicalDumpEnabled)
500 PE.DumpAllInfo(World);
495 501
496 // step the physical world one interval 502 // step the physical world one interval
497 m_simulationStep++; 503 m_simulationStep++;
498 int numSubSteps = 0; 504 int numSubSteps = 0;
499
500 try 505 try
501 { 506 {
502 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 507 if (PhysicsLogging.Enabled)
503 if (PhysicsLogging.Enabled) beforeTime = Util.EnvironmentTickCount(); 508 beforeTime = Util.EnvironmentTickCount();
504 509
505 numSubSteps = BulletSimAPI.PhysicsStep2(World.ptr, timeStep, m_maxSubSteps, m_fixedTimeStep, 510 numSubSteps = PE.PhysicsStep(World, timeStep, m_maxSubSteps, m_fixedTimeStep, out updatedEntityCount, out collidersCount);
506 out updatedEntityCount, out updatedEntitiesPtr, out collidersCount, out collidersPtr);
507 511
508 if (PhysicsLogging.Enabled) simTime = Util.EnvironmentTickCountSubtract(beforeTime); 512 if (PhysicsLogging.Enabled)
509 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}", 513 {
510 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps, updatedEntityCount, collidersCount); 514 simTime = Util.EnvironmentTickCountSubtract(beforeTime);
511 if (VehicleLoggingEnabled) DumpVehicles(); // DEBUG 515 DetailLog("{0},Simulate,call, frame={1}, nTaints={2}, simTime={3}, substeps={4}, updates={5}, colliders={6}, objWColl={7}",
516 DetailLogZero, m_simulationStep, numTaints, simTime, numSubSteps,
517 updatedEntityCount, collidersCount, ObjectsWithCollisions.Count);
518 }
512 } 519 }
513 catch (Exception e) 520 catch (Exception e)
514 { 521 {
@@ -520,9 +527,10 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
520 collidersCount = 0; 527 collidersCount = 0;
521 } 528 }
522 529
523 // Don't have to use the pointers passed back since we know it is the same pinned memory we passed in 530 if ((m_simulationStep % PhysicsMetricDumpFrames) == 0)
531 PE.DumpPhysicsStatistics(World);
524 532
525 // Get a value for 'now' so all the collision and update routines don't have to get their own 533 // Get a value for 'now' so all the collision and update routines don't have to get their own.
526 SimulationNowTime = Util.EnvironmentTickCount(); 534 SimulationNowTime = Util.EnvironmentTickCount();
527 535
528 // If there were collisions, process them by sending the event to the prim. 536 // If there were collisions, process them by sending the event to the prim.
@@ -562,12 +570,16 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
562 570
563 // Objects that are done colliding are removed from the ObjectsWithCollisions list. 571 // Objects that are done colliding are removed from the ObjectsWithCollisions list.
564 // Not done above because it is inside an iteration of ObjectWithCollisions. 572 // Not done above because it is inside an iteration of ObjectWithCollisions.
573 // This complex collision processing is required to create an empty collision
574 // event call after all real collisions have happened on an object. This enables
575 // the simulator to generate the 'collision end' event.
565 if (ObjectsWithNoMoreCollisions.Count > 0) 576 if (ObjectsWithNoMoreCollisions.Count > 0)
566 { 577 {
567 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions) 578 foreach (BSPhysObject po in ObjectsWithNoMoreCollisions)
568 ObjectsWithCollisions.Remove(po); 579 ObjectsWithCollisions.Remove(po);
569 ObjectsWithNoMoreCollisions.Clear(); 580 ObjectsWithNoMoreCollisions.Clear();
570 } 581 }
582 // Done with collisions.
571 583
572 // If any of the objects had updated properties, tell the object it has been changed by the physics engine 584 // If any of the objects had updated properties, tell the object it has been changed by the physics engine
573 if (updatedEntityCount > 0) 585 if (updatedEntityCount > 0)
@@ -583,17 +595,17 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
583 } 595 }
584 } 596 }
585 597
586 ProcessPostStepTaints(); 598 TriggerPostStepEvent(timeStep);
587 599
588 // This causes the unmanaged code to output ALL the values found in ALL the objects in the world. 600 // The following causes the unmanaged code to output ALL the values found in ALL the objects in the world.
589 // Only enable this in a limited test world with few objects. 601 // Only enable this in a limited test world with few objects.
590 // BulletSimAPI.DumpAllInfo2(World.ptr); // DEBUG DEBUG DEBUG 602 if (m_physicsPhysicalDumpEnabled)
603 PE.DumpAllInfo(World);
591 604
592 // The physics engine returns the number of milliseconds it simulated this call. 605 // The physics engine returns the number of milliseconds it simulated this call.
593 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS. 606 // These are summed and normalized to one second and divided by 1000 to give the reported physics FPS.
594 // We multiply by 55 to give a recognizable running rate (55 or less). 607 // Multiply by a fixed nominal frame rate to give a rate similar to the simulator (usually 55).
595 return numSubSteps * m_fixedTimeStep * 1000 * 55; 608 return (float)numSubSteps * m_fixedTimeStep * 1000f * NominalFrameRate;
596 // return timeStep * 1000 * 55;
597 } 609 }
598 610
599 // Something has collided 611 // Something has collided
@@ -639,12 +651,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
639 651
640 public override void SetWaterLevel(float baseheight) 652 public override void SetWaterLevel(float baseheight)
641 { 653 {
642 m_waterLevel = baseheight; 654 SimpleWaterLevel = baseheight;
643 }
644 // Someday....
645 public float GetWaterLevelAtXYZ(Vector3 loc)
646 {
647 return m_waterLevel;
648 } 655 }
649 656
650 public override void DeleteTerrain() 657 public override void DeleteTerrain()
@@ -681,6 +688,15 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
681 public override bool IsThreaded { get { return false; } } 688 public override bool IsThreaded { get { return false; } }
682 689
683 #region Taints 690 #region Taints
691 // The simulation execution order is:
692 // Simulate()
693 // DoOneTimeTaints
694 // TriggerPreStepEvent
695 // DoOneTimeTaints
696 // Step()
697 // ProcessAndForwardCollisions
698 // ProcessAndForwardPropertyUpdates
699 // TriggerPostStepEvent
684 700
685 // Calls to the PhysicsActors can't directly call into the physics engine 701 // Calls to the PhysicsActors can't directly call into the physics engine
686 // because it might be busy. We delay changes to a known time. 702 // because it might be busy. We delay changes to a known time.
@@ -707,58 +723,35 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
707 TaintedObject(ident, callback); 723 TaintedObject(ident, callback);
708 } 724 }
709 725
726 private void TriggerPreStepEvent(float timeStep)
727 {
728 PreStepAction actions = BeforeStep;
729 if (actions != null)
730 actions(timeStep);
731
732 }
733
734 private void TriggerPostStepEvent(float timeStep)
735 {
736 PreStepAction actions = AfterStep;
737 if (actions != null)
738 actions(timeStep);
739
740 }
741
710 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues 742 // When someone tries to change a property on a BSPrim or BSCharacter, the object queues
711 // a callback into itself to do the actual property change. That callback is called 743 // a callback into itself to do the actual property change. That callback is called
712 // here just before the physics engine is called to step the simulation. 744 // here just before the physics engine is called to step the simulation.
713 public void ProcessTaints() 745 public void ProcessTaints()
714 { 746 {
715 InTaintTime = true; // Only used for debugging so locking is not necessary.
716 ProcessRegularTaints(); 747 ProcessRegularTaints();
717 ProcessPostTaintTaints(); 748 ProcessPostTaintTaints();
718 InTaintTime = false;
719 } 749 }
720 750
721 private void ProcessRegularTaints() 751 private void ProcessRegularTaints()
722 { 752 {
723 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process 753 if (_taintOperations.Count > 0) // save allocating new list if there is nothing to process
724 { 754 {
725 /*
726 // Code to limit the number of taints processed per step. Meant to limit step time.
727 // Unsure if a good idea as code assumes that taints are done before the step.
728 int taintCount = m_taintsToProcessPerStep;
729 TaintCallbackEntry oneCallback = new TaintCallbackEntry();
730 while (_taintOperations.Count > 0 && taintCount-- > 0)
731 {
732 bool gotOne = false;
733 lock (_taintLock)
734 {
735 if (_taintOperations.Count > 0)
736 {
737 oneCallback = _taintOperations[0];
738 _taintOperations.RemoveAt(0);
739 gotOne = true;
740 }
741 }
742 if (gotOne)
743 {
744 try
745 {
746 DetailLog("{0},BSScene.ProcessTaints,doTaint,id={1}", DetailLogZero, oneCallback.ident);
747 oneCallback.callback();
748 }
749 catch (Exception e)
750 {
751 DetailLog("{0},BSScene.ProcessTaints,doTaintException,id={1}", DetailLogZero, oneCallback.ident); // DEBUG DEBUG DEBUG
752 m_log.ErrorFormat("{0}: ProcessTaints: {1}: Exception: {2}", LogHeader, oneCallback.ident, e);
753 }
754 }
755 }
756 if (_taintOperations.Count > 0)
757 {
758 DetailLog("{0},BSScene.ProcessTaints,leftTaintsOnList,numNotProcessed={1}", DetailLogZero, _taintOperations.Count);
759 }
760 */
761
762 // swizzle a new list into the list location so we can process what's there 755 // swizzle a new list into the list location so we can process what's there
763 List<TaintCallbackEntry> oldList; 756 List<TaintCallbackEntry> oldList;
764 lock (_taintLock) 757 lock (_taintLock)
@@ -797,6 +790,7 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
797 return; 790 return;
798 } 791 }
799 792
793 // Taints that happen after the normal taint processing but before the simulation step.
800 private void ProcessPostTaintTaints() 794 private void ProcessPostTaintTaints()
801 { 795 {
802 if (_postTaintOperations.Count > 0) 796 if (_postTaintOperations.Count > 0)
@@ -824,45 +818,6 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
824 } 818 }
825 } 819 }
826 820
827 public void PostStepTaintObject(String ident, TaintCallback callback)
828 {
829 if (!m_initialized) return;
830
831 lock (_taintLock)
832 {
833 _postStepOperations.Add(new TaintCallbackEntry(ident, callback));
834 }
835
836 return;
837 }
838
839 private void ProcessPostStepTaints()
840 {
841 if (_postStepOperations.Count > 0)
842 {
843 List<TaintCallbackEntry> oldList;
844 lock (_taintLock)
845 {
846 oldList = _postStepOperations;
847 _postStepOperations = new List<TaintCallbackEntry>();
848 }
849
850 foreach (TaintCallbackEntry tcbe in oldList)
851 {
852 try
853 {
854 DetailLog("{0},BSScene.ProcessPostStepTaints,doTaint,id={1}", DetailLogZero, tcbe.ident); // DEBUG DEBUG DEBUG
855 tcbe.callback();
856 }
857 catch (Exception e)
858 {
859 m_log.ErrorFormat("{0}: ProcessPostStepTaints: {1}: Exception: {2}", LogHeader, tcbe.ident, e);
860 }
861 }
862 oldList.Clear();
863 }
864 }
865
866 // Only used for debugging. Does not change state of anything so locking is not necessary. 821 // Only used for debugging. Does not change state of anything so locking is not necessary.
867 public bool AssertInTaintTime(string whereFrom) 822 public bool AssertInTaintTime(string whereFrom)
868 { 823 {
@@ -870,517 +825,21 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
870 { 825 {
871 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom); 826 DetailLog("{0},BSScene.AssertInTaintTime,NOT IN TAINT TIME,Region={1},Where={2}", DetailLogZero, RegionName, whereFrom);
872 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom); 827 m_log.ErrorFormat("{0} NOT IN TAINT TIME!! Region={1}, Where={2}", LogHeader, RegionName, whereFrom);
873 Util.PrintCallStack(); // Prints the stack into the DEBUG log file. 828 Util.PrintCallStack(DetailLog);
874 } 829 }
875 return InTaintTime; 830 return InTaintTime;
876 } 831 }
877 832
878 #endregion // Taints 833 #endregion // Taints
879 834
880 #region Vehicles
881
882 public void VehicleInSceneTypeChanged(BSPrim vehic, Vehicle newType)
883 {
884 RemoveVehiclePrim(vehic);
885 if (newType != Vehicle.TYPE_NONE)
886 {
887 // make it so the scene will call us each tick to do vehicle things
888 AddVehiclePrim(vehic);
889 }
890 }
891
892 // Make so the scene will call this prim for vehicle actions each tick.
893 // Safe to call if prim is already in the vehicle list.
894 public void AddVehiclePrim(BSPrim vehicle)
895 {
896 lock (m_vehicles)
897 {
898 if (!m_vehicles.Contains(vehicle))
899 {
900 m_vehicles.Add(vehicle);
901 }
902 }
903 }
904
905 // Remove a prim from our list of vehicles.
906 // Safe to call if the prim is not in the vehicle list.
907 public void RemoveVehiclePrim(BSPrim vehicle)
908 {
909 lock (m_vehicles)
910 {
911 if (m_vehicles.Contains(vehicle))
912 {
913 m_vehicles.Remove(vehicle);
914 }
915 }
916 }
917
918 // Some prims have extra vehicle actions
919 // Called at taint time!
920 private void ProcessVehicles(float timeStep)
921 {
922 foreach (BSPhysObject pobj in m_vehicles)
923 {
924 pobj.StepVehicle(timeStep);
925 }
926 }
927 #endregion Vehicles
928
929 #region INI and command line parameter processing 835 #region INI and command line parameter processing
930 836
931 delegate void ParamUser(BSScene scene, IConfig conf, string paramName, float val);
932 delegate float ParamGet(BSScene scene);
933 delegate void ParamSet(BSScene scene, string paramName, uint localID, float val);
934 delegate void SetOnObject(BSScene scene, BSPhysObject obj, float val);
935
936 private struct ParameterDefn
937 {
938 public string name; // string name of the parameter
939 public string desc; // a short description of what the parameter means
940 public float defaultValue; // default value if not specified anywhere else
941 public ParamUser userParam; // get the value from the configuration file
942 public ParamGet getter; // return the current value stored for this parameter
943 public ParamSet setter; // set the current value for this parameter
944 public SetOnObject onObject; // set the value on an object in the physical domain
945 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s)
946 {
947 name = n;
948 desc = d;
949 defaultValue = v;
950 userParam = u;
951 getter = g;
952 setter = s;
953 onObject = null;
954 }
955 public ParameterDefn(string n, string d, float v, ParamUser u, ParamGet g, ParamSet s, SetOnObject o)
956 {
957 name = n;
958 desc = d;
959 defaultValue = v;
960 userParam = u;
961 getter = g;
962 setter = s;
963 onObject = o;
964 }
965 }
966
967 // List of all of the externally visible parameters.
968 // For each parameter, this table maps a text name to getter and setters.
969 // To add a new externally referencable/settable parameter, add the paramter storage
970 // location somewhere in the program and make an entry in this table with the
971 // getters and setters.
972 // It is easiest to find an existing definition and copy it.
973 // Parameter values are floats. Booleans are converted to a floating value.
974 //
975 // A ParameterDefn() takes the following parameters:
976 // -- the text name of the parameter. This is used for console input and ini file.
977 // -- a short text description of the parameter. This shows up in the console listing.
978 // -- a delegate for fetching the parameter from the ini file.
979 // Should handle fetching the right type from the ini file and converting it.
980 // -- a delegate for getting the value as a float
981 // -- a delegate for setting the value from a float
982 //
983 // The single letter parameters for the delegates are:
984 // s = BSScene
985 // o = BSPhysObject
986 // p = string parameter name
987 // l = localID of referenced object
988 // v = float value
989 // cf = parameter configuration class (for fetching values from ini file)
990 private ParameterDefn[] ParameterDefinitions =
991 {
992 new ParameterDefn("MeshSculptedPrim", "Whether to create meshes for sculpties",
993 ConfigurationParameters.numericTrue,
994 (s,cf,p,v) => { s.ShouldMeshSculptedPrim = cf.GetBoolean(p, s.BoolNumeric(v)); },
995 (s) => { return s.NumericBool(s.ShouldMeshSculptedPrim); },
996 (s,p,l,v) => { s.ShouldMeshSculptedPrim = s.BoolNumeric(v); } ),
997 new ParameterDefn("ForceSimplePrimMeshing", "If true, only use primitive meshes for objects",
998 ConfigurationParameters.numericFalse,
999 (s,cf,p,v) => { s.ShouldForceSimplePrimMeshing = cf.GetBoolean(p, s.BoolNumeric(v)); },
1000 (s) => { return s.NumericBool(s.ShouldForceSimplePrimMeshing); },
1001 (s,p,l,v) => { s.ShouldForceSimplePrimMeshing = s.BoolNumeric(v); } ),
1002 new ParameterDefn("UseHullsForPhysicalObjects", "If true, create hulls for physical objects",
1003 ConfigurationParameters.numericTrue,
1004 (s,cf,p,v) => { s.ShouldUseHullsForPhysicalObjects = cf.GetBoolean(p, s.BoolNumeric(v)); },
1005 (s) => { return s.NumericBool(s.ShouldUseHullsForPhysicalObjects); },
1006 (s,p,l,v) => { s.ShouldUseHullsForPhysicalObjects = s.BoolNumeric(v); } ),
1007
1008 new ParameterDefn("MeshLevelOfDetail", "Level of detail to render meshes (32, 16, 8 or 4. 32=most detailed)",
1009 8f,
1010 (s,cf,p,v) => { s.MeshLOD = (float)cf.GetInt(p, (int)v); },
1011 (s) => { return s.MeshLOD; },
1012 (s,p,l,v) => { s.MeshLOD = v; } ),
1013 new ParameterDefn("MeshLevelOfDetailMegaPrim", "Level of detail to render meshes larger than threshold meters",
1014 16f,
1015 (s,cf,p,v) => { s.MeshMegaPrimLOD = (float)cf.GetInt(p, (int)v); },
1016 (s) => { return s.MeshMegaPrimLOD; },
1017 (s,p,l,v) => { s.MeshMegaPrimLOD = v; } ),
1018 new ParameterDefn("MeshLevelOfDetailMegaPrimThreshold", "Size (in meters) of a mesh before using MeshMegaPrimLOD",
1019 10f,
1020 (s,cf,p,v) => { s.MeshMegaPrimThreshold = (float)cf.GetInt(p, (int)v); },
1021 (s) => { return s.MeshMegaPrimThreshold; },
1022 (s,p,l,v) => { s.MeshMegaPrimThreshold = v; } ),
1023 new ParameterDefn("SculptLevelOfDetail", "Level of detail to render sculpties (32, 16, 8 or 4. 32=most detailed)",
1024 32f,
1025 (s,cf,p,v) => { s.SculptLOD = (float)cf.GetInt(p, (int)v); },
1026 (s) => { return s.SculptLOD; },
1027 (s,p,l,v) => { s.SculptLOD = v; } ),
1028
1029 new ParameterDefn("MaxSubStep", "In simulation step, maximum number of substeps",
1030 10f,
1031 (s,cf,p,v) => { s.m_maxSubSteps = cf.GetInt(p, (int)v); },
1032 (s) => { return (float)s.m_maxSubSteps; },
1033 (s,p,l,v) => { s.m_maxSubSteps = (int)v; } ),
1034 new ParameterDefn("FixedTimeStep", "In simulation step, seconds of one substep (1/60)",
1035 1f / 60f,
1036 (s,cf,p,v) => { s.m_fixedTimeStep = cf.GetFloat(p, v); },
1037 (s) => { return (float)s.m_fixedTimeStep; },
1038 (s,p,l,v) => { s.m_fixedTimeStep = v; } ),
1039 new ParameterDefn("MaxCollisionsPerFrame", "Max collisions returned at end of each frame",
1040 2048f,
1041 (s,cf,p,v) => { s.m_maxCollisionsPerFrame = cf.GetInt(p, (int)v); },
1042 (s) => { return (float)s.m_maxCollisionsPerFrame; },
1043 (s,p,l,v) => { s.m_maxCollisionsPerFrame = (int)v; } ),
1044 new ParameterDefn("MaxUpdatesPerFrame", "Max updates returned at end of each frame",
1045 8000f,
1046 (s,cf,p,v) => { s.m_maxUpdatesPerFrame = cf.GetInt(p, (int)v); },
1047 (s) => { return (float)s.m_maxUpdatesPerFrame; },
1048 (s,p,l,v) => { s.m_maxUpdatesPerFrame = (int)v; } ),
1049 new ParameterDefn("MaxTaintsToProcessPerStep", "Number of update taints to process before each simulation step",
1050 500f,
1051 (s,cf,p,v) => { s.m_taintsToProcessPerStep = cf.GetInt(p, (int)v); },
1052 (s) => { return (float)s.m_taintsToProcessPerStep; },
1053 (s,p,l,v) => { s.m_taintsToProcessPerStep = (int)v; } ),
1054 new ParameterDefn("MaxObjectMass", "Maximum object mass (10000.01)",
1055 10000.01f,
1056 (s,cf,p,v) => { s.MaximumObjectMass = cf.GetFloat(p, v); },
1057 (s) => { return (float)s.MaximumObjectMass; },
1058 (s,p,l,v) => { s.MaximumObjectMass = v; } ),
1059
1060 new ParameterDefn("PID_D", "Derivitive factor for motion smoothing",
1061 2200f,
1062 (s,cf,p,v) => { s.PID_D = cf.GetFloat(p, v); },
1063 (s) => { return (float)s.PID_D; },
1064 (s,p,l,v) => { s.PID_D = v; } ),
1065 new ParameterDefn("PID_P", "Parameteric factor for motion smoothing",
1066 900f,
1067 (s,cf,p,v) => { s.PID_P = cf.GetFloat(p, v); },
1068 (s) => { return (float)s.PID_P; },
1069 (s,p,l,v) => { s.PID_P = v; } ),
1070
1071 new ParameterDefn("DefaultFriction", "Friction factor used on new objects",
1072 0.5f,
1073 (s,cf,p,v) => { s.m_params[0].defaultFriction = cf.GetFloat(p, v); },
1074 (s) => { return s.m_params[0].defaultFriction; },
1075 (s,p,l,v) => { s.m_params[0].defaultFriction = v; } ),
1076 new ParameterDefn("DefaultDensity", "Density for new objects" ,
1077 10.000006836f, // Aluminum g/cm3
1078 (s,cf,p,v) => { s.m_params[0].defaultDensity = cf.GetFloat(p, v); },
1079 (s) => { return s.m_params[0].defaultDensity; },
1080 (s,p,l,v) => { s.m_params[0].defaultDensity = v; } ),
1081 new ParameterDefn("DefaultRestitution", "Bouncyness of an object" ,
1082 0f,
1083 (s,cf,p,v) => { s.m_params[0].defaultRestitution = cf.GetFloat(p, v); },
1084 (s) => { return s.m_params[0].defaultRestitution; },
1085 (s,p,l,v) => { s.m_params[0].defaultRestitution = v; } ),
1086 new ParameterDefn("CollisionMargin", "Margin around objects before collisions are calculated (must be zero!)",
1087 0f,
1088 (s,cf,p,v) => { s.m_params[0].collisionMargin = cf.GetFloat(p, v); },
1089 (s) => { return s.m_params[0].collisionMargin; },
1090 (s,p,l,v) => { s.m_params[0].collisionMargin = v; } ),
1091 new ParameterDefn("Gravity", "Vertical force of gravity (negative means down)",
1092 -9.80665f,
1093 (s,cf,p,v) => { s.m_params[0].gravity = cf.GetFloat(p, v); },
1094 (s) => { return s.m_params[0].gravity; },
1095 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].gravity, p, PhysParameterEntry.APPLY_TO_NONE, v); },
1096 (s,o,v) => { BulletSimAPI.SetGravity2(s.World.ptr, new Vector3(0f,0f,v)); } ),
1097
1098
1099 new ParameterDefn("LinearDamping", "Factor to damp linear movement per second (0.0 - 1.0)",
1100 0f,
1101 (s,cf,p,v) => { s.m_params[0].linearDamping = cf.GetFloat(p, v); },
1102 (s) => { return s.m_params[0].linearDamping; },
1103 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearDamping, p, l, v); },
1104 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, v, s.m_params[0].angularDamping); } ),
1105 new ParameterDefn("AngularDamping", "Factor to damp angular movement per second (0.0 - 1.0)",
1106 0f,
1107 (s,cf,p,v) => { s.m_params[0].angularDamping = cf.GetFloat(p, v); },
1108 (s) => { return s.m_params[0].angularDamping; },
1109 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularDamping, p, l, v); },
1110 (s,o,v) => { BulletSimAPI.SetDamping2(o.PhysBody.ptr, s.m_params[0].linearDamping, v); } ),
1111 new ParameterDefn("DeactivationTime", "Seconds before considering an object potentially static",
1112 0.2f,
1113 (s,cf,p,v) => { s.m_params[0].deactivationTime = cf.GetFloat(p, v); },
1114 (s) => { return s.m_params[0].deactivationTime; },
1115 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].deactivationTime, p, l, v); },
1116 (s,o,v) => { BulletSimAPI.SetDeactivationTime2(o.PhysBody.ptr, v); } ),
1117 new ParameterDefn("LinearSleepingThreshold", "Seconds to measure linear movement before considering static",
1118 0.8f,
1119 (s,cf,p,v) => { s.m_params[0].linearSleepingThreshold = cf.GetFloat(p, v); },
1120 (s) => { return s.m_params[0].linearSleepingThreshold; },
1121 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].linearSleepingThreshold, p, l, v); },
1122 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
1123 new ParameterDefn("AngularSleepingThreshold", "Seconds to measure angular movement before considering static",
1124 1.0f,
1125 (s,cf,p,v) => { s.m_params[0].angularSleepingThreshold = cf.GetFloat(p, v); },
1126 (s) => { return s.m_params[0].angularSleepingThreshold; },
1127 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].angularSleepingThreshold, p, l, v); },
1128 (s,o,v) => { BulletSimAPI.SetSleepingThresholds2(o.PhysBody.ptr, v, v); } ),
1129 new ParameterDefn("CcdMotionThreshold", "Continuious collision detection threshold (0 means no CCD)" ,
1130 0f, // set to zero to disable
1131 (s,cf,p,v) => { s.m_params[0].ccdMotionThreshold = cf.GetFloat(p, v); },
1132 (s) => { return s.m_params[0].ccdMotionThreshold; },
1133 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdMotionThreshold, p, l, v); },
1134 (s,o,v) => { BulletSimAPI.SetCcdMotionThreshold2(o.PhysBody.ptr, v); } ),
1135 new ParameterDefn("CcdSweptSphereRadius", "Continuious collision detection test radius" ,
1136 0f,
1137 (s,cf,p,v) => { s.m_params[0].ccdSweptSphereRadius = cf.GetFloat(p, v); },
1138 (s) => { return s.m_params[0].ccdSweptSphereRadius; },
1139 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].ccdSweptSphereRadius, p, l, v); },
1140 (s,o,v) => { BulletSimAPI.SetCcdSweptSphereRadius2(o.PhysBody.ptr, v); } ),
1141 new ParameterDefn("ContactProcessingThreshold", "Distance between contacts before doing collision check" ,
1142 0.1f,
1143 (s,cf,p,v) => { s.m_params[0].contactProcessingThreshold = cf.GetFloat(p, v); },
1144 (s) => { return s.m_params[0].contactProcessingThreshold; },
1145 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].contactProcessingThreshold, p, l, v); },
1146 (s,o,v) => { BulletSimAPI.SetContactProcessingThreshold2(o.PhysBody.ptr, v); } ),
1147
1148 new ParameterDefn("TerrainImplementation", "Type of shape to use for terrain (0=heightmap, 1=mesh)",
1149 (float)BSTerrainPhys.TerrainImplementation.Mesh,
1150 (s,cf,p,v) => { s.m_params[0].terrainImplementation = cf.GetFloat(p,v); },
1151 (s) => { return s.m_params[0].terrainImplementation; },
1152 (s,p,l,v) => { s.m_params[0].terrainImplementation = v; } ),
1153 new ParameterDefn("TerrainFriction", "Factor to reduce movement against terrain surface" ,
1154 0.5f,
1155 (s,cf,p,v) => { s.m_params[0].terrainFriction = cf.GetFloat(p, v); },
1156 (s) => { return s.m_params[0].terrainFriction; },
1157 (s,p,l,v) => { s.m_params[0].terrainFriction = v; /* TODO: set on real terrain */} ),
1158 new ParameterDefn("TerrainHitFraction", "Distance to measure hit collisions" ,
1159 0.8f,
1160 (s,cf,p,v) => { s.m_params[0].terrainHitFraction = cf.GetFloat(p, v); },
1161 (s) => { return s.m_params[0].terrainHitFraction; },
1162 (s,p,l,v) => { s.m_params[0].terrainHitFraction = v; /* TODO: set on real terrain */ } ),
1163 new ParameterDefn("TerrainRestitution", "Bouncyness" ,
1164 0f,
1165 (s,cf,p,v) => { s.m_params[0].terrainRestitution = cf.GetFloat(p, v); },
1166 (s) => { return s.m_params[0].terrainRestitution; },
1167 (s,p,l,v) => { s.m_params[0].terrainRestitution = v; /* TODO: set on real terrain */ } ),
1168 new ParameterDefn("AvatarFriction", "Factor to reduce movement against an avatar. Changed on avatar recreation.",
1169 0.2f,
1170 (s,cf,p,v) => { s.m_params[0].avatarFriction = cf.GetFloat(p, v); },
1171 (s) => { return s.m_params[0].avatarFriction; },
1172 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarFriction, p, l, v); } ),
1173 new ParameterDefn("AvatarStandingFriction", "Avatar friction when standing. Changed on avatar recreation.",
1174 10f,
1175 (s,cf,p,v) => { s.m_params[0].avatarStandingFriction = cf.GetFloat(p, v); },
1176 (s) => { return s.m_params[0].avatarStandingFriction; },
1177 (s,p,l,v) => { s.m_params[0].avatarStandingFriction = v; } ),
1178 new ParameterDefn("AvatarDensity", "Density of an avatar. Changed on avatar recreation.",
1179 60f,
1180 (s,cf,p,v) => { s.m_params[0].avatarDensity = cf.GetFloat(p, v); },
1181 (s) => { return s.m_params[0].avatarDensity; },
1182 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarDensity, p, l, v); } ),
1183 new ParameterDefn("AvatarRestitution", "Bouncyness. Changed on avatar recreation.",
1184 0f,
1185 (s,cf,p,v) => { s.m_params[0].avatarRestitution = cf.GetFloat(p, v); },
1186 (s) => { return s.m_params[0].avatarRestitution; },
1187 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarRestitution, p, l, v); } ),
1188 new ParameterDefn("AvatarCapsuleWidth", "The distance between the sides of the avatar capsule",
1189 0.6f,
1190 (s,cf,p,v) => { s.m_params[0].avatarCapsuleWidth = cf.GetFloat(p, v); },
1191 (s) => { return s.m_params[0].avatarCapsuleWidth; },
1192 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleWidth, p, l, v); } ),
1193 new ParameterDefn("AvatarCapsuleDepth", "The distance between the front and back of the avatar capsule",
1194 0.45f,
1195 (s,cf,p,v) => { s.m_params[0].avatarCapsuleDepth = cf.GetFloat(p, v); },
1196 (s) => { return s.m_params[0].avatarCapsuleDepth; },
1197 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleDepth, p, l, v); } ),
1198 new ParameterDefn("AvatarCapsuleHeight", "Default height of space around avatar",
1199 1.5f,
1200 (s,cf,p,v) => { s.m_params[0].avatarCapsuleHeight = cf.GetFloat(p, v); },
1201 (s) => { return s.m_params[0].avatarCapsuleHeight; },
1202 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarCapsuleHeight, p, l, v); } ),
1203 new ParameterDefn("AvatarContactProcessingThreshold", "Distance from capsule to check for collisions",
1204 0.1f,
1205 (s,cf,p,v) => { s.m_params[0].avatarContactProcessingThreshold = cf.GetFloat(p, v); },
1206 (s) => { return s.m_params[0].avatarContactProcessingThreshold; },
1207 (s,p,l,v) => { s.UpdateParameterObject(ref s.m_params[0].avatarContactProcessingThreshold, p, l, v); } ),
1208
1209
1210 new ParameterDefn("MaxPersistantManifoldPoolSize", "Number of manifolds pooled (0 means default of 4096)",
1211 0f,
1212 (s,cf,p,v) => { s.m_params[0].maxPersistantManifoldPoolSize = cf.GetFloat(p, v); },
1213 (s) => { return s.m_params[0].maxPersistantManifoldPoolSize; },
1214 (s,p,l,v) => { s.m_params[0].maxPersistantManifoldPoolSize = v; } ),
1215 new ParameterDefn("MaxCollisionAlgorithmPoolSize", "Number of collisions pooled (0 means default of 4096)",
1216 0f,
1217 (s,cf,p,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = cf.GetFloat(p, v); },
1218 (s) => { return s.m_params[0].maxCollisionAlgorithmPoolSize; },
1219 (s,p,l,v) => { s.m_params[0].maxCollisionAlgorithmPoolSize = v; } ),
1220 new ParameterDefn("ShouldDisableContactPoolDynamicAllocation", "Enable to allow large changes in object count",
1221 ConfigurationParameters.numericFalse,
1222 (s,cf,p,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1223 (s) => { return s.m_params[0].shouldDisableContactPoolDynamicAllocation; },
1224 (s,p,l,v) => { s.m_params[0].shouldDisableContactPoolDynamicAllocation = v; } ),
1225 new ParameterDefn("ShouldForceUpdateAllAabbs", "Enable to recomputer AABBs every simulator step",
1226 ConfigurationParameters.numericFalse,
1227 (s,cf,p,v) => { s.m_params[0].shouldForceUpdateAllAabbs = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1228 (s) => { return s.m_params[0].shouldForceUpdateAllAabbs; },
1229 (s,p,l,v) => { s.m_params[0].shouldForceUpdateAllAabbs = v; } ),
1230 new ParameterDefn("ShouldRandomizeSolverOrder", "Enable for slightly better stacking interaction",
1231 ConfigurationParameters.numericTrue,
1232 (s,cf,p,v) => { s.m_params[0].shouldRandomizeSolverOrder = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1233 (s) => { return s.m_params[0].shouldRandomizeSolverOrder; },
1234 (s,p,l,v) => { s.m_params[0].shouldRandomizeSolverOrder = v; } ),
1235 new ParameterDefn("ShouldSplitSimulationIslands", "Enable splitting active object scanning islands",
1236 ConfigurationParameters.numericTrue,
1237 (s,cf,p,v) => { s.m_params[0].shouldSplitSimulationIslands = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1238 (s) => { return s.m_params[0].shouldSplitSimulationIslands; },
1239 (s,p,l,v) => { s.m_params[0].shouldSplitSimulationIslands = v; } ),
1240 new ParameterDefn("ShouldEnableFrictionCaching", "Enable friction computation caching",
1241 ConfigurationParameters.numericFalse,
1242 (s,cf,p,v) => { s.m_params[0].shouldEnableFrictionCaching = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1243 (s) => { return s.m_params[0].shouldEnableFrictionCaching; },
1244 (s,p,l,v) => { s.m_params[0].shouldEnableFrictionCaching = v; } ),
1245 new ParameterDefn("NumberOfSolverIterations", "Number of internal iterations (0 means default)",
1246 0f, // zero says use Bullet default
1247 (s,cf,p,v) => { s.m_params[0].numberOfSolverIterations = cf.GetFloat(p, v); },
1248 (s) => { return s.m_params[0].numberOfSolverIterations; },
1249 (s,p,l,v) => { s.m_params[0].numberOfSolverIterations = v; } ),
1250
1251 new ParameterDefn("LinksetImplementation", "Type of linkset implementation (0=Constraint, 1=Compound, 2=Manual)",
1252 (float)BSLinkset.LinksetImplementation.Compound,
1253 (s,cf,p,v) => { s.m_params[0].linksetImplementation = cf.GetFloat(p,v); },
1254 (s) => { return s.m_params[0].linksetImplementation; },
1255 (s,p,l,v) => { s.m_params[0].linksetImplementation = v; } ),
1256 new ParameterDefn("LinkConstraintUseFrameOffset", "For linksets built with constraints, enable frame offsetFor linksets built with constraints, enable frame offset.",
1257 ConfigurationParameters.numericFalse,
1258 (s,cf,p,v) => { s.m_params[0].linkConstraintUseFrameOffset = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1259 (s) => { return s.m_params[0].linkConstraintUseFrameOffset; },
1260 (s,p,l,v) => { s.m_params[0].linkConstraintUseFrameOffset = v; } ),
1261 new ParameterDefn("LinkConstraintEnableTransMotor", "Whether to enable translational motor on linkset constraints",
1262 ConfigurationParameters.numericTrue,
1263 (s,cf,p,v) => { s.m_params[0].linkConstraintEnableTransMotor = s.NumericBool(cf.GetBoolean(p, s.BoolNumeric(v))); },
1264 (s) => { return s.m_params[0].linkConstraintEnableTransMotor; },
1265 (s,p,l,v) => { s.m_params[0].linkConstraintEnableTransMotor = v; } ),
1266 new ParameterDefn("LinkConstraintTransMotorMaxVel", "Maximum velocity to be applied by translational motor in linkset constraints",
1267 5.0f,
1268 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = cf.GetFloat(p, v); },
1269 (s) => { return s.m_params[0].linkConstraintTransMotorMaxVel; },
1270 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxVel = v; } ),
1271 new ParameterDefn("LinkConstraintTransMotorMaxForce", "Maximum force to be applied by translational motor in linkset constraints",
1272 0.1f,
1273 (s,cf,p,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = cf.GetFloat(p, v); },
1274 (s) => { return s.m_params[0].linkConstraintTransMotorMaxForce; },
1275 (s,p,l,v) => { s.m_params[0].linkConstraintTransMotorMaxForce = v; } ),
1276 new ParameterDefn("LinkConstraintCFM", "Amount constraint can be violated. 0=no violation, 1=infinite. Default=0.1",
1277 0.1f,
1278 (s,cf,p,v) => { s.m_params[0].linkConstraintCFM = cf.GetFloat(p, v); },
1279 (s) => { return s.m_params[0].linkConstraintCFM; },
1280 (s,p,l,v) => { s.m_params[0].linkConstraintCFM = v; } ),
1281 new ParameterDefn("LinkConstraintERP", "Amount constraint is corrected each tick. 0=none, 1=all. Default = 0.2",
1282 0.1f,
1283 (s,cf,p,v) => { s.m_params[0].linkConstraintERP = cf.GetFloat(p, v); },
1284 (s) => { return s.m_params[0].linkConstraintERP; },
1285 (s,p,l,v) => { s.m_params[0].linkConstraintERP = v; } ),
1286 new ParameterDefn("LinkConstraintSolverIterations", "Number of solver iterations when computing constraint. (0 = Bullet default)",
1287 40,
1288 (s,cf,p,v) => { s.m_params[0].linkConstraintSolverIterations = cf.GetFloat(p, v); },
1289 (s) => { return s.m_params[0].linkConstraintSolverIterations; },
1290 (s,p,l,v) => { s.m_params[0].linkConstraintSolverIterations = v; } ),
1291
1292 new ParameterDefn("LogPhysicsStatisticsFrames", "Frames between outputting detailed phys stats. (0 is off)",
1293 0f,
1294 (s,cf,p,v) => { s.m_params[0].physicsLoggingFrames = cf.GetInt(p, (int)v); },
1295 (s) => { return (float)s.m_params[0].physicsLoggingFrames; },
1296 (s,p,l,v) => { s.m_params[0].physicsLoggingFrames = (int)v; } ),
1297 };
1298
1299 // Convert a boolean to our numeric true and false values
1300 public float NumericBool(bool b)
1301 {
1302 return (b ? ConfigurationParameters.numericTrue : ConfigurationParameters.numericFalse);
1303 }
1304
1305 // Convert numeric true and false values to a boolean
1306 public bool BoolNumeric(float b)
1307 {
1308 return (b == ConfigurationParameters.numericTrue ? true : false);
1309 }
1310
1311 // Search through the parameter definitions and return the matching
1312 // ParameterDefn structure.
1313 // Case does not matter as names are compared after converting to lower case.
1314 // Returns 'false' if the parameter is not found.
1315 private bool TryGetParameter(string paramName, out ParameterDefn defn)
1316 {
1317 bool ret = false;
1318 ParameterDefn foundDefn = new ParameterDefn();
1319 string pName = paramName.ToLower();
1320
1321 foreach (ParameterDefn parm in ParameterDefinitions)
1322 {
1323 if (pName == parm.name.ToLower())
1324 {
1325 foundDefn = parm;
1326 ret = true;
1327 break;
1328 }
1329 }
1330 defn = foundDefn;
1331 return ret;
1332 }
1333
1334 // Pass through the settable parameters and set the default values
1335 private void SetParameterDefaultValues()
1336 {
1337 foreach (ParameterDefn parm in ParameterDefinitions)
1338 {
1339 parm.setter(this, parm.name, PhysParameterEntry.APPLY_TO_NONE, parm.defaultValue);
1340 }
1341 }
1342
1343 // Get user set values out of the ini file.
1344 private void SetParameterConfigurationValues(IConfig cfg)
1345 {
1346 foreach (ParameterDefn parm in ParameterDefinitions)
1347 {
1348 parm.userParam(this, cfg, parm.name, parm.defaultValue);
1349 }
1350 }
1351
1352 private PhysParameterEntry[] SettableParameters = new PhysParameterEntry[1];
1353
1354 // This creates an array in the correct format for returning the list of
1355 // parameters. This is used by the 'list' option of the 'physics' command.
1356 private void BuildParameterTable()
1357 {
1358 if (SettableParameters.Length < ParameterDefinitions.Length)
1359 {
1360 List<PhysParameterEntry> entries = new List<PhysParameterEntry>();
1361 for (int ii = 0; ii < ParameterDefinitions.Length; ii++)
1362 {
1363 ParameterDefn pd = ParameterDefinitions[ii];
1364 entries.Add(new PhysParameterEntry(pd.name, pd.desc));
1365 }
1366
1367 // make the list in alphabetical order for estetic reasons
1368 entries.Sort(delegate(PhysParameterEntry ppe1, PhysParameterEntry ppe2)
1369 {
1370 return ppe1.name.CompareTo(ppe2.name);
1371 });
1372
1373 SettableParameters = entries.ToArray();
1374 }
1375 }
1376
1377
1378 #region IPhysicsParameters 837 #region IPhysicsParameters
1379 // Get the list of parameters this physics engine supports 838 // Get the list of parameters this physics engine supports
1380 public PhysParameterEntry[] GetParameterList() 839 public PhysParameterEntry[] GetParameterList()
1381 { 840 {
1382 BuildParameterTable(); 841 BSParam.BuildParameterTable();
1383 return SettableParameters; 842 return BSParam.SettableParameters;
1384 } 843 }
1385 844
1386 // Set parameter on a specific or all instances. 845 // Set parameter on a specific or all instances.
@@ -1392,8 +851,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1392 public bool SetPhysicsParameter(string parm, float val, uint localID) 851 public bool SetPhysicsParameter(string parm, float val, uint localID)
1393 { 852 {
1394 bool ret = false; 853 bool ret = false;
1395 ParameterDefn theParam; 854 BSParam.ParameterDefn theParam;
1396 if (TryGetParameter(parm, out theParam)) 855 if (BSParam.TryGetParameter(parm, out theParam))
1397 { 856 {
1398 theParam.setter(this, parm, localID, val); 857 theParam.setter(this, parm, localID, val);
1399 ret = true; 858 ret = true;
@@ -1405,19 +864,20 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1405 // If the local ID is APPLY_TO_NONE, just change the default value 864 // If the local ID is APPLY_TO_NONE, just change the default value
1406 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs 865 // If the localID is APPLY_TO_ALL change the default value and apply the new value to all the lIDs
1407 // If the localID is a specific object, apply the parameter change to only that object 866 // If the localID is a specific object, apply the parameter change to only that object
1408 private void UpdateParameterObject(ref float defaultLoc, string parm, uint localID, float val) 867 internal delegate void AssignVal(float x);
868 internal void UpdateParameterObject(AssignVal setDefault, string parm, uint localID, float val)
1409 { 869 {
1410 List<uint> objectIDs = new List<uint>(); 870 List<uint> objectIDs = new List<uint>();
1411 switch (localID) 871 switch (localID)
1412 { 872 {
1413 case PhysParameterEntry.APPLY_TO_NONE: 873 case PhysParameterEntry.APPLY_TO_NONE:
1414 defaultLoc = val; // setting only the default value 874 setDefault(val); // setting only the default value
1415 // This will cause a call into the physical world if some operation is specified (SetOnObject). 875 // This will cause a call into the physical world if some operation is specified (SetOnObject).
1416 objectIDs.Add(TERRAIN_ID); 876 objectIDs.Add(TERRAIN_ID);
1417 TaintedUpdateParameter(parm, objectIDs, val); 877 TaintedUpdateParameter(parm, objectIDs, val);
1418 break; 878 break;
1419 case PhysParameterEntry.APPLY_TO_ALL: 879 case PhysParameterEntry.APPLY_TO_ALL:
1420 defaultLoc = val; // setting ALL also sets the default value 880 setDefault(val); // setting ALL also sets the default value
1421 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys); 881 lock (PhysObjects) objectIDs = new List<uint>(PhysObjects.Keys);
1422 TaintedUpdateParameter(parm, objectIDs, val); 882 TaintedUpdateParameter(parm, objectIDs, val);
1423 break; 883 break;
@@ -1436,8 +896,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1436 List<uint> xlIDs = lIDs; 896 List<uint> xlIDs = lIDs;
1437 string xparm = parm; 897 string xparm = parm;
1438 TaintedObject("BSScene.UpdateParameterSet", delegate() { 898 TaintedObject("BSScene.UpdateParameterSet", delegate() {
1439 ParameterDefn thisParam; 899 BSParam.ParameterDefn thisParam;
1440 if (TryGetParameter(xparm, out thisParam)) 900 if (BSParam.TryGetParameter(xparm, out thisParam))
1441 { 901 {
1442 if (thisParam.onObject != null) 902 if (thisParam.onObject != null)
1443 { 903 {
@@ -1458,8 +918,8 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1458 { 918 {
1459 float val = 0f; 919 float val = 0f;
1460 bool ret = false; 920 bool ret = false;
1461 ParameterDefn theParam; 921 BSParam.ParameterDefn theParam;
1462 if (TryGetParameter(parm, out theParam)) 922 if (BSParam.TryGetParameter(parm, out theParam))
1463 { 923 {
1464 val = theParam.getter(this); 924 val = theParam.getter(this);
1465 ret = true; 925 ret = true;
@@ -1472,22 +932,12 @@ public sealed class BSScene : PhysicsScene, IPhysicsParameters
1472 932
1473 #endregion Runtime settable parameters 933 #endregion Runtime settable parameters
1474 934
1475 // Debugging routine for dumping detailed physical information for vehicle prims
1476 private void DumpVehicles()
1477 {
1478 foreach (BSPrim prim in m_vehicles)
1479 {
1480 BulletSimAPI.DumpRigidBody2(World.ptr, prim.PhysBody.ptr);
1481 BulletSimAPI.DumpCollisionShape2(World.ptr, prim.PhysShape.ptr);
1482 }
1483 }
1484
1485 // Invoke the detailed logger and output something if it's enabled. 935 // Invoke the detailed logger and output something if it's enabled.
1486 public void DetailLog(string msg, params Object[] args) 936 public void DetailLog(string msg, params Object[] args)
1487 { 937 {
1488 PhysicsLogging.Write(msg, args); 938 PhysicsLogging.Write(msg, args);
1489 // Add the Flush() if debugging crashes. Gets all the messages written out. 939 // Add the Flush() if debugging crashes. Gets all the messages written out.
1490 // PhysicsLogging.Flush(); 940 if (m_physicsLoggingDoFlush) PhysicsLogging.Flush();
1491 } 941 }
1492 // Used to fill in the LocalID when there isn't one. It's the correct number of characters. 942 // Used to fill in the LocalID when there isn't one. It's the correct number of characters.
1493 public const string DetailLogZero = "0000000000"; 943 public const string DetailLogZero = "0000000000";
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
index 892c34b..b4f764b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapeCollection.cs
@@ -45,7 +45,7 @@ public sealed class BSShapeCollection : IDisposable
45 // Description of a Mesh 45 // Description of a Mesh
46 private struct MeshDesc 46 private struct MeshDesc
47 { 47 {
48 public IntPtr ptr; 48 public BulletShape shape;
49 public int referenceCount; 49 public int referenceCount;
50 public DateTime lastReferenced; 50 public DateTime lastReferenced;
51 public UInt64 shapeKey; 51 public UInt64 shapeKey;
@@ -55,7 +55,7 @@ public sealed class BSShapeCollection : IDisposable
55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations. 55 // Meshes and hulls have the same shape hash key but we only need hulls for efficient collision calculations.
56 private struct HullDesc 56 private struct HullDesc
57 { 57 {
58 public IntPtr ptr; 58 public BulletShape shape;
59 public int referenceCount; 59 public int referenceCount;
60 public DateTime lastReferenced; 60 public DateTime lastReferenced;
61 public UInt64 shapeKey; 61 public UInt64 shapeKey;
@@ -65,9 +65,16 @@ public sealed class BSShapeCollection : IDisposable
65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>(); 65 private Dictionary<System.UInt64, MeshDesc> Meshes = new Dictionary<System.UInt64, MeshDesc>();
66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>(); 66 private Dictionary<System.UInt64, HullDesc> Hulls = new Dictionary<System.UInt64, HullDesc>();
67 67
68 private bool DDetail = false;
69
68 public BSShapeCollection(BSScene physScene) 70 public BSShapeCollection(BSScene physScene)
69 { 71 {
70 PhysicsScene = physScene; 72 PhysicsScene = physScene;
73 // Set the next to 'true' for very detailed shape update detailed logging (detailed details?)
74 // While detailed debugging is still active, this is better than commenting out all the
75 // DetailLog statements. When debugging slows down, this and the protected logging
76 // statements can be commented/removed.
77 DDetail = true;
71 } 78 }
72 79
73 public void Dispose() 80 public void Dispose()
@@ -91,7 +98,7 @@ public sealed class BSShapeCollection : IDisposable
91 // higher level dependencies on the shape or body. Mostly used for LinkSets to 98 // higher level dependencies on the shape or body. Mostly used for LinkSets to
92 // remove the physical constraints before the body is destroyed. 99 // remove the physical constraints before the body is destroyed.
93 // Called at taint-time!! 100 // Called at taint-time!!
94 public bool GetBodyAndShape(bool forceRebuild, BulletSim sim, BSPhysObject prim, 101 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim,
95 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback) 102 ShapeDestructionCallback shapeCallback, BodyDestructionCallback bodyCallback)
96 { 103 {
97 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape"); 104 PhysicsScene.AssertInTaintTime("BSShapeCollection.GetBodyAndShape");
@@ -119,6 +126,11 @@ public sealed class BSShapeCollection : IDisposable
119 return ret; 126 return ret;
120 } 127 }
121 128
129 public bool GetBodyAndShape(bool forceRebuild, BulletWorld sim, BSPhysObject prim)
130 {
131 return GetBodyAndShape(forceRebuild, sim, prim, null, null);
132 }
133
122 // Track another user of a body. 134 // Track another user of a body.
123 // We presume the caller has allocated the body. 135 // We presume the caller has allocated the body.
124 // Bodies only have one user so the body is just put into the world if not already there. 136 // Bodies only have one user so the body is just put into the world if not already there.
@@ -126,13 +138,13 @@ public sealed class BSShapeCollection : IDisposable
126 { 138 {
127 lock (m_collectionActivityLock) 139 lock (m_collectionActivityLock)
128 { 140 {
129 DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body); 141 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,newBody,body={1}", body.ID, body);
130 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate() 142 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.ReferenceBody", delegate()
131 { 143 {
132 if (!BulletSimAPI.IsInWorld2(body.ptr)) 144 if (!PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
133 { 145 {
134 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, body.ptr); 146 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, body);
135 DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body); 147 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceBody,addedToWorld,ref={1}", body.ID, body);
136 } 148 }
137 }); 149 });
138 } 150 }
@@ -142,27 +154,27 @@ public sealed class BSShapeCollection : IDisposable
142 // Called when releasing use of a BSBody. BSShape is handled separately. 154 // Called when releasing use of a BSBody. BSShape is handled separately.
143 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback ) 155 public void DereferenceBody(BulletBody body, bool inTaintTime, BodyDestructionCallback bodyCallback )
144 { 156 {
145 if (body.ptr == IntPtr.Zero) 157 if (!body.HasPhysicalBody)
146 return; 158 return;
147 159
148 lock (m_collectionActivityLock) 160 lock (m_collectionActivityLock)
149 { 161 {
150 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate() 162 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceBody", delegate()
151 { 163 {
152 DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}", 164 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,DestroyingBody,body={1},inTaintTime={2}",
153 body.ID, body, inTaintTime); 165 body.ID, body, inTaintTime);
154 // If the caller needs to know the old body is going away, pass the event up. 166 // If the caller needs to know the old body is going away, pass the event up.
155 if (bodyCallback != null) bodyCallback(body); 167 if (bodyCallback != null) bodyCallback(body);
156 168
157 if (BulletSimAPI.IsInWorld2(body.ptr)) 169 if (PhysicsScene.PE.IsInWorld(PhysicsScene.World, body))
158 { 170 {
159 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, body.ptr); 171 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, body);
160 DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body); 172 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceBody,removingFromWorld. Body={1}", body.ID, body);
161 } 173 }
162 174
163 // Zero any reference to the shape so it is not freed when the body is deleted. 175 // Zero any reference to the shape so it is not freed when the body is deleted.
164 BulletSimAPI.SetCollisionShape2(PhysicsScene.World.ptr, body.ptr, IntPtr.Zero); 176 PhysicsScene.PE.SetCollisionShape(PhysicsScene.World, body, null);
165 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, body.ptr); 177 PhysicsScene.PE.DestroyObject(PhysicsScene.World, body);
166 }); 178 });
167 } 179 }
168 } 180 }
@@ -184,17 +196,17 @@ public sealed class BSShapeCollection : IDisposable
184 { 196 {
185 // There is an existing instance of this mesh. 197 // There is an existing instance of this mesh.
186 meshDesc.referenceCount++; 198 meshDesc.referenceCount++;
187 DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}", 199 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingMesh,key={1},cnt={2}",
188 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 200 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
189 } 201 }
190 else 202 else
191 { 203 {
192 // This is a new reference to a mesh 204 // This is a new reference to a mesh
193 meshDesc.ptr = shape.ptr; 205 meshDesc.shape = shape.Clone();
194 meshDesc.shapeKey = shape.shapeKey; 206 meshDesc.shapeKey = shape.shapeKey;
195 // We keep a reference to the underlying IMesh data so a hull can be built 207 // We keep a reference to the underlying IMesh data so a hull can be built
196 meshDesc.referenceCount = 1; 208 meshDesc.referenceCount = 1;
197 DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}", 209 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newMesh,key={1},cnt={2}",
198 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount); 210 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), meshDesc.referenceCount);
199 ret = true; 211 ret = true;
200 } 212 }
@@ -207,16 +219,16 @@ public sealed class BSShapeCollection : IDisposable
207 { 219 {
208 // There is an existing instance of this hull. 220 // There is an existing instance of this hull.
209 hullDesc.referenceCount++; 221 hullDesc.referenceCount++;
210 DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}", 222 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,existingHull,key={1},cnt={2}",
211 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 223 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
212 } 224 }
213 else 225 else
214 { 226 {
215 // This is a new reference to a hull 227 // This is a new reference to a hull
216 hullDesc.ptr = shape.ptr; 228 hullDesc.shape = shape.Clone();
217 hullDesc.shapeKey = shape.shapeKey; 229 hullDesc.shapeKey = shape.shapeKey;
218 hullDesc.referenceCount = 1; 230 hullDesc.referenceCount = 1;
219 DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}", 231 if (DDetail) DetailLog("{0},BSShapeCollection.ReferenceShape,newHull,key={1},cnt={2}",
220 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount); 232 BSScene.DetailLogZero, shape.shapeKey.ToString("X"), hullDesc.referenceCount);
221 ret = true; 233 ret = true;
222 234
@@ -236,20 +248,20 @@ public sealed class BSShapeCollection : IDisposable
236 // Release the usage of a shape. 248 // Release the usage of a shape.
237 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback) 249 public void DereferenceShape(BulletShape shape, bool inTaintTime, ShapeDestructionCallback shapeCallback)
238 { 250 {
239 if (shape.ptr == IntPtr.Zero) 251 if (!shape.HasPhysicalShape)
240 return; 252 return;
241 253
242 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate() 254 PhysicsScene.TaintedObject(inTaintTime, "BSShapeCollection.DereferenceShape", delegate()
243 { 255 {
244 if (shape.ptr != IntPtr.Zero) 256 if (shape.HasPhysicalShape)
245 { 257 {
246 if (shape.isNativeShape) 258 if (shape.isNativeShape)
247 { 259 {
248 // Native shapes are not tracked and are released immediately 260 // Native shapes are not tracked and are released immediately
249 DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}", 261 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,ptr={1},taintTime={2}",
250 BSScene.DetailLogZero, shape.ptr.ToString("X"), inTaintTime); 262 BSScene.DetailLogZero, shape.AddrString, inTaintTime);
251 if (shapeCallback != null) shapeCallback(shape); 263 if (shapeCallback != null) shapeCallback(shape);
252 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 264 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
253 } 265 }
254 else 266 else
255 { 267 {
@@ -286,7 +298,7 @@ public sealed class BSShapeCollection : IDisposable
286 if (shapeCallback != null) shapeCallback(shape); 298 if (shapeCallback != null) shapeCallback(shape);
287 meshDesc.lastReferenced = System.DateTime.Now; 299 meshDesc.lastReferenced = System.DateTime.Now;
288 Meshes[shape.shapeKey] = meshDesc; 300 Meshes[shape.shapeKey] = meshDesc;
289 DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}", 301 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceMesh,shape={1},refCnt={2}",
290 BSScene.DetailLogZero, shape, meshDesc.referenceCount); 302 BSScene.DetailLogZero, shape, meshDesc.referenceCount);
291 303
292 } 304 }
@@ -307,7 +319,7 @@ public sealed class BSShapeCollection : IDisposable
307 319
308 hullDesc.lastReferenced = System.DateTime.Now; 320 hullDesc.lastReferenced = System.DateTime.Now;
309 Hulls[shape.shapeKey] = hullDesc; 321 Hulls[shape.shapeKey] = hullDesc;
310 DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}", 322 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceHull,shape={1},refCnt={2}",
311 BSScene.DetailLogZero, shape, hullDesc.referenceCount); 323 BSScene.DetailLogZero, shape, hullDesc.referenceCount);
312 } 324 }
313 } 325 }
@@ -320,57 +332,56 @@ public sealed class BSShapeCollection : IDisposable
320 // Called at taint-time. 332 // Called at taint-time.
321 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback) 333 private void DereferenceCompound(BulletShape shape, ShapeDestructionCallback shapeCallback)
322 { 334 {
323 if (!BulletSimAPI.IsCompound2(shape.ptr)) 335 if (!PhysicsScene.PE.IsCompound(shape))
324 { 336 {
325 // Failed the sanity check!! 337 // Failed the sanity check!!
326 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}", 338 PhysicsScene.Logger.ErrorFormat("{0} Attempt to free a compound shape that is not compound!! type={1}, ptr={2}",
327 LogHeader, shape.type, shape.ptr.ToString("X")); 339 LogHeader, shape.type, shape.AddrString);
328 DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}", 340 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,notACompoundShape,type={1},ptr={2}",
329 BSScene.DetailLogZero, shape.type, shape.ptr.ToString("X")); 341 BSScene.DetailLogZero, shape.type, shape.AddrString);
330 return; 342 return;
331 } 343 }
332 344
333 int numChildren = BulletSimAPI.GetNumberOfCompoundChildren2(shape.ptr); 345 int numChildren = PhysicsScene.PE.GetNumberOfCompoundChildren(shape);
334 DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren); 346 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceCompound,shape={1},children={2}", BSScene.DetailLogZero, shape, numChildren);
335 347
336 for (int ii = numChildren - 1; ii >= 0; ii--) 348 for (int ii = numChildren - 1; ii >= 0; ii--)
337 { 349 {
338 IntPtr childShape = BulletSimAPI.RemoveChildShapeFromCompoundShapeIndex2(shape.ptr, ii); 350 BulletShape childShape = PhysicsScene.PE.RemoveChildShapeFromCompoundShapeIndex(shape, ii);
339 DereferenceAnonCollisionShape(childShape); 351 DereferenceAnonCollisionShape(childShape);
340 } 352 }
341 BulletSimAPI.DeleteCollisionShape2(PhysicsScene.World.ptr, shape.ptr); 353 PhysicsScene.PE.DeleteCollisionShape(PhysicsScene.World, shape);
342 } 354 }
343 355
344 // Sometimes we have a pointer to a collision shape but don't know what type it is. 356 // Sometimes we have a pointer to a collision shape but don't know what type it is.
345 // Figure out type and call the correct dereference routine. 357 // Figure out type and call the correct dereference routine.
346 // Called at taint-time. 358 // Called at taint-time.
347 private void DereferenceAnonCollisionShape(IntPtr cShape) 359 private void DereferenceAnonCollisionShape(BulletShape shapeInfo)
348 { 360 {
349 MeshDesc meshDesc; 361 MeshDesc meshDesc;
350 HullDesc hullDesc; 362 HullDesc hullDesc;
351 363
352 BulletShape shapeInfo = new BulletShape(cShape); 364 if (TryGetMeshByPtr(shapeInfo, out meshDesc))
353 if (TryGetMeshByPtr(cShape, out meshDesc))
354 { 365 {
355 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH; 366 shapeInfo.type = BSPhysicsShapeType.SHAPE_MESH;
356 shapeInfo.shapeKey = meshDesc.shapeKey; 367 shapeInfo.shapeKey = meshDesc.shapeKey;
357 } 368 }
358 else 369 else
359 { 370 {
360 if (TryGetHullByPtr(cShape, out hullDesc)) 371 if (TryGetHullByPtr(shapeInfo, out hullDesc))
361 { 372 {
362 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL; 373 shapeInfo.type = BSPhysicsShapeType.SHAPE_HULL;
363 shapeInfo.shapeKey = hullDesc.shapeKey; 374 shapeInfo.shapeKey = hullDesc.shapeKey;
364 } 375 }
365 else 376 else
366 { 377 {
367 if (BulletSimAPI.IsCompound2(cShape)) 378 if (PhysicsScene.PE.IsCompound(shapeInfo))
368 { 379 {
369 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND; 380 shapeInfo.type = BSPhysicsShapeType.SHAPE_COMPOUND;
370 } 381 }
371 else 382 else
372 { 383 {
373 if (BulletSimAPI.IsNativeShape2(cShape)) 384 if (PhysicsScene.PE.IsNativeShape(shapeInfo))
374 { 385 {
375 shapeInfo.isNativeShape = true; 386 shapeInfo.isNativeShape = true;
376 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter) 387 shapeInfo.type = BSPhysicsShapeType.SHAPE_BOX; // (technically, type doesn't matter)
@@ -379,7 +390,7 @@ public sealed class BSShapeCollection : IDisposable
379 } 390 }
380 } 391 }
381 392
382 DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo); 393 if (DDetail) DetailLog("{0},BSShapeCollection.DereferenceAnonCollisionShape,shape={1}", BSScene.DetailLogZero, shapeInfo);
383 394
384 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN) 395 if (shapeInfo.type != BSPhysicsShapeType.SHAPE_UNKNOWN)
385 { 396 {
@@ -388,7 +399,7 @@ public sealed class BSShapeCollection : IDisposable
388 else 399 else
389 { 400 {
390 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}", 401 PhysicsScene.Logger.ErrorFormat("{0} Could not decypher shape type. Region={1}, addr={2}",
391 LogHeader, PhysicsScene.RegionName, cShape.ToString("X")); 402 LogHeader, PhysicsScene.RegionName, shapeInfo.AddrString);
392 } 403 }
393 } 404 }
394 405
@@ -408,19 +419,18 @@ public sealed class BSShapeCollection : IDisposable
408 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE) 419 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_CAPSULE)
409 { 420 {
410 // an avatar capsule is close to a native shape (it is not shared) 421 // an avatar capsule is close to a native shape (it is not shared)
411 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, 422 GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_CAPSULE, FixedShapeKey.KEY_CAPSULE, shapeCallback);
412 FixedShapeKey.KEY_CAPSULE, shapeCallback); 423 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
413 DetailLog("{0},BSShapeCollection.CreateGeom,avatarCapsule,shape={1}", prim.LocalID, prim.PhysShape);
414 ret = true; 424 ret = true;
415 haveShape = true; 425 haveShape = true;
416 } 426 }
417 427
418 // Compound shapes are handled special as they are rebuilt from scratch. 428 // Compound shapes are handled special as they are rebuilt from scratch.
419 // This isn't too great a hardship since most of the child shapes will already been created. 429 // This isn't too great a hardship since most of the child shapes will have already been created.
420 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND) 430 if (!haveShape && prim.PreferredPhysicalShape == BSPhysicsShapeType.SHAPE_COMPOUND)
421 { 431 {
422 ret = GetReferenceToCompoundShape(prim, shapeCallback); 432 ret = GetReferenceToCompoundShape(prim, shapeCallback);
423 DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape); 433 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,compoundShape,shape={1}", prim.LocalID, prim.PhysShape);
424 haveShape = true; 434 haveShape = true;
425 } 435 }
426 436
@@ -433,7 +443,7 @@ public sealed class BSShapeCollection : IDisposable
433 } 443 }
434 444
435 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'. 445 // Create a mesh/hull shape or a native shape if 'nativeShapePossible' is 'true'.
436 private bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback) 446 public bool CreateGeomNonSpecial(bool forceRebuild, BSPhysObject prim, ShapeDestructionCallback shapeCallback)
437 { 447 {
438 bool ret = false; 448 bool ret = false;
439 bool haveShape = false; 449 bool haveShape = false;
@@ -443,8 +453,9 @@ public sealed class BSShapeCollection : IDisposable
443 // If the prim attributes are simple, this could be a simple Bullet native shape 453 // If the prim attributes are simple, this could be a simple Bullet native shape
444 if (!haveShape 454 if (!haveShape
445 && pbs != null 455 && pbs != null
456 && !pbs.SculptEntry
446 && nativeShapePossible 457 && nativeShapePossible
447 && ((pbs.SculptEntry && !PhysicsScene.ShouldMeshSculptedPrim) 458 && ((pbs.SculptEntry && !BSParam.ShouldMeshSculptedPrim)
448 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0 459 || (pbs.ProfileBegin == 0 && pbs.ProfileEnd == 0
449 && pbs.ProfileHollow == 0 460 && pbs.ProfileHollow == 0
450 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0 461 && pbs.PathTwist == 0 && pbs.PathTwistBegin == 0
@@ -453,19 +464,27 @@ public sealed class BSShapeCollection : IDisposable
453 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100 464 && pbs.PathScaleX == 100 && pbs.PathScaleY == 100
454 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) ) 465 && pbs.PathShearX == 0 && pbs.PathShearY == 0) ) )
455 { 466 {
467 // Get the scale of any existing shape so we can see if the new shape is same native type and same size.
468 OMV.Vector3 scaleOfExistingShape = OMV.Vector3.Zero;
469 if (prim.PhysShape.HasPhysicalShape)
470 scaleOfExistingShape = PhysicsScene.PE.GetLocalScaling(prim.PhysShape);
471
472 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,maybeNative,force={1},primScale={2},primSize={3},primShape={4}",
473 prim.LocalID, forceRebuild, prim.Scale, prim.Size, prim.PhysShape.type);
474
456 // It doesn't look like Bullet scales spheres so make sure the scales are all equal 475 // It doesn't look like Bullet scales spheres so make sure the scales are all equal
457 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1) 476 if ((pbs.ProfileShape == ProfileShape.HalfCircle && pbs.PathCurve == (byte)Extrusion.Curve1)
458 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z) 477 && pbs.Scale.X == pbs.Scale.Y && pbs.Scale.Y == pbs.Scale.Z)
459 { 478 {
460 haveShape = true; 479 haveShape = true;
461 if (forceRebuild 480 if (forceRebuild
462 || prim.Scale != prim.Size 481 || prim.Scale != scaleOfExistingShape
463 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE 482 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_SPHERE
464 ) 483 )
465 { 484 {
466 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE, 485 ret = GetReferenceToNativeShape(prim, BSPhysicsShapeType.SHAPE_SPHERE,
467 FixedShapeKey.KEY_SPHERE, shapeCallback); 486 FixedShapeKey.KEY_SPHERE, shapeCallback);
468 DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}", 487 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,sphere,force={1},shape={2}",
469 prim.LocalID, forceRebuild, prim.PhysShape); 488 prim.LocalID, forceRebuild, prim.PhysShape);
470 } 489 }
471 } 490 }
@@ -473,13 +492,13 @@ public sealed class BSShapeCollection : IDisposable
473 { 492 {
474 haveShape = true; 493 haveShape = true;
475 if (forceRebuild 494 if (forceRebuild
476 || prim.Scale != prim.Size 495 || prim.Scale != scaleOfExistingShape
477 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX 496 || prim.PhysShape.type != BSPhysicsShapeType.SHAPE_BOX
478 ) 497 )
479 { 498 {
480 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX, 499 ret = GetReferenceToNativeShape( prim, BSPhysicsShapeType.SHAPE_BOX,
481 FixedShapeKey.KEY_BOX, shapeCallback); 500 FixedShapeKey.KEY_BOX, shapeCallback);
482 DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}", 501 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,box,force={1},shape={2}",
483 prim.LocalID, forceRebuild, prim.PhysShape); 502 prim.LocalID, forceRebuild, prim.PhysShape);
484 } 503 }
485 } 504 }
@@ -500,17 +519,17 @@ public sealed class BSShapeCollection : IDisposable
500 bool ret = false; 519 bool ret = false;
501 // Note that if it's a native shape, the check for physical/non-physical is not 520 // Note that if it's a native shape, the check for physical/non-physical is not
502 // made. Native shapes work in either case. 521 // made. Native shapes work in either case.
503 if (prim.IsPhysical && PhysicsScene.ShouldUseHullsForPhysicalObjects) 522 if (prim.IsPhysical && BSParam.ShouldUseHullsForPhysicalObjects)
504 { 523 {
505 // Update prim.BSShape to reference a hull of this shape. 524 // Update prim.BSShape to reference a hull of this shape.
506 ret = GetReferenceToHull(prim,shapeCallback); 525 ret = GetReferenceToHull(prim,shapeCallback);
507 DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}", 526 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,hull,shape={1},key={2}",
508 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 527 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
509 } 528 }
510 else 529 else
511 { 530 {
512 ret = GetReferenceToMesh(prim, shapeCallback); 531 ret = GetReferenceToMesh(prim, shapeCallback);
513 DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}", 532 if (DDetail) DetailLog("{0},BSShapeCollection.CreateGeom,mesh,shape={1},key={2}",
514 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X")); 533 prim.LocalID, prim.PhysShape, prim.PhysShape.shapeKey.ToString("X"));
515 } 534 }
516 return ret; 535 return ret;
@@ -528,9 +547,10 @@ public sealed class BSShapeCollection : IDisposable
528 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey); 547 BulletShape newShape = BuildPhysicalNativeShape(prim, shapeType, shapeKey);
529 548
530 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared. 549 // Don't need to do a 'ReferenceShape()' here because native shapes are not shared.
531 DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}", 550 if (DDetail) DetailLog("{0},BSShapeCollection.AddNativeShapeToPrim,create,newshape={1},scale={2}",
532 prim.LocalID, newShape, prim.Scale); 551 prim.LocalID, newShape, prim.Scale);
533 552
553 // native shapes are scaled by Bullet
534 prim.PhysShape = newShape; 554 prim.PhysShape = newShape;
535 return true; 555 return true;
536 } 556 }
@@ -550,20 +570,17 @@ public sealed class BSShapeCollection : IDisposable
550 570
551 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 571 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
552 { 572 {
553 // The proper scale has been calculated in the prim. 573
554 newShape = new BulletShape( 574 newShape = PhysicsScene.PE.BuildCapsuleShape(PhysicsScene.World, 1f, 1f, prim.Scale);
555 BulletSimAPI.BuildCapsuleShape2(PhysicsScene.World.ptr, 1f, 1f, prim.Scale) 575 if (DDetail) DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
556 , shapeType);
557 DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
558 } 576 }
559 else 577 else
560 { 578 {
561 // Native shapes are scaled in Bullet so set the scaling to the size 579 // Native shapes are scaled in Bullet so set the scaling to the size
562 prim.Scale = prim.Size; 580 newShape = PhysicsScene.PE.BuildNativeShape(PhysicsScene.World, nativeShapeData);
563 nativeShapeData.Scale = prim.Scale; 581
564 newShape = new BulletShape(BulletSimAPI.BuildNativeShape2(PhysicsScene.World.ptr, nativeShapeData), shapeType);
565 } 582 }
566 if (newShape.ptr == IntPtr.Zero) 583 if (!newShape.HasPhysicalShape)
567 { 584 {
568 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}", 585 PhysicsScene.Logger.ErrorFormat("{0} BuildPhysicalNativeShape failed. ID={1}, shape={2}",
569 LogHeader, prim.LocalID, shapeType); 586 LogHeader, prim.LocalID, shapeType);
@@ -580,7 +597,7 @@ public sealed class BSShapeCollection : IDisposable
580 // Called at taint-time! 597 // Called at taint-time!
581 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback) 598 private bool GetReferenceToMesh(BSPhysObject prim, ShapeDestructionCallback shapeCallback)
582 { 599 {
583 BulletShape newShape = new BulletShape(IntPtr.Zero); 600 BulletShape newShape = new BulletShape();
584 601
585 float lod; 602 float lod;
586 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod); 603 System.UInt64 newMeshKey = ComputeShapeKey(prim.Size, prim.BaseShape, out lod);
@@ -589,7 +606,7 @@ public sealed class BSShapeCollection : IDisposable
589 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH) 606 if (newMeshKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_MESH)
590 return false; 607 return false;
591 608
592 DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}", 609 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToMesh,create,oldKey={1},newKey={2}",
593 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X")); 610 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newMeshKey.ToString("X"));
594 611
595 // Since we're recreating new, get rid of the reference to the previous shape 612 // Since we're recreating new, get rid of the reference to the previous shape
@@ -601,8 +618,6 @@ public sealed class BSShapeCollection : IDisposable
601 618
602 ReferenceShape(newShape); 619 ReferenceShape(newShape);
603 620
604 // meshes are already scaled by the meshmerizer
605 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
606 prim.PhysShape = newShape; 621 prim.PhysShape = newShape;
607 622
608 return true; // 'true' means a new shape has been added to this prim 623 return true; // 'true' means a new shape has been added to this prim
@@ -610,18 +625,18 @@ public sealed class BSShapeCollection : IDisposable
610 625
611 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 626 private BulletShape CreatePhysicalMesh(string objName, System.UInt64 newMeshKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
612 { 627 {
628 BulletShape newShape = new BulletShape();
613 IMesh meshData = null; 629 IMesh meshData = null;
614 IntPtr meshPtr = IntPtr.Zero; 630
615 MeshDesc meshDesc; 631 MeshDesc meshDesc;
616 if (Meshes.TryGetValue(newMeshKey, out meshDesc)) 632 if (Meshes.TryGetValue(newMeshKey, out meshDesc))
617 { 633 {
618 // If the mesh has already been built just use it. 634 // If the mesh has already been built just use it.
619 meshPtr = meshDesc.ptr; 635 newShape = meshDesc.shape.Clone();
620 } 636 }
621 else 637 else
622 { 638 {
623 // Pass false for physicalness as this creates some sort of bounding box which we don't need 639 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
624 meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false);
625 640
626 if (meshData != null) 641 if (meshData != null)
627 { 642 {
@@ -640,11 +655,10 @@ public sealed class BSShapeCollection : IDisposable
640 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}", 655 // m_log.DebugFormat("{0}: BSShapeCollection.CreatePhysicalMesh: calling CreateMesh. lid={1}, key={2}, indices={3}, vertices={4}",
641 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count); 656 // LogHeader, prim.LocalID, newMeshKey, indices.Length, vertices.Count);
642 657
643 meshPtr = BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 658 newShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World,
644 indices.GetLength(0), indices, vertices.Count, verticesAsFloats); 659 indices.GetLength(0), indices, vertices.Count, verticesAsFloats);
645 } 660 }
646 } 661 }
647 BulletShape newShape = new BulletShape(meshPtr, BSPhysicsShapeType.SHAPE_MESH);
648 newShape.shapeKey = newMeshKey; 662 newShape.shapeKey = newMeshKey;
649 663
650 return newShape; 664 return newShape;
@@ -663,7 +677,7 @@ public sealed class BSShapeCollection : IDisposable
663 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL) 677 if (newHullKey == prim.PhysShape.shapeKey && prim.PhysShape.type == BSPhysicsShapeType.SHAPE_HULL)
664 return false; 678 return false;
665 679
666 DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}", 680 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToHull,create,oldKey={1},newKey={2}",
667 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X")); 681 prim.LocalID, prim.PhysShape.shapeKey.ToString("X"), newHullKey.ToString("X"));
668 682
669 // Remove usage of the previous shape. 683 // Remove usage of the previous shape.
@@ -674,8 +688,6 @@ public sealed class BSShapeCollection : IDisposable
674 688
675 ReferenceShape(newShape); 689 ReferenceShape(newShape);
676 690
677 // hulls are already scaled by the meshmerizer
678 prim.Scale = new OMV.Vector3(1f, 1f, 1f);
679 prim.PhysShape = newShape; 691 prim.PhysShape = newShape;
680 return true; // 'true' means a new shape has been added to this prim 692 return true; // 'true' means a new shape has been added to this prim
681 } 693 }
@@ -684,18 +696,20 @@ public sealed class BSShapeCollection : IDisposable
684 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod) 696 private BulletShape CreatePhysicalHull(string objName, System.UInt64 newHullKey, PrimitiveBaseShape pbs, OMV.Vector3 size, float lod)
685 { 697 {
686 698
699 BulletShape newShape = new BulletShape();
687 IntPtr hullPtr = IntPtr.Zero; 700 IntPtr hullPtr = IntPtr.Zero;
701
688 HullDesc hullDesc; 702 HullDesc hullDesc;
689 if (Hulls.TryGetValue(newHullKey, out hullDesc)) 703 if (Hulls.TryGetValue(newHullKey, out hullDesc))
690 { 704 {
691 // If the hull shape already is created, just use it. 705 // If the hull shape already is created, just use it.
692 hullPtr = hullDesc.ptr; 706 newShape = hullDesc.shape.Clone();
693 } 707 }
694 else 708 else
695 { 709 {
696 // Build a new hull in the physical world 710 // Build a new hull in the physical world
697 // Pass false for physicalness as this creates some sort of bounding box which we don't need 711 // Pass true for physicalness as this creates some sort of bounding box which we don't need
698 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, false); 712 IMesh meshData = PhysicsScene.mesher.CreateMesh(objName, pbs, size, lod, true, false, false, false);
699 if (meshData != null) 713 if (meshData != null)
700 { 714 {
701 715
@@ -777,14 +791,13 @@ public sealed class BSShapeCollection : IDisposable
777 } 791 }
778 } 792 }
779 // create the hull data structure in Bullet 793 // create the hull data structure in Bullet
780 hullPtr = BulletSimAPI.CreateHullShape2(PhysicsScene.World.ptr, hullCount, convHulls); 794 newShape = PhysicsScene.PE.CreateHullShape(PhysicsScene.World, hullCount, convHulls);
781 } 795 }
782 } 796 }
783 797
784 BulletShape newShape = new BulletShape(hullPtr, BSPhysicsShapeType.SHAPE_HULL);
785 newShape.shapeKey = newHullKey; 798 newShape.shapeKey = newHullKey;
786 799
787 return newShape; // 'true' means a new shape has been added to this prim 800 return newShape;
788 } 801 }
789 802
790 // Callback from convex hull creater with a newly created hull. 803 // Callback from convex hull creater with a newly created hull.
@@ -803,13 +816,13 @@ public sealed class BSShapeCollection : IDisposable
803 // Don't need to do this as the shape is freed when the new root shape is created below. 816 // Don't need to do this as the shape is freed when the new root shape is created below.
804 // DereferenceShape(prim.PhysShape, true, shapeCallback); 817 // DereferenceShape(prim.PhysShape, true, shapeCallback);
805 818
806 BulletShape cShape = new BulletShape( 819
807 BulletSimAPI.CreateCompoundShape2(PhysicsScene.World.ptr, false), BSPhysicsShapeType.SHAPE_COMPOUND); 820 BulletShape cShape = PhysicsScene.PE.CreateCompoundShape(PhysicsScene.World, false);
808 821
809 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape. 822 // Create the shape for the root prim and add it to the compound shape. Cannot be a native shape.
810 CreateGeomMeshOrHull(prim, shapeCallback); 823 CreateGeomMeshOrHull(prim, shapeCallback);
811 BulletSimAPI.AddChildShapeToCompoundShape2(cShape.ptr, prim.PhysShape.ptr, OMV.Vector3.Zero, OMV.Quaternion.Identity); 824 PhysicsScene.PE.AddChildShapeToCompoundShape(cShape, prim.PhysShape, OMV.Vector3.Zero, OMV.Quaternion.Identity);
812 DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}", 825 if (DDetail) DetailLog("{0},BSShapeCollection.GetReferenceToCompoundShape,addRootPrim,compShape={1},rootShape={2}",
813 prim.LocalID, cShape, prim.PhysShape); 826 prim.LocalID, cShape, prim.PhysShape);
814 827
815 prim.PhysShape = cShape; 828 prim.PhysShape = cShape;
@@ -822,14 +835,14 @@ public sealed class BSShapeCollection : IDisposable
822 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod) 835 private System.UInt64 ComputeShapeKey(OMV.Vector3 size, PrimitiveBaseShape pbs, out float retLod)
823 { 836 {
824 // level of detail based on size and type of the object 837 // level of detail based on size and type of the object
825 float lod = PhysicsScene.MeshLOD; 838 float lod = BSParam.MeshLOD;
826 if (pbs.SculptEntry) 839 if (pbs.SculptEntry)
827 lod = PhysicsScene.SculptLOD; 840 lod = BSParam.SculptLOD;
828 841
829 // Mega prims usually get more detail because one can interact with shape approximations at this size. 842 // Mega prims usually get more detail because one can interact with shape approximations at this size.
830 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z)); 843 float maxAxis = Math.Max(size.X, Math.Max(size.Y, size.Z));
831 if (maxAxis > PhysicsScene.MeshMegaPrimThreshold) 844 if (maxAxis > BSParam.MeshMegaPrimThreshold)
832 lod = PhysicsScene.MeshMegaPrimLOD; 845 lod = BSParam.MeshMegaPrimLOD;
833 846
834 retLod = lod; 847 retLod = lod;
835 return pbs.GetMeshKey(size, lod); 848 return pbs.GetMeshKey(size, lod);
@@ -851,7 +864,7 @@ public sealed class BSShapeCollection : IDisposable
851 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim) 864 private BulletShape VerifyMeshCreated(BulletShape newShape, BSPhysObject prim)
852 { 865 {
853 // If the shape was successfully created, nothing more to do 866 // If the shape was successfully created, nothing more to do
854 if (newShape.ptr != IntPtr.Zero) 867 if (newShape.HasPhysicalShape)
855 return newShape; 868 return newShape;
856 869
857 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset 870 // If this mesh has an underlying asset and we have not failed getting it before, fetch the asset
@@ -904,19 +917,19 @@ public sealed class BSShapeCollection : IDisposable
904 // Updates prim.BSBody with the information about the new body if one is created. 917 // Updates prim.BSBody with the information about the new body if one is created.
905 // Returns 'true' if an object was actually created. 918 // Returns 'true' if an object was actually created.
906 // Called at taint-time. 919 // Called at taint-time.
907 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletSim sim, BulletShape shape, 920 private bool CreateBody(bool forceRebuild, BSPhysObject prim, BulletWorld sim, BulletShape shape,
908 BodyDestructionCallback bodyCallback) 921 BodyDestructionCallback bodyCallback)
909 { 922 {
910 bool ret = false; 923 bool ret = false;
911 924
912 // the mesh, hull or native shape must have already been created in Bullet 925 // the mesh, hull or native shape must have already been created in Bullet
913 bool mustRebuild = (prim.PhysBody.ptr == IntPtr.Zero); 926 bool mustRebuild = !prim.PhysBody.HasPhysicalBody;
914 927
915 // If there is an existing body, verify it's of an acceptable type. 928 // If there is an existing body, verify it's of an acceptable type.
916 // If not a solid object, body is a GhostObject. Otherwise a RigidBody. 929 // If not a solid object, body is a GhostObject. Otherwise a RigidBody.
917 if (!mustRebuild) 930 if (!mustRebuild)
918 { 931 {
919 CollisionObjectTypes bodyType = (CollisionObjectTypes)BulletSimAPI.GetBodyType2(prim.PhysBody.ptr); 932 CollisionObjectTypes bodyType = (CollisionObjectTypes)PhysicsScene.PE.GetBodyType(prim.PhysBody);
920 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY 933 if (prim.IsSolid && bodyType != CollisionObjectTypes.CO_RIGID_BODY
921 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT) 934 || !prim.IsSolid && bodyType != CollisionObjectTypes.CO_GHOST_OBJECT)
922 { 935 {
@@ -931,20 +944,16 @@ public sealed class BSShapeCollection : IDisposable
931 DereferenceBody(prim.PhysBody, true, bodyCallback); 944 DereferenceBody(prim.PhysBody, true, bodyCallback);
932 945
933 BulletBody aBody; 946 BulletBody aBody;
934 IntPtr bodyPtr = IntPtr.Zero;
935 if (prim.IsSolid) 947 if (prim.IsSolid)
936 { 948 {
937 bodyPtr = BulletSimAPI.CreateBodyFromShape2(sim.ptr, shape.ptr, 949 aBody = PhysicsScene.PE.CreateBodyFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
938 prim.LocalID, prim.RawPosition, prim.RawOrientation); 950 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,mesh,body={1}", prim.LocalID, aBody);
939 DetailLog("{0},BSShapeCollection.CreateBody,mesh,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
940 } 951 }
941 else 952 else
942 { 953 {
943 bodyPtr = BulletSimAPI.CreateGhostFromShape2(sim.ptr, shape.ptr, 954 aBody = PhysicsScene.PE.CreateGhostFromShape(sim, shape, prim.LocalID, prim.RawPosition, prim.RawOrientation);
944 prim.LocalID, prim.RawPosition, prim.RawOrientation); 955 if (DDetail) DetailLog("{0},BSShapeCollection.CreateBody,ghost,body={1}", prim.LocalID, aBody);
945 DetailLog("{0},BSShapeCollection.CreateBody,ghost,ptr={1}", prim.LocalID, bodyPtr.ToString("X"));
946 } 956 }
947 aBody = new BulletBody(prim.LocalID, bodyPtr);
948 957
949 ReferenceBody(aBody, true); 958 ReferenceBody(aBody, true);
950 959
@@ -956,13 +965,13 @@ public sealed class BSShapeCollection : IDisposable
956 return ret; 965 return ret;
957 } 966 }
958 967
959 private bool TryGetMeshByPtr(IntPtr addr, out MeshDesc outDesc) 968 private bool TryGetMeshByPtr(BulletShape shape, out MeshDesc outDesc)
960 { 969 {
961 bool ret = false; 970 bool ret = false;
962 MeshDesc foundDesc = new MeshDesc(); 971 MeshDesc foundDesc = new MeshDesc();
963 foreach (MeshDesc md in Meshes.Values) 972 foreach (MeshDesc md in Meshes.Values)
964 { 973 {
965 if (md.ptr == addr) 974 if (md.shape.ReferenceSame(shape))
966 { 975 {
967 foundDesc = md; 976 foundDesc = md;
968 ret = true; 977 ret = true;
@@ -974,13 +983,13 @@ public sealed class BSShapeCollection : IDisposable
974 return ret; 983 return ret;
975 } 984 }
976 985
977 private bool TryGetHullByPtr(IntPtr addr, out HullDesc outDesc) 986 private bool TryGetHullByPtr(BulletShape shape, out HullDesc outDesc)
978 { 987 {
979 bool ret = false; 988 bool ret = false;
980 HullDesc foundDesc = new HullDesc(); 989 HullDesc foundDesc = new HullDesc();
981 foreach (HullDesc hd in Hulls.Values) 990 foreach (HullDesc hd in Hulls.Values)
982 { 991 {
983 if (hd.ptr == addr) 992 if (hd.shape.ReferenceSame(shape))
984 { 993 {
985 foundDesc = hd; 994 foundDesc = hd;
986 ret = true; 995 ret = true;
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
index 96cd55e..c75eb9b 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSShapes.cs
@@ -91,11 +91,17 @@ public abstract class BSShape
91 // All shapes have a static call to get a reference to the physical shape 91 // All shapes have a static call to get a reference to the physical shape
92 // protected abstract static BSShape GetReference(); 92 // protected abstract static BSShape GetReference();
93 93
94 // Returns a string for debugging that uniquily identifies the memory used by this instance
95 public string AddrString
96 {
97 get { return ptr.ToString("X"); }
98 }
99
94 public override string ToString() 100 public override string ToString()
95 { 101 {
96 StringBuilder buff = new StringBuilder(); 102 StringBuilder buff = new StringBuilder();
97 buff.Append("<p="); 103 buff.Append("<p=");
98 buff.Append(ptr.ToString("X")); 104 buff.Append(AddrString);
99 buff.Append(",s="); 105 buff.Append(",s=");
100 buff.Append(type.ToString()); 106 buff.Append(type.ToString());
101 buff.Append(",k="); 107 buff.Append(",k=");
@@ -126,7 +132,8 @@ public class BSShapeNative : BSShape
126 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey) 132 BSPhysicsShapeType shapeType, FixedShapeKey shapeKey)
127 { 133 {
128 // Native shapes are not shared and are always built anew. 134 // Native shapes are not shared and are always built anew.
129 return new BSShapeNative(physicsScene, prim, shapeType, shapeKey); 135 //return new BSShapeNative(physicsScene, prim, shapeType, shapeKey);
136 return null;
130 } 137 }
131 138
132 private BSShapeNative(BSScene physicsScene, BSPhysObject prim, 139 private BSShapeNative(BSScene physicsScene, BSPhysObject prim,
@@ -141,14 +148,15 @@ public class BSShapeNative : BSShape
141 nativeShapeData.HullKey = (ulong)shapeKey; 148 nativeShapeData.HullKey = (ulong)shapeKey;
142 149
143 150
151 /*
144 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE) 152 if (shapeType == BSPhysicsShapeType.SHAPE_CAPSULE)
145 { 153 {
146 ptr = BulletSimAPI.BuildCapsuleShape2(physicsScene.World.ptr, 1f, 1f, prim.Scale); 154 ptr = PhysicsScene.PE.BuildCapsuleShape(physicsScene.World, 1f, 1f, prim.Scale);
147 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale); 155 physicsScene.DetailLog("{0},BSShapeCollection.BuiletPhysicalNativeShape,capsule,scale={1}", prim.LocalID, prim.Scale);
148 } 156 }
149 else 157 else
150 { 158 {
151 ptr = BulletSimAPI.BuildNativeShape2(physicsScene.World.ptr, nativeShapeData); 159 ptr = PhysicsScene.PE.BuildNativeShape(physicsScene.World, nativeShapeData);
152 } 160 }
153 if (ptr == IntPtr.Zero) 161 if (ptr == IntPtr.Zero)
154 { 162 {
@@ -157,15 +165,18 @@ public class BSShapeNative : BSShape
157 } 165 }
158 type = shapeType; 166 type = shapeType;
159 key = (UInt64)shapeKey; 167 key = (UInt64)shapeKey;
168 */
160 } 169 }
161 // Make this reference to the physical shape go away since native shapes are not shared. 170 // Make this reference to the physical shape go away since native shapes are not shared.
162 public override void Dereference(BSScene physicsScene) 171 public override void Dereference(BSScene physicsScene)
163 { 172 {
173 /*
164 // Native shapes are not tracked and are released immediately 174 // Native shapes are not tracked and are released immediately
165 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this); 175 physicsScene.DetailLog("{0},BSShapeCollection.DereferenceShape,deleteNativeShape,shape={1}", BSScene.DetailLogZero, this);
166 BulletSimAPI.DeleteCollisionShape2(physicsScene.World.ptr, ptr); 176 PhysicsScene.PE.DeleteCollisionShape(physicsScene.World, this);
167 ptr = IntPtr.Zero; 177 ptr = IntPtr.Zero;
168 // Garbage collection will free up this instance. 178 // Garbage collection will free up this instance.
179 */
169 } 180 }
170} 181}
171 182
@@ -205,4 +216,17 @@ public class BSShapeCompound : BSShape
205 } 216 }
206 public override void Dereference(BSScene physicsScene) { } 217 public override void Dereference(BSScene physicsScene) { }
207} 218}
219
220public class BSShapeAvatar : BSShape
221{
222 private static string LogHeader = "[BULLETSIM SHAPE AVATAR]";
223 public BSShapeAvatar() : base()
224 {
225 }
226 public static BSShape GetReference(BSPhysObject prim)
227 {
228 return new BSShapeNull();
229 }
230 public override void Dereference(BSScene physicsScene) { }
231}
208} 232}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
index 3ca756c..e4fecc3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainHeightmap.cs
@@ -44,7 +44,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
44{ 44{
45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]"; 45 static string LogHeader = "[BULLETSIM TERRAIN HEIGHTMAP]";
46 46
47 BulletHeightMapInfo m_mapInfo = null; 47 BulletHMapInfo m_mapInfo = null;
48 48
49 // Constructor to build a default, flat heightmap terrain. 49 // Constructor to build a default, flat heightmap terrain.
50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize) 50 public BSTerrainHeightmap(BSScene physicsScene, Vector3 regionBase, uint id, Vector3 regionSize)
@@ -58,7 +58,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
58 { 58 {
59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION; 59 initialMap[ii] = BSTerrainManager.HEIGHT_INITIALIZATION;
60 } 60 }
61 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); 61 m_mapInfo = new BulletHMapInfo(id, initialMap);
62 m_mapInfo.minCoords = minTerrainCoords; 62 m_mapInfo.minCoords = minTerrainCoords;
63 m_mapInfo.maxCoords = maxTerrainCoords; 63 m_mapInfo.maxCoords = maxTerrainCoords;
64 m_mapInfo.terrainRegionBase = TerrainBase; 64 m_mapInfo.terrainRegionBase = TerrainBase;
@@ -72,7 +72,7 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
72 Vector3 minCoords, Vector3 maxCoords) 72 Vector3 minCoords, Vector3 maxCoords)
73 : base(physicsScene, regionBase, id) 73 : base(physicsScene, regionBase, id)
74 { 74 {
75 m_mapInfo = new BulletHeightMapInfo(id, initialMap, IntPtr.Zero); 75 m_mapInfo = new BulletHMapInfo(id, initialMap);
76 m_mapInfo.minCoords = minCoords; 76 m_mapInfo.minCoords = minCoords;
77 m_mapInfo.maxCoords = maxCoords; 77 m_mapInfo.maxCoords = maxCoords;
78 m_mapInfo.minZ = minCoords.Z; 78 m_mapInfo.minZ = minCoords.Z;
@@ -91,13 +91,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
91 // Using the information in m_mapInfo, create the physical representation of the heightmap. 91 // Using the information in m_mapInfo, create the physical representation of the heightmap.
92 private void BuildHeightmapTerrain() 92 private void BuildHeightmapTerrain()
93 { 93 {
94 m_mapInfo.Ptr = BulletSimAPI.CreateHeightMapInfo2(PhysicsScene.World.ptr, m_mapInfo.ID,
95 m_mapInfo.minCoords, m_mapInfo.maxCoords,
96 m_mapInfo.heightMap, BSTerrainManager.TERRAIN_COLLISION_MARGIN);
97
98 // Create the terrain shape from the mapInfo 94 // Create the terrain shape from the mapInfo
99 m_mapInfo.terrainShape = new BulletShape(BulletSimAPI.CreateTerrainShape2(m_mapInfo.Ptr), 95 m_mapInfo.terrainShape = PhysicsScene.PE.CreateTerrainShape( m_mapInfo.ID,
100 BSPhysicsShapeType.SHAPE_TERRAIN); 96 new Vector3(m_mapInfo.sizeX, m_mapInfo.sizeY, 0), m_mapInfo.minZ, m_mapInfo.maxZ,
97 m_mapInfo.heightMap, 1f, BSParam.TerrainCollisionMargin);
98
101 99
102 // The terrain object initial position is at the center of the object 100 // The terrain object initial position is at the center of the object
103 Vector3 centerPos; 101 Vector3 centerPos;
@@ -105,28 +103,26 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
105 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f); 103 centerPos.Y = m_mapInfo.minCoords.Y + (m_mapInfo.sizeY / 2f);
106 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f); 104 centerPos.Z = m_mapInfo.minZ + ((m_mapInfo.maxZ - m_mapInfo.minZ) / 2f);
107 105
108 m_mapInfo.terrainBody = new BulletBody(m_mapInfo.ID, 106 m_mapInfo.terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_mapInfo.terrainShape,
109 BulletSimAPI.CreateBodyWithDefaultMotionState2(m_mapInfo.terrainShape.ptr, 107 m_mapInfo.ID, centerPos, Quaternion.Identity);
110 m_mapInfo.ID, centerPos, Quaternion.Identity));
111 108
112 // Set current terrain attributes 109 // Set current terrain attributes
113 BulletSimAPI.SetFriction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainFriction); 110 PhysicsScene.PE.SetFriction(m_mapInfo.terrainBody, BSParam.TerrainFriction);
114 BulletSimAPI.SetHitFraction2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 111 PhysicsScene.PE.SetHitFraction(m_mapInfo.terrainBody, BSParam.TerrainHitFraction);
115 BulletSimAPI.SetRestitution2(m_mapInfo.terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 112 PhysicsScene.PE.SetRestitution(m_mapInfo.terrainBody, BSParam.TerrainRestitution);
116 BulletSimAPI.SetCollisionFlags2(m_mapInfo.terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 113 PhysicsScene.PE.SetCollisionFlags(m_mapInfo.terrainBody, CollisionFlags.CF_STATIC_OBJECT);
117 114
118 // Return the new terrain to the world of physical objects 115 // Return the new terrain to the world of physical objects
119 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 116 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_mapInfo.terrainBody);
120 117
121 // redo its bounding box now that it is in the world 118 // redo its bounding box now that it is in the world
122 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 119 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_mapInfo.terrainBody);
123 120
124 BulletSimAPI.SetCollisionFilterMask2(m_mapInfo.terrainBody.ptr, 121 m_mapInfo.terrainBody.collisionType = CollisionType.Terrain;
125 (uint)CollisionFilterGroups.TerrainFilter, 122 m_mapInfo.terrainBody.ApplyCollisionMask(PhysicsScene);
126 (uint)CollisionFilterGroups.TerrainMask);
127 123
128 // Make it so the terrain will not move or be considered for movement. 124 // Make it so the terrain will not move or be considered for movement.
129 BulletSimAPI.ForceActivationState2(m_mapInfo.terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 125 PhysicsScene.PE.ForceActivationState(m_mapInfo.terrainBody, ActivationState.DISABLE_SIMULATION);
130 126
131 return; 127 return;
132 } 128 }
@@ -136,19 +132,18 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
136 { 132 {
137 if (m_mapInfo != null) 133 if (m_mapInfo != null)
138 { 134 {
139 if (m_mapInfo.terrainBody.ptr != IntPtr.Zero) 135 if (m_mapInfo.terrainBody.HasPhysicalBody)
140 { 136 {
141 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 137 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_mapInfo.terrainBody);
142 // Frees both the body and the shape. 138 // Frees both the body and the shape.
143 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_mapInfo.terrainBody.ptr); 139 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_mapInfo.terrainBody);
144 BulletSimAPI.ReleaseHeightMapInfo2(m_mapInfo.Ptr);
145 } 140 }
146 } 141 }
147 m_mapInfo = null; 142 m_mapInfo = null;
148 } 143 }
149 144
150 // The passed position is relative to the base of the region. 145 // The passed position is relative to the base of the region.
151 public override float GetHeightAtXYZ(Vector3 pos) 146 public override float GetTerrainHeightAtXYZ(Vector3 pos)
152 { 147 {
153 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET; 148 float ret = BSTerrainManager.HEIGHT_GETHEIGHT_RET;
154 149
@@ -166,5 +161,11 @@ public sealed class BSTerrainHeightmap : BSTerrainPhys
166 } 161 }
167 return ret; 162 return ret;
168 } 163 }
164
165 // The passed position is relative to the base of the region.
166 public override float GetWaterLevelAtXYZ(Vector3 pos)
167 {
168 return PhysicsScene.SimpleWaterLevel;
169 }
169} 170}
170} 171}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
index 23fcfd3..2e9db39 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainManager.cs
@@ -62,11 +62,12 @@ public abstract class BSTerrainPhys : IDisposable
62 ID = id; 62 ID = id;
63 } 63 }
64 public abstract void Dispose(); 64 public abstract void Dispose();
65 public abstract float GetHeightAtXYZ(Vector3 pos); 65 public abstract float GetTerrainHeightAtXYZ(Vector3 pos);
66 public abstract float GetWaterLevelAtXYZ(Vector3 pos);
66} 67}
67 68
68// ========================================================================================== 69// ==========================================================================================
69public sealed class BSTerrainManager 70public sealed class BSTerrainManager : IDisposable
70{ 71{
71 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]"; 72 static string LogHeader = "[BULLETSIM TERRAIN MANAGER]";
72 73
@@ -75,13 +76,12 @@ public sealed class BSTerrainManager
75 public const float HEIGHT_INITIALIZATION = 24.987f; 76 public const float HEIGHT_INITIALIZATION = 24.987f;
76 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f; 77 public const float HEIGHT_INITIAL_LASTHEIGHT = 24.876f;
77 public const float HEIGHT_GETHEIGHT_RET = 24.765f; 78 public const float HEIGHT_GETHEIGHT_RET = 24.765f;
79 public const float WATER_HEIGHT_GETHEIGHT_RET = 19.998f;
78 80
79 // If the min and max height are equal, we reduce the min by this 81 // If the min and max height are equal, we reduce the min by this
80 // amount to make sure that a bounding box is built for the terrain. 82 // amount to make sure that a bounding box is built for the terrain.
81 public const float HEIGHT_EQUAL_FUDGE = 0.2f; 83 public const float HEIGHT_EQUAL_FUDGE = 0.2f;
82 84
83 public const float TERRAIN_COLLISION_MARGIN = 0.0f;
84
85 // Until the whole simulator is changed to pass us the region size, we rely on constants. 85 // Until the whole simulator is changed to pass us the region size, we rely on constants.
86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight); 86 public Vector3 DefaultRegionSize = new Vector3(Constants.RegionSize, Constants.RegionSize, Constants.RegionHeight);
87 87
@@ -122,25 +122,28 @@ public sealed class BSTerrainManager
122 MegaRegionParentPhysicsScene = null; 122 MegaRegionParentPhysicsScene = null;
123 } 123 }
124 124
125 public void Dispose()
126 {
127 ReleaseGroundPlaneAndTerrain();
128 }
129
125 // Create the initial instance of terrain and the underlying ground plane. 130 // Create the initial instance of terrain and the underlying ground plane.
126 // This is called from the initialization routine so we presume it is 131 // This is called from the initialization routine so we presume it is
127 // safe to call Bullet in real time. We hope no one is moving prims around yet. 132 // safe to call Bullet in real time. We hope no one is moving prims around yet.
128 public void CreateInitialGroundPlaneAndTerrain() 133 public void CreateInitialGroundPlaneAndTerrain()
129 { 134 {
130 // The ground plane is here to catch things that are trying to drop to negative infinity 135 // The ground plane is here to catch things that are trying to drop to negative infinity
131 BulletShape groundPlaneShape = new BulletShape( 136 BulletShape groundPlaneShape = PhysicsScene.PE.CreateGroundPlaneShape(BSScene.GROUNDPLANE_ID, 1f, BSParam.TerrainCollisionMargin);
132 BulletSimAPI.CreateGroundPlaneShape2(BSScene.GROUNDPLANE_ID, 1f, TERRAIN_COLLISION_MARGIN), 137 m_groundPlane = PhysicsScene.PE.CreateBodyWithDefaultMotionState(groundPlaneShape,
133 BSPhysicsShapeType.SHAPE_GROUNDPLANE); 138 BSScene.GROUNDPLANE_ID, Vector3.Zero, Quaternion.Identity);
134 m_groundPlane = new BulletBody(BSScene.GROUNDPLANE_ID, 139
135 BulletSimAPI.CreateBodyWithDefaultMotionState2(groundPlaneShape.ptr, BSScene.GROUNDPLANE_ID, 140 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_groundPlane);
136 Vector3.Zero, Quaternion.Identity)); 141 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_groundPlane);
137 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr);
138 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_groundPlane.ptr);
139 // Ground plane does not move 142 // Ground plane does not move
140 BulletSimAPI.ForceActivationState2(m_groundPlane.ptr, ActivationState.DISABLE_SIMULATION); 143 PhysicsScene.PE.ForceActivationState(m_groundPlane, ActivationState.DISABLE_SIMULATION);
141 // Everything collides with the ground plane. 144 // Everything collides with the ground plane.
142 BulletSimAPI.SetCollisionFilterMask2(m_groundPlane.ptr, 145 m_groundPlane.collisionType = CollisionType.Groundplane;
143 (uint)CollisionFilterGroups.GroundPlaneFilter, (uint)CollisionFilterGroups.GroundPlaneMask); 146 m_groundPlane.ApplyCollisionMask(PhysicsScene);
144 147
145 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain. 148 // Build an initial terrain and put it in the world. This quickly gets replaced by the real region terrain.
146 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize); 149 BSTerrainPhys initialTerrain = new BSTerrainHeightmap(PhysicsScene, Vector3.Zero, BSScene.TERRAIN_ID, DefaultRegionSize);
@@ -150,13 +153,13 @@ public sealed class BSTerrainManager
150 // Release all the terrain structures we might have allocated 153 // Release all the terrain structures we might have allocated
151 public void ReleaseGroundPlaneAndTerrain() 154 public void ReleaseGroundPlaneAndTerrain()
152 { 155 {
153 if (m_groundPlane.ptr != IntPtr.Zero) 156 if (m_groundPlane.HasPhysicalBody)
154 { 157 {
155 if (BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_groundPlane.ptr)) 158 if (PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_groundPlane))
156 { 159 {
157 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_groundPlane.ptr); 160 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_groundPlane);
158 } 161 }
159 m_groundPlane.ptr = IntPtr.Zero; 162 m_groundPlane.Clear();
160 } 163 }
161 164
162 ReleaseTerrain(); 165 ReleaseTerrain();
@@ -165,17 +168,22 @@ public sealed class BSTerrainManager
165 // Release all the terrain we have allocated 168 // Release all the terrain we have allocated
166 public void ReleaseTerrain() 169 public void ReleaseTerrain()
167 { 170 {
168 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains) 171 lock (m_terrains)
169 { 172 {
170 kvp.Value.Dispose(); 173 foreach (KeyValuePair<Vector3, BSTerrainPhys> kvp in m_terrains)
174 {
175 kvp.Value.Dispose();
176 }
177 m_terrains.Clear();
171 } 178 }
172 m_terrains.Clear();
173 } 179 }
174 180
175 // The simulator wants to set a new heightmap for the terrain. 181 // The simulator wants to set a new heightmap for the terrain.
176 public void SetTerrain(float[] heightMap) { 182 public void SetTerrain(float[] heightMap) {
177 float[] localHeightMap = heightMap; 183 float[] localHeightMap = heightMap;
178 PhysicsScene.TaintedObject("TerrainManager.SetTerrain", delegate() 184 // If there are multiple requests for changes to the same terrain between ticks,
185 // only do that last one.
186 PhysicsScene.PostTaintObject("TerrainManager.SetTerrain-"+ m_worldOffset.ToString(), 0, delegate()
179 { 187 {
180 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null) 188 if (m_worldOffset != Vector3.Zero && MegaRegionParentPhysicsScene != null)
181 { 189 {
@@ -211,6 +219,7 @@ public sealed class BSTerrainManager
211 // terrain shape is created and added to the body. 219 // terrain shape is created and added to the body.
212 // This call is most often used to update the heightMap and parameters of the terrain. 220 // This call is most often used to update the heightMap and parameters of the terrain.
213 // (The above does suggest that some simplification/refactoring is in order.) 221 // (The above does suggest that some simplification/refactoring is in order.)
222 // Called during taint-time.
214 private void UpdateTerrain(uint id, float[] heightMap, 223 private void UpdateTerrain(uint id, float[] heightMap,
215 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime) 224 Vector3 minCoords, Vector3 maxCoords, bool inTaintTime)
216 { 225 {
@@ -220,7 +229,7 @@ public sealed class BSTerrainManager
220 // Find high and low points of passed heightmap. 229 // Find high and low points of passed heightmap.
221 // The min and max passed in is usually the area objects can be in (maximum 230 // The min and max passed in is usually the area objects can be in (maximum
222 // object height, for instance). The terrain wants the bounding box for the 231 // object height, for instance). The terrain wants the bounding box for the
223 // terrain so we replace passed min and max Z with the actual terrain min/max Z. 232 // terrain so replace passed min and max Z with the actual terrain min/max Z.
224 float minZ = float.MaxValue; 233 float minZ = float.MaxValue;
225 float maxZ = float.MinValue; 234 float maxZ = float.MinValue;
226 foreach (float height in heightMap) 235 foreach (float height in heightMap)
@@ -238,15 +247,15 @@ public sealed class BSTerrainManager
238 247
239 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f); 248 Vector3 terrainRegionBase = new Vector3(minCoords.X, minCoords.Y, 0f);
240 249
241 BSTerrainPhys terrainPhys; 250 lock (m_terrains)
242 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
243 { 251 {
244 // There is already a terrain in this spot. Free the old and build the new. 252 BSTerrainPhys terrainPhys;
245 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}", 253 if (m_terrains.TryGetValue(terrainRegionBase, out terrainPhys))
246 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
247
248 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:UpdateExisting", delegate()
249 { 254 {
255 // There is already a terrain in this spot. Free the old and build the new.
256 DetailLog("{0},UpdateTerrain:UpdateExisting,call,id={1},base={2},minC={3},maxC={4}",
257 BSScene.DetailLogZero, id, terrainRegionBase, minCoords, minCoords);
258
250 // Remove old terrain from the collection 259 // Remove old terrain from the collection
251 m_terrains.Remove(terrainRegionBase); 260 m_terrains.Remove(terrainRegionBase);
252 // Release any physical memory it may be using. 261 // Release any physical memory it may be using.
@@ -271,35 +280,24 @@ public sealed class BSTerrainManager
271 // I hate doing this, but just bail 280 // I hate doing this, but just bail
272 return; 281 return;
273 } 282 }
274 }); 283 }
275 } 284 else
276 else 285 {
277 { 286 // We don't know about this terrain so either we are creating a new terrain or
278 // We don't know about this terrain so either we are creating a new terrain or 287 // our mega-prim child is giving us a new terrain to add to the phys world
279 // our mega-prim child is giving us a new terrain to add to the phys world
280
281 // if this is a child terrain, calculate a unique terrain id
282 uint newTerrainID = id;
283 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
284 newTerrainID = ++m_terrainCount;
285
286 float[] heightMapX = heightMap;
287 Vector3 minCoordsX = minCoords;
288 Vector3 maxCoordsX = maxCoords;
289 288
290 DetailLog("{0},UpdateTerrain:NewTerrain,call,id={1}, minC={2}, maxC={3}", 289 // if this is a child terrain, calculate a unique terrain id
291 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords); 290 uint newTerrainID = id;
291 if (newTerrainID >= BSScene.CHILDTERRAIN_ID)
292 newTerrainID = ++m_terrainCount;
292 293
293 // Code that must happen at taint-time 294 DetailLog("{0},UpdateTerrain:NewTerrain,taint,newID={1},minCoord={2},maxCoord={3}",
294 PhysicsScene.TaintedObject(inTaintTime, "BSScene.UpdateTerrain:NewTerrain", delegate() 295 BSScene.DetailLogZero, newTerrainID, minCoords, minCoords);
295 {
296 DetailLog("{0},UpdateTerrain:NewTerrain,taint,baseX={1},baseY={2}",
297 BSScene.DetailLogZero, minCoordsX.X, minCoordsX.Y);
298 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords); 296 BSTerrainPhys newTerrainPhys = BuildPhysicalTerrain(terrainRegionBase, id, heightMap, minCoords, maxCoords);
299 m_terrains.Add(terrainRegionBase, newTerrainPhys); 297 m_terrains.Add(terrainRegionBase, newTerrainPhys);
300 298
301 m_terrainModified = true; 299 m_terrainModified = true;
302 }); 300 }
303 } 301 }
304 } 302 }
305 303
@@ -308,9 +306,9 @@ public sealed class BSTerrainManager
308 { 306 {
309 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}", 307 PhysicsScene.Logger.DebugFormat("{0} Terrain for {1}/{2} created with {3}",
310 LogHeader, PhysicsScene.RegionName, terrainRegionBase, 308 LogHeader, PhysicsScene.RegionName, terrainRegionBase,
311 (BSTerrainPhys.TerrainImplementation)PhysicsScene.Params.terrainImplementation); 309 (BSTerrainPhys.TerrainImplementation)BSParam.TerrainImplementation);
312 BSTerrainPhys newTerrainPhys = null; 310 BSTerrainPhys newTerrainPhys = null;
313 switch ((int)PhysicsScene.Params.terrainImplementation) 311 switch ((int)BSParam.TerrainImplementation)
314 { 312 {
315 case (int)BSTerrainPhys.TerrainImplementation.Heightmap: 313 case (int)BSTerrainPhys.TerrainImplementation.Heightmap:
316 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id, 314 newTerrainPhys = new BSTerrainHeightmap(PhysicsScene, terrainRegionBase, id,
@@ -323,14 +321,21 @@ public sealed class BSTerrainManager
323 default: 321 default:
324 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}", 322 PhysicsScene.Logger.ErrorFormat("{0} Bad terrain implementation specified. Type={1}/{2},Region={3}/{4}",
325 LogHeader, 323 LogHeader,
326 (int)PhysicsScene.Params.terrainImplementation, 324 (int)BSParam.TerrainImplementation,
327 PhysicsScene.Params.terrainImplementation, 325 BSParam.TerrainImplementation,
328 PhysicsScene.RegionName, terrainRegionBase); 326 PhysicsScene.RegionName, terrainRegionBase);
329 break; 327 break;
330 } 328 }
331 return newTerrainPhys; 329 return newTerrainPhys;
332 } 330 }
333 331
332 // Return 'true' of this position is somewhere in known physical terrain space
333 public bool IsWithinKnownTerrain(Vector3 pos)
334 {
335 Vector3 terrainBaseXYZ;
336 BSTerrainPhys physTerrain;
337 return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
338 }
334 339
335 // Given an X and Y, find the height of the terrain. 340 // Given an X and Y, find the height of the terrain.
336 // Since we could be handling multiple terrains for a mega-region, 341 // Since we could be handling multiple terrains for a mega-region,
@@ -341,40 +346,74 @@ public sealed class BSTerrainManager
341 private float lastHeightTX = 999999f; 346 private float lastHeightTX = 999999f;
342 private float lastHeightTY = 999999f; 347 private float lastHeightTY = 999999f;
343 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT; 348 private float lastHeight = HEIGHT_INITIAL_LASTHEIGHT;
344 public float GetTerrainHeightAtXYZ(Vector3 loc) 349 public float GetTerrainHeightAtXYZ(Vector3 pos)
345 { 350 {
346 float tX = loc.X; 351 float tX = pos.X;
347 float tY = loc.Y; 352 float tY = pos.Y;
348 // You'd be surprized at the number of times this routine is called 353 // You'd be surprized at the number of times this routine is called
349 // with the same parameters as last time. 354 // with the same parameters as last time.
350 if (!m_terrainModified && lastHeightTX == tX && lastHeightTY == tY) 355 if (!m_terrainModified && (lastHeightTX == tX) && (lastHeightTY == tY))
351 return lastHeight; 356 return lastHeight;
357 m_terrainModified = false;
352 358
353 lastHeightTX = tX; 359 lastHeightTX = tX;
354 lastHeightTY = tY; 360 lastHeightTY = tY;
355 float ret = HEIGHT_GETHEIGHT_RET; 361 float ret = HEIGHT_GETHEIGHT_RET;
356 362
357 int offsetX = ((int)(tX / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X; 363 Vector3 terrainBaseXYZ;
358 int offsetY = ((int)(tY / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
359 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
360
361 BSTerrainPhys physTerrain; 364 BSTerrainPhys physTerrain;
362 if (m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain)) 365 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
363 { 366 {
364 ret = physTerrain.GetHeightAtXYZ(loc - terrainBaseXYZ); 367 ret = physTerrain.GetTerrainHeightAtXYZ(pos - terrainBaseXYZ);
365 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,loc={1},base={2},height={3}",
366 BSScene.DetailLogZero, loc, terrainBaseXYZ, ret);
367 } 368 }
368 else 369 else
369 { 370 {
370 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}", 371 PhysicsScene.Logger.ErrorFormat("{0} GetTerrainHeightAtXY: terrain not found: region={1}, x={2}, y={3}",
371 LogHeader, PhysicsScene.RegionName, tX, tY); 372 LogHeader, PhysicsScene.RegionName, tX, tY);
373 DetailLog("{0},BSTerrainManager.GetTerrainHeightAtXYZ,terrainNotFound,pos={1},base={2}",
374 BSScene.DetailLogZero, pos, terrainBaseXYZ);
372 } 375 }
373 m_terrainModified = false; 376
374 lastHeight = ret; 377 lastHeight = ret;
375 return ret; 378 return ret;
376 } 379 }
377 380
381 public float GetWaterLevelAtXYZ(Vector3 pos)
382 {
383 float ret = WATER_HEIGHT_GETHEIGHT_RET;
384
385 Vector3 terrainBaseXYZ;
386 BSTerrainPhys physTerrain;
387 if (GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ))
388 {
389 ret = physTerrain.GetWaterLevelAtXYZ(pos);
390 }
391 else
392 {
393 PhysicsScene.Logger.ErrorFormat("{0} GetWaterHeightAtXY: terrain not found: pos={1}, terrainBase={2}, height={3}",
394 LogHeader, PhysicsScene.RegionName, pos, terrainBaseXYZ, ret);
395 }
396 return ret;
397 }
398
399 // Given an address, return 'true' of there is a description of that terrain and output
400 // the descriptor class and the 'base' fo the addresses therein.
401 private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
402 {
403 int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
404 int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
405 Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
406
407 BSTerrainPhys physTerrain = null;
408 lock (m_terrains)
409 {
410 m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
411 }
412 outTerrainBase = terrainBaseXYZ;
413 outPhysTerrain = physTerrain;
414 return (physTerrain != null);
415 }
416
378 // Although no one seems to check this, I do support combining. 417 // Although no one seems to check this, I do support combining.
379 public bool SupportsCombining() 418 public bool SupportsCombining()
380 { 419 {
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
index dca7150..1d55ce3 100755
--- a/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
+++ b/OpenSim/Region/Physics/BulletSPlugin/BSTerrainMesh.cs
@@ -88,11 +88,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
88 // Something is very messed up and a crash is in our future. 88 // Something is very messed up and a crash is in our future.
89 return; 89 return;
90 } 90 }
91 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,meshed,indices={1},indSz={2},vertices={3},vertSz={4}",
92 ID, indicesCount, indices.Length, verticesCount, vertices.Length);
91 93
92 m_terrainShape = new BulletShape(BulletSimAPI.CreateMeshShape2(PhysicsScene.World.ptr, 94 m_terrainShape = PhysicsScene.PE.CreateMeshShape(PhysicsScene.World, indicesCount, indices, verticesCount, vertices);
93 indicesCount, indices, verticesCount, vertices), 95 if (!m_terrainShape.HasPhysicalShape)
94 BSPhysicsShapeType.SHAPE_MESH);
95 if (m_terrainShape.ptr == IntPtr.Zero)
96 { 96 {
97 // DISASTER!! 97 // DISASTER!!
98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID); 98 PhysicsScene.DetailLog("{0},BSTerrainMesh.create,failedCreationOfShape", ID);
@@ -104,8 +104,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
104 Vector3 pos = regionBase; 104 Vector3 pos = regionBase;
105 Quaternion rot = Quaternion.Identity; 105 Quaternion rot = Quaternion.Identity;
106 106
107 m_terrainBody = new BulletBody(id, BulletSimAPI.CreateBodyWithDefaultMotionState2( m_terrainShape.ptr, ID, pos, rot)); 107 m_terrainBody = PhysicsScene.PE.CreateBodyWithDefaultMotionState(m_terrainShape, ID, pos, rot);
108 if (m_terrainBody.ptr == IntPtr.Zero) 108 if (!m_terrainBody.HasPhysicalBody)
109 { 109 {
110 // DISASTER!! 110 // DISASTER!!
111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase); 111 physicsScene.Logger.ErrorFormat("{0} Failed creation of terrain body! base={1}", LogHeader, TerrainBase);
@@ -114,39 +114,38 @@ public sealed class BSTerrainMesh : BSTerrainPhys
114 } 114 }
115 115
116 // Set current terrain attributes 116 // Set current terrain attributes
117 BulletSimAPI.SetFriction2(m_terrainBody.ptr, PhysicsScene.Params.terrainFriction); 117 PhysicsScene.PE.SetFriction(m_terrainBody, BSParam.TerrainFriction);
118 BulletSimAPI.SetHitFraction2(m_terrainBody.ptr, PhysicsScene.Params.terrainHitFraction); 118 PhysicsScene.PE.SetHitFraction(m_terrainBody, BSParam.TerrainHitFraction);
119 BulletSimAPI.SetRestitution2(m_terrainBody.ptr, PhysicsScene.Params.terrainRestitution); 119 PhysicsScene.PE.SetRestitution(m_terrainBody, BSParam.TerrainRestitution);
120 BulletSimAPI.SetCollisionFlags2(m_terrainBody.ptr, CollisionFlags.CF_STATIC_OBJECT); 120 PhysicsScene.PE.SetCollisionFlags(m_terrainBody, CollisionFlags.CF_STATIC_OBJECT);
121 121
122 // Static objects are not very massive. 122 // Static objects are not very massive.
123 BulletSimAPI.SetMassProps2(m_terrainBody.ptr, 0f, Vector3.Zero); 123 PhysicsScene.PE.SetMassProps(m_terrainBody, 0f, Vector3.Zero);
124 124
125 // Return the new terrain to the world of physical objects 125 // Put the new terrain to the world of physical objects
126 BulletSimAPI.AddObjectToWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 126 PhysicsScene.PE.AddObjectToWorld(PhysicsScene.World, m_terrainBody);
127 127
128 // redo its bounding box now that it is in the world 128 // Redo its bounding box now that it is in the world
129 BulletSimAPI.UpdateSingleAabb2(PhysicsScene.World.ptr, m_terrainBody.ptr); 129 PhysicsScene.PE.UpdateSingleAabb(PhysicsScene.World, m_terrainBody);
130 130
131 BulletSimAPI.SetCollisionFilterMask2(m_terrainBody.ptr, 131 m_terrainBody.collisionType = CollisionType.Terrain;
132 (uint)CollisionFilterGroups.TerrainFilter, 132 m_terrainBody.ApplyCollisionMask(PhysicsScene);
133 (uint)CollisionFilterGroups.TerrainMask);
134 133
135 // Make it so the terrain will not move or be considered for movement. 134 // Make it so the terrain will not move or be considered for movement.
136 BulletSimAPI.ForceActivationState2(m_terrainBody.ptr, ActivationState.DISABLE_SIMULATION); 135 PhysicsScene.PE.ForceActivationState(m_terrainBody, ActivationState.DISABLE_SIMULATION);
137 } 136 }
138 137
139 public override void Dispose() 138 public override void Dispose()
140 { 139 {
141 if (m_terrainBody.ptr != IntPtr.Zero) 140 if (m_terrainBody.HasPhysicalBody)
142 { 141 {
143 BulletSimAPI.RemoveObjectFromWorld2(PhysicsScene.World.ptr, m_terrainBody.ptr); 142 PhysicsScene.PE.RemoveObjectFromWorld(PhysicsScene.World, m_terrainBody);
144 // Frees both the body and the shape. 143 // Frees both the body and the shape.
145 BulletSimAPI.DestroyObject2(PhysicsScene.World.ptr, m_terrainBody.ptr); 144 PhysicsScene.PE.DestroyObject(PhysicsScene.World, m_terrainBody);
146 } 145 }
147 } 146 }
148 147
149 public override float GetHeightAtXYZ(Vector3 pos) 148 public override float GetTerrainHeightAtXYZ(Vector3 pos)
150 { 149 {
151 // For the moment use the saved heightmap to get the terrain height. 150 // For the moment use the saved heightmap to get the terrain height.
152 // TODO: raycast downward to find the true terrain below the position. 151 // TODO: raycast downward to find the true terrain below the position.
@@ -167,6 +166,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
167 return ret; 166 return ret;
168 } 167 }
169 168
169 // The passed position is relative to the base of the region.
170 public override float GetWaterLevelAtXYZ(Vector3 pos)
171 {
172 return PhysicsScene.SimpleWaterLevel;
173 }
174
170 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2(). 175 // Convert the passed heightmap to mesh information suitable for CreateMeshShape2().
171 // Return 'true' if successfully created. 176 // Return 'true' if successfully created.
172 public static bool ConvertHeightmapToMesh( 177 public static bool ConvertHeightmapToMesh(
@@ -188,6 +193,11 @@ public sealed class BSTerrainMesh : BSTerrainPhys
188 // Simple mesh creation which assumes magnification == 1. 193 // Simple mesh creation which assumes magnification == 1.
189 // TODO: do a more general solution that scales, adds new vertices and smoothes the result. 194 // TODO: do a more general solution that scales, adds new vertices and smoothes the result.
190 195
196 // Create an array of vertices that is sizeX+1 by sizeY+1 (note the loop
197 // from zero to <= sizeX). The triangle indices are then generated as two triangles
198 // per heightmap point. There are sizeX by sizeY of these squares. The extra row and
199 // column of vertices are used to complete the triangles of the last row and column
200 // of the heightmap.
191 try 201 try
192 { 202 {
193 // One vertice per heightmap value plus the vertices off the top and bottom edge. 203 // One vertice per heightmap value plus the vertices off the top and bottom edge.
@@ -200,16 +210,18 @@ public sealed class BSTerrainMesh : BSTerrainPhys
200 float magY = (float)sizeY / extentY; 210 float magY = (float)sizeY / extentY;
201 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}", 211 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
202 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY); 212 BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
213 float minHeight = float.MaxValue;
203 // Note that sizeX+1 vertices are created since there is land between this and the next region. 214 // Note that sizeX+1 vertices are created since there is land between this and the next region.
204 for (int yy = 0; yy <= sizeY; yy++) 215 for (int yy = 0; yy <= sizeY; yy++)
205 { 216 {
206 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we got through sizeX + 1 times 217 for (int xx = 0; xx <= sizeX; xx++) // Hint: the "<=" means we go around sizeX + 1 times
207 { 218 {
208 int offset = yy * sizeX + xx; 219 int offset = yy * sizeX + xx;
209 // Extend the height from the height from the last row or column 220 // Extend the height with the height from the last row or column
210 if (yy == sizeY) offset -= sizeX; 221 if (yy == sizeY) offset -= sizeX;
211 if (xx == sizeX) offset -= 1; 222 if (xx == sizeX) offset -= 1;
212 float height = heightMap[offset]; 223 float height = heightMap[offset];
224 minHeight = Math.Min(minHeight, height);
213 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X; 225 vertices[verticesCount + 0] = (float)xx * magX + extentBase.X;
214 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y; 226 vertices[verticesCount + 1] = (float)yy * magY + extentBase.Y;
215 vertices[verticesCount + 2] = height + extentBase.Z; 227 vertices[verticesCount + 2] = height + extentBase.Z;
@@ -217,14 +229,12 @@ public sealed class BSTerrainMesh : BSTerrainPhys
217 } 229 }
218 } 230 }
219 verticesCount = verticesCount / 3; 231 verticesCount = verticesCount / 3;
220 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeVerts,verCount={1}",
221 BSScene.DetailLogZero, verticesCount);
222 232
223 for (int yy = 0; yy < sizeY; yy++) 233 for (int yy = 0; yy < sizeY; yy++)
224 { 234 {
225 for (int xx = 0; xx < sizeX; xx++) 235 for (int xx = 0; xx < sizeX; xx++)
226 { 236 {
227 int offset = yy * sizeX + xx; 237 int offset = yy * (sizeX + 1) + xx;
228 // Each vertices is presumed to be the upper left corner of a box of two triangles 238 // Each vertices is presumed to be the upper left corner of a box of two triangles
229 indices[indicesCount + 0] = offset; 239 indices[indicesCount + 0] = offset;
230 indices[indicesCount + 1] = offset + 1; 240 indices[indicesCount + 1] = offset + 1;
@@ -235,8 +245,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
235 indicesCount += 6; 245 indicesCount += 6;
236 } 246 }
237 } 247 }
238 physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,completeIndices,indCount={1}", // DEEBUG DEBUG DEBUG 248
239 LogHeader, indicesCount); // DEBUG
240 ret = true; 249 ret = true;
241 } 250 }
242 catch (Exception e) 251 catch (Exception e)
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
deleted file mode 100644
index e60a760..0000000
--- a/OpenSim/Region/Physics/BulletSPlugin/BulletSimAPI.cs
+++ /dev/null
@@ -1,1015 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Runtime.InteropServices;
29using System.Security;
30using System.Text;
31using OpenMetaverse;
32
33namespace OpenSim.Region.Physics.BulletSPlugin {
34
35// Classes to allow some type checking for the API
36// These hold pointers to allocated objects in the unmanaged space.
37
38// The physics engine controller class created at initialization
39public struct BulletSim
40{
41 public BulletSim(uint worldId, BSScene bss, IntPtr xx)
42 {
43 ptr = xx;
44 worldID = worldId;
45 physicsScene = bss;
46 }
47 public IntPtr ptr;
48 public uint worldID;
49 // The scene is only in here so very low level routines have a handle to print debug/error messages
50 public BSScene physicsScene;
51}
52
53// An allocated Bullet btRigidBody
54public struct BulletBody
55{
56 public BulletBody(uint id, IntPtr xx)
57 {
58 ID = id;
59 ptr = xx;
60 collisionFilter = 0;
61 collisionMask = 0;
62 }
63 public IntPtr ptr;
64 public uint ID;
65 public CollisionFilterGroups collisionFilter;
66 public CollisionFilterGroups collisionMask;
67 public override string ToString()
68 {
69 StringBuilder buff = new StringBuilder();
70 buff.Append("<id=");
71 buff.Append(ID.ToString());
72 buff.Append(",p=");
73 buff.Append(ptr.ToString("X"));
74 if (collisionFilter != 0 || collisionMask != 0)
75 {
76 buff.Append(",f=");
77 buff.Append(collisionFilter.ToString("X"));
78 buff.Append(",m=");
79 buff.Append(collisionMask.ToString("X"));
80 }
81 buff.Append(">");
82 return buff.ToString();
83 }
84}
85
86public struct BulletShape
87{
88 public BulletShape(IntPtr xx)
89 {
90 ptr = xx;
91 type=BSPhysicsShapeType.SHAPE_UNKNOWN;
92 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
93 isNativeShape = false;
94 }
95 public BulletShape(IntPtr xx, BSPhysicsShapeType typ)
96 {
97 ptr = xx;
98 type = typ;
99 shapeKey = 0;
100 isNativeShape = false;
101 }
102 public IntPtr ptr;
103 public BSPhysicsShapeType type;
104 public System.UInt64 shapeKey;
105 public bool isNativeShape;
106 public override string ToString()
107 {
108 StringBuilder buff = new StringBuilder();
109 buff.Append("<p=");
110 buff.Append(ptr.ToString("X"));
111 buff.Append(",s=");
112 buff.Append(type.ToString());
113 buff.Append(",k=");
114 buff.Append(shapeKey.ToString("X"));
115 buff.Append(",n=");
116 buff.Append(isNativeShape.ToString());
117 buff.Append(">");
118 return buff.ToString();
119 }
120}
121
122 // Constraint type values as defined by Bullet
123public enum ConstraintType : int
124{
125 POINT2POINT_CONSTRAINT_TYPE = 3,
126 HINGE_CONSTRAINT_TYPE,
127 CONETWIST_CONSTRAINT_TYPE,
128 D6_CONSTRAINT_TYPE,
129 SLIDER_CONSTRAINT_TYPE,
130 CONTACT_CONSTRAINT_TYPE,
131 D6_SPRING_CONSTRAINT_TYPE,
132 MAX_CONSTRAINT_TYPE
133}
134
135// An allocated Bullet btConstraint
136public struct BulletConstraint
137{
138 public BulletConstraint(IntPtr xx)
139 {
140 ptr = xx;
141 }
142 public IntPtr ptr;
143}
144
145// An allocated HeightMapThing which holds various heightmap info.
146// Made a class rather than a struct so there would be only one
147// instance of this and C# will pass around pointers rather
148// than making copies.
149public class BulletHeightMapInfo
150{
151 public BulletHeightMapInfo(uint id, float[] hm, IntPtr xx) {
152 ID = id;
153 Ptr = xx;
154 heightMap = hm;
155 terrainRegionBase = Vector3.Zero;
156 minCoords = new Vector3(100f, 100f, 25f);
157 maxCoords = new Vector3(101f, 101f, 26f);
158 minZ = maxZ = 0f;
159 sizeX = sizeY = 256f;
160 }
161 public uint ID;
162 public IntPtr Ptr;
163 public float[] heightMap;
164 public Vector3 terrainRegionBase;
165 public Vector3 minCoords;
166 public Vector3 maxCoords;
167 public float sizeX, sizeY;
168 public float minZ, maxZ;
169 public BulletShape terrainShape;
170 public BulletBody terrainBody;
171}
172
173// ===============================================================================
174[StructLayout(LayoutKind.Sequential)]
175public struct ConvexHull
176{
177 Vector3 Offset;
178 int VertexCount;
179 Vector3[] Vertices;
180}
181public enum BSPhysicsShapeType
182{
183 SHAPE_UNKNOWN = 0,
184 SHAPE_CAPSULE = 1,
185 SHAPE_BOX = 2,
186 SHAPE_CONE = 3,
187 SHAPE_CYLINDER = 4,
188 SHAPE_SPHERE = 5,
189 SHAPE_MESH = 6,
190 SHAPE_HULL = 7,
191 // following defined by BulletSim
192 SHAPE_GROUNDPLANE = 20,
193 SHAPE_TERRAIN = 21,
194 SHAPE_COMPOUND = 22,
195 SHAPE_HEIGHTMAP = 23,
196};
197
198// The native shapes have predefined shape hash keys
199public enum FixedShapeKey : ulong
200{
201 KEY_NONE = 0,
202 KEY_BOX = 1,
203 KEY_SPHERE = 2,
204 KEY_CONE = 3,
205 KEY_CYLINDER = 4,
206 KEY_CAPSULE = 5,
207}
208
209[StructLayout(LayoutKind.Sequential)]
210public struct ShapeData
211{
212 public uint ID;
213 public BSPhysicsShapeType Type;
214 public Vector3 Position;
215 public Quaternion Rotation;
216 public Vector3 Velocity;
217 public Vector3 Scale;
218 public float Mass;
219 public float Buoyancy;
220 public System.UInt64 HullKey;
221 public System.UInt64 MeshKey;
222 public float Friction;
223 public float Restitution;
224 public float Collidable; // true of things bump into this
225 public float Static; // true if a static object. Otherwise gravity, etc.
226 public float Solid; // true if object cannot be passed through
227 public Vector3 Size;
228
229 // note that bools are passed as floats since bool size changes by language and architecture
230 public const float numericTrue = 1f;
231 public const float numericFalse = 0f;
232}
233[StructLayout(LayoutKind.Sequential)]
234public struct SweepHit
235{
236 public uint ID;
237 public float Fraction;
238 public Vector3 Normal;
239 public Vector3 Point;
240}
241[StructLayout(LayoutKind.Sequential)]
242public struct RaycastHit
243{
244 public uint ID;
245 public float Fraction;
246 public Vector3 Normal;
247}
248[StructLayout(LayoutKind.Sequential)]
249public struct CollisionDesc
250{
251 public uint aID;
252 public uint bID;
253 public Vector3 point;
254 public Vector3 normal;
255}
256[StructLayout(LayoutKind.Sequential)]
257public struct EntityProperties
258{
259 public uint ID;
260 public Vector3 Position;
261 public Quaternion Rotation;
262 public Vector3 Velocity;
263 public Vector3 Acceleration;
264 public Vector3 RotationalVelocity;
265}
266
267// Format of this structure must match the definition in the C++ code
268[StructLayout(LayoutKind.Sequential)]
269public struct ConfigurationParameters
270{
271 public float defaultFriction;
272 public float defaultDensity;
273 public float defaultRestitution;
274 public float collisionMargin;
275 public float gravity;
276
277 public float linearDamping;
278 public float angularDamping;
279 public float deactivationTime;
280 public float linearSleepingThreshold;
281 public float angularSleepingThreshold;
282 public float ccdMotionThreshold;
283 public float ccdSweptSphereRadius;
284 public float contactProcessingThreshold;
285
286 public float terrainImplementation;
287 public float terrainFriction;
288 public float terrainHitFraction;
289 public float terrainRestitution;
290 public float avatarFriction;
291 public float avatarStandingFriction;
292 public float avatarDensity;
293 public float avatarRestitution;
294 public float avatarCapsuleWidth;
295 public float avatarCapsuleDepth;
296 public float avatarCapsuleHeight;
297 public float avatarContactProcessingThreshold;
298
299 public float maxPersistantManifoldPoolSize;
300 public float maxCollisionAlgorithmPoolSize;
301 public float shouldDisableContactPoolDynamicAllocation;
302 public float shouldForceUpdateAllAabbs;
303 public float shouldRandomizeSolverOrder;
304 public float shouldSplitSimulationIslands;
305 public float shouldEnableFrictionCaching;
306 public float numberOfSolverIterations;
307
308 public float linksetImplementation;
309 public float linkConstraintUseFrameOffset;
310 public float linkConstraintEnableTransMotor;
311 public float linkConstraintTransMotorMaxVel;
312 public float linkConstraintTransMotorMaxForce;
313 public float linkConstraintERP;
314 public float linkConstraintCFM;
315 public float linkConstraintSolverIterations;
316
317 public float physicsLoggingFrames;
318
319 public const float numericTrue = 1f;
320 public const float numericFalse = 0f;
321}
322
323
324// The states a bullet collision object can have
325public enum ActivationState : uint
326{
327 ACTIVE_TAG = 1,
328 ISLAND_SLEEPING,
329 WANTS_DEACTIVATION,
330 DISABLE_DEACTIVATION,
331 DISABLE_SIMULATION,
332}
333
334public enum CollisionObjectTypes : int
335{
336 CO_COLLISION_OBJECT = 1 << 0,
337 CO_RIGID_BODY = 1 << 1,
338 CO_GHOST_OBJECT = 1 << 2,
339 CO_SOFT_BODY = 1 << 3,
340 CO_HF_FLUID = 1 << 4,
341 CO_USER_TYPE = 1 << 5,
342}
343
344// Values used by Bullet and BulletSim to control object properties.
345// Bullet's "CollisionFlags" has more to do with operations on the
346// object (if collisions happen, if gravity effects it, ...).
347public enum CollisionFlags : uint
348{
349 CF_STATIC_OBJECT = 1 << 0,
350 CF_KINEMATIC_OBJECT = 1 << 1,
351 CF_NO_CONTACT_RESPONSE = 1 << 2,
352 CF_CUSTOM_MATERIAL_CALLBACK = 1 << 3,
353 CF_CHARACTER_OBJECT = 1 << 4,
354 CF_DISABLE_VISUALIZE_OBJECT = 1 << 5,
355 CF_DISABLE_SPU_COLLISION_PROCESS = 1 << 6,
356 // Following used by BulletSim to control collisions
357 BS_SUBSCRIBE_COLLISION_EVENTS = 1 << 10,
358 BS_FLOATS_ON_WATER = 1 << 11,
359 BS_NONE = 0,
360 BS_ALL = 0xFFFFFFFF,
361
362 // These are the collision flags switched depending on physical state.
363 // The other flags are used for other things and should not be fooled with.
364 BS_ACTIVE = CF_STATIC_OBJECT
365 | CF_KINEMATIC_OBJECT
366 | CF_NO_CONTACT_RESPONSE
367};
368
369// Values for collisions groups and masks
370public enum CollisionFilterGroups : uint
371{
372 // Don't use the bit definitions!! Define the use in a
373 // filter/mask definition below. This way collision interactions
374 // are more easily debugged.
375 BNoneFilter = 0,
376 BDefaultFilter = 1 << 0,
377 BStaticFilter = 1 << 1,
378 BKinematicFilter = 1 << 2,
379 BDebrisFilter = 1 << 3,
380 BSensorTrigger = 1 << 4,
381 BCharacterFilter = 1 << 5,
382 BAllFilter = 0xFFFFFFFF,
383 // Filter groups defined by BulletSim
384 BGroundPlaneFilter = 1 << 10,
385 BTerrainFilter = 1 << 11,
386 BRaycastFilter = 1 << 12,
387 BSolidFilter = 1 << 13,
388 BLinksetFilter = 1 << 14,
389
390 // The collsion filters and masked are defined in one place -- don't want them scattered
391 AvatarFilter = BCharacterFilter,
392 AvatarMask = BAllFilter,
393 ObjectFilter = BSolidFilter,
394 ObjectMask = BAllFilter,
395 StaticObjectFilter = BStaticFilter,
396 StaticObjectMask = BAllFilter & ~BStaticFilter, // static objects don't collide with each other
397 LinksetFilter = BLinksetFilter,
398 LinksetMask = BAllFilter & ~BLinksetFilter, // linkset objects don't collide with each other
399 VolumeDetectFilter = BSensorTrigger,
400 VolumeDetectMask = ~BSensorTrigger,
401 TerrainFilter = BTerrainFilter,
402 TerrainMask = BAllFilter & ~BStaticFilter, // static objects on the ground don't collide
403 GroundPlaneFilter = BGroundPlaneFilter,
404 GroundPlaneMask = BAllFilter
405
406};
407
408// CFM controls the 'hardness' of the constraint. 0=fixed, 0..1=violatable. Default=0
409// ERP controls amount of correction per tick. Usable range=0.1..0.8. Default=0.2.
410public enum ConstraintParams : int
411{
412 BT_CONSTRAINT_ERP = 1, // this one is not used in Bullet as of 20120730
413 BT_CONSTRAINT_STOP_ERP,
414 BT_CONSTRAINT_CFM,
415 BT_CONSTRAINT_STOP_CFM,
416};
417public enum ConstraintParamAxis : int
418{
419 AXIS_LINEAR_X = 0,
420 AXIS_LINEAR_Y,
421 AXIS_LINEAR_Z,
422 AXIS_ANGULAR_X,
423 AXIS_ANGULAR_Y,
424 AXIS_ANGULAR_Z,
425 AXIS_LINEAR_ALL = 20, // these last three added by BulletSim so we don't have to do zillions of calls
426 AXIS_ANGULAR_ALL,
427 AXIS_ALL
428};
429
430// ===============================================================================
431static class BulletSimAPI {
432
433// Link back to the managed code for outputting log messages
434[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
435public delegate void DebugLogCallback([MarshalAs(UnmanagedType.LPStr)]string msg);
436
437// ===============================================================================
438// Initialization and simulation
439[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
440public static extern IntPtr Initialize2(Vector3 maxPosition, IntPtr parms,
441 int maxCollisions, IntPtr collisionArray,
442 int maxUpdates, IntPtr updateArray,
443 DebugLogCallback logRoutine);
444
445[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
446public static extern bool UpdateParameter2(IntPtr world, uint localID, String parm, float value);
447
448[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
449public static extern void SetHeightMap2(IntPtr world, float[] heightmap);
450
451[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
452public static extern void Shutdown2(IntPtr sim);
453
454[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
455public static extern int PhysicsStep2(IntPtr world, float timeStep, int maxSubSteps, float fixedTimeStep,
456 out int updatedEntityCount,
457 out IntPtr updatedEntitiesPtr,
458 out int collidersCount,
459 out IntPtr collidersPtr);
460
461[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
462public static extern bool PushUpdate2(IntPtr obj);
463
464// =====================================================================================
465// Mesh, hull, shape and body creation helper routines
466[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
467public static extern IntPtr CreateMeshShape2(IntPtr world,
468 int indicesCount, [MarshalAs(UnmanagedType.LPArray)] int[] indices,
469 int verticesCount, [MarshalAs(UnmanagedType.LPArray)] float[] vertices );
470
471[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
472public static extern IntPtr CreateHullShape2(IntPtr world,
473 int hullCount, [MarshalAs(UnmanagedType.LPArray)] float[] hulls);
474
475[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
476public static extern IntPtr BuildHullShapeFromMesh2(IntPtr world, IntPtr meshShape);
477
478[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
479public static extern IntPtr BuildNativeShape2(IntPtr world, ShapeData shapeData);
480
481[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
482public static extern bool IsNativeShape2(IntPtr shape);
483
484[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
485public static extern IntPtr BuildCapsuleShape2(IntPtr world, float radius, float height, Vector3 scale);
486
487[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
488public static extern IntPtr CreateCompoundShape2(IntPtr sim, bool enableDynamicAabbTree);
489
490[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
491public static extern int GetNumberOfCompoundChildren2(IntPtr cShape);
492
493[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
494public static extern void AddChildShapeToCompoundShape2(IntPtr cShape, IntPtr addShape, Vector3 pos, Quaternion rot);
495
496[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
497public static extern IntPtr GetChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
498
499[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
500public static extern IntPtr RemoveChildShapeFromCompoundShapeIndex2(IntPtr cShape, int indx);
501
502[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
503public static extern void RemoveChildShapeFromCompoundShape2(IntPtr cShape, IntPtr removeShape);
504
505[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
506public static extern void RecalculateCompoundShapeLocalAabb2(IntPtr cShape);
507
508[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
509public static extern IntPtr DuplicateCollisionShape2(IntPtr sim, IntPtr srcShape, uint id);
510
511[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
512public static extern IntPtr CreateBodyFromShapeAndInfo2(IntPtr sim, IntPtr shape, uint id, IntPtr constructionInfo);
513
514[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
515public static extern bool DeleteCollisionShape2(IntPtr world, IntPtr shape);
516
517[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
518public static extern int GetBodyType2(IntPtr obj);
519
520[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
521public static extern IntPtr CreateBodyFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
522
523[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
524public static extern IntPtr CreateBodyWithDefaultMotionState2(IntPtr shape, uint id, Vector3 pos, Quaternion rot);
525
526[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
527public static extern IntPtr CreateGhostFromShape2(IntPtr sim, IntPtr shape, uint id, Vector3 pos, Quaternion rot);
528
529[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
530public static extern IntPtr AllocateBodyInfo2(IntPtr obj);
531
532[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
533public static extern void ReleaseBodyInfo2(IntPtr obj);
534
535[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
536public static extern void DestroyObject2(IntPtr sim, IntPtr obj);
537
538// =====================================================================================
539// Terrain creation and helper routines
540[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
541public static extern IntPtr CreateHeightMapInfo2(IntPtr sim, uint id, Vector3 minCoords, Vector3 maxCoords,
542 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
543
544[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
545public static extern IntPtr FillHeightMapInfo2(IntPtr sim, IntPtr mapInfo, uint id, Vector3 minCoords, Vector3 maxCoords,
546 [MarshalAs(UnmanagedType.LPArray)] float[] heightMap, float collisionMargin);
547
548[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
549public static extern bool ReleaseHeightMapInfo2(IntPtr heightMapInfo);
550
551[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
552public static extern IntPtr CreateGroundPlaneShape2(uint id, float height, float collisionMargin);
553
554[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
555public static extern IntPtr CreateTerrainShape2(IntPtr mapInfo);
556
557// =====================================================================================
558// Constraint creation and helper routines
559[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
560public static extern IntPtr Create6DofConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
561 Vector3 frame1loc, Quaternion frame1rot,
562 Vector3 frame2loc, Quaternion frame2rot,
563 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
564
565[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
566public static extern IntPtr Create6DofConstraintToPoint2(IntPtr world, IntPtr obj1, IntPtr obj2,
567 Vector3 joinPoint,
568 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
569
570[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
571public static extern IntPtr CreateHingeConstraint2(IntPtr world, IntPtr obj1, IntPtr obj2,
572 Vector3 pivotinA, Vector3 pivotinB,
573 Vector3 axisInA, Vector3 axisInB,
574 bool useLinearReferenceFrameA, bool disableCollisionsBetweenLinkedBodies);
575
576[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
577public static extern void SetConstraintEnable2(IntPtr constrain, float numericTrueFalse);
578
579[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
580public static extern void SetConstraintNumSolverIterations2(IntPtr constrain, float iterations);
581
582[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
583public static extern bool SetFrames2(IntPtr constrain,
584 Vector3 frameA, Quaternion frameArot, Vector3 frameB, Quaternion frameBrot);
585
586[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
587public static extern bool SetLinearLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
588
589[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
590public static extern bool SetAngularLimits2(IntPtr constrain, Vector3 low, Vector3 hi);
591
592[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
593public static extern bool UseFrameOffset2(IntPtr constrain, float enable);
594
595[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
596public static extern bool TranslationalLimitMotor2(IntPtr constrain, float enable, float targetVel, float maxMotorForce);
597
598[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
599public static extern bool SetBreakingImpulseThreshold2(IntPtr constrain, float threshold);
600
601[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
602public static extern bool CalculateTransforms2(IntPtr constrain);
603
604[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
605public static extern bool SetConstraintParam2(IntPtr constrain, ConstraintParams paramIndex, float value, ConstraintParamAxis axis);
606
607[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
608public static extern bool DestroyConstraint2(IntPtr world, IntPtr constrain);
609
610// =====================================================================================
611// btCollisionWorld entries
612[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
613public static extern void UpdateSingleAabb2(IntPtr world, IntPtr obj);
614
615[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
616public static extern void UpdateAabbs2(IntPtr world);
617
618[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
619public static extern bool GetForceUpdateAllAabbs2(IntPtr world);
620
621[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
622public static extern void SetForceUpdateAllAabbs2(IntPtr world, bool force);
623
624// =====================================================================================
625// btDynamicsWorld entries
626[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
627public static extern bool AddObjectToWorld2(IntPtr world, IntPtr obj);
628
629[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
630public static extern bool RemoveObjectFromWorld2(IntPtr world, IntPtr obj);
631
632[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
633public static extern bool AddConstraintToWorld2(IntPtr world, IntPtr constrain, bool disableCollisionsBetweenLinkedObjects);
634
635[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
636public static extern bool RemoveConstraintFromWorld2(IntPtr world, IntPtr constrain);
637// =====================================================================================
638// btCollisionObject entries
639[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
640public static extern Vector3 GetAnisotripicFriction2(IntPtr constrain);
641
642[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
643public static extern Vector3 SetAnisotripicFriction2(IntPtr constrain, Vector3 frict);
644
645[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
646public static extern bool HasAnisotripicFriction2(IntPtr constrain);
647
648[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
649public static extern void SetContactProcessingThreshold2(IntPtr obj, float val);
650
651[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
652public static extern float GetContactProcessingThreshold2(IntPtr obj);
653
654[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
655public static extern bool IsStaticObject2(IntPtr obj);
656
657[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
658public static extern bool IsKinematicObject2(IntPtr obj);
659
660[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
661public static extern bool IsStaticOrKinematicObject2(IntPtr obj);
662
663[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
664public static extern bool HasContactResponse2(IntPtr obj);
665
666[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
667public static extern void SetCollisionShape2(IntPtr sim, IntPtr obj, IntPtr shape);
668
669[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
670public static extern IntPtr GetCollisionShape2(IntPtr obj);
671
672[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
673public static extern int GetActivationState2(IntPtr obj);
674
675[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
676public static extern void SetActivationState2(IntPtr obj, int state);
677
678[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
679public static extern void SetDeactivationTime2(IntPtr obj, float dtime);
680
681[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
682public static extern float GetDeactivationTime2(IntPtr obj);
683
684[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
685public static extern void ForceActivationState2(IntPtr obj, ActivationState state);
686
687[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
688public static extern void Activate2(IntPtr obj, bool forceActivation);
689
690[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
691public static extern bool IsActive2(IntPtr obj);
692
693[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
694public static extern void SetRestitution2(IntPtr obj, float val);
695
696[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
697public static extern float GetRestitution2(IntPtr obj);
698
699[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
700public static extern void SetFriction2(IntPtr obj, float val);
701
702[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
703public static extern float GetFriction2(IntPtr obj);
704
705 /* Haven't defined the type 'Transform'
706[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
707public static extern Transform GetWorldTransform2(IntPtr obj);
708
709[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
710public static extern void setWorldTransform2(IntPtr obj, Transform trans);
711 */
712
713[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
714public static extern Vector3 GetPosition2(IntPtr obj);
715
716[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
717public static extern Quaternion GetOrientation2(IntPtr obj);
718
719[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
720public static extern void SetTranslation2(IntPtr obj, Vector3 position, Quaternion rotation);
721
722[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
723public static extern IntPtr GetBroadphaseHandle2(IntPtr obj);
724
725[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
726public static extern void SetBroadphaseHandle2(IntPtr obj, IntPtr handle);
727
728 /*
729[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
730public static extern Transform GetInterpolationWorldTransform2(IntPtr obj);
731
732[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
733public static extern void SetInterpolationWorldTransform2(IntPtr obj, Transform trans);
734 */
735
736[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
737public static extern void SetInterpolationLinearVelocity2(IntPtr obj, Vector3 vel);
738
739[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
740public static extern void SetInterpolationAngularVelocity2(IntPtr obj, Vector3 vel);
741
742[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
743public static extern void SetInterpolationVelocity2(IntPtr obj, Vector3 linearVel, Vector3 angularVel);
744
745[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
746public static extern float GetHitFraction2(IntPtr obj);
747
748[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
749public static extern void SetHitFraction2(IntPtr obj, float val);
750
751[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
752public static extern CollisionFlags GetCollisionFlags2(IntPtr obj);
753
754[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
755public static extern CollisionFlags SetCollisionFlags2(IntPtr obj, CollisionFlags flags);
756
757[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
758public static extern CollisionFlags AddToCollisionFlags2(IntPtr obj, CollisionFlags flags);
759
760[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
761public static extern CollisionFlags RemoveFromCollisionFlags2(IntPtr obj, CollisionFlags flags);
762
763[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
764public static extern float GetCcdMotionThreshold2(IntPtr obj);
765
766[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
767public static extern void SetCcdMotionThreshold2(IntPtr obj, float val);
768
769[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
770public static extern float GetCcdSweptSphereRadius2(IntPtr obj);
771
772[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
773public static extern void SetCcdSweptSphereRadius2(IntPtr obj, float val);
774
775[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
776public static extern IntPtr GetUserPointer2(IntPtr obj);
777
778[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
779public static extern void SetUserPointer2(IntPtr obj, IntPtr val);
780
781// =====================================================================================
782// btRigidBody entries
783[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
784public static extern void ApplyGravity2(IntPtr obj);
785
786[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
787public static extern void SetGravity2(IntPtr obj, Vector3 val);
788
789[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
790public static extern Vector3 GetGravity2(IntPtr obj);
791
792[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
793public static extern void SetDamping2(IntPtr obj, float lin_damping, float ang_damping);
794
795[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
796public static extern void SetLinearDamping2(IntPtr obj, float lin_damping);
797
798[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
799public static extern void SetAngularDamping2(IntPtr obj, float ang_damping);
800
801[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
802public static extern float GetLinearDamping2(IntPtr obj);
803
804[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
805public static extern float GetAngularDamping2(IntPtr obj);
806
807[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
808public static extern float GetLinearSleepingThreshold2(IntPtr obj);
809
810[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
811public static extern float GetAngularSleepingThreshold2(IntPtr obj);
812
813[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
814public static extern void ApplyDamping2(IntPtr obj, float timeStep);
815
816[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
817public static extern void SetMassProps2(IntPtr obj, float mass, Vector3 inertia);
818
819[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
820public static extern Vector3 GetLinearFactor2(IntPtr obj);
821
822[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
823public static extern void SetLinearFactor2(IntPtr obj, Vector3 factor);
824
825 /*
826[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
827public static extern void SetCenterOfMassTransform2(IntPtr obj, Transform trans);
828 */
829
830[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
831public static extern void SetCenterOfMassByPosRot2(IntPtr obj, Vector3 pos, Quaternion rot);
832
833// Add a force to the object as if its mass is one.
834[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
835public static extern void ApplyCentralForce2(IntPtr obj, Vector3 force);
836
837// Set the force being applied to the object as if its mass is one.
838[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
839public static extern void SetObjectForce2(IntPtr obj, Vector3 force);
840
841[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
842public static extern Vector3 GetTotalForce2(IntPtr obj);
843
844[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
845public static extern Vector3 GetTotalTorque2(IntPtr obj);
846
847[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
848public static extern Vector3 GetInvInertiaDiagLocal2(IntPtr obj);
849
850[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
851public static extern void SetInvInertiaDiagLocal2(IntPtr obj, Vector3 inert);
852
853[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
854public static extern void SetSleepingThresholds2(IntPtr obj, float lin_threshold, float ang_threshold);
855
856[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
857public static extern void ApplyTorque2(IntPtr obj, Vector3 torque);
858
859// Apply force at the given point. Will add torque to the object.
860[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
861public static extern void ApplyForce2(IntPtr obj, Vector3 force, Vector3 pos);
862
863// Apply impulse to the object. Same as "ApplycentralForce" but force scaled by object's mass.
864[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
865public static extern void ApplyCentralImpulse2(IntPtr obj, Vector3 imp);
866
867// Apply impulse to the object's torque. Force is scaled by object's mass.
868[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
869public static extern void ApplyTorqueImpulse2(IntPtr obj, Vector3 imp);
870
871// Apply impulse at the point given. For is scaled by object's mass and effects both linear and angular forces.
872[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
873public static extern void ApplyImpulse2(IntPtr obj, Vector3 imp, Vector3 pos);
874
875[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
876public static extern void ClearForces2(IntPtr obj);
877
878[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
879public static extern void ClearAllForces2(IntPtr obj);
880
881[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
882public static extern void UpdateInertiaTensor2(IntPtr obj);
883
884[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
885public static extern Vector3 GetCenterOfMassPosition2(IntPtr obj);
886
887 /*
888[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
889public static extern Transform GetCenterOfMassTransform2(IntPtr obj);
890 */
891
892[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
893public static extern Vector3 GetLinearVelocity2(IntPtr obj);
894
895[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
896public static extern Vector3 GetAngularVelocity2(IntPtr obj);
897
898[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
899public static extern void SetLinearVelocity2(IntPtr obj, Vector3 val);
900
901[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
902public static extern void SetAngularVelocity2(IntPtr obj, Vector3 angularVelocity);
903
904[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
905public static extern Vector3 GetVelocityInLocalPoint2(IntPtr obj, Vector3 pos);
906
907[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
908public static extern void Translate2(IntPtr obj, Vector3 trans);
909
910[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
911public static extern void UpdateDeactivation2(IntPtr obj, float timeStep);
912
913[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
914public static extern bool WantsSleeping2(IntPtr obj);
915
916[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
917public static extern void SetAngularFactor2(IntPtr obj, float factor);
918
919[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
920public static extern void SetAngularFactorV2(IntPtr obj, Vector3 factor);
921
922[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
923public static extern Vector3 GetAngularFactor2(IntPtr obj);
924
925[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
926public static extern bool IsInWorld2(IntPtr obj);
927
928[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
929public static extern void AddConstraintRef2(IntPtr obj, IntPtr constrain);
930
931[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
932public static extern void RemoveConstraintRef2(IntPtr obj, IntPtr constrain);
933
934[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
935public static extern IntPtr GetConstraintRef2(IntPtr obj, int index);
936
937[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
938public static extern int GetNumConstraintRefs2(IntPtr obj);
939
940[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
941public static extern void SetCollisionFilterMask2(IntPtr body, uint filter, uint mask);
942
943// =====================================================================================
944// btCollisionShape entries
945
946[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
947public static extern float GetAngularMotionDisc2(IntPtr shape);
948
949[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
950public static extern float GetContactBreakingThreshold2(IntPtr shape, float defaultFactor);
951
952[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
953public static extern bool IsPolyhedral2(IntPtr shape);
954
955[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
956public static extern bool IsConvex2d2(IntPtr shape);
957
958[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
959public static extern bool IsConvex2(IntPtr shape);
960
961[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
962public static extern bool IsNonMoving2(IntPtr shape);
963
964[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
965public static extern bool IsConcave2(IntPtr shape);
966
967[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
968public static extern bool IsCompound2(IntPtr shape);
969
970[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
971public static extern bool IsSoftBody2(IntPtr shape);
972
973[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
974public static extern bool IsInfinite2(IntPtr shape);
975
976[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
977public static extern void SetLocalScaling2(IntPtr shape, Vector3 scale);
978
979[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
980public static extern Vector3 GetLocalScaling2(IntPtr shape);
981
982[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
983public static extern Vector3 CalculateLocalInertia2(IntPtr shape, float mass);
984
985[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
986public static extern int GetShapeType2(IntPtr shape);
987
988[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
989public static extern void SetMargin2(IntPtr shape, float val);
990
991[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
992public static extern float GetMargin2(IntPtr shape);
993
994// =====================================================================================
995// Debugging
996[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
997public static extern void DumpRigidBody2(IntPtr sim, IntPtr collisionObject);
998
999[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1000public static extern void DumpCollisionShape2(IntPtr sim, IntPtr collisionShape);
1001
1002[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1003public static extern void DumpConstraint2(IntPtr sim, IntPtr constrain);
1004
1005[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1006public static extern void DumpAllInfo2(IntPtr sim);
1007
1008[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1009public static extern void DumpMapInfo2(IntPtr sim, IntPtr manInfo);
1010
1011[DllImport("BulletSim", CallingConvention = CallingConvention.Cdecl), SuppressUnmanagedCodeSecurity]
1012public static extern void DumpPhysicsStatistics2(IntPtr sim);
1013
1014}
1015}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
new file mode 100755
index 0000000..662dd68
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimData.cs
@@ -0,0 +1,263 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyrightD
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Text;
30using OMV = OpenMetaverse;
31
32namespace OpenSim.Region.Physics.BulletSPlugin
33{
34// Classes to allow some type checking for the API
35// These hold pointers to allocated objects in the unmanaged space.
36// These classes are subclassed by the various physical implementations of
37// objects. In particular, there is a version for physical instances in
38// unmanaged memory ("unman") and one for in managed memory ("XNA").
39
40// Currently, the instances of these classes are a reference to a
41// physical representation and this has no releationship to other
42// instances. Someday, refarb the usage of these classes so each instance
43// refers to a particular physical instance and this class controls reference
44// counts and such. This should be done along with adding BSShapes.
45
46public class BulletWorld
47{
48 public BulletWorld(uint worldId, BSScene bss)
49 {
50 worldID = worldId;
51 physicsScene = bss;
52 }
53 public uint worldID;
54 // The scene is only in here so very low level routines have a handle to print debug/error messages
55 public BSScene physicsScene;
56}
57
58// An allocated Bullet btRigidBody
59public class BulletBody
60{
61 public BulletBody(uint id)
62 {
63 ID = id;
64 collisionType = CollisionType.Static;
65 }
66 public uint ID;
67 public CollisionType collisionType;
68
69 public virtual void Clear() { }
70 public virtual bool HasPhysicalBody { get { return false; } }
71
72 // Apply the specificed collision mask into the physical world
73 public virtual bool ApplyCollisionMask(BSScene physicsScene)
74 {
75 // Should assert the body has been added to the physical world.
76 // (The collision masks are stored in the collision proxy cache which only exists for
77 // a collision body that is in the world.)
78 return physicsScene.PE.SetCollisionGroupMask(this,
79 BulletSimData.CollisionTypeMasks[collisionType].group,
80 BulletSimData.CollisionTypeMasks[collisionType].mask);
81 }
82
83 // Used for log messages for a unique display of the memory/object allocated to this instance
84 public virtual string AddrString
85 {
86 get { return "unknown"; }
87 }
88
89 public override string ToString()
90 {
91 StringBuilder buff = new StringBuilder();
92 buff.Append("<id=");
93 buff.Append(ID.ToString());
94 buff.Append(",p=");
95 buff.Append(AddrString);
96 buff.Append(",c=");
97 buff.Append(collisionType);
98 buff.Append(">");
99 return buff.ToString();
100 }
101}
102
103public class BulletShape
104{
105 public BulletShape()
106 {
107 type = BSPhysicsShapeType.SHAPE_UNKNOWN;
108 shapeKey = (System.UInt64)FixedShapeKey.KEY_NONE;
109 isNativeShape = false;
110 }
111 public BSPhysicsShapeType type;
112 public System.UInt64 shapeKey;
113 public bool isNativeShape;
114
115 public virtual void Clear() { }
116 public virtual bool HasPhysicalShape { get { return false; } }
117 // Make another reference to this physical object.
118 public virtual BulletShape Clone() { return new BulletShape(); }
119 // Return 'true' if this and other refer to the same physical object
120 public virtual bool ReferenceSame(BulletShape xx) { return false; }
121
122 // Used for log messages for a unique display of the memory/object allocated to this instance
123 public virtual string AddrString
124 {
125 get { return "unknown"; }
126 }
127
128 public override string ToString()
129 {
130 StringBuilder buff = new StringBuilder();
131 buff.Append("<p=");
132 buff.Append(AddrString);
133 buff.Append(",s=");
134 buff.Append(type.ToString());
135 buff.Append(",k=");
136 buff.Append(shapeKey.ToString("X"));
137 buff.Append(",n=");
138 buff.Append(isNativeShape.ToString());
139 buff.Append(">");
140 return buff.ToString();
141 }
142}
143
144// An allocated Bullet btConstraint
145public class BulletConstraint
146{
147 public BulletConstraint()
148 {
149 }
150 public virtual void Clear() { }
151 public virtual bool HasPhysicalConstraint { get { return false; } }
152
153 // Used for log messages for a unique display of the memory/object allocated to this instance
154 public virtual string AddrString
155 {
156 get { return "unknown"; }
157 }
158}
159
160// An allocated HeightMapThing which holds various heightmap info.
161// Made a class rather than a struct so there would be only one
162// instance of this and C# will pass around pointers rather
163// than making copies.
164public class BulletHMapInfo
165{
166 public BulletHMapInfo(uint id, float[] hm) {
167 ID = id;
168 heightMap = hm;
169 terrainRegionBase = OMV.Vector3.Zero;
170 minCoords = new OMV.Vector3(100f, 100f, 25f);
171 maxCoords = new OMV.Vector3(101f, 101f, 26f);
172 minZ = maxZ = 0f;
173 sizeX = sizeY = 256f;
174 }
175 public uint ID;
176 public float[] heightMap;
177 public OMV.Vector3 terrainRegionBase;
178 public OMV.Vector3 minCoords;
179 public OMV.Vector3 maxCoords;
180 public float sizeX, sizeY;
181 public float minZ, maxZ;
182 public BulletShape terrainShape;
183 public BulletBody terrainBody;
184}
185
186// The general class of collsion object.
187public enum CollisionType
188{
189 Avatar,
190 Groundplane,
191 Terrain,
192 Static,
193 Dynamic,
194 VolumeDetect,
195 // Linkset, // A linkset should be either Static or Dynamic
196 LinksetChild,
197 Unknown
198};
199
200// Hold specification of group and mask collision flags for a CollisionType
201public struct CollisionTypeFilterGroup
202{
203 public CollisionTypeFilterGroup(CollisionType t, uint g, uint m)
204 {
205 type = t;
206 group = g;
207 mask = m;
208 }
209 public CollisionType type;
210 public uint group;
211 public uint mask;
212};
213
214public static class BulletSimData
215{
216
217// Map of collisionTypes to flags for collision groups and masks.
218// As mentioned above, don't use the CollisionFilterGroups definitions directly in the code
219// but, instead, use references to this dictionary. Finding and debugging
220// collision flag problems will be made easier.
221public static Dictionary<CollisionType, CollisionTypeFilterGroup> CollisionTypeMasks
222 = new Dictionary<CollisionType, CollisionTypeFilterGroup>()
223{
224 { CollisionType.Avatar,
225 new CollisionTypeFilterGroup(CollisionType.Avatar,
226 (uint)CollisionFilterGroups.BCharacterGroup,
227 (uint)CollisionFilterGroups.BAllGroup)
228 },
229 { CollisionType.Groundplane,
230 new CollisionTypeFilterGroup(CollisionType.Groundplane,
231 (uint)CollisionFilterGroups.BGroundPlaneGroup,
232 (uint)CollisionFilterGroups.BAllGroup)
233 },
234 { CollisionType.Terrain,
235 new CollisionTypeFilterGroup(CollisionType.Terrain,
236 (uint)CollisionFilterGroups.BTerrainGroup,
237 (uint)(CollisionFilterGroups.BAllGroup & ~CollisionFilterGroups.BStaticGroup))
238 },
239 { CollisionType.Static,
240 new CollisionTypeFilterGroup(CollisionType.Static,
241 (uint)CollisionFilterGroups.BStaticGroup,
242 (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
243 },
244 { CollisionType.Dynamic,
245 new CollisionTypeFilterGroup(CollisionType.Dynamic,
246 (uint)CollisionFilterGroups.BSolidGroup,
247 (uint)(CollisionFilterGroups.BAllGroup))
248 },
249 { CollisionType.VolumeDetect,
250 new CollisionTypeFilterGroup(CollisionType.VolumeDetect,
251 (uint)CollisionFilterGroups.BSensorTrigger,
252 (uint)(~CollisionFilterGroups.BSensorTrigger))
253 },
254 { CollisionType.LinksetChild,
255 new CollisionTypeFilterGroup(CollisionType.LinksetChild,
256 (uint)CollisionFilterGroups.BLinksetChildGroup,
257 (uint)(CollisionFilterGroups.BNoneGroup))
258 // (uint)(CollisionFilterGroups.BCharacterGroup | CollisionFilterGroups.BSolidGroup))
259 },
260};
261
262}
263}
diff --git a/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
new file mode 100755
index 0000000..facf720
--- /dev/null
+++ b/OpenSim/Region/Physics/BulletSPlugin/BulletSimTODO.txt
@@ -0,0 +1,276 @@
1CURRENT PRIORITIES
2=================================================
3Redo BulletSimAPI to allow native C# implementation of Bullet option (DONE)
4Meshes rendering as bounding boxes
5llMoveToTarget
6Vehicle movement on terrain smoothness
7limitMotorUp calibration (more down?)
8Preferred orientatino angular correction fix
9Surfboard go wonky when turning
10 Angular motor direction is global coordinates rather than local coordinates?
11Boats float low in the water
12Avatar movement
13 flying into a wall doesn't stop avatar who keeps appearing to move through the obstacle (DONE)
14 walking up stairs is not calibrated correctly (stairs out of Kepler cabin)
15 avatar capsule rotation completed (NOT DONE - Bullet's capsule shape is not the solution)
16Enable vehicle border crossings (at least as poorly as ODE)
17 Terrain skirts
18 Avatar created in previous region and not new region when crossing border
19 Vehicle recreated in new sim at small Z value (offset from root value?) (DONE)
20Vehicle script tuning/debugging
21 Avanti speed script
22 Weapon shooter script
23Add material densities to the material types
24
25CRASHES
26=================================================
2720121129.1411: editting/moving phys object across region boundries causes crash
28 getPos-> btRigidBody::upcast -> getBodyType -> BOOM
2920121128.1600: mesh object not rezzing (no physics mesh).
30 Causes many errors. Doesn't stop after first error with box shape.
31 Eventually crashes when deleting the object.
3220121206.1434: rez Sam-pan into OSGrid BulletSim11 region
33 Immediate simulator crash. Mono does not output any stacktrace and
34 log just stops after reporting taint-time linking of the linkset.
35
36VEHICLES TODO LIST:
37=================================================
38Angular motor direction is global coordinates rather than local coordinates
39Border crossing with linked vehicle causes crash
40Vehicles (Move smoothly)
41Add vehicle collisions so IsColliding is properly reported.
42 Needed for banking, limitMotorUp, movementLimiting, ...
43VehicleAddForce is not scaled by the simulation step but it is only
44 applied for one step. Should it be scaled?
45Some vehicles should not be able to turn if no speed or off ground.
46Cannot edit/move a vehicle being ridden: it jumps back to the origional position.
47Neb car jiggling left and right
48 Happens on terrain and any other mesh object. Flat cubes are much smoother.
49 This has been reduced but not eliminated.
50Implement referenceFrame for all the motion routines.
51Angular motion around Z moves the vehicle in world Z and not vehicle Z in ODE.
52 Verify that angular motion specified around Z moves in the vehicle coordinates.
53Verify llGetVel() is returning a smooth and good value for vehicle movement.
54llGetVel() should return the root's velocity if requested in a child prim.
55Implement function efficiency for lineaar and angular motion.
56After getting off a vehicle, the root prim is phantom (can be walked through)
57 Need to force a position update for the root prim after compound shape destruction
58Linkset explosion after three "rides" on Nebadon lite vehicle (LinksetConstraint)
59For limitMotorUp, use raycast down to find if vehicle is in the air.
60Remove vehicle angular velocity zeroing in BSPrim.UpdateProperties().
61 A kludge that isn't fixing the real problem of Bullet adding extra motion.
62Incorporate inter-relationship of angular corrections. For instance, angularDeflection
63 and angularMotorUp will compute same X or Y correction. When added together
64 creates over-correction and over-shoot and wabbling.
65
66BULLETSIM TODO LIST:
67=================================================
68Implement an avatar mesh shape. The Bullet capsule is way too limited.
69 Consider just hand creating a vertex/index array in a new BSShapeAvatar.
70Revisit CollisionMargin. Builders notice the 0.04 spacing between prims.
71Duplicating a physical prim causes old prim to jump away
72 Dup a phys prim and the original become unselected and thus interacts w/ selected prim.
73Scenes with hundred of thousands of static objects take a lot of physics CPU time.
74BSPrim.Force should set a continious force on the prim. The force should be
75 applied each tick. Some limits?
76Gun sending shooter flying.
77Collision margin (gap between physical objects lying on each other)
78Boundry checking (crashes related to crossing boundry)
79 Add check for border edge position for avatars and objects.
80 Verify the events are created for border crossings.
81Avatar rotation (check out changes to ScenePresence for physical rotation)
82Avatar running (what does phys engine need to do?)
83Small physical objects do not interact correctly
84 Create chain of .5x.5x.1 torui and make all but top physical so to hang.
85 The chain will fall apart and pairs will dance around on ground
86 Chains of 1x1x.2 will stay connected but will dance.
87 Chains above 2x2x.4 are more stable and get stablier as torui get larger.
88Add PID motor for avatar movement (slow to stop, ...)
89setForce should set a constant force. Different than AddImpulse.
90Implement raycast.
91Implement ShapeCollection.Dispose()
92Implement water as a plain so raycasting and collisions can happen with same.
93Add osGetPhysicsEngineName() so scripters can tell whether BulletSim or ODE
94 Also osGetPhysicsEngineVerion() maybe.
95Linkset.Position and Linkset.Orientation requre rewrite to properly return
96 child position. LinksetConstraint acts like it's at taint time!!
97Implement LockAngularMotion -- implements llSetStatus(ROTATE_AXIS_*, T/F)
98Should the different PID factors have non-equal contributions for different
99 values of Efficiency?
100Selecting and deselecting physical objects causes CPU processing time to jump
101 http://www.youtube.com/watch?v=Hjg57fWg8yI&hd=1
102 put thousand physical objects, select and deselect same. CPU time will be large.
103Re-implement buoyancy as a separate force on the object rather than diddling gravity.
104 Register a pre-step event to add the force.
105More efficient memory usage when passing hull information from BSPrim to BulletSim
106Avatar movement motor check for zero or small movement. Somehow suppress small movements
107 when avatar has stopped and is just standing. Simple test for near zero has
108 the problem of preventing starting up (increase from zero) especially when falling.
109Physical and phantom will drop through the terrain
110
111
112LINKSETS
113======================================================
114Offset the center of the linkset to be the geometric center of all the prims
115 Not quite the same as the center-of-gravity
116Linksets should allow collisions to individual children
117 Add LocalID to children shapes in LinksetCompound and create events for individuals
118LinksetCompound: when one of the children changes orientation (like tires
119 turning on a vehicle, the whole compound object is rebuilt. Optimize this
120 so orientation/position of individual children can change without a rebuild.
121Verify/think through scripts in children of linksets. What do they reference
122 and return when getting position, velocity, ...
123Confirm constraint linksets still work after making all the changes for compound linksets.
124Add 'changed' flag or similar to reduce the number of times a linkset is rebuilt.
125 For compound linksets, add ability to remove or reposition individual child shapes.
126Disable activity of passive linkset children.
127 Since the linkset is a compound object, the old prims are left lying
128 around and need to be phantomized so they don't collide, ...
129Speed up creation of large physical linksets
130 For instance, sitting in Neb's car (130 prims) takes several seconds to become physical.
131 REALLY bad for very large physical linksets (freezes the sim for many seconds).
132Eliminate collisions between objects in a linkset. (LinksetConstraint)
133 Have UserPointer point to struct with localID and linksetID?
134 Objects in original linkset still collide with each other?
135
136MORE
137======================================================
138Test avatar walking up stairs. How does compare with SL.
139 Radius of the capsule affects ability to climb edges.
140Debounce avatar contact so legs don't keep folding up when standing.
141Implement LSL physics controls. Like STATUS_ROTATE_X.
142Add border extensions to terrain to help region crossings and objects leaving region.
143Use a different capsule shape for avatar when sitting
144 LL uses a pyrimidal shape scaled by the avatar's bounding box
145 http://wiki.secondlife.com/wiki/File:Avmeshforms.png
146
147Performance test with lots of avatars. Can BulletSim support a thousand?
148Optimize collisions in C++: only send up to the object subscribed to collisions.
149 Use collision subscription and remove the collsion(A,B) and collision(B,A)
150Check whether SimMotionState needs large if statement (see TODO).
151
152Implement 'top colliders' info.
153Avatar jump
154Performance measurement and changes to make quicker.
155Implement detailed physics stats (GetStats()).
156
157Measure performance improvement from hulls
158Test not using ghost objects for volume detect implementation.
159Performance of closures and delegates for taint processing
160 Are there faster ways?
161 Is any slowdown introduced by the existing implementation significant?
162Is there are more efficient method of implementing pre and post step actions?
163 See http://www.codeproject.com/Articles/29922/Weak-Events-in-C
164
165Physics Arena central pyramid: why is one side permiable?
166
167In SL, perfect spheres don't seem to have rolling friction. Add special case.
168Enforce physical parameter min/max:
169 Gravity: [-1, 28]
170 Friction: [0, 255]
171 Density: [1, 22587]
172 Restitution [0, 1]
173 http://wiki.secondlife.com/wiki/Physics_Material_Settings_test
174Avatar attachments have no mass? http://forums-archive.secondlife.com/54/f0/31796/1.html
175
176INTERNAL IMPROVEMENT/CLEANUP
177=================================================
178Create the physical wrapper classes (BulletBody, BulletShape) by methods on
179 BSAPITemplate and make their actual implementation Bullet engine specific.
180 For the short term, just call the existing functions in ShapeCollection.
181Consider moving prim/character body and shape destruction in destroy()
182 to postTimeTime rather than protecting all the potential sets that
183 might have been queued up.
184Remove unused fields from ShapeData (not used in API2)
185Remove unused fields from pinned memory shared parameter block
186 Create parameter variables in BSScene to replace same.
187Breakout code for mesh/hull/compound/native into separate BSShape* classes
188 Standardize access to building and reference code.
189 The skeleton classes are in the sources but are not complete or linked in.
190Make BSBody and BSShape real classes to centralize creation/changin/destruction
191 Convert state and parameter calls from BulletSimAPI direct calls to
192 calls on BSBody and BSShape
193Generalize Dynamics and PID with standardized motors.
194Generalize Linkset and vehicles into PropertyManagers
195 Methods for Refresh, RemoveBodyDependencies, RestoreBodyDependencies
196 Potentially add events for shape destruction, etc.
197Complete implemention of preStepActions
198 Replace vehicle step call with prestep event.
199 Is there a need for postStepActions? postStepTaints?
200Implement linkset by setting position of children when root updated. (LinksetManual)
201 Linkset implementation using manual prim movement.
202LinkablePrim class? Would that simplify/centralize the linkset logic?
203BSScene.UpdateParameterSet() is broken. How to set params on objects?
204Remove HeightmapInfo from terrain specification
205 Since C++ code does not need terrain height, this structure et al are not needed.
206Add floating motor for BS_FLOATS_ON_WATER so prim and avatar will
207 bob at the water level. BSPrim.PositionSanityCheck().
208Should taints check for existance or activeness of target?
209 When destroying linksets/etc, taints can be generated for objects that are
210 actually gone when the taint happens. Crashes don't happen because the taint closure
211 keeps the object from being freed, but that is just an accident.
212 Possibly have and 'active' flag that is checked by the taint processor?
213Parameters for physics logging should be moved from BSScene to BSParam (at least boolean ones)
214Can some of the physical wrapper classes (BulletBody, BulletWorld, BulletShape) be 'sealed'?
215There are TOO MANY interfaces from BulletSim core to Bullet itself
216 Think of something to eliminate one or more of the layers
217
218THREADING
219=================================================
220Do taint action immediately if not actually executing Bullet.
221 Add lock around Bullet execution and just do taint actions if simulation is not happening.
222
223DONE DONE DONE DONE
224=================================================
225Cleanup code in BSDynamics by using motors. (Resolution: started)
226Consider implementing terrain with a mesh rather than heightmap. (Resolution: done)
227 Would have better and adjustable resolution.
228Build terrain mesh so heighmap is height of the center of the square meter.
229 Resolution: NOT DONE: SL and ODE define meter square as being at one corner with one diagional.
230Terrain as mesh. (Resolution: done)
231How are static linksets seen by the physics engine?
232 Resolution: they are not linked in physics. When moved, all the children are repositioned.
233Convert BSCharacter to use all API2 (Resolution: done)
234Avatar pushing difficult (too heavy?)
235Use asset service passed to BulletSim to get sculptie bodies, etc. (Resolution: done)
236Remove old code in DLL (all non-API2 stuff). (Resolution: done)
237Measurements of mega-physical prim performance (with graph) (Resolution: done, email)
238Debug Bullet internal stats output (why is timing all wrong?)
239 Resolution: Bullet stats logging only works with a single instance of Bullet (one region).
240Implement meshes or just verify that they work. (Resolution: they do!)
241Do prim hash codes work for sculpties and meshes? (Resolution: yes)
242Linkset implementation using compound shapes. (Resolution: implemented LinksetCompound)
243 Compound shapes will need the LocalID in the shapes and collision
244 processing to get it from there.
245Light cycle not banking (Resolution: It doesn't. Banking is roll adding yaw.)
246Package Bullet source mods for Bullet internal stats output
247 (Resolution: move code into WorldData.h rather than relying on patches)
248Single prim vehicles don't seem to properly vehiclize.
249 (Resolution: mass was not getting set properly for single prim linksets)
250Add material type linkage and input all the material property definitions.
251 Skeleton classes and table are in the sources but are not filled or used.
252 (Resolution:
253Neb vehicle taking > 25ms of physics time!!
254 (Resolution: compound linksets were being rebuild WAY too often)
255Avatar height off after unsitting (floats off ground)
256 Editting appearance then moving restores.
257 Must not be initializing height when recreating capsule after unsit.
258 (Resolution: confusion of scale vs size for native objects removed)
259Light cycle falling over when driving (Resolution: implemented angularMotorUp)
260Should vehicle angular/linear movement friction happen after all the components
261 or does it only apply to the basic movement?
262 (Resolution: friction added before returning newly computed motor value.
263 What is expected by some vehicles (turning up friction to moderate speed))
264Tune terrain/object friction to be closer to SL.
265 (Resolution: added material type with friction and resolution)
266Smooth avatar movement with motor (DONE)
267 Should motor update be all at taint-time? (Yes, DONE)
268 Fix avatar slowly sliding when standing (zero motion when stopped) (DONE)
269 (Resolution: added BSVMotor for avatar starting and stopping)
270llApplyImpulse()
271 Compare mass/movement in OS and SL. Calibrate actions. (DONE)
272 (Resolution: tested on SL and OS. AddForce scales the force for timestep)
273llSetBuoyancy() (DONE)
274 (Resolution: Bullet resets object gravity when added to world. Moved set gravity)
275Avatar density is WAY off. Compare and calibrate with what's in SL. (DONE)
276 (Resolution: set default density to 3.5 (from 60) which is closer to SL)